113 lines
3.9 KiB
JavaScript
113 lines
3.9 KiB
JavaScript
import * as THREE from '/app/thirdparty/Three/three.module.js'
|
|
|
|
if(!app.helpers) app.helpers = {}
|
|
/**
|
|
* Mixing add-in methods to your view instance.
|
|
* All of this should not be a helper, but inherited this from WindozDomContent, but not my framework anymore.
|
|
*/
|
|
app.helpers.helpers3D = {
|
|
|
|
agentFromJSON(id, desc){
|
|
let obj, wrapper
|
|
if(desc.type === 'Mesh') {
|
|
const geom = new THREE[desc.geometry.type](...(desc.geometry.args || []))
|
|
const matType = desc.material.type
|
|
const matProps = { ...desc.material }
|
|
for (const key in matProps) {
|
|
if (key === 'type') continue
|
|
if (typeof matProps[key] === 'string' && THREE[matProps[key]] !== undefined) {
|
|
matProps[key] = THREE[matProps[key]]
|
|
}
|
|
}
|
|
// convert color strings like "0xffffaa" to numbers
|
|
if (typeof matProps.color === 'string' && matProps.color.startsWith('0x')) {
|
|
matProps.color = parseInt(matProps.color)
|
|
}
|
|
const mat = new THREE[matType](matProps)
|
|
|
|
|
|
obj = new THREE.Mesh(geom, mat)
|
|
if(desc.translate){
|
|
wrapper = new THREE.Object3D()
|
|
wrapper.add(obj)
|
|
obj.position.x = desc.translate[0]
|
|
obj.position.y = desc.translate[1]
|
|
obj.position.z = desc.translate[2]
|
|
}
|
|
|
|
} 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 => {
|
|
const childId = (childDesc.childSuffix) ? `${id}_${childDesc.childSuffix}` : ''
|
|
obj.add(this.agentFromJSON(childId, childDesc))
|
|
})
|
|
}
|
|
if(wrapper) obj=wrapper
|
|
obj.name = id
|
|
return obj
|
|
},
|
|
|
|
cameraAutoFrame(object, camera, offset = 1.5, controls) {
|
|
const box = new THREE.Box3().setFromObject(object)
|
|
const size = new THREE.Vector3()
|
|
const center = new THREE.Vector3()
|
|
box.getSize(size)
|
|
box.getCenter(center)
|
|
|
|
const maxDim = Math.max(size.x, size.y, size.z)
|
|
const fov = camera.fov * Math.PI / 180
|
|
let cameraZ = maxDim / (2 * Math.tan(fov / 2)) * offset
|
|
|
|
camera.position.copy(center)
|
|
camera.position.z += cameraZ
|
|
camera.lookAt(center)
|
|
|
|
if (controls) {
|
|
controls.target.copy(center)
|
|
controls.update()
|
|
}
|
|
},
|
|
|
|
getObjectCenter(object) {
|
|
object.updateWorldMatrix(true, true)
|
|
const box = new THREE.Box3().setFromObject(object)
|
|
const center = new THREE.Vector3()
|
|
box.getCenter(center) // world coords
|
|
return center
|
|
},
|
|
|
|
makePivotAtGeomCenter(object, scene) {
|
|
object.updateWorldMatrix(true, true)
|
|
const box = new THREE.Box3().setFromObject(object)
|
|
const centerW = box.getCenter(new THREE.Vector3())
|
|
|
|
// Create pivot at world center of the object
|
|
const pivot = new THREE.Object3D()
|
|
pivot.position.copy(centerW)
|
|
pivot.matrixAutoUpdate = true
|
|
scene.add(pivot)
|
|
|
|
// Compute the center in the object's local space
|
|
const centerLocal = object.worldToLocal(centerW.clone())
|
|
|
|
// Shift the object so its center sits at its own origin
|
|
object.position.sub(centerLocal)
|
|
|
|
// Reparent under the pivot (world pose preserved)
|
|
pivot.add(object)
|
|
|
|
return pivot
|
|
},
|
|
|
|
} |