App.vue 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <template>
  2. <div id="root">
  3. <!-- <header role="banner">
  4. <div class="wrapper">
  5. <h1
  6. class="site-title"
  7. tabindex="0"
  8. >
  9. </h1>
  10. </div>
  11. </header> -->
  12. <section role="main-content">
  13. <div class="wrapper">
  14. <renderer :obj="myRenderer" :size="size">
  15. <scene :obj="myScene" @update:obj="handleScene">
  16. <!-- <orbit-controls ref="cam_controls" :position="init_cam_pos" :rotation="{ x: 0, y: 0, z: 0 }">
  17. <camera />
  18. </orbit-controls> -->
  19. <camera ref="camera" :position="init_cam_pos" :rotation="{x:0, y:0, z:0}" />
  20. <light :hex="0xffffff" :intensity="5" :position="{x:-100,y:150,z:50}" />
  21. <light :hex="0xffffff" :intensity="2" :position="{x:100,y:-150,z:-50}" :options="light_opts" />
  22. <animation :fn="animate" :speed="3" />
  23. <template v-if="debug">
  24. <cube :size="{x:30,y:1,z:1}" :position="{x:15,y:0,z:0}" :color="0x992222" />
  25. <cube :size="{x:1,y:30,z:1}" :position="{x:0,y:15,z:0}" :color="0x00BBFF" />
  26. <cube :size="{x:1,y:1,z:30}" :position="{x:0,y:0,z:15}" :color="0x17d100" />
  27. </template>
  28. <plan :size="{w:5000,h:5000}" :position="{x:0,y:0,z:0}" :color="0x1a1a1a" :rotation="{x:90,y:0,z:0}" />
  29. <template v-if="projects.length">
  30. <project
  31. v-for="(project, index) in projects"
  32. :key="project.id"
  33. :data="project"
  34. :len="projects.length"
  35. :index="index"
  36. />
  37. </template>
  38. </scene>
  39. </renderer>
  40. </div>
  41. </section>
  42. <footer />
  43. </div>
  44. </template>
  45. <script>
  46. import { mapState, mapActions } from 'vuex'
  47. import mixins from 'components/mixins'
  48. import * as THREE from 'three'
  49. import TWEEN from '@tweenjs/tween.js'
  50. import Plan from './components/objects/Plan'
  51. import Cube from './components/objects/Cube'
  52. import Project from './components/objects/Project'
  53. // const TWEEN = require('@tweenjs/tween.js')
  54. const _debug = true
  55. export default {
  56. metaInfo: {
  57. // if no subcomponents specify a metaInfo.title, this title will be used
  58. title: 'Home',
  59. // all titles will be injected into this template
  60. titleTemplate: '%s | Muntadas'
  61. },
  62. components: {
  63. Cube,
  64. Project,
  65. Plan
  66. },
  67. mixins: [mixins],
  68. data () {
  69. // const envcolor = 0xffffff
  70. let renderer = new THREE.WebGLRenderer({ alpha: false, antialias: true })
  71. renderer.setClearColor(0x000000, 0)
  72. renderer.shadowMap.enabled = true
  73. // scene obj is well overwrited but background color not visible
  74. let scene = new THREE.Scene()
  75. scene.background = new THREE.Color(0x1a1a1a)
  76. scene.fog = new THREE.Fog(scene.background, 50, 400)
  77. // console.log('myScene', scene)
  78. // let cameraHelper = new THREE.CameraHelper()
  79. // scene.add(cameraHelper)
  80. return {
  81. debug: _debug,
  82. myRenderer: renderer,
  83. myScene: scene,
  84. // mouse_start: new THREE.Vector2(),
  85. // mouse: new THREE.Vector2(),
  86. camera: null,
  87. mouse: new THREE.Vector2(),
  88. controls: {
  89. user_interact: false,
  90. mouse: new THREE.Vector2(),
  91. mouse_start: new THREE.Vector2(),
  92. lon: 0,
  93. lat: 0,
  94. lon_start: 0,
  95. lat_start: 0,
  96. phi: 0,
  97. theta: 0,
  98. cam_target: new THREE.Vector3(0, 0, 0)
  99. },
  100. // cam_controls: null,
  101. init_cam_pos: { x: 0, y: 10, z: 150 },
  102. raycaster: new THREE.Raycaster(),
  103. interactive_objects: [],
  104. light_opts: {
  105. castShadow: true
  106. }
  107. }
  108. },
  109. computed: {
  110. ...mapState({
  111. projects: state => state.Projects.projects
  112. }),
  113. size () {
  114. return {
  115. w: window.innerWidth,
  116. h: window.innerHeight
  117. }
  118. }
  119. },
  120. created () {
  121. if (!this.projects.length) {
  122. this.getProjects()
  123. }
  124. },
  125. mounted () {
  126. console.log('mounted', this)
  127. this.camera = this.$refs.camera.curObj
  128. // this.cam_controls = this.$refs.cam_controls.controls
  129. // console.log('cam_controls', this.cam_controls)
  130. // this.cam_controls = new THREE.PointerLockControls(this.camera)
  131. // console.log('this.cam_controls', this.cam_controls)
  132. this.updatedInteractiveObjects()
  133. document.addEventListener('mousedown', this.onDocMouseDown, false)
  134. document.addEventListener('mousemove', this.onDocMouseMove, false)
  135. document.addEventListener('mouseup', this.onDocMouseup, false)
  136. },
  137. updated () {
  138. this.updatedInteractiveObjects()
  139. },
  140. methods: {
  141. ...mapActions({
  142. getProjects: 'Projects/getProjects'
  143. }),
  144. handleScene (scene) {
  145. console.log('handlescene', scene)
  146. },
  147. updatedInteractiveObjects () {
  148. this.interactive_objects = []
  149. for (var i = 0; i < this.myScene.children.length; i++) {
  150. if (this.myScene.children[i].name === 'Project') {
  151. this.interactive_objects.push(this.myScene.children[i])
  152. }
  153. }
  154. // console.log('this.interactive_objects', this.interactive_objects)
  155. },
  156. onDocMouseDown (e) {
  157. // controls
  158. this.controls.mouse_start.x = e.clientX
  159. this.controls.mouse_start.y = e.clientY
  160. this.controls.lon_start = this.controls.lon
  161. this.controls.lat_start = this.controls.lat
  162. this.controls.user_interact = true
  163. },
  164. onDocMouseMove (e) {
  165. // RAY CASTING : update the mouse variable
  166. this.mouse.x = (e.clientX / window.innerWidth) * 2 - 1
  167. this.mouse.y = -(e.clientY / window.innerHeight) * 2 + 1
  168. // CONTROLS
  169. if (this.controls.user_interact) {
  170. // lon = ( onMouseDownMouseX - clientX ) * 0.1 + onMouseDownLon;
  171. this.controls.lon = (this.controls.mouse_start.x - e.clientX) * 0.1 + this.controls.lon_start
  172. // lat = ( clientY - onMouseDownMouseY ) * 0.1 + onMouseDownLat;
  173. this.controls.lat = (e.clientY - this.controls.mouse_start.y) * 0.1 + this.controls.lat_start
  174. }
  175. },
  176. onDocMouseup (e) {
  177. // console.log('onDocumentMouseup', e)
  178. // CONTROLS
  179. this.controls.user_interact = false
  180. // INTERACT
  181. // TODO: check if draging
  182. // update the picking ray with the camera and mouse position
  183. this.raycaster.setFromCamera(this.mouse, this.camera)
  184. // calculate objects intersecting the picking ray
  185. var intersects = this.raycaster.intersectObjects(this.interactive_objects)
  186. // console.log('intersects', intersects)
  187. // console.log('camera', this.camera)
  188. // console.log('TWEEN', TWEEN)
  189. let object, vnode, topos
  190. let cam = this.camera
  191. // let camControls = this.cam_controls
  192. let camPos = { ...this.camera.position }
  193. // console.log('camPos', camPos)
  194. if (intersects.length) {
  195. for (var i = 0; i < intersects.length; i++) {
  196. // intersects[i].object.material.color.set(0xff0000)
  197. object = intersects[i].object
  198. vnode = object.userData.vnode
  199. vnode.isOpened = true
  200. // this.cam_controls.target = object.position
  201. new TWEEN.Tween(this.controls.cam_target)
  202. .to(object.position, 400)
  203. .start()
  204. // cam.position.set({ x: camPos.x, y: camPos.y, z: camPos.z })
  205. // camControls.update()
  206. topos = { ...object.position }
  207. topos.z += 20
  208. topos.y = 5
  209. new TWEEN.Tween(camPos)
  210. .easing(TWEEN.Easing.Quadratic.InOut)
  211. .to(topos, 3000)
  212. .onUpdate(function () {
  213. // console.log('tween update', this._object)
  214. cam.position.set(this._object.x, this._object.y, this._object.z)
  215. // camControls.update()
  216. })
  217. .start()
  218. // console.log('tween', tween)
  219. break
  220. }
  221. } else {
  222. // new TWEEN.Tween(this.camera.position)
  223. // .to(this.init_cam_pos, 1000)
  224. // .start()
  225. }
  226. },
  227. animate (tt) {
  228. this.controls.lat = Math.max(-85, Math.min(85, this.controls.lat))
  229. this.controls.phi = this.deg2rad(90 - this.controls.lat)
  230. this.controls.theta = this.deg2rad(this.controls.lon)
  231. // if (this.controls.user_interact === false) {
  232. // this.controls.lon += 0.1
  233. // }
  234. this.controls.cam_target.x = 500 * Math.sin(this.controls.phi) * Math.cos(this.controls.theta)
  235. this.controls.cam_target.y = 500 * Math.cos(this.controls.phi)
  236. this.controls.cam_target.z = 500 * Math.sin(this.controls.phi) * Math.sin(this.controls.theta)
  237. if (this.camera && this.controls.user_interact) {
  238. this.camera.lookAt(this.controls.cam_target)
  239. }
  240. TWEEN.update()
  241. }
  242. }
  243. }
  244. </script>
  245. <style lang="scss" scoped>
  246. .container{
  247. // font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
  248. max-width: 1200px;
  249. }
  250. </style>