@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
133 lines (123 loc) • 4.39 kB
text/typescript
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);
}
}