forked from trent_larson/crowd-funder-for-time-pwa
- Fix Vue template syntax in App.vue by using proper event handler format - Update Vite config to properly handle ESM imports and crypto modules - Add manual chunks for better code splitting - Improve environment variable handling in vite-env.d.ts - Fix TypeScript linting errors in App.vue
111 lines
2.9 KiB
JavaScript
111 lines
2.9 KiB
JavaScript
// 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 }
|