starting navigation inside projects

This commit is contained in:
2020-08-31 12:14:19 +02:00
parent 2a268a33b6
commit 643f857dd8
5 changed files with 178 additions and 117 deletions
+96 -61
View File
@@ -6,7 +6,7 @@
class="site-title" class="site-title"
tabindex="0" tabindex="0"
> >
Muntadas Muntadas
</h1> </h1>
</div> </div>
</header> </header>
@@ -33,7 +33,7 @@
<cube :size="{x:1,y:1,z:30}" :position="{x:0,y:0,z:15}" :color="0x17d100" /> <cube :size="{x:1,y:1,z:30}" :position="{x:0,y:0,z:15}" :color="0x17d100" />
</template> </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"> <template v-if="projects.length">
<project <project
@@ -101,7 +101,7 @@ export default {
var uniforms = { var uniforms = {
'topColor': { value: new THREE.Color(0x0077ff) }, 'topColor': { value: new THREE.Color(0x0077ff) },
'horizontColor': { value: new THREE.Color(0xffffff) }, 'horizontColor': { value: new THREE.Color(0xffffff) },
'waterColor': { value: new THREE.Color(0x0000aa) }, 'waterColor': { value: new THREE.Color(0x13719a) },
'bottomColor': { value: new THREE.Color(0x000000) }, 'bottomColor': { value: new THREE.Color(0x000000) },
'offset': { value: 33 }, 'offset': { value: 33 },
'wateroffset': { value: 33 }, 'wateroffset': { value: 33 },
@@ -124,20 +124,42 @@ export default {
fragmentShader: WaterFragment, fragmentShader: WaterFragment,
side: THREE.BackSide side: THREE.BackSide
}) })
var ground = new THREE.Mesh(bgGeo, waterMat) var water = new THREE.Mesh(bgGeo, waterMat)
ground.rotateZ(this.deg2rad(180)) water.rotateZ(this.deg2rad(180))
scene.add(ground) scene.add(water)
// SEA
// lights // lights
var sun = new THREE.PointLight(0xffffff, 5) var sun = new THREE.PointLight(0xfcfcf9, 2)
var sunGeo = new THREE.SphereBufferGeometry(1, 16, 8) sun.position.set(-150, 150, 110)
var sunMat = new THREE.MeshBasicMaterial({ color: 0xffffff })
sun.add(new THREE.Mesh(sunGeo, sunMat))
sun.position.set(-150, 150, 50)
sun.castShadows = true sun.castShadows = true
// sun.target.position.set(0, 0, 0) // sun.target.position.set(0, 0, 0)
scene.add(sun) scene.add(sun)
// scene.add(sun.target) // 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 { return {
debug: _debug, debug: _debug,
myRenderer: renderer, myRenderer: renderer,
@@ -148,9 +170,10 @@ export default {
mouse: new THREE.Vector2(), mouse: new THREE.Vector2(),
controls: { controls: {
user_interact: false, user_interact: false,
is_dragging: false,
mouse: new THREE.Vector2(), mouse: new THREE.Vector2(),
mouse_start: new THREE.Vector2(), mouse_start: new THREE.Vector2(),
lon: 0, lon: -91,
lat: 0, lat: 0,
lon_start: 0, lon_start: 0,
lat_start: 0, lat_start: 0,
@@ -161,6 +184,7 @@ export default {
// cam_controls: null, // cam_controls: null,
init_cam_pos: { x: 0, y: 10, z: 100 }, init_cam_pos: { x: 0, y: 10, z: 100 },
raycaster: new THREE.Raycaster(), raycaster: new THREE.Raycaster(),
interactive_objects_names: ['Project', 'ContentBlock'],
interactive_objects: [], interactive_objects: [],
light_opts: { light_opts: {
castShadow: true castShadow: true
@@ -182,10 +206,14 @@ export default {
if (!this.projects.length) { if (!this.projects.length) {
this.getProjects() this.getProjects()
} }
this.$env3d.scene = this.myScene
this.$env3d.renderer = this.myRenderer
}, },
mounted () { mounted () {
console.log('mounted', this) console.log('App mounted', this)
this.camera = this.$refs.camera.curObj console.log('App mounted $env3d', this.$env3d)
this.camera = this.$env3d.camera = this.$refs.camera.curObj
// this.cam_controls = this.$refs.cam_controls.controls // this.cam_controls = this.$refs.cam_controls.controls
// console.log('cam_controls', this.cam_controls) // console.log('cam_controls', this.cam_controls)
@@ -193,6 +221,8 @@ export default {
// console.log('this.cam_controls', this.cam_controls) // console.log('this.cam_controls', this.cam_controls)
this.updatedInteractiveObjects() 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('mousedown', this.onDocMouseDown, false)
document.addEventListener('mousemove', this.onDocMouseMove, false) document.addEventListener('mousemove', this.onDocMouseMove, false)
document.addEventListener('mouseup', this.onDocMouseup, false) document.addEventListener('mouseup', this.onDocMouseup, false)
@@ -208,16 +238,17 @@ export default {
console.log('handlescene', scene) console.log('handlescene', scene)
}, },
updatedInteractiveObjects () { updatedInteractiveObjects () {
console.log('updatedInteractiveObjects', this.myScene.children)
this.interactive_objects = [] this.interactive_objects = []
for (var i = 0; i < this.myScene.children.length; i++) { 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]) this.interactive_objects.push(this.myScene.children[i])
} }
} }
// console.log('this.interactive_objects', this.interactive_objects) // console.log('this.interactive_objects', this.interactive_objects)
}, },
onDocMouseDown (e) { onDocMouseDown (e) {
// controls // CONTROLS
this.controls.mouse_start.x = e.clientX this.controls.mouse_start.x = e.clientX
this.controls.mouse_start.y = e.clientY this.controls.mouse_start.y = e.clientY
this.controls.lon_start = this.controls.lon this.controls.lon_start = this.controls.lon
@@ -231,9 +262,7 @@ export default {
// CONTROLS // CONTROLS
if (this.controls.user_interact) { 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 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 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 this.controls.user_interact = false
// INTERACTIONS // INTERACTIONS
// TODO: check if draging this.updatedInteractiveObjects()
// 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 // check if draging
// let cam = this.camera if (Math.hypot(e.clientX - this.controls.mouse_start.x, e.clientY - this.controls.mouse_start.y) < 5) {
// let camPos = { ...this.camera.position } // update the picking ray with the camera and mouse position
if (intersects.length) { this.raycaster.setFromCamera(this.mouse, this.camera)
for (var i = 0; i < intersects.length; i++) { // calculate objects intersecting the picking ray
object = intersects[i].object var intersects = this.raycaster.intersectObjects(this.interactive_objects)
vnode = object.userData.vnode // console.log('intersects', intersects)
vnode.isOpened = true
// new TWEEN.Tween(this.controls.cam_target) let object, vnode, toPos
// .to(object.position, 400) 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() // .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()
// console.log('tween', tween)
break
} }
} else { } // end if dragging
// new TWEEN.Tween(this.camera.position)
// .to(this.init_cam_pos, 1000)
// .start()
}
}, },
animate (tt) { animate (tt) {
// CONTROLS
this.controls.lat = Math.max(-85, Math.min(85, this.controls.lat)) this.controls.lat = Math.max(-85, Math.min(85, this.controls.lat))
this.controls.phi = this.deg2rad(90 - this.controls.lat) this.controls.phi = this.deg2rad(90 - this.controls.lat)
this.controls.theta = this.deg2rad(this.controls.lon) this.controls.theta = this.deg2rad(this.controls.lon)
// if (this.controls.user_interact === false) { // if (this.controls.user_interact === false) {
// this.controls.lon += 0.1 // 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.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.y = 500 * Math.cos(this.controls.phi)
this.controls.cam_target.z = 500 * Math.sin(this.controls.phi) * Math.sin(this.controls.theta) 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) { // TWEENS
this.camera.lookAt(this.controls.cam_target)
}
TWEEN.update() TWEEN.update()
} }
} }
+33 -1
View File
@@ -1,8 +1,40 @@
// https://forum.vuejs.org/t/how-to-use-helper-functions-for-imported-modules-in-vuejs-vue-template/6266/5 // https://forum.vuejs.org/t/how-to-use-helper-functions-for-imported-modules-in-vuejs-vue-template/6266/5
export default { export default {
methods: { methods: {
deg2rad: function (deg) { deg2rad (deg) {
return deg * (Math.PI / 180) 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
View File
@@ -1,5 +1,5 @@
<template> <template>
<mesh name="ContentBlock" :position="position"> <mesh ref="block3d" name="ContentBlock" :position="position">
<geometry type="Box" :args="[size.x, size.y, size.z]" /> <geometry type="Box" :args="[size.x, size.y, size.z]" />
<material type="MeshLambert" :color="color" :options="opts" /> <material type="MeshLambert" :color="color" :options="opts" />
</mesh> </mesh>
@@ -13,27 +13,36 @@ export default {
// mixins: [Object3D], // mixins: [Object3D],
props: { prtPosition: Object, prtSize: Object }, props: { prtPosition: Object, prtSize: Object },
data: () => ({ data: () => ({
color: 0xffffff, block3d: null,
size: { x: 2, y: 2, z: 2 }, size: { x: 2, y: 3, z: 0.1 },
position: { x: 0, y: 5, z: 2 }, position: { x: 0, y: 0, z: 0 },
opts: { opts: {
side: THREE.DoubleSide side: THREE.DoubleSide
// wireframe: false, // wireframe: false,
// transparent: false, // transparent: false,
// opacity: 0.6 // opacity: 0.6
} },
isOpened: false
}), }),
computed: {
color () {
return this.opened ? 0xff0000 : 0x0000ff
}
},
created () { created () {
console.log('ContentBlock created', this.prtSize) console.log('ContentBlock created', this.prtSize)
this.position.x = this.prtPosition.x - this.prtSize.x / 2 + Math.random() * this.prtSize.x this.position.x = this.prtPosition.x - this.prtSize.x / 2 + Math.random() * this.prtSize.x
this.position.y = this.prtPosition.y - this.prtSize.y / 2 + Math.random() * this.prtSize.y
// console.log('this.position.y', this.position.y) this.position.z = this.prtPosition.z - this.prtSize.z / 2 + Math.random() * this.prtSize.z
if (Math.random() > 0.5) { },
this.position.y = this.prtPosition.y + this.prtSize.y / 2 + Math.random() * 20 mounted () {
} else { this.block3d = this.$refs.block3d.curObj
this.position.y = this.prtPosition.y - this.prtSize.y / 2 - Math.random() * 20 // this.block3d.castShadow = true
// this.block3d.receiveShadow = true
// record self references
this.block3d.userData = {
vnode: this
} }
// this.position.z = this.prtPosition.Z
} }
} }
</script> </script>
+20 -43
View File
@@ -22,6 +22,7 @@
import * as THREE from 'three' import * as THREE from 'three'
// import { Base } from 'vue-threejs' // import { Base } from 'vue-threejs'
import mixins from 'components/mixins'
import ContentBlock from 'components/objects/ContentBlock' import ContentBlock from 'components/objects/ContentBlock'
export default { export default {
@@ -29,17 +30,10 @@ export default {
components: { components: {
ContentBlock ContentBlock
}, },
// mixins: [Base], mixins: [mixins],
// props: { size: Object, texture: String, position: Object, color: Number }, // props: { size: Object, texture: String, position: Object, color: Number },
props: { data: Object, len: Number, index: Number }, props: { data: Object, len: Number, index: Number },
data: () => ({ data: () => ({
// mesh_opts: {
// userData: {
// test: 'Hello!'
// },
// receiveShadow: true,
// castShadow: true
// },
block3d: null, block3d: null,
block_opts: { block_opts: {
side: THREE.DoubleSide side: THREE.DoubleSide
@@ -52,7 +46,7 @@ export default {
label_opts: { label_opts: {
side: THREE.DoubleSide, side: THREE.DoubleSide,
// wireframe: false, // wireframe: false,
transparent: false transparent: true
// opacity: 0.6 // opacity: 0.6
// renderOrder: 0 // renderOrder: 0
}, },
@@ -79,13 +73,19 @@ export default {
// randomize size and positions // randomize size and positions
this.size.y = 100 + Math.random() * 90 this.size.y = 100 + Math.random() * 90
this.size.z = 10 + Math.random() * 30 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.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.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_position.z = this.position.z + this.size.z / 2 + 0.1
this.label_canvas = this.createLabelCanvas()
// console.log('this.label_canvas', this.label_canvas) // console.log('this.label_canvas', this.label_canvas)
},
mounted () {
// console.log('project mounted', this)
// mesh options // mesh options
this.block3d = this.$refs.block3d.curObj this.block3d = this.$refs.block3d.curObj
this.block3d.castShadow = true this.block3d.castShadow = true
@@ -95,38 +95,15 @@ export default {
vnode: this vnode: this
} }
this.label3d = this.$refs.label3d.curObj this.label3d = this.$refs.label3d.curObj
},
mounted () {
// console.log('project mounted', this)
}, // light
methods: { // console.log('project mounted', this.$env3d)
createLabelCanvas () { // var light = new THREE.AmbientLight(0xbf1a1a) // soft white light
// console.log('createLabelCanvas', this.data.Titre) // this.$env3d.scene.add(light)
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
}
} }
// ,
// methods: {
//
// }
} }
</script> </script>
+8
View File
@@ -14,6 +14,14 @@ import 'assets/css/app.scss'
Vue.use(Meta) Vue.use(Meta)
Vue.use(VueThreejs) 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, router) // done. Returns an unsync callback fn
// sync(store) // sync(store)