UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

133 lines (123 loc) 4.39 kB
import type {Collider, Cuboid} from '@dimforge/rapier3d-compat'; import {Object3D, Vector3} from 'three'; import { CorePhysicsAttribute, PhysicsRBDColliderType, physicsAttribNameLive, PhysicsRBDCuboidAttribute, } from '../PhysicsAttribute'; import {_getRBDFromObject} from '../PhysicsRBD'; import {PhysicsLib} from '../CorePhysics'; import {touchRBDProperty} from '../../reactivity/RBDPropertyReactivity'; import {coreObjectClassFactory} from '../../geometry/CoreObjectFactory'; const EXPECTED_TYPE = PhysicsRBDColliderType.CUBOID; export enum RBDCuboidProperty { SIZES = 'sizes', } const tmp = new Vector3(); let _currentSizes = new Vector3(); let _targetSizes = new Vector3(); let _targetHalfSizes = new Vector3(); let _originalSizes = new Vector3(); const SAFETY_OFFSET = 0.001; const attribSizeLiveByObject: WeakMap<Object3D, Vector3> = new WeakMap(); function _getAttribSizeLiveByObject(object3D: Object3D) { let v = attribSizeLiveByObject.get(object3D); if (!v) { v = new Vector3(); attribSizeLiveByObject.set(object3D, v); } return v; } export function createPhysicsCuboid(PhysicsLib: PhysicsLib, object: Object3D) { CorePhysicsAttribute.getCuboidSizes(object, tmp); const size = CorePhysicsAttribute.getCuboidSize(object); tmp.multiplyScalar(size * 0.5); tmp.multiply(object.scale); const borderRadius = CorePhysicsAttribute.getBorderRadius(object); if (borderRadius <= 0) { return PhysicsLib.ColliderDesc.cuboid(tmp.x, tmp.y, tmp.z); } else { // We reduce the size by the border radius, // but we also need to make sure that the size will not be 0 const minDim = Math.min(tmp.x, tmp.y, tmp.z); const borderRadiusAdjusted = Math.min(borderRadius, minDim - SAFETY_OFFSET); tmp.subScalar(borderRadiusAdjusted); return PhysicsLib.ColliderDesc.roundCuboid(tmp.x, tmp.y, tmp.z, borderRadiusAdjusted); } } const attributeSizesLive = physicsAttribNameLive(PhysicsRBDCuboidAttribute.SIZES); export function currentSizes(object: Object3D, collider: Collider, target: Vector3): void { const coreObjectClass = coreObjectClassFactory(object); let result: Vector3 | undefined = coreObjectClass.attribValue(object, attributeSizesLive, 0, target) as | Vector3 | undefined; if (result == null) { const shape = collider.shape as Cuboid; const v = shape.halfExtents; target.set(v.x, v.y, v.z).multiplyScalar(2); coreObjectClass.setAttribute(object, attributeSizesLive, new Vector3().copy(target)); } } export function _getPhysicsRBDCuboidSizes(object: Object3D, target: Vector3): void { const body = _getRBDFromObject(object); if (!body) { console.warn('no rbd found'); return; } const colliderType = CorePhysicsAttribute.getColliderType(object); if (colliderType == null || colliderType != EXPECTED_TYPE) { return; } const collider = body.collider(0); if (!collider) { return; } currentSizes(object, collider, target); } export function _setPhysicsRBDCuboidProperty( object: Object3D, targetSizes: Vector3, targetSize: number, lerp: number, updateObjectMatrix: boolean ) { const body = _getRBDFromObject(object); if (!body) { console.warn('no rbd found'); return; } const colliderType = CorePhysicsAttribute.getColliderType(object); if (colliderType == null || colliderType != EXPECTED_TYPE) { return; } const collidersCount = body.numColliders(); CorePhysicsAttribute.getCuboidSizes(object, _originalSizes); const originalSize = CorePhysicsAttribute.getCuboidSize(object); _originalSizes.multiplyScalar(originalSize); for (let i = 0; i < collidersCount; i++) { const collider = body.collider(i); if (!collider) { return; } _targetSizes.copy(targetSizes).multiplyScalar(targetSize); if (lerp < 1) { currentSizes(object, collider, _currentSizes); _targetSizes.lerp(_currentSizes, 1 - lerp); } // update radius on shape and object const v = _getAttribSizeLiveByObject(object); v.copy(_targetSizes); const coreObjectClass = coreObjectClassFactory(object); coreObjectClass.setAttribute(object, attributeSizesLive, v); touchRBDProperty(object, RBDCuboidProperty.SIZES); // update scale object.scale.copy(_targetSizes).divide(_originalSizes); if (updateObjectMatrix) { object.updateMatrix(); } // update rbd in the end, so that we scale size *.5 last _targetHalfSizes.copy(_targetSizes).multiplyScalar(0.5); collider.setHalfExtents(_targetHalfSizes); } }