// from https://medium.com/nicasource/building-an-interactive-web-portfolio-with-vue-three-js-part-three-implementing-three-js-452cb375ef80 import * as TWEEN from '@tweenjs/tween.js' import * as THREE from 'three' import { createCamera } from './components/camera.js' import { createLights } from './components/lights.js' import { createScene } from './components/scene.js' import { loadLandmarks } from './components/objects/landmarks.js' import { createTerrain } from './components/objects/terrain.js' import { Loop } from './systems/Loop.js' import { Resizer } from './systems/Resizer.js' import { createControls } from './systems/controls.js' import { createRenderer } from './systems/renderer.js' const COLOR1 = '#dddddd' const COLOR2 = '#0055aa' class World { constructor(container, vue) { this.PLATFORM_BORDER = 5 this.PLATFORM_EDGE_FOR_UNKNOWNS = 10 this.PLATFORM_SIZE = 100 // note that the loadLandmarks calculations may still assume 100 this.update = this.update.bind(this) this.vue = vue // Instances of camera, scene, and renderer this.camera = createCamera() this.scene = createScene(COLOR2) this.renderer = createRenderer() // necessary for models, says https://threejs.org/docs/index.html#examples/en/loaders/GLTFLoader this.renderer.outputColorSpace = THREE.SRGBColorSpace this.light = null this.lights = [] this.bushes = [] // Initialize Loop this.loop = new Loop(this.camera, this.scene, this.renderer) container.append(this.renderer.domElement) // Orbit Controls const controls = createControls(this.camera, this.renderer.domElement) // Light Instance, with optional light helper const { light } = createLights(COLOR1) // Terrain Instance const terrain = createTerrain({ color: COLOR1, height: this.PLATFORM_SIZE + this.PLATFORM_BORDER * 2, width: this.PLATFORM_SIZE + this.PLATFORM_BORDER * 2 + this.PLATFORM_EDGE_FOR_UNKNOWNS * 2 }) this.loop.updatables.push(controls) this.loop.updatables.push(light) this.loop.updatables.push(terrain) this.scene.add(light, terrain) loadLandmarks(vue, this, this.scene, this.loop) requestAnimationFrame(this.update) // Responsive handler const resizer = new Resizer(container, this.camera, this.renderer) resizer.onResize = () => { this.render() } } update(time) { TWEEN.update(time) this.lights.forEach((light) => { light.updateMatrixWorld() light.target.updateMatrixWorld() }) this.lights.forEach((bush) => { bush.updateMatrixWorld() }) requestAnimationFrame(this.update) } render() { // draw a single frame this.renderer.render(this.scene, this.camera) } // Animation handlers start() { this.loop.start() } stop() { this.loop.stop() } setExposedWorldProperties(key, value) { this.vue.setWorldProperty(key, value) } } export { World }