// Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. #ifndef __ARTI_DYNAMIC_CUH__ #define __ARTI_DYNAMIC_CUH__ #include "PxgArticulation.h" #include "PxgArticulationLink.h" #include "DyFeatherstoneArticulationUtils.h" #include "DyFeatherstoneArticulation.h" //This function stores Q-stZ to mDeferredQstZ static __device__ Cm::UnAlignedSpatialVector propagateImpulseW_0(const PxVec3& childToParent, PxgArticulationBlockDofData* PX_RESTRICT dofData, const Cm::UnAlignedSpatialVector& Z, const PxU32 dofCount, const PxU32 threadIndexInWarp, const PxReal* PX_RESTRICT jointForce = NULL, const PxReal jointForceMultiplier = 1.0f) { Cm::UnAlignedSpatialVector temp = Z; Cm::UnAlignedSpatialVector sas[3]; Cm::UnAlignedSpatialVector isInvD[3]; PxReal jf[3]; // the split into two separate loops is an optimization that allows dispatching the loads as early as possible. #pragma unroll 3 for (PxU32 ind = 0; ind < 3; ++ind) { if (ind < dofCount) { sas[ind] = loadSpatialVector(dofData[ind].mWorldMotionMatrix, threadIndexInWarp); isInvD[ind] = loadSpatialVector(dofData[ind].mIsInvDW, threadIndexInWarp); jf[ind] = (jointForce ? jointForce[ind] * jointForceMultiplier : 0.0f); } } #pragma unroll 3 for (PxU32 ind = 0; ind < 3; ++ind) { if (ind < dofCount) { const PxReal stZ = jf[ind] - sas[ind].innerProduct(Z); dofData[ind].mDeferredQstZ[threadIndexInWarp] += stZ; temp += isInvD[ind] * stZ; } } //parent space's spatial zero acceleration impulse return Dy::FeatherstoneArticulation::translateSpatialVector(childToParent, temp); } static __device__ Cm::UnAlignedSpatialVector propagateImpulseWTemp(const PxVec3& childToParent, PxgArticulationBlockDofData* PX_RESTRICT dofData, const Cm::UnAlignedSpatialVector& Z, const PxU32 dofCount, const PxU32 threadIndexInWarp) { Cm::UnAlignedSpatialVector temp = Z; assert(dofCount<=3); for (PxU32 ind = 0; ind < 3; ++ind) { if(ind 1) { Cm::UnAlignedSpatialVector nextMotionV = loadSpatialVector(artiLinks[1].mMotionVelocity, threadIndexInWarp); PxU32 nextNbDofs = artiLinks[1].mDofs[threadIndexInWarp]; PxU32 nextParent = artiLinks[1].mParents[threadIndexInWarp]; //Cm::UnAlignedSpatialVector nextDeferredZ = loadSpatialVector(artiLinks[1].mDeferredZ, threadIndexInWarp); for (PxU32 i = 1; i < linkCount; i++) { PxgArticulationBlockLinkData& tLink = artiLinks[i]; const PxU32 nbDofs = nextNbDofs; const PxU32 parent = nextParent; const Cm::UnAlignedSpatialVector preloadedConstraintForces = loadSpatialVector(tLink.mConstraintForces, threadIndexInWarp); const Cm::UnAlignedSpatialVector preloadedSolverSpatialDeltaVel = loadSpatialVector(tLink.mSolverSpatialDeltaVel, threadIndexInWarp); Cm::UnAlignedSpatialVector motionV = nextMotionV; //const Cm::UnAlignedSpatialVector deferredZ = nextDeferredZ; //storeSpatialVector(tLink.mDeferredZ, Cm::UnAlignedSpatialVector::Zero(), threadIndexInWarp); if ((i + 1) < linkCount) { nextMotionV = loadSpatialVector(artiLinks[i + 1].mMotionVelocity, threadIndexInWarp); nextNbDofs = artiLinks[i + 1].mDofs[threadIndexInWarp]; nextParent = artiLinks[i + 1].mParents[threadIndexInWarp]; //nextDeferredZ = loadSpatialVector(artiLinks[i + 1].mDeferredZ, threadIndexInWarp); } if (parent != (i - 1)) deltaV = loadSpatialVector(artiLinks[parent].mScratchDeltaV, threadIndexInWarp); deltaV = propagateAccelerationW(tLink, dofs, nbDofs, deltaV, threadIndexInWarp); //Accumulate the DeltaVel arising from solver impulses applied to this link. storeSpatialVector(tLink.mSolverSpatialDeltaVel, preloadedSolverSpatialDeltaVel + deltaV, threadIndexInWarp); //zeroing mDeferredQstZ for (PxU32 ind = 0; ind < nbDofs; ++ind) { dofs[ind].mDeferredQstZ[threadIndexInWarp] = 0.f; } motionV += deltaV; storeSpatialVector(tLink.mScratchDeltaV, deltaV, threadIndexInWarp); //const PxTransform& tBody2World = poses[i]; storeSpatialVector(tLink.mMotionVelocity, motionV, threadIndexInWarp); storeSpatialVector(tLink.mConstraintForces, preloadedConstraintForces + deltaV, threadIndexInWarp); dofs += nbDofs; } } } #endif