aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/SimulationController/src/ScConstraintSim.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/SimulationController/src/ScConstraintSim.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/SimulationController/src/ScConstraintSim.cpp')
-rw-r--r--PhysX_3.4/Source/SimulationController/src/ScConstraintSim.cpp511
1 files changed, 511 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/SimulationController/src/ScConstraintSim.cpp b/PhysX_3.4/Source/SimulationController/src/ScConstraintSim.cpp
new file mode 100644
index 00000000..3b81ebc4
--- /dev/null
+++ b/PhysX_3.4/Source/SimulationController/src/ScConstraintSim.cpp
@@ -0,0 +1,511 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "ScScene.h"
+#include "ScConstraintProjectionManager.h"
+#include "ScBodySim.h"
+#include "ScStaticSim.h"
+#include "PxsContext.h"
+#include "ScConstraintCore.h"
+#include "ScConstraintSim.h"
+#include "ScConstraintInteraction.h"
+#include "ScRbElementInteraction.h"
+#include "CmVisualization.h"
+#include "ScObjectIDTracker.h"
+#include "DyContext.h"
+
+using namespace physx;
+
+
+PX_FORCE_INLINE void invalidateConstraintGroupsOnAdd(Sc::ConstraintProjectionManager& cpm, Sc::BodySim* b0, Sc::BodySim* b1, Sc::ConstraintSim& constraint)
+{
+ // constraint groups get built by starting from dirty constraints that need projection. If a non-projecting constraint gets added
+ // we need to restart the whole process (we do not want to track dirty non-projecting constraints because of a scenario where
+ // all constraints of a group get switched to non-projecting which should kill the group and not rebuild a new one).
+ if (b0 && b0->getConstraintGroup())
+ cpm.invalidateGroup(*b0->getConstraintGroup(), &constraint);
+ if (b1 && b1->getConstraintGroup())
+ cpm.invalidateGroup(*b1->getConstraintGroup(), &constraint);
+}
+
+
+Sc::ConstraintSim::ConstraintSim(ConstraintCore& core, RigidCore* r0, RigidCore* r1, Scene& scene) :
+ mScene (scene),
+ mCore (core),
+ mInteraction(NULL),
+ mFlags (0)
+{
+
+ mBodies[0] = (r0 && (r0->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r0->getSim()) : 0;
+ mBodies[1] = (r1 && (r1->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r1->getSim()) : 0;
+
+ mLowLevelConstraint.index = scene.getConstraintIDTracker().createID();
+ Ps::Array<Dy::ConstraintWriteback, Ps::VirtualAllocator>& writeBackPool = scene.getDynamicsContext()->getConstraintWriteBackPool();
+ if (mLowLevelConstraint.index >= writeBackPool.capacity())
+ {
+ writeBackPool.reserve(writeBackPool.capacity() * 2);
+ }
+
+ writeBackPool.resize(PxMax(writeBackPool.size(), mLowLevelConstraint.index + 1));
+ writeBackPool[mLowLevelConstraint.index].initialize();
+
+ if (!createLLConstraint())
+ return;
+
+ PxReal linBreakForce, angBreakForce;
+ core.getBreakForce(linBreakForce, angBreakForce);
+ if ((linBreakForce < PX_MAX_F32) || (angBreakForce < PX_MAX_F32))
+ setFlag(eBREAKABLE);
+
+ core.setSim(this);
+
+ ConstraintProjectionManager& cpm = scene.getProjectionManager();
+ if (!needsProjection())
+ invalidateConstraintGroupsOnAdd(cpm, mBodies[0], mBodies[1], *this);
+ else
+ cpm.addToPendingGroupUpdates(*this);
+
+ ConstraintSim* cs = this; // to make the Wii U compiler happy
+ mInteraction = mScene.getConstraintInteractionPool()->construct(cs,
+ r0 ? *r0->getSim() : scene.getStaticAnchor(),
+ r1 ? *r1->getSim() : scene.getStaticAnchor());
+
+ PX_ASSERT(!mInteraction->isRegistered()); // constraint interactions must not register in the scene, there is a list of Sc::ConstraintSim instead
+}
+
+
+Sc::ConstraintSim::~ConstraintSim()
+{
+ PX_ASSERT(mInteraction); // This is fine now, a body which gets removed from the scene removes all constraints automatically
+ PX_ASSERT(!mInteraction->isRegistered()); // constraint interactions must not register in the scene, there is a list of Sc::ConstraintSim instead
+
+ if (readFlag(ConstraintSim::ePENDING_GROUP_UPDATE))
+ mScene.getProjectionManager().removeFromPendingGroupUpdates(*this);
+
+ if (!isBroken())
+ mInteraction->destroy();
+
+ mScene.getConstraintIDTracker().releaseID(mLowLevelConstraint.index);
+ mScene.getConstraintInteractionPool()->destroy(mInteraction);
+
+ destroyLLConstraint();
+
+ mCore.setSim(NULL);
+}
+
+
+bool Sc::ConstraintSim::createLLConstraint()
+{
+ Dy::Constraint& llc = mLowLevelConstraint;
+ ConstraintCore& core = getCore();
+ PxU32 constantBlockSize = core.getConstantBlockSize();
+
+ void* constantBlock = mScene.allocateConstraintBlock(constantBlockSize);
+ if(!constantBlock)
+ {
+ Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Constraint: could not allocate low-level resources.");
+ return false;
+ }
+
+ //Ensure the constant block isn't just random data because some functions may attempt to use it before it is
+ //setup. Specifically pvd visualization of joints
+ //-CN
+
+ PxMemZero( constantBlock, constantBlockSize);
+
+ core.getBreakForce(llc.linBreakForce, llc.angBreakForce);
+ llc.flags = PxU32(core.getFlags());
+ llc.constantBlockSize = constantBlockSize;
+
+ llc.solverPrep = core.getSolverPrep();
+ llc.project = core.getProject();
+ llc.constantBlock = constantBlock;
+
+ //llc.index = mLowLevelConstraint.index;
+ llc.body0 = mBodies[0] ? &mBodies[0]->getLowLevelBody() : 0;
+ llc.body1 = mBodies[1] ? &mBodies[1]->getLowLevelBody() : 0;
+ llc.bodyCore0 = mBodies[0] ? &llc.body0->getCore() : NULL;
+ llc.bodyCore1 = mBodies[1] ? &llc.body1->getCore() : NULL;
+
+ llc.minResponseThreshold = core.getMinResponseThreshold();
+
+ return true;
+}
+
+
+void Sc::ConstraintSim::destroyLLConstraint()
+{
+ if(mLowLevelConstraint.constantBlock)
+ {
+ mScene.deallocateConstraintBlock(mLowLevelConstraint.constantBlock,
+ mLowLevelConstraint.constantBlockSize);
+ }
+}
+
+void Sc::ConstraintSim::preBodiesChange()
+{
+ PX_ASSERT(mInteraction);
+
+ BodySim* b = getConstraintGroupBody();
+ if (b)
+ mScene.getProjectionManager().invalidateGroup(*b->getConstraintGroup(), this);
+
+ if (!isBroken())
+ mInteraction->destroy();
+
+ mScene.getConstraintInteractionPool()->destroy(mInteraction);
+ mInteraction = NULL;
+}
+
+void Sc::ConstraintSim::postBodiesChange(RigidCore* r0, RigidCore* r1)
+{
+ PX_ASSERT(mInteraction == NULL);
+
+ BodySim* b0 = (r0 && (r0->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r0->getSim()) : 0;
+ BodySim* b1 = (r1 && (r1->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r1->getSim()) : 0;
+
+ ConstraintProjectionManager& cpm = mScene.getProjectionManager();
+ PxConstraintFlags::InternalType projectionNeeded = getCore().getFlags() & PxConstraintFlag::ePROJECTION; // can not use "needsProjection()" because that takes into account whether the constraint is broken
+ if (!projectionNeeded)
+ invalidateConstraintGroupsOnAdd(cpm, b0, b1, *this);
+ else if (!readFlag(ConstraintSim::ePENDING_GROUP_UPDATE))
+ cpm.addToPendingGroupUpdates(*this);
+
+ Dy::Constraint& c = mLowLevelConstraint;
+
+ c.body0 = b0 ? &b0->getLowLevelBody() : NULL;
+ c.body1 = b1 ? &b1->getLowLevelBody() : NULL;
+
+ c.bodyCore0 = c.body0 ? &c.body0->getCore() : NULL;
+ c.bodyCore1 = c.body1 ? &c.body1->getCore() : NULL;
+
+ mBodies[0] = b0;
+ mBodies[1] = b1;
+
+ ConstraintSim* cs = this; // to make the Wii U compiler happy
+ mInteraction = mScene.getConstraintInteractionPool()->construct(cs,
+ r0 ? *r0->getSim() : mScene.getStaticAnchor(),
+ r1 ? *r1->getSim() : mScene.getStaticAnchor());
+}
+
+void Sc::ConstraintSim::checkMaxForceExceeded()
+{
+ PX_ASSERT(readFlag(eCHECK_MAX_FORCE_EXCEEDED));
+
+ Dy::ConstraintWriteback& solverOutput = mScene.getDynamicsContext()->getConstraintWriteBackPool()[mLowLevelConstraint.index];
+ if (solverOutput.broken)
+ {
+ setFlag(ConstraintSim::eBROKEN);
+ mScene.addBrokenConstraint(&mCore);
+ mCore.breakApart();
+ mInteraction->destroy();
+
+ updateRelatedSIPs();
+
+ PX_ASSERT(!readFlag(eCHECK_MAX_FORCE_EXCEEDED));
+ }
+}
+
+void Sc::ConstraintSim::getForce(PxVec3& lin, PxVec3& ang)
+{
+ const PxReal recipDt = mScene.getOneOverDt();
+ Dy::ConstraintWriteback& solverOutput= mScene.getDynamicsContext()->getConstraintWriteBackPool()[mLowLevelConstraint.index];
+ lin = solverOutput.linearImpulse * recipDt;
+ ang = solverOutput.angularImpulse * recipDt;
+}
+
+void Sc::ConstraintSim::updateRelatedSIPs()
+{
+ ActorSim& a0 = mInteraction->getActor0();
+ ActorSim& a1 = mInteraction->getActor1();
+ ActorSim& actor = (a0.getActorInteractionCount()< a1.getActorInteractionCount()) ? a0 : a1;
+
+ actor.setActorsInteractionsDirty(InteractionDirtyFlag::eFILTER_STATE, NULL, InteractionFlag::eRB_ELEMENT);
+ // because broken constraints can re-enable contact response between the two bodies
+}
+
+
+void Sc::ConstraintSim::setBreakForceLL(PxReal linear, PxReal angular)
+{
+ PxU8 wasBreakable = readFlag(eBREAKABLE);
+ PxU8 isBreakable;
+ if ((linear < PX_MAX_F32) || (angular < PX_MAX_F32))
+ isBreakable = eBREAKABLE;
+ else
+ isBreakable = 0;
+
+ if (isBreakable != wasBreakable)
+ {
+ if (isBreakable)
+ {
+ PX_ASSERT(!readFlag(eCHECK_MAX_FORCE_EXCEEDED));
+ setFlag(eBREAKABLE);
+ if (mInteraction->readInteractionFlag(InteractionFlag::eIS_ACTIVE))
+ mScene.addActiveBreakableConstraint(this, mInteraction);
+ }
+ else
+ {
+ if (readFlag(eCHECK_MAX_FORCE_EXCEEDED))
+ mScene.removeActiveBreakableConstraint(this);
+ clearFlag(eBREAKABLE);
+ }
+ }
+
+ mLowLevelConstraint.linBreakForce = linear;
+ mLowLevelConstraint.angBreakForce = angular;
+}
+
+
+void Sc::ConstraintSim::postFlagChange(PxConstraintFlags oldFlags, PxConstraintFlags newFlags)
+{
+ mLowLevelConstraint.flags = newFlags;
+
+ // PT: don't convert to bool if not needed
+ const PxU32 hadProjection = (oldFlags & PxConstraintFlag::ePROJECTION);
+ const PxU32 needsProjection = (newFlags & PxConstraintFlag::ePROJECTION);
+
+ if(needsProjection && !hadProjection)
+ {
+ PX_ASSERT(!readFlag(ConstraintSim::ePENDING_GROUP_UPDATE)); // Non-projecting constrainst should not be part of the update list
+
+ Sc::BodySim* b0 = getBody(0);
+ Sc::BodySim* b1 = getBody(1);
+ if ((!b0 || b0->getConstraintGroup()) && (!b1 || b1->getConstraintGroup()))
+ {
+ // Already part of a constraint group but not as a projection constraint -> re-generate projection tree
+ PX_ASSERT(b0 != NULL || b1 != NULL);
+ if (b0)
+ b0->getConstraintGroup()->markForProjectionTreeRebuild(mScene.getProjectionManager());
+ else
+ b1->getConstraintGroup()->markForProjectionTreeRebuild(mScene.getProjectionManager());
+ }
+ else
+ {
+ // Not part of a constraint group yet
+ mScene.getProjectionManager().addToPendingGroupUpdates(*this);
+ }
+ }
+ else if(!needsProjection && hadProjection)
+ {
+ if (!readFlag(ConstraintSim::ePENDING_GROUP_UPDATE))
+ {
+ Sc::BodySim* b = getConstraintGroupBody();
+ if (b)
+ {
+ PX_ASSERT(b->getConstraintGroup());
+ mScene.getProjectionManager().invalidateGroup(*b->getConstraintGroup(), NULL);
+ }
+ // This is conservative but it could be the case that this constraint with projection was the only
+ // one in the group and thus the whole group must be killed. If we had a counter for the number of
+ // projecting constraints per group, we could just update the projection tree if the counter was
+ // larger than 1. But switching the projection flag does not seem likely anyway.
+ }
+ else
+ mScene.getProjectionManager().removeFromPendingGroupUpdates(*this); // Was part of a group which got invalidated
+
+ PX_ASSERT(!readFlag(ConstraintSim::ePENDING_GROUP_UPDATE)); // make sure the expected post-condition is met for all paths
+ }
+}
+
+
+Sc::RigidSim& Sc::ConstraintSim::getRigid(PxU32 i)
+{
+ PX_ASSERT(mInteraction);
+
+ if (i == 0)
+ return static_cast<RigidSim&>(mInteraction->getActor0());
+ else
+ return static_cast<RigidSim&>(mInteraction->getActor1());
+}
+
+
+bool Sc::ConstraintSim::hasDynamicBody()
+{
+ return (mBodies[0] && (!mBodies[0]->isKinematic())) || (mBodies[1] && (!mBodies[1]->isKinematic()));
+}
+
+bool Sc::ConstraintSim::isBroken() const
+{
+ return !!(mFlags & ConstraintSim::eBROKEN);
+}
+
+static void constrainMotion(PxsRigidBody* body, PxTransform& targetPose)
+{
+ //Now constraint deltaPos and deltaRot
+ PxU32 lockFlags = body->mCore->lockFlags;
+
+ if (lockFlags)
+ {
+ const PxTransform& currBody2World = body->mCore->body2World;
+
+ PxVec3 deltaPos = targetPose.p - currBody2World.p;
+
+ PxQuat deltaQ = targetPose.q * currBody2World.q.getConjugate();
+
+ if (deltaQ.w < 0) //shortest angle.
+ deltaQ = -deltaQ;
+
+ PxReal angle;
+ PxVec3 axis;
+ deltaQ.toRadiansAndUnitAxis(angle, axis);
+ PxVec3 deltaRot = axis * angle;
+
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_X)
+ deltaPos.x = 0.f;
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_Y)
+ deltaPos.y = 0.f;
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_Z)
+ deltaPos.z = 0.f;
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_X)
+ deltaRot.x = 0.f;
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y)
+ deltaRot.y = 0.f;
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_Z)
+ deltaRot.z = 0.f;
+
+ targetPose.p = currBody2World.p + deltaPos;
+
+
+ PxReal w2 = deltaRot.magnitudeSquared();
+ if (w2 != 0.f)
+ {
+ PxReal w = PxSqrt(w2);
+
+ const PxReal v = w * 0.5f;
+ PxReal s, q;
+ Ps::sincos(v, s, q);
+ s /= w;
+
+ const PxVec3 pqr = deltaRot * s;
+ const PxQuat quatVel(pqr.x, pqr.y, pqr.z, 0);
+ PxQuat result = quatVel * currBody2World.q;
+
+ result += currBody2World.q * q;
+
+ targetPose.q = result.getNormalized();
+ }
+ else
+ {
+ targetPose.q = currBody2World.q;
+ }
+ }
+
+
+
+}
+
+void Sc::ConstraintSim::projectPose(BodySim* childBody, Ps::Array<BodySim*>& projectedBodies)
+{
+#if PX_DEBUG
+ // We expect bodies in low level constraints to have same order as high level counterpart
+ PxsRigidBody* b0 = mLowLevelConstraint.body0;
+ PxsRigidBody* b1 = mLowLevelConstraint.body1;
+ PX_ASSERT( (childBody == getBody(0) && &childBody->getLowLevelBody() == b0) ||
+ (childBody == getBody(1) && &childBody->getLowLevelBody() == b1) );
+#endif
+
+ Dy::Constraint& constraint = getLowLevelConstraint();
+ bool projectToBody0 = childBody == getBody(1);
+
+ PxsRigidBody* body0 = constraint.body0,
+ * body1 = constraint.body1;
+
+ PxTransform body0ToWorld = body0 ? body0->getPose() : PxTransform(PxIdentity);
+ PxTransform body1ToWorld = body1 ? body1->getPose() : PxTransform(PxIdentity);
+
+ (*constraint.project)(constraint.constantBlock, body0ToWorld, body1ToWorld, projectToBody0);
+
+ if(projectToBody0)
+ {
+ PX_ASSERT(body1);
+ //Constrain new pose to valid world motion
+ constrainMotion(body1, body1ToWorld);
+ body1->setPose(body1ToWorld);
+ projectedBodies.pushBack(getBody(1));
+ }
+ else
+ {
+ PX_ASSERT(body0);
+ //Constrain new pose to valid world motion
+ constrainMotion(body0, body0ToWorld);
+ body0->setPose(body0ToWorld);
+ projectedBodies.pushBack(getBody(0));
+ }
+}
+
+
+bool Sc::ConstraintSim::needsProjection()
+{
+ Dy::ConstraintWriteback& solverOutput = mScene.getDynamicsContext()->getConstraintWriteBackPool()[mLowLevelConstraint.index];
+ return (getCore().getFlags() & PxConstraintFlag::ePROJECTION ) && !solverOutput.broken;
+}
+
+
+PX_INLINE Sc::BodySim* Sc::ConstraintSim::getConstraintGroupBody()
+{
+ BodySim* b = NULL;
+ if (mBodies[0] && mBodies[0]->getConstraintGroup())
+ b = mBodies[0];
+ else if (mBodies[1] && mBodies[1]->getConstraintGroup())
+ b = mBodies[1];
+
+ return b;
+}
+
+
+void Sc::ConstraintSim::visualize(PxRenderBuffer& output)
+{
+ if (!(getCore().getFlags() & PxConstraintFlag::eVISUALIZATION))
+ return;
+
+ PxsRigidBody* b0 = mLowLevelConstraint.body0;
+ PxsRigidBody* b1 = mLowLevelConstraint.body1;
+
+ const PxTransform& t0 = b0 ? b0->getPose() : PxTransform(PxIdentity);
+ const PxTransform& t1 = b1 ? b1->getPose() : PxTransform(PxIdentity);
+
+ PxReal frameScale = mScene.getVisualizationScale() * mScene.getVisualizationParameter(PxVisualizationParameter::eJOINT_LOCAL_FRAMES);
+ PxReal limitScale = mScene.getVisualizationScale() * mScene.getVisualizationParameter(PxVisualizationParameter::eJOINT_LIMITS);
+
+ Cm::RenderOutput renderOut( static_cast<Cm::RenderBuffer &>( output ) );
+ Cm::ConstraintImmediateVisualizer viz( frameScale, limitScale, renderOut );
+
+ mCore.getVisualize()(viz, mLowLevelConstraint.constantBlock, t0, t1,
+ PxConstraintVisualizationFlag::eLOCAL_FRAMES | PxConstraintVisualizationFlag::eLIMITS);
+}
+
+
+void Sc::ConstraintSim::setConstantsLL(void* addr)
+{
+ PxMemCopy(mLowLevelConstraint.constantBlock, addr, mLowLevelConstraint.constantBlockSize);
+
+ getAnyBody()->getScene().getSimulationController()->updateJoint(mInteraction->getEdgeIndex(), &mLowLevelConstraint);
+
+}