@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
425 lines (424 loc) • 14.5 kB
JavaScript
"use strict";
import { TypeAssert } from "./../../engine/poly/Assert";
import { PhysicsRBDColliderType, PhysicsRBDType, CorePhysicsAttribute } from "./PhysicsAttribute";
import { Vector3, Quaternion } from "three";
import { CorePhysicsLoaded } from "./CorePhysics";
import { createPhysicsSphere } from "./shapes/RBDSphere";
import { createPhysicsCuboid } from "./shapes/RBDCuboid";
import { createPhysicsCapsule } from "./shapes/RBDCapsule";
import { createPhysicsCone } from "./shapes/RBDCone";
import { createPhysicsCylinder } from "./shapes/RBDCylinder";
import { createPhysicsTriMesh } from "./shapes/RBDTrimesh";
import { createPhysicsConvexHull } from "./shapes/ConvexHull";
import { createPhysicsHeightField } from "./shapes/HeightField";
import { touchRBDProperties, touchRBDProperty } from "../reactivity/RBDPropertyReactivity";
import { OBJECT_TRANSFORM_PROPERTIES, touchObjectProperties } from "../reactivity/ObjectPropertyReactivity";
import { removeFromParent } from "../../engine/poly/PolyOnObjectsAddRemoveHooksController";
import { getRBDFromId, object3DFromRBD } from "./PhysicsWorld";
export var RBDProperty = /* @__PURE__ */ ((RBDProperty2) => {
RBDProperty2["ANGULAR_VELOCITY"] = "angVel";
RBDProperty2["LINEAR_VELOCITY"] = "linVel";
RBDProperty2["POSITION"] = "position";
RBDProperty2["ROTATION"] = "rotation";
RBDProperty2["LINEAR_DAMPING"] = "linearDamping";
RBDProperty2["ANGULAR_DAMPING"] = "angularDamping";
RBDProperty2["IS_SLEEPING"] = "isSleeping";
RBDProperty2["IS_MOVING"] = "isMoving";
return RBDProperty2;
})(RBDProperty || {});
const tmpV3 = new Vector3();
const currentPos = new Vector3();
const currentLinearVelocity = new Vector3();
const currentAngularVelocity = new Vector3();
const newPos = new Vector3();
const newLinearVelocity = new Vector3();
const newAngularVelocity = new Vector3();
const currentQuaternion = new Quaternion();
const newQuaternion = new Quaternion();
const linearVelocity = new Vector3();
const angularVelocity = new Vector3();
const physicsRBDByRBDHandle = /* @__PURE__ */ new Map();
const worldByRBD = /* @__PURE__ */ new WeakMap();
function _createRBDFromDescAndId(world, rigidBodyDesc, rbdId) {
const rigidBody = world.createRigidBody(rigidBodyDesc);
const handle = rigidBody.handle;
worldByRBD.set(rigidBody, world);
physicsRBDByRBDHandle.set(handle, rigidBody);
return rigidBody;
}
function _createRBDFromDescAndObject(world, rigidBodyDesc, object) {
const rbdId = CorePhysicsAttribute.getRBDId(object);
const rigidBody = _createRBDFromDescAndId(world, rigidBodyDesc, rbdId);
CorePhysicsAttribute.setRBDHandle(object, rigidBody.handle);
return rigidBody;
}
function _createRBDFromAttributes(options) {
const { PhysicsLib: PhysicsLib2, world, object, rigidBodyById, objectsByRBD, newRBDIds } = options;
const type = CorePhysicsAttribute.getRBDType(object);
if (type == null) {
return;
}
const rbdType = PhysicsRBDTypeToRigidBodyType(type);
if (rbdType == null) {
return;
}
const linearDamping = CorePhysicsAttribute.getLinearDamping(object);
const angularDamping = CorePhysicsAttribute.getAngularDamping(object);
linearVelocity.set(0, 0, 0);
angularVelocity.set(0, 0, 0);
CorePhysicsAttribute.getLinearVelocity(object, linearVelocity);
CorePhysicsAttribute.getAngularVelocity(object, angularVelocity);
const gravityScale = CorePhysicsAttribute.getGravityScale(object);
const canSleep = CorePhysicsAttribute.getCanSleep(object);
const rigidBodyDesc = new PhysicsLib2.RigidBodyDesc(rbdType);
rigidBodyDesc.setTranslation(object.position.x, object.position.y, object.position.z);
rigidBodyDesc.setRotation(object.quaternion);
rigidBodyDesc.setLinvel(linearVelocity.x, linearVelocity.y, linearVelocity.z);
rigidBodyDesc.setAngvel(angularVelocity);
if (linearDamping != null) {
rigidBodyDesc.setLinearDamping(linearDamping);
}
if (angularDamping != null) {
rigidBodyDesc.setAngularDamping(angularDamping);
}
if (gravityScale != null) {
rigidBodyDesc.setGravityScale(gravityScale);
}
if (canSleep != null) {
rigidBodyDesc.setCanSleep(canSleep);
}
const rigidBody = _createRBDFromDescAndObject(world, rigidBodyDesc, object);
objectsByRBD.set(rigidBody, object);
const rbdId = CorePhysicsAttribute.getRBDId(object);
if (rbdId) {
rigidBodyById.set(rbdId, rigidBody);
newRBDIds.add(rbdId);
}
return rigidBody;
}
function _createColliderDesc(PhysicsLib2, object) {
const colliderType = CorePhysicsAttribute.getColliderType(object);
if (!(colliderType != null)) {
return;
}
const colliderDesc = PhysicsRBDCollider(PhysicsLib2, colliderType, object);
if (!colliderDesc) {
console.error("no collider", object);
return;
}
const restitution = CorePhysicsAttribute.getRestitution(object);
const friction = CorePhysicsAttribute.getFriction(object);
const density = CorePhysicsAttribute.getDensity(object);
if (restitution != null) {
colliderDesc.setRestitution(restitution);
}
if (friction != null) {
colliderDesc.setFriction(friction);
}
if (density != null) {
colliderDesc.setDensity(density);
}
return colliderDesc;
}
export function _getRBDFromId(rbdId) {
const rigidBody = getRBDFromId(rbdId);
if (!rigidBody) {
return;
}
return object3DFromRBD(rigidBody);
}
export function _getRBDFromObject(object) {
const handle = CorePhysicsAttribute.getRBDHandle(object);
if (handle == null) {
return;
}
return physicsRBDByRBDHandle.get(handle);
}
export function _getPhysicsWorldFromRBD(object) {
const rbd = _getRBDFromObject(object);
if (!rbd) {
return;
}
return worldByRBD.get(rbd);
}
export function _physicsRBDDelete(scene, object) {
const handle = CorePhysicsAttribute.getRBDHandle(object);
if (handle == null) {
return;
}
const body = physicsRBDByRBDHandle.get(handle);
if (!body) {
return;
}
const world = worldByRBD.get(body);
if (!world) {
return;
}
world.removeRigidBody(body);
worldByRBD.delete(body);
physicsRBDByRBDHandle.delete(handle);
CorePhysicsAttribute.deleteRBDHandle(object);
removeFromParent(scene, object);
}
export function _physicsCreateRBD(options) {
const { PhysicsLib: PhysicsLib2, world, object, rigidBodyById, objectsByRBD, newRBDIds } = options;
const rigidBody = _createRBDFromAttributes({
PhysicsLib: PhysicsLib2,
world,
object,
rigidBodyById,
objectsByRBD,
newRBDIds
});
if (!rigidBody) {
for (const child of object.children) {
_physicsCreateRBD({ PhysicsLib: PhysicsLib2, world, rigidBodyById, objectsByRBD, object: child, newRBDIds });
}
return;
}
let childrenColliderDesc;
if (object.children.length > 0) {
object.traverse((child) => {
if (child != object) {
const childColliderDesc = _createColliderDesc(PhysicsLib2, child);
if (childColliderDesc) {
childrenColliderDesc = childrenColliderDesc || [];
childrenColliderDesc.push({ object: child, colliderDesc: childColliderDesc });
}
}
});
}
const colliderDesc = _createColliderDesc(PhysicsLib2, object);
if (!(colliderDesc || childrenColliderDesc)) {
return;
}
if (colliderDesc) {
world.createCollider(colliderDesc, rigidBody);
}
if (childrenColliderDesc) {
for (const childCollider of childrenColliderDesc) {
const collider = world.createCollider(childCollider.colliderDesc, rigidBody);
tmpV3.copy(childCollider.object.position);
childCollider.object.localToWorld(tmpV3);
object.worldToLocal(tmpV3);
collider.setTranslationWrtParent(tmpV3);
collider.setRotationWrtParent(childCollider.object.quaternion);
}
}
}
export function physicsUpdateRBD(object, rigidBody) {
const position = rigidBody.translation();
const rotation = rigidBody.rotation();
object.position.set(position.x, position.y, position.z);
object.quaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
object.updateMatrix();
updateRBDRefs(object);
}
const SIM_PROPERTIES = [
"angVel" /* ANGULAR_VELOCITY */,
"linVel" /* LINEAR_VELOCITY */,
"position" /* POSITION */,
"rotation" /* ROTATION */,
"isSleeping" /* IS_SLEEPING */,
"isMoving" /* IS_MOVING */
];
function updateRBDRefs(object) {
touchRBDProperties(object, SIM_PROPERTIES);
touchObjectProperties(object, OBJECT_TRANSFORM_PROPERTIES);
}
export function _physicsRBDApplyImpulse(object, impulse) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
body.applyImpulse(impulse, true);
}
export function _physicsRBDApplyImpulseAtPoint(object, impulse, point) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
body.applyImpulseAtPoint(impulse, point, true);
}
export function _physicsRBDApplyTorqueImpulse(object, impulse) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
body.applyTorqueImpulse(impulse, true);
}
export function _physicsRBDAddForce(object, force) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
body.addForce(force, true);
}
export function _physicsRBDAddForceAtPoint(object, force, point) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
body.addForceAtPoint(force, point, true);
}
export function _physicsRBDAddTorque(object, torque) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
body.addTorque(torque, true);
}
export function _physicsRBDResetAll(object, wakeup) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
body.resetForces(wakeup);
body.resetTorques(wakeup);
body.setLinvel({ x: 0, y: 0, z: 0 }, wakeup);
body.setAngvel({ x: 0, y: 0, z: 0 }, wakeup);
}
export function _physicsRBDResetForces(object, wakeup) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
body.resetForces(wakeup);
}
export function _physicsRBDResetTorques(object, wakeup) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
body.resetTorques(wakeup);
}
export function _setPhysicsRBDPosition(object, targetPosition, lerp) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
const translateFunc = body.isKinematic() ? body.setNextKinematicTranslation.bind(body) : body.setTranslation.bind(body);
if (lerp < 1) {
const rbdPosition = body.translation();
currentPos.set(rbdPosition.x, rbdPosition.y, rbdPosition.z);
newPos.copy(targetPosition);
currentPos.lerp(newPos, lerp);
translateFunc(currentPos, true);
} else {
translateFunc(targetPosition, true);
}
touchRBDProperty(object, "position" /* POSITION */);
}
export function _setPhysicsRBDRotation(object, targetQuaternion, lerp) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
const rotateFunc = body.isKinematic() ? body.setNextKinematicRotation.bind(body) : body.setRotation.bind(body);
if (lerp < 1) {
const rbdRotation = body.rotation();
currentQuaternion.set(rbdRotation.x, rbdRotation.y, rbdRotation.z, rbdRotation.w);
newQuaternion.copy(currentQuaternion);
currentQuaternion.slerp(newQuaternion, lerp);
rotateFunc(currentQuaternion, true);
} else {
rotateFunc(targetQuaternion, true);
}
touchRBDProperty(object, "rotation" /* ROTATION */);
}
export function _setPhysicsRBDLinearVelocity(object, targetVelocity, lerp) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
if (lerp < 1) {
const rbdLinearVelocity = body.linvel();
currentLinearVelocity.set(rbdLinearVelocity.x, rbdLinearVelocity.y, rbdLinearVelocity.z);
newLinearVelocity.copy(targetVelocity);
currentLinearVelocity.lerp(newPos, lerp);
body.setLinvel(currentLinearVelocity, true);
} else {
body.setLinvel(targetVelocity, true);
}
touchRBDProperty(object, "linVel" /* LINEAR_VELOCITY */);
}
export function _setPhysicsRBDAngularVelocity(object, targetVelocity, lerp) {
const body = _getRBDFromObject(object);
if (!body) {
console.warn("no rbd found");
return;
}
if (lerp < 1) {
const rbdAngularVelocity = body.angvel();
currentAngularVelocity.set(rbdAngularVelocity.x, rbdAngularVelocity.y, rbdAngularVelocity.z);
newAngularVelocity.copy(targetVelocity);
currentAngularVelocity.lerp(newPos, lerp);
body.setAngvel(currentAngularVelocity, true);
} else {
body.setAngvel(targetVelocity, true);
}
touchRBDProperty(object, "angVel" /* ANGULAR_VELOCITY */);
}
function PhysicsRBDTypeToRigidBodyType(type) {
var _a;
const RigidBodyType2 = (_a = CorePhysicsLoaded()) == null ? void 0 : _a.RigidBodyType;
if (!RigidBodyType2) {
return;
}
switch (type) {
case PhysicsRBDType.FIXED: {
return RigidBodyType2.Fixed;
}
case PhysicsRBDType.DYNAMIC: {
return RigidBodyType2.Dynamic;
}
case PhysicsRBDType.KINEMATIC_POS: {
return RigidBodyType2.KinematicPositionBased;
}
case PhysicsRBDType.KINEMATIC_VEL: {
return RigidBodyType2.KinematicVelocityBased;
}
}
TypeAssert.unreachable(type);
}
function PhysicsRBDCollider(PhysicsLib2, colliderType, object) {
switch (colliderType) {
case PhysicsRBDColliderType.CAPSULE: {
return createPhysicsCapsule(PhysicsLib2, object);
}
case PhysicsRBDColliderType.CUBOID: {
return createPhysicsCuboid(PhysicsLib2, object);
}
case PhysicsRBDColliderType.CONE: {
return createPhysicsCone(PhysicsLib2, object);
}
case PhysicsRBDColliderType.CONVEX_HULL: {
return createPhysicsConvexHull(PhysicsLib2, object);
}
case PhysicsRBDColliderType.TRIMESH: {
return createPhysicsTriMesh(PhysicsLib2, object);
}
case PhysicsRBDColliderType.CYLINDER: {
return createPhysicsCylinder(PhysicsLib2, object);
}
case PhysicsRBDColliderType.SPHERE: {
return createPhysicsSphere(PhysicsLib2, object);
}
case PhysicsRBDColliderType.HEIGHT_FIELD: {
return createPhysicsHeightField(PhysicsLib2, object);
}
}
TypeAssert.unreachable(colliderType);
}