146 lines
5.1 KiB
JavaScript
146 lines
5.1 KiB
JavaScript
import * as THREE from './three.module.js'
|
|
import { OrbitControls } from './OrbitControls.module.js'
|
|
import * as TWEEN from './tween.module.js'
|
|
|
|
export class Threetobus{
|
|
|
|
constructor(){
|
|
this.cameras = {}
|
|
this.renderers = []
|
|
}
|
|
|
|
initScene(){
|
|
// Scene
|
|
this.scene = new THREE.Scene()
|
|
|
|
this.grid = new THREE.GridHelper(20, 20, 0x8888AA, 0x8888AA)
|
|
this.scene.add(this.grid)
|
|
|
|
// Cameras
|
|
this.cameras.camPerspective = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
|
|
this.cameras.camPerspective.position.set(3, 3, 5)
|
|
const aspect = window.innerWidth / window.innerHeight
|
|
const frustumSize = 10
|
|
this.cameras.cam2Dtop = new THREE.OrthographicCamera(
|
|
-frustumSize * aspect / 2,
|
|
frustumSize * aspect / 2,
|
|
frustumSize / 2,
|
|
-frustumSize / 2,
|
|
0.1,
|
|
1000
|
|
)
|
|
this.cameras.cam2Dtop.position.set(0, 100, 0)
|
|
this.cameras.cam2Dtop.lookAt(0, 0, 0)
|
|
|
|
// Lights
|
|
const light = new THREE.DirectionalLight(0xffffff, 1)
|
|
light.position.set(5, 5, 5)
|
|
light.intensity = 2
|
|
this.scene.add(light)
|
|
this.scene.add(new THREE.AmbientLight(0xffffff, 0.4))
|
|
|
|
}
|
|
|
|
startRendering(canvasEl, mode){
|
|
let renderEngine
|
|
if(mode=='2D'){
|
|
renderEngine = new RenderingEngine(canvasEl, this.scene, this.cameras.cam2Dtop)
|
|
} else if(mode=='3D') {
|
|
renderEngine = new RenderingEngine(canvasEl, this.scene, this.cameras.camPerspective)
|
|
renderEngine.addControls()
|
|
} else console.error('Unknown rendering mode !')
|
|
|
|
renderEngine.render()
|
|
this.renderers.push(renderEngine)
|
|
}
|
|
|
|
|
|
buildFromJSON(desc){
|
|
let obj
|
|
if(desc.type === 'Mesh') {
|
|
const geom = new THREE[desc.geometry.type](...(desc.geometry.args || []))
|
|
const mat = new THREE[desc.material.type]( desc.material.color ? { color: desc.material.color } : {} )
|
|
obj = new THREE.Mesh(geom, mat)
|
|
} else if(desc.type === 'Group') {
|
|
obj = new THREE.Group()
|
|
} else {
|
|
throw new Error("Unknown type: " + desc.type)
|
|
}
|
|
|
|
// Apply transforms
|
|
if(desc.position) obj.position.set(...desc.position)
|
|
if(desc.rotation) obj.rotation.set(...desc.rotation)
|
|
if(desc.scale) obj.scale.set(...desc.scale)
|
|
|
|
// Recursively add children
|
|
if(desc.children) {
|
|
desc.children.forEach(childDesc => {
|
|
obj.add(this.buildFromJSON(childDesc))
|
|
})
|
|
}
|
|
|
|
return obj
|
|
}
|
|
|
|
|
|
smoothRelMove(options){
|
|
// options: object, dX, dY, dZ, delay, easing, easingMode
|
|
// easings: Linear, Quadratic, Cubic, Quartic, Quintic, Sinusoidal, Exponential, Circular, Elastic, Back, Bounce
|
|
// easingMode: In → starts slow, accelerates towards the end.
|
|
// Out → starts fast, decelerates smoothly.
|
|
// InOut → slow at both ends, faster in the middle.
|
|
options.easing = options.easing ? options.easing : 'Quadratic'
|
|
options.easingMode = options.easingMode ? options.easingMode : 'InOut'
|
|
|
|
new TWEEN.Tween(options.object.position)
|
|
.to({ x: options.object.position.x + options.dX,
|
|
y: options.object.position.y + options.dY,
|
|
z: options.object.position.z + options.dZ,
|
|
}, options.delay)
|
|
.easing(TWEEN.Easing[options.easing][options.easingMode])
|
|
.start()
|
|
}
|
|
}
|
|
|
|
class RenderingEngine{
|
|
constructor(canvasEl, scene, camera){
|
|
this.canvasEl = canvasEl
|
|
this.scene = scene
|
|
this.renderer = new THREE.WebGLRenderer({ antialias: true, canvas: this.canvasEl })
|
|
this.camera = camera
|
|
}
|
|
|
|
addControls(){
|
|
this.controls = new OrbitControls(this.camera, this.canvasEl)
|
|
window.addEventListener('resize', () => {
|
|
this.camera.aspect = window.innerWidth / window.innerHeight
|
|
this.camera.updateProjectionMatrix()
|
|
this.renderer.setSize(window.innerWidth, window.innerHeight)
|
|
})
|
|
}
|
|
|
|
render() {
|
|
TWEEN.update()
|
|
if(this.resizeRendererToDisplaySize()) {
|
|
this.camera.aspect = this.renderer.domElement.clientWidth / this.canvasEl.clientHeight
|
|
this.camera.updateProjectionMatrix()
|
|
}
|
|
this.renderer.render(this.scene, this.camera)
|
|
requestAnimationFrame(this.render.bind(this))
|
|
}
|
|
|
|
|
|
resizeRendererToDisplaySize() {
|
|
const width = this.canvasEl.clientWidth
|
|
const height = this.canvasEl.clientHeight
|
|
if (this.canvasEl.width !== width || this.canvasEl.height !== height) {
|
|
this.renderer.setSize(width, height, false)
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
// Make this module available to common JS
|
|
if(!app.LoadedModules) app.LoadedModules = {}
|
|
app.LoadedModules.Threetobus = Threetobus |