123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- <template>
- <div id="root">
- <header role="banner">
- <div class="wrapper">
- <h1
- class="site-title"
- tabindex="0"
- >
- Media Architecture Projects <sup>ALPHA</sup>
- </h1>
- <h2>Antoni Muntadas</h2>
- </div>
- </header>
- <section role="main-content">
- <div class="wrapper">
- <renderer :obj="myRenderer" :size="size">
- <scene :obj="myScene" @update:obj="handleScene">
- <!-- <SkyBox :size="{x:500,y:500,z:500}" :position="{x:0,y:0,z:0}" :color="0x992222" /> -->
- <!-- <orbit-controls ref="cam_controls" :position="init_cam_pos" :rotation="{ x: 0, y: 0, z: 0 }">
- <camera />
- </orbit-controls> -->
- <camera ref="camera" :position="init_cam_pos" :rotation="init_cam_rot" />
- <!-- <light :hex="0xffffff" :intensity="5" :position="{x:-100,y:150,z:50}" />
- <light :hex="0xffffff" :intensity="2" :position="{x:100,y:-150,z:-50}" :options="light_opts" /> -->
- <animation :fn="animate" :speed="3" />
- <template v-if="debug">
- <cube :size="{x:30,y:1,z:1}" :position="{x:15,y:0,z:0}" :color="0x992222" />
- <cube :size="{x:1,y:30,z:1}" :position="{x:0,y:15,z:0}" :color="0x00BBFF" />
- <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="0x133f52" :rotation="{x:90,y:0,z:0}" />
- <template v-if="projects.length">
- <project
- v-for="(project) in projects"
- :key="project.id"
- :id="project.id"
- />
- </template>
- </scene>
- </renderer>
- <Content v-if="content_data" :data="content_data" @onClose="onCloseContent" />
- </div>
- </section>
- <footer />
- </div>
- </template>
- <script>
- import { mapState, mapActions } from 'vuex'
- import mixins from 'components/mixins'
- import * as THREE from 'three'
- import TWEEN from '@tweenjs/tween.js'
- import BgVertex from 'assets/glsl/BgVertex'
- import SkyFragment from 'assets/glsl/SkyFragment'
- import WaterFragment from 'assets/glsl/WaterFragment'
- import Ground from './components/objects/Ground'
- import Cube from './components/objects/Cube'
- import Project from './components/objects/Project'
- import Content from './components/Content'
- // const TWEEN = require('@tweenjs/tween.js')
- const _debug = false
- export default {
- metaInfo: {
- // if no subcomponents specify a metaInfo.title, this title will be used
- title: 'Home',
- // all titles will be injected into this template
- titleTemplate: '%s | Muntadas'
- },
- components: {
- Cube,
- Project,
- Ground,
- Content
- },
- mixins: [mixins],
- data () {
- // const envcolor = 0xffffff
- let renderer = new THREE.WebGLRenderer({ alpha: false, antialias: true })
- renderer.setClearColor(0x000000, 0)
- // renderer.shadowMap.enabled = true
- // // to antialias the shadow
- // renderer.shadowMap.type = THREE.PCFSoftShadowMap
- // scene obj is well overwrited but background color not visible
- let scene = new THREE.Scene()
- scene.background = new THREE.Color(0x1a1a1a)
- // scene.fog = new THREE.Fog(new THREE.Color(0xffffff), 50, 200)
- // console.log('myScene', scene)
- // scene.add(new THREE.AxesHelper(500))
- // SKYDOME
- // https://github.com/mrdoob/three.js/blob/master/examples/webgl_lights_hemisphere.html
- // https://gamedevelopment.tutsplus.com/tutorials/a-beginners-guide-to-coding-graphics-shaders--cms-23313
- var uniforms = {
- 'topColor': { value: new THREE.Color(0x0077ff) },
- 'horizontColor': { value: new THREE.Color(0xffffff) },
- 'waterColor': { value: new THREE.Color(0x13719a) },
- 'bottomColor': { value: new THREE.Color(0x000000) },
- 'offset': { value: 33 },
- 'wateroffset': { value: 33 },
- 'exponent': { value: 0.6 },
- 'waterexponent': { value: 0.6 }
- }
- // SphereBufferGeometry(radius : Float, widthSegments : Integer, heightSegments : Integer, phiStart : Float, phiLength : Float, thetaStart : Float, thetaLength : Float)
- var bgGeo = new THREE.SphereBufferGeometry(700, 32, 15, 0, 2 * Math.PI, 0, 0.5 * Math.PI)
- var skyMat = new THREE.ShaderMaterial({
- uniforms: uniforms,
- vertexShader: BgVertex,
- fragmentShader: SkyFragment,
- side: THREE.BackSide
- })
- var sky = new THREE.Mesh(bgGeo, skyMat)
- scene.add(sky)
- var waterMat = new THREE.ShaderMaterial({
- uniforms: uniforms,
- vertexShader: BgVertex,
- fragmentShader: WaterFragment,
- side: THREE.BackSide
- })
- var water = new THREE.Mesh(bgGeo, waterMat)
- water.rotateZ(this.deg2rad(180))
- scene.add(water)
- // SEA
- // lights
- var ambient = new THREE.AmbientLight(0xfcfcf9, 1)
- scene.add(ambient)
- // var sun = new THREE.PointLight(0xfcfcf9, 1)
- // // var sun = new THREE.DirectionalLight(0xfcfcf9, 2)
- // sun.position.set(-150, 200, 110)
- // // sun.castShadow = true
- // // sun.shadow.bias = -0.0001
- // // sun.shadow.mapSize.width = 1024 * 4
- // // sun.shadow.mapSize.height = 1024 * 4
- // // sun.target.position.set(0, 0, 0)
- // scene.add(sun)
- // // scene.add(sun.target)
- // var sun2 = new THREE.PointLight(0xfcfcf9, 1)
- // sun2.position.set(150, -200, -110)
- // // sun2.castShadow = 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.castShadow = 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.castShadow = true
- // // sun4.target.position.set(0, 0, 0)
- // scene.add(sun4)
- // // scene.add(sun2.target)
- // RETURN DATA
- return {
- debug: _debug,
- myRenderer: renderer,
- myScene: scene,
- // mouse_start: new THREE.Vector2(),
- // mouse: new THREE.Vector2(),
- camera: null,
- mouse: new THREE.Vector2(),
- controls: {
- user_interact: false,
- is_dragging: false,
- mouse: new THREE.Vector2(),
- mouse_start: new THREE.Vector2(),
- lon: -90,
- lat: -5.73,
- lon_start: 0,
- lat_start: 0,
- phi: 0,
- theta: 0,
- cam_target: new THREE.Vector3(0, 0, 0)
- },
- // cam_controls: null,
- init_cam_pos: { x: 0, y: 10, z: 100 },
- // init_cam_pos: { x: 0, y: 150, z: 0 },
- init_cam_rot: { x: this.deg2rad(180), y: 0, z: 0 },
- raycaster: new THREE.Raycaster(),
- interactive_objects_names: ['Project', 'Content'],
- interactive_objects: [],
- // light_opts: {
- // castShadow: true
- // },
- opened_vnode: null,
- content_data: null
- }
- },
- computed: {
- ...mapState({
- projects: state => state.Projects.projects
- }),
- size () {
- return {
- w: window.innerWidth,
- h: window.innerHeight
- }
- }
- },
- // watch: {
- // projects (n, o) {
- // console.log(`watch projects new, old`, n, o)
- // }
- // },
- created () {
- if (!this.projects.length) {
- this.loadProjects()
- }
- this.$env3d.scene = this.myScene
- this.$env3d.renderer = this.myRenderer
- },
- mounted () {
- 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)
- // this.cam_controls = new THREE.PointerLockControls(this.camera)
- // 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)
- },
- updated () {
- this.updatedInteractiveObjects()
- },
- methods: {
- ...mapActions({
- loadProjects: 'Projects/loadProjects'
- }),
- handleScene (scene) {
- 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.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
- this.controls.mouse_start.x = e.clientX
- this.controls.mouse_start.y = e.clientY
- this.controls.lon_start = this.controls.lon
- this.controls.lat_start = this.controls.lat
- this.controls.user_interact = true
- },
- onDocMouseMove (e) {
- // RAY CASTING : update the mouse variable
- this.mouse.x = (e.clientX / window.innerWidth) * 2 - 1
- this.mouse.y = -(e.clientY / window.innerHeight) * 2 + 1
- // CONTROLS
- if (this.controls.user_interact) {
- this.controls.lon = (this.controls.mouse_start.x - e.clientX) * 0.1 + this.controls.lon_start
- this.controls.lat = (e.clientY - this.controls.mouse_start.y) * 0.1 + this.controls.lat_start
- // console.log(`lon: ${this.controls.lon}, lat: ${this.controls.lat}`)
- }
- },
- onDocMouseup (e) {
- console.log('onDocumentMouseup', e)
- // CONTROLS
- this.controls.user_interact = false
- // check if event is not a classic html link
- if (e.target.className === 'close-btn') {
- // console.log('close-btn: vnode', this.opened_vnode)
- // this.opened_vnode.isOpened = false
- return
- }
- // INTERACTIONS
- this.updatedInteractiveObjects()
- // check if not 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)
- // if we clicked on 3Dobject
- if (intersects.length) {
- let cam = this.camera
- console.log('onDocMouseUp intersects', intersects)
- let object = intersects[0].object
- console.log('object[0].name', object.name)
- let vnode = object.userData.vnode
- if (object.name === 'Content' && vnode.isOpened) {
- this.content_data = vnode.data
- }
- // close precedent vnode
- if (this.opened_vnode && this.opened_vnode.$options._componentTag === 'ContentBlock') {
- // console.log('opened_vnode', this.opened_vnode)
- this.opened_vnode.isOpened = false
- }
- // open current vnode
- // vnode.isOpened = true
- vnode.open()
- // recorde vnode as precedent vnode
- this.opened_vnode = vnode
- // get new camera target pos
- let toPos = { ...object.position }
- if (object.name === 'Content') {
- this.controls.lat = 0
- switch (vnode.face) {
- case 'left':
- toPos.x += 4
- this.controls.lon = 180
- break
- // case 'back':
- // toPos.z += 4
- // break
- case 'right':
- toPos.x -= 4
- this.controls.lon = 0
- break
- // case 'front':
- // toPos.z -= 4
- // break
- }
- // TODO: we need to update lon and lat accordingly when chaging camera orientation
- // let controls = this.controls
- // let rad2deg = this.rad2deg
- // let camTarget = { ...this.controls.cam_target }
- new TWEEN.Tween(this.controls.cam_target)
- .easing(TWEEN.Easing.Quadratic.InOut)
- .to(object.position, 2000)
- .start()
- } else if (object.name === 'Project') {
- toPos.z *= 0.5
- toPos.y = 2
- }
- // toPos.y = 5
- let camPos = { ...this.camera.position }
- 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)
- })
- .start()
- // console.log('tween', tween)
- // break
- // }
- } else {
- // new TWEEN.Tween(this.camera.position)
- // .to(this.init_cam_pos, 1000)
- // .start()
- }
- } // end if dragging
- },
- animate (tt) {
- // CONTROLS
- if (this.controls.user_interact) {
- 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.camera.lookAt(this.controls.cam_target)
- }
- // TWEENS
- TWEEN.update()
- },
- onCloseContent () {
- this.content_data = null
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .container{
- // font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
- max-width: 1200px;
- }
- </style>
|