import * as RE from 'rogue-engine'; import * as THREE from 'three'; import * as CANNON from 'cannon-es'; import CannonShape from './CannonShape'; export default class CannonTrimesh extends CannonShape { shape: CANNON.Trimesh; @RE.props.vector3() sizeOffset: THREE.Vector3 = new THREE.Vector3(1, 1, 1); private _collisionResponse = true; @RE.props.checkbox() get collisionResponse() { return this._collisionResponse; }; set collisionResponse(value: boolean) { this._collisionResponse = value; if (!this.shape) return; this.shape.collisionResponse = value; }; worldScale = new THREE.Vector3(); worldPos = new THREE.Vector3(); tmpVec0 = new CANNON.Vec3(); tmpVec1 = new CANNON.Vec3(); tmpVec2 = new CANNON.Vec3(); tmpQuat0 = new CANNON.Vec3(); createShape() { if (!(this.object3d instanceof THREE.Mesh)) return; this.object3d.updateWorldMatrix(true, true); this.object3d.getWorldScale(this.worldScale); this.object3d.getWorldPosition(this.worldPos); this.object3d.getWorldQuaternion(this.worldQuaternion); const mesh = this.object3d; let geometry = (mesh.geometry as THREE.BufferGeometry); geometry.computeBoundingSphere(); geometry.normalizeNormals(); if (geometry.index !== null) { const nonIndexedGeo = geometry.toNonIndexed(); geometry.copy(nonIndexedGeo); } const vertices = this.getVertices(geometry); if (!vertices.length) return; const indices = Object.keys(vertices).map(Number); this.shape = new CANNON.Trimesh(vertices as unknown as number[], indices); this.shape.collisionResponse = this._collisionResponse; } getVertices (geometry: THREE.BufferGeometry) { const position = geometry.attributes.position; const vertices = new Float32Array(position.count * 3); for (let i = 0; i < position.count; i++) { vertices[i * 3] = position.getX(i) * this.worldScale.x; vertices[i * 3 + 1] = position.getY(i) * this.worldScale.y; vertices[i * 3 + 2] = position.getZ(i) * this.worldScale.z; } return vertices; } } RE.registerComponent(CannonTrimesh);