Revision control
++ // Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
++ // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
++ // SPDX-FileCopyrightText: Copyright (c) 2008-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
++ // SPDX-License-Identifier: Apache-2.0
++
++ #include "foundation/PxMathUtils.h"
++ #include "foundation/PxQuat.h"
++ #include "geometry/PxSphereGeometry.h"
++ #include "geometry/PxBoxGeometry.h"
++ #include "geometry/PxCapsuleGeometry.h"
++ #include "geometry/PxConvexMeshGeometry.h"
++ #include "geometry/PxPlaneGeometry.h"
++ #include "extensions/PxRigidBodyExt.h"
++ #include "extensions/PxSimpleFactory.h"
++ #include "PxPhysics.h"
++ #include "PxScene.h"
++ #include "PxRigidStatic.h"
++ #include "PxRigidStatic.h"
++ #include "PxRigidDynamic.h"
++ #include "PxShape.h"
++
++ #include "foundation/PxUtilities.h"
++ #include "foundation/PxInlineArray.h"
++
++ using namespace physx;
++
++ static bool isDynamicGeometry(PxGeometryType::Enum type)
++ {
++ return type == PxGeometryType::eBOX
++ || type == PxGeometryType::eSPHERE
++ || type == PxGeometryType::eCAPSULE
++ || type == PxGeometryType::eCONVEXCORE
++ || type == PxGeometryType::eCUSTOM
++ || type == PxGeometryType::eCONVEXMESH;
++ }
++
++ namespace physx
++ {
++ PxRigidDynamic* PxCreateDynamic(PxPhysics& sdk,
++ const PxTransform& transform,
++ PxShape& shape,
++ PxReal density)
++ {
++ PX_CHECK_AND_RETURN_NULL(transform.isValid(), "PxCreateDynamic: transform is not valid.");
++
++ PxRigidDynamic* actor = sdk.createRigidDynamic(transform);
++ if(actor)
++ {
++ if(!actor->attachShape(shape))
++ {
++ actor->release();
++ return NULL;
++ }
++ if(!PxRigidBodyExt::updateMassAndInertia(*actor, density))
++ {
++ actor->release();
++ return NULL;
++ }
++ }
++ return actor;
++ }
++
++ PxRigidDynamic* PxCreateDynamic(PxPhysics& sdk,
++ const PxTransform& transform,
++ const PxGeometry& geometry,
++ PxMaterial& material,
++ PxReal density,
++ const PxTransform& shapeOffset)
++ {
++ PX_CHECK_AND_RETURN_NULL(transform.isValid(), "PxCreateDynamic: transform is not valid.");
++ PX_CHECK_AND_RETURN_NULL(shapeOffset.isValid(), "PxCreateDynamic: shapeOffset is not valid.");
++
++ if(!isDynamicGeometry(geometry.getType()) || density <= 0.0f)
++ return NULL;
++
++ PxShape* shape = sdk.createShape(geometry, material, true);
++ if(!shape)
++ return NULL;
++
++ shape->setLocalPose(shapeOffset);
++
++ PxRigidDynamic* body = PxCreateDynamic(sdk, transform, *shape, density);
++ shape->release();
++ return body;
++ }
++
++ PxRigidDynamic* PxCreateKinematic(PxPhysics& sdk,
++ const PxTransform& transform,
++ PxShape& shape,
++ PxReal density)
++ {
++ PX_CHECK_AND_RETURN_NULL(transform.isValid(), "PxCreateKinematic: transform is not valid.");
++
++ bool isDynGeom = isDynamicGeometry(shape.getGeometry().getType());
++ if(isDynGeom && density <= 0.0f)
++ return NULL;
++
++ PxRigidDynamic* actor = sdk.createRigidDynamic(transform);
++ if(actor)
++ {
++ actor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
++ if(!isDynGeom)
++ shape.setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
++
++ actor->attachShape(shape);
++
++ if(isDynGeom)
++ PxRigidBodyExt::updateMassAndInertia(*actor, density);
++ else
++ {
++ actor->setMass(1.f);
++ actor->setMassSpaceInertiaTensor(PxVec3(1.f,1.f,1.f));
++ }
++ }
++
++ return actor;
++ }
++
++ PxRigidDynamic* PxCreateKinematic(PxPhysics& sdk,
++ const PxTransform& transform,
++ const PxGeometry& geometry,
++ PxMaterial& material,
++ PxReal density,
++ const PxTransform& shapeOffset)
++ {
++ PX_CHECK_AND_RETURN_NULL(transform.isValid(), "PxCreateKinematic: transform is not valid.");
++ PX_CHECK_AND_RETURN_NULL(shapeOffset.isValid(), "PxCreateKinematic: shapeOffset is not valid.");
++
++ bool isDynGeom = isDynamicGeometry(geometry.getType());
++ if(isDynGeom && density <= 0.0f)
++ return NULL;
++
++ PxShape* shape = sdk.createShape(geometry, material, true);
++ if(!shape)
++ return NULL;
++
++ shape->setLocalPose(shapeOffset);
++
++ PxRigidDynamic* body = PxCreateKinematic(sdk, transform, *shape, density);
++ shape->release();
++ return body;
++ }
++
++ PxRigidStatic* PxCreateStatic(PxPhysics& sdk,
++ const PxTransform& transform,
++ PxShape& shape)
++ {
++ PX_CHECK_AND_RETURN_NULL(transform.isValid(), "PxCreateStatic: transform is not valid.");
++
++ PxRigidStatic* s = sdk.createRigidStatic(transform);
++ if(s)
++ s->attachShape(shape);
++ return s;
++ }
++
++ PxRigidStatic* PxCreateStatic(PxPhysics& sdk,
++ const PxTransform& transform,
++ const PxGeometry& geometry,
++ PxMaterial& material,
++ const PxTransform& shapeOffset)
++ {
++ PX_CHECK_AND_RETURN_NULL(transform.isValid(), "PxCreateStatic: transform is not valid.");
++ PX_CHECK_AND_RETURN_NULL(shapeOffset.isValid(), "PxCreateStatic: shapeOffset is not valid.");
++
++ PxShape* shape = sdk.createShape(geometry, material, true);
++ if(!shape)
++ return NULL;
++
++ shape->setLocalPose(shapeOffset);
++
++ PxRigidStatic* s = PxCreateStatic(sdk, transform, *shape);
++ shape->release();
++ return s;
++ }
++
++ PxRigidStatic* PxCreatePlane(PxPhysics& sdk,
++ const PxPlane& plane,
++ PxMaterial& material)
++ {
++ PX_CHECK_AND_RETURN_NULL(plane.n.isFinite(), "PxCreatePlane: plane normal is not valid.");
++
++ if (!plane.n.isNormalized())
++ return NULL;
++
++ return PxCreateStatic(sdk, PxTransformFromPlaneEquation(plane), PxPlaneGeometry(), material);
++ }
++
++ PxShape* PxCloneShape(PxPhysics& physics, const PxShape& from, bool isExclusive)
++ {
++ PxInlineArray<PxMaterial*, 64> materials;
++ PxU16 materialCount = from.getNbMaterials();
++ materials.resize(materialCount);
++ from.getMaterials(materials.begin(), materialCount);
++
++ PxShape* to = physics.createShape(from.getGeometry(), materials.begin(), materialCount, isExclusive, from.getFlags());
++
++ to->setLocalPose(from.getLocalPose());
++ to->setContactOffset(from.getContactOffset());
++ to->setRestOffset(from.getRestOffset());
++ to->setSimulationFilterData(from.getSimulationFilterData());
++ to->setQueryFilterData(from.getQueryFilterData());
++ to->setTorsionalPatchRadius(from.getTorsionalPatchRadius());
++ to->setMinTorsionalPatchRadius(from.getMinTorsionalPatchRadius());
++ return to;
++ }
++
++ static void copyStaticProperties(PxPhysics& physics, PxRigidActor& to, const PxRigidActor& from)
++ {
++ PxInlineArray<PxShape*, 64> shapes;
++ shapes.resize(from.getNbShapes());
++
++ PxU32 shapeCount = from.getNbShapes();
++ from.getShapes(shapes.begin(), shapeCount);
++
++ for(PxU32 i = 0; i < shapeCount; i++)
++ {
++ PxShape* s = shapes[i];
++ if(!s->isExclusive())
++ to.attachShape(*s);
++ else
++ {
++ PxShape* newShape = physx::PxCloneShape(physics, *s, true);
++ to.attachShape(*newShape);
++ newShape->release();
++ }
++ }
++
++ to.setActorFlags(from.getActorFlags());
++ to.setOwnerClient(from.getOwnerClient());
++ to.setDominanceGroup(from.getDominanceGroup());
++ to.setEnvironmentID(from.getEnvironmentID());
++ }
++
++ PxRigidStatic* PxCloneStatic(PxPhysics& physicsSDK,
++ const PxTransform& transform,
++ const PxRigidActor& from)
++ {
++ PxRigidStatic* to = physicsSDK.createRigidStatic(transform);
++ if(!to)
++ return NULL;
++
++ copyStaticProperties(physicsSDK, *to, from);
++
++ return to;
++ }
++
++ PxRigidDynamic* PxCloneDynamic(PxPhysics& physicsSDK,
++ const PxTransform& transform,
++ const PxRigidDynamic& from)
++ {
++ PxRigidDynamic* to = physicsSDK.createRigidDynamic(transform);
++ if(!to)
++ return NULL;
++
++ copyStaticProperties(physicsSDK, *to, from);
++
++ to->setRigidBodyFlags(from.getRigidBodyFlags());
++
++ to->setMass(from.getMass());
++ to->setMassSpaceInertiaTensor(from.getMassSpaceInertiaTensor());
++ to->setCMassLocalPose(from.getCMassLocalPose());
++
++ to->setLinearVelocity(from.getLinearVelocity());
++ to->setAngularVelocity(from.getAngularVelocity());
++
++ to->setLinearDamping(from.getLinearDamping());
++ to->setAngularDamping(from.getAngularDamping());
++
++ PxU32 posIters, velIters;
++ from.getSolverIterationCounts(posIters, velIters);
++ to->setSolverIterationCounts(posIters, velIters);
++
++ to->setMaxLinearVelocity(from.getMaxLinearVelocity());
++ to->setMaxAngularVelocity(from.getMaxAngularVelocity());
++ to->setMaxDepenetrationVelocity(from.getMaxDepenetrationVelocity());
++ to->setSleepThreshold(from.getSleepThreshold());
++ to->setStabilizationThreshold(from.getStabilizationThreshold());
++ to->setMinCCDAdvanceCoefficient(from.getMinCCDAdvanceCoefficient());
++ to->setContactReportThreshold(from.getContactReportThreshold());
++ to->setMaxContactImpulse(from.getMaxContactImpulse());
++
++ PxTransform target;
++ if (from.getKinematicTarget(target))
++ to->setKinematicTarget(target);
++
++ to->setRigidDynamicLockFlags(from.getRigidDynamicLockFlags());
++
++ return to;
++ }
++
++ static PxTransform scalePosition(const PxTransform& t, PxReal scale)
++ {
++ return PxTransform(t.p*scale, t.q);
++ }
++
++ void PxScaleRigidActor(PxRigidActor& actor, PxReal scale, bool scaleMassProps)
++ {
++ PX_CHECK_AND_RETURN(scale > 0,
++ "PxScaleRigidActor requires that the scale parameter is greater than zero");
++
++ PxInlineArray<PxShape*, 64> shapes;
++ shapes.resize(actor.getNbShapes());
++ actor.getShapes(shapes.begin(), shapes.size());
++
++ for(PxU32 i=0;i<shapes.size();i++)
++ {
++ shapes[i]->setLocalPose(scalePosition(shapes[i]->getLocalPose(), scale));
++ PxGeometryHolder h(shapes[i]->getGeometry());
++
++ switch(h.getType())
++ {
++ case PxGeometryType::eSPHERE:
++ h.sphere().radius *= scale;
++ break;
++ case PxGeometryType::ePLANE:
++ break;
++ case PxGeometryType::eCAPSULE:
++ h.capsule().halfHeight *= scale;
++ h.capsule().radius *= scale;
++ break;
++ case PxGeometryType::eBOX:
++ h.box().halfExtents *= scale;
++ break;
++ case PxGeometryType::eCONVEXMESH:
++ h.convexMesh().scale.scale *= scale;
++ break;
++ case PxGeometryType::eTRIANGLEMESH:
++ h.triangleMesh().scale.scale *= scale;
++ break;
++ case PxGeometryType::eHEIGHTFIELD:
++ h.heightField().heightScale *= scale;
++ h.heightField().rowScale *= scale;
++ h.heightField().columnScale *= scale;
++ break;
++ default:
++ PX_ASSERT(0);
++ }
++ shapes[i]->setGeometry(h.any());
++ }
++
++ if(!scaleMassProps)
++ return;
++
++ PxRigidDynamic* dynamic = (&actor)->is<PxRigidDynamic>();
++ if(!dynamic)
++ return;
++
++ PxReal scale3 = scale*scale*scale;
++ dynamic->setMass(dynamic->getMass()*scale3);
++ dynamic->setMassSpaceInertiaTensor(dynamic->getMassSpaceInertiaTensor()*scale3*scale*scale);
++ dynamic->setCMassLocalPose(scalePosition(dynamic->getCMassLocalPose(), scale));
++ }
++ }