Browse Source

starting navigation inside projects

Bachir Soussi Chiadmi 3 years ago
parent
commit
643f857dd8
5 changed files with 180 additions and 119 deletions
  1. 98 63
      src/App.vue
  2. 33 1
      src/components/mixins.js
  3. 21 12
      src/components/objects/ContentBlock.vue
  4. 20 43
      src/components/objects/Project.vue
  5. 8 0
      src/index.js

+ 98 - 63
src/App.vue

@@ -6,7 +6,7 @@
           class="site-title"
           tabindex="0"
         >
-        Muntadas
+          Muntadas
         </h1>
       </div>
     </header>
@@ -33,7 +33,7 @@
               <cube :size="{x:1,y:1,z:30}" :position="{x:0,y:0,z:15}" :color="0x17d100" />
             </template>
 
-            <ground :size="{w:5000,h:5000}" :position="{x:0,y:0,z:0}" :color="0x000011" :rotation="{x:90,y:0,z:0}" />
+            <ground :size="{w:5000,h:5000}" :position="{x:0,y:0,z:0}" :color="0x133f52" :rotation="{x:90,y:0,z:0}" />
 
             <template v-if="projects.length">
               <project
@@ -101,7 +101,7 @@ export default {
     var uniforms = {
       'topColor': { value: new THREE.Color(0x0077ff) },
       'horizontColor': { value: new THREE.Color(0xffffff) },
-      'waterColor': { value: new THREE.Color(0x0000aa) },
+      'waterColor': { value: new THREE.Color(0x13719a) },
       'bottomColor': { value: new THREE.Color(0x000000) },
       'offset': { value: 33 },
       'wateroffset': { value: 33 },
@@ -124,20 +124,42 @@ export default {
       fragmentShader: WaterFragment,
       side: THREE.BackSide
     })
-    var ground = new THREE.Mesh(bgGeo, waterMat)
-    ground.rotateZ(this.deg2rad(180))
-    scene.add(ground)
+    var water = new THREE.Mesh(bgGeo, waterMat)
+    water.rotateZ(this.deg2rad(180))
+    scene.add(water)
+
+    // SEA
 
     // lights
-    var sun = new THREE.PointLight(0xffffff, 5)
-    var sunGeo = new THREE.SphereBufferGeometry(1, 16, 8)
-    var sunMat = new THREE.MeshBasicMaterial({ color: 0xffffff })
-    sun.add(new THREE.Mesh(sunGeo, sunMat))
-    sun.position.set(-150, 150, 50)
+    var sun = new THREE.PointLight(0xfcfcf9, 2)
+    sun.position.set(-150, 150, 110)
     sun.castShadows = true
     // sun.target.position.set(0, 0, 0)
     scene.add(sun)
     // scene.add(sun.target)
+
+    var sun2 = new THREE.PointLight(0xfcfcf9, 0.6)
+    sun2.position.set(150, 150, 110)
+    sun2.castShadows = true
+    // sun2.target.position.set(0, 0, 0)
+    scene.add(sun2)
+    // scene.add(sun2.target)
+
+    var sun3 = new THREE.PointLight(0xfcfcf9, 0.6)
+    sun3.position.set(0, 150, -110)
+    sun3.castShadows = true
+    // sun3.target.position.set(0, 0, 0)
+    scene.add(sun3)
+    // scene.add(sun2.target)
+
+    var sun4 = new THREE.PointLight(0xfcfcf9, 0.6)
+    sun4.position.set(0, -150, -110)
+    sun4.castShadows = true
+    // sun4.target.position.set(0, 0, 0)
+    scene.add(sun4)
+    // scene.add(sun2.target)
+
+    // RETURN DATA
     return {
       debug: _debug,
       myRenderer: renderer,
@@ -148,9 +170,10 @@ export default {
       mouse: new THREE.Vector2(),
       controls: {
         user_interact: false,
+        is_dragging: false,
         mouse: new THREE.Vector2(),
         mouse_start: new THREE.Vector2(),
-        lon: 0,
+        lon: -91,
         lat: 0,
         lon_start: 0,
         lat_start: 0,
@@ -161,6 +184,7 @@ export default {
       // cam_controls: null,
       init_cam_pos: { x: 0, y: 10, z: 100 },
       raycaster: new THREE.Raycaster(),
+      interactive_objects_names: ['Project', 'ContentBlock'],
       interactive_objects: [],
       light_opts: {
         castShadow: true
@@ -182,10 +206,14 @@ export default {
     if (!this.projects.length) {
       this.getProjects()
     }
+    this.$env3d.scene = this.myScene
+    this.$env3d.renderer = this.myRenderer
   },
   mounted () {
-    console.log('mounted', this)
-    this.camera = this.$refs.camera.curObj
+    console.log('App mounted', this)
+    console.log('App mounted $env3d', this.$env3d)
+
+    this.camera = this.$env3d.camera = this.$refs.camera.curObj
     // this.cam_controls = this.$refs.cam_controls.controls
     // console.log('cam_controls', this.cam_controls)
 
@@ -193,6 +221,8 @@ export default {
     // console.log('this.cam_controls', this.cam_controls)
 
     this.updatedInteractiveObjects()
+    // CONTROLS
+    // https://blogs.perficient.com/2020/05/21/3d-camera-movement-in-three-js-i-learned-the-hard-way-so-you-dont-have-to/
     document.addEventListener('mousedown', this.onDocMouseDown, false)
     document.addEventListener('mousemove', this.onDocMouseMove, false)
     document.addEventListener('mouseup', this.onDocMouseup, false)
@@ -208,16 +238,17 @@ export default {
       console.log('handlescene', scene)
     },
     updatedInteractiveObjects () {
+      console.log('updatedInteractiveObjects', this.myScene.children)
       this.interactive_objects = []
       for (var i = 0; i < this.myScene.children.length; i++) {
-        if (this.myScene.children[i].name === 'Project') {
+        if (this.interactive_objects_names.indexOf(this.myScene.children[i].name) !== -1) {
           this.interactive_objects.push(this.myScene.children[i])
         }
       }
       // console.log('this.interactive_objects', this.interactive_objects)
     },
     onDocMouseDown (e) {
-      // controls
+      // CONTROLS
       this.controls.mouse_start.x = e.clientX
       this.controls.mouse_start.y = e.clientY
       this.controls.lon_start = this.controls.lon
@@ -231,9 +262,7 @@ export default {
 
       // CONTROLS
       if (this.controls.user_interact) {
-        // lon = ( onMouseDownMouseX - clientX ) * 0.1 + onMouseDownLon;
         this.controls.lon = (this.controls.mouse_start.x - e.clientX) * 0.1 + this.controls.lon_start
-        // lat = ( clientY - onMouseDownMouseY ) * 0.1 + onMouseDownLat;
         this.controls.lat = (e.clientY - this.controls.mouse_start.y) * 0.1 + this.controls.lat_start
       }
     },
@@ -243,65 +272,71 @@ export default {
       this.controls.user_interact = false
 
       // INTERACTIONS
-      // TODO: check if draging
-      // update the picking ray with the camera and mouse position
-      this.raycaster.setFromCamera(this.mouse, this.camera)
-      // calculate objects intersecting the picking ray
-      var intersects = this.raycaster.intersectObjects(this.interactive_objects)
-      // console.log('intersects', intersects)
-
-      let object, vnode//, toPos
-      // let cam = this.camera
-      // let camPos = { ...this.camera.position }
-      if (intersects.length) {
-        for (var i = 0; i < intersects.length; i++) {
-          object = intersects[i].object
-          vnode = object.userData.vnode
-          vnode.isOpened = true
-
-          // new TWEEN.Tween(this.controls.cam_target)
-          //   .to(object.position, 400)
-          //   .start()
-          //
-          // toPos = { ...object.position }
-          // toPos.z += 20
-          // toPos.y = 5
-          // new TWEEN.Tween(camPos)
-          //   .easing(TWEEN.Easing.Quadratic.InOut)
-          //   .to(toPos, 3000)
-          //   .onUpdate(function () {
-          //     // console.log('tween update', this._object)
-          //     cam.position.set(this._object.x, this._object.y, this._object.z)
-          //     // camControls.update()
-          //   })
-          //   .start()
+      this.updatedInteractiveObjects()
+
+      // check if draging
+      if (Math.hypot(e.clientX - this.controls.mouse_start.x, e.clientY - this.controls.mouse_start.y) < 5) {
+        // update the picking ray with the camera and mouse position
+        this.raycaster.setFromCamera(this.mouse, this.camera)
+        // calculate objects intersecting the picking ray
+        var intersects = this.raycaster.intersectObjects(this.interactive_objects)
+        // console.log('intersects', intersects)
 
-          // console.log('tween', tween)
-          break
+        let object, vnode, toPos
+        let cam = this.camera
+        let camPos = { ...this.camera.position }
+        if (intersects.length) {
+          console.log('onDocMouseUp intersects', intersects)
+          for (var i = 0; i < intersects.length; i++) {
+            object = intersects[i].object
+            vnode = object.userData.vnode
+            vnode.isOpened = true
+
+            // new TWEEN.Tween(this.controls.cam_target)
+            //   .to(object.position, 400)
+            //   .start()
+            //
+            toPos = { ...object.position }
+            if (object.name === 'ContentBlock') {
+              toPos.z += 1
+            }
+            // toPos.y = 5
+            new TWEEN.Tween(camPos)
+              .easing(TWEEN.Easing.Quadratic.InOut)
+              .to(toPos, 3000)
+              .onUpdate(function () {
+                // console.log('tween update', this._object)
+                cam.position.set(this._object.x, this._object.y, this._object.z)
+                // camControls.update()
+              })
+              .start()
+
+            // console.log('tween', tween)
+            break
+          }
+        } else {
+          // new TWEEN.Tween(this.camera.position)
+          //   .to(this.init_cam_pos, 1000)
+          //   .start()
         }
-      } else {
-        // new TWEEN.Tween(this.camera.position)
-        //   .to(this.init_cam_pos, 1000)
-        //   .start()
-      }
+      } // end if dragging
     },
     animate (tt) {
+      // CONTROLS
       this.controls.lat = Math.max(-85, Math.min(85, this.controls.lat))
       this.controls.phi = this.deg2rad(90 - this.controls.lat)
       this.controls.theta = this.deg2rad(this.controls.lon)
-
       // if (this.controls.user_interact === false) {
       //   this.controls.lon += 0.1
       // }
-
       this.controls.cam_target.x = 500 * Math.sin(this.controls.phi) * Math.cos(this.controls.theta)
       this.controls.cam_target.y = 500 * Math.cos(this.controls.phi)
       this.controls.cam_target.z = 500 * Math.sin(this.controls.phi) * Math.sin(this.controls.theta)
+      // if (this.camera && this.controls.user_interact) {
+      this.camera.lookAt(this.controls.cam_target)
+      // }
 
-      if (this.camera && this.controls.user_interact) {
-        this.camera.lookAt(this.controls.cam_target)
-      }
-
+      // TWEENS
       TWEEN.update()
     }
   }

+ 33 - 1
src/components/mixins.js

@@ -1,8 +1,40 @@
 // https://forum.vuejs.org/t/how-to-use-helper-functions-for-imported-modules-in-vuejs-vue-template/6266/5
 export default {
   methods: {
-    deg2rad: function (deg) {
+    deg2rad (deg) {
       return deg * (Math.PI / 180)
+    },
+    createLabelCanvas (text, fontsize) {
+      // console.log('createLabelCanvas', this.data.Titre)
+      const size = fontsize
+      const borderSize = 5
+      let lines = text.split('\n')
+      const ctx = document.createElement('canvas').getContext('2d')
+      const font = `${size}px bold noto_sans,sans-serif`
+      ctx.font = font
+      // measure how long the name will be
+      const doubleBorderSize = borderSize * 2
+      let width = 0
+      for (var i = 0; i < lines.length; i++) {
+        width = Math.max(width, ctx.measureText(lines[i]).width + doubleBorderSize)
+      }
+      const height = size * lines.length + doubleBorderSize
+      this.label_size = { x: width / 21, y: height / 21 }
+      ctx.canvas.width = width
+      ctx.canvas.height = height
+
+      // need to set font again after resizing canvas
+      ctx.font = font
+      ctx.textBaseline = 'top'
+
+      // ctx.fillStyle = 'red'
+      // ctx.fillRect(0, 0, width, height)
+      ctx.fillStyle = 'black'
+      for (var j = 0; j < lines.length; j++) {
+        ctx.fillText(lines[j], borderSize, borderSize + j * size)
+      }
+      // console.log('createLabelCanvas', ctx)
+      return ctx.canvas
     }
   }
 }

+ 21 - 12
src/components/objects/ContentBlock.vue

@@ -1,5 +1,5 @@
 <template>
-  <mesh name="ContentBlock" :position="position">
+  <mesh ref="block3d" name="ContentBlock" :position="position">
     <geometry type="Box" :args="[size.x, size.y, size.z]" />
     <material type="MeshLambert" :color="color" :options="opts" />
   </mesh>
@@ -13,27 +13,36 @@ export default {
   // mixins: [Object3D],
   props: { prtPosition: Object, prtSize: Object },
   data: () => ({
-    color: 0xffffff,
-    size: { x: 2, y: 2, z: 2 },
-    position: { x: 0, y: 5, z: 2 },
+    block3d: null,
+    size: { x: 2, y: 3, z: 0.1 },
+    position: { x: 0, y: 0, z: 0 },
     opts: {
       side: THREE.DoubleSide
       // wireframe: false,
       // transparent: false,
       // opacity: 0.6
-    }
+    },
+    isOpened: false
   }),
+  computed: {
+    color () {
+      return this.opened ? 0xff0000 : 0x0000ff
+    }
+  },
   created () {
     console.log('ContentBlock created', this.prtSize)
     this.position.x = this.prtPosition.x - this.prtSize.x / 2 + Math.random() * this.prtSize.x
-
-    // console.log('this.position.y', this.position.y)
-    if (Math.random() > 0.5) {
-      this.position.y = this.prtPosition.y + this.prtSize.y / 2 + Math.random() * 20
-    } else {
-      this.position.y = this.prtPosition.y - this.prtSize.y / 2 - Math.random() * 20
+    this.position.y = this.prtPosition.y - this.prtSize.y / 2 + Math.random() * this.prtSize.y
+    this.position.z = this.prtPosition.z - this.prtSize.z / 2 + Math.random() * this.prtSize.z
+  },
+  mounted () {
+    this.block3d = this.$refs.block3d.curObj
+    // this.block3d.castShadow = true
+    // this.block3d.receiveShadow = true
+    // record self references
+    this.block3d.userData = {
+      vnode: this
     }
-    // this.position.z = this.prtPosition.Z
   }
 }
 </script>

+ 20 - 43
src/components/objects/Project.vue

@@ -22,6 +22,7 @@
 import * as THREE from 'three'
 // import { Base } from 'vue-threejs'
 
+import mixins from 'components/mixins'
 import ContentBlock from 'components/objects/ContentBlock'
 
 export default {
@@ -29,17 +30,10 @@ export default {
   components: {
     ContentBlock
   },
-  // mixins: [Base],
+  mixins: [mixins],
   // props: { size: Object, texture: String, position: Object, color: Number },
   props: { data: Object, len: Number, index: Number },
   data: () => ({
-    // mesh_opts: {
-    //   userData: {
-    //     test: 'Hello!'
-    //   },
-    //   receiveShadow: true,
-    //   castShadow: true
-    // },
     block3d: null,
     block_opts: {
       side: THREE.DoubleSide
@@ -52,7 +46,7 @@ export default {
     label_opts: {
       side: THREE.DoubleSide,
       // wireframe: false,
-      transparent: false
+      transparent: true
       // opacity: 0.6
       // renderOrder: 0
     },
@@ -79,13 +73,19 @@ export default {
     // randomize size and positions
     this.size.y = 100 + Math.random() * 90
     this.size.z = 10 + Math.random() * 30
-    this.position.x = this.label_position.x = (-this.len + 1) / 2 * (this.size.x + 5) + (this.size.x + 5) * this.index
+
+    this.position.x = (-this.len + 1) / 2 * (this.size.x + 5) + (this.size.x + 5) * this.index
     this.position.y = -1 * this.size.y / 2 + 10 + Math.random() * 30// -10 + Math.random() * this.size.y / 2
     this.position.z = -10 + Math.random() * 10
-    this.label_position.y = 5
+
+    this.label_canvas = this.createLabelCanvas(this.data.Titre.replace(/ /g, '\n').toUpperCase(), 48)
+    this.label_position.x = this.position.x - this.size.x / 2 + this.label_size.x / 2 + 1
+    this.label_position.y = this.position.y + this.size.y / 2 - this.label_size.y / 2 - 1
     this.label_position.z = this.position.z + this.size.z / 2 + 0.1
-    this.label_canvas = this.createLabelCanvas()
     // console.log('this.label_canvas', this.label_canvas)
+  },
+  mounted () {
+    // console.log('project mounted', this)
     // mesh options
     this.block3d = this.$refs.block3d.curObj
     this.block3d.castShadow = true
@@ -95,38 +95,15 @@ export default {
       vnode: this
     }
     this.label3d = this.$refs.label3d.curObj
-  },
-  mounted () {
-    // console.log('project mounted', this)
-
-  },
-  methods: {
-    createLabelCanvas () {
-      // console.log('createLabelCanvas', this.data.Titre)
-      const size = 48
-      const borderSize = 5
-      const ctx = document.createElement('canvas').getContext('2d')
-      const font = `${size}px bold noto_sans`
-      ctx.font = font
-      // measure how long the name will be
-      const doubleBorderSize = borderSize * 2
-      const width = ctx.measureText(this.data.Titre).width + doubleBorderSize
-      const height = size + doubleBorderSize
-      this.label_size = { x: width / 21, y: height / 21 }
-      ctx.canvas.width = width
-      ctx.canvas.height = height
-
-      // need to set font again after resizing canvas
-      ctx.font = font
-      ctx.textBaseline = 'top'
 
-      ctx.fillStyle = 'white'
-      ctx.fillRect(0, 0, width, height)
-      ctx.fillStyle = 'black'
-      ctx.fillText(this.data.Titre, borderSize, borderSize)
-      // console.log('createLabelCanvas', ctx)
-      return ctx.canvas
-    }
+    // light
+    // console.log('project mounted', this.$env3d)
+    // var light = new THREE.AmbientLight(0xbf1a1a) // soft white light
+    // this.$env3d.scene.add(light)
   }
+  // ,
+  // methods: {
+  //
+  // }
 }
 </script>

+ 8 - 0
src/index.js

@@ -14,6 +14,14 @@ import 'assets/css/app.scss'
 Vue.use(Meta)
 Vue.use(VueThreejs)
 
+// https://stackoverflow.com/a/43193455
+var env3d = {
+  scene: null,
+  renderer: null,
+  camera: null
+}
+Vue.prototype.$env3d = env3d
+
 // sync(store, router) // done. Returns an unsync callback fn
 // sync(store)