aboutsummaryrefslogtreecommitdiff
path: root/sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp
diff options
context:
space:
mode:
authorBryan Galdrikian <[email protected]>2018-05-31 11:36:08 -0700
committerBryan Galdrikian <[email protected]>2018-05-31 11:36:08 -0700
commit7115f60b91b5717d90f643fd692010905c7004db (patch)
treeeffd68c6978751c517d54c2f2bb5bb6e7dc93e18 /sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp
parentUpdating BlastTool zip (diff)
downloadblast-1.1.3_rc1.tar.xz
blast-1.1.3_rc1.zip
Blast 1.1.3. See docs/release_notes.txt.v1.1.3_rc1
Diffstat (limited to 'sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp')
-rwxr-xr-x[-rw-r--r--]sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp978
1 files changed, 489 insertions, 489 deletions
diff --git a/sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp b/sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp
index 205c77e..7f86021 100644..100755
--- a/sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp
+++ b/sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp
@@ -1,489 +1,489 @@
-// 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) 2016-2018 NVIDIA Corporation. All rights reserved.
-
-
-#include "NvBlastExtImpactDamageManager.h"
-#include "NvBlastExtPxManager.h"
-#include "NvBlastExtPxFamily.h"
-#include "NvBlastExtPxActor.h"
-#include "NvBlastExtPxAsset.h"
-#include "NvBlastExtPxListener.h"
-
-#include "NvBlastAssert.h"
-
-#include "NvBlastExtDamageShaders.h"
-#include "NvBlastArray.h"
-
-#include "PxRigidDynamic.h"
-#include "PxSimulationEventCallback.h"
-#include "PxRigidBodyExt.h"
-
-#include "NvBlastTkFramework.h"
-#include "NvBlastTkActor.h"
-#include "NvBlastTkFamily.h"
-#include "NvBlastTkAsset.h"
-
-
-namespace Nv
-{
-namespace Blast
-{
-
-using namespace physx;
-
-const float MIN_IMPACT_VELOCITY_SQUARED = 1.0f;
-
-
-class ExtImpactDamageManagerImpl final : public ExtImpactDamageManager
-{
-public:
- ExtImpactDamageManagerImpl(ExtPxManager* pxManager, ExtImpactSettings settings)
- : m_pxManager(pxManager), m_settings(settings), m_listener(this), m_usePxUserData(m_pxManager->isPxUserDataUsed())
- {
- NVBLAST_ASSERT_WITH_MESSAGE(pxManager != nullptr, "ExtImpactDamageManager creation: input ExtPxManager is nullptr.");
- m_pxManager->subscribe(m_listener);
-
- m_impactDamageBuffer.reserve(32);
- }
-
- ~ExtImpactDamageManagerImpl()
- {
- m_pxManager->unsubscribe(m_listener);
- }
-
- virtual void release() override
- {
- NVBLAST_DELETE(this, ExtImpactDamageManagerImpl);
- }
-
-
- //////// interface ////////
-
- virtual void setSettings(const ExtImpactSettings& settings) override
- {
- m_settings = settings;
- }
-
- virtual void onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, uint32_t nbPairs) override;
-
- virtual void applyDamage() override;
-
-
- //////// public methods ////////
-
- void queueImpactDamage(ExtPxActor* actor, PxVec3 force, PxVec3 position, PxShape* shape)
- {
- ImpactDamageData data = { actor, force, position, shape };
- m_impactDamageBuffer.pushBack(data);
- }
-
-
-private:
- //////// physics manager listener ////////
-
- class PxManagerListener : public ExtPxListener
- {
- public:
- PxManagerListener(ExtImpactDamageManagerImpl* manager) : m_manager(manager) {}
-
- virtual void onActorCreated(ExtPxFamily&, ExtPxActor&) override {}
- virtual void onActorDestroyed(ExtPxFamily& family, ExtPxActor& actor) override
- {
- NV_UNUSED(family);
-
- // filter out actor from queued buffer
- auto& buffer = m_manager->m_impactDamageBuffer;
- for (int32_t i = 0; i < (int32_t)buffer.size(); ++i)
- {
- if (buffer[i].actor == &actor)
- {
- buffer.replaceWithLast(i);
- i--;
- }
- }
- }
- private:
- ExtImpactDamageManagerImpl* m_manager;
- };
-
-
- //////// private methods ////////
-
- void ensureBuffersSize(ExtPxActor* actor);
- void damageActor(ExtPxActor* actor, PxShape* shape, PxVec3 position, PxVec3 force);
-
-
- //////// data ////////
-
- ExtPxManager* m_pxManager;
- ExtImpactSettings m_settings;
- PxManagerListener m_listener;
- Array<PxContactPairPoint>::type m_pairPointBuffer;
- bool m_usePxUserData;
-
- struct ImpactDamageData
- {
- ExtPxActor* actor;
- PxVec3 force;
- PxVec3 position;
- PxShape* shape;
- };
-
- Array<ImpactDamageData>::type m_impactDamageBuffer;
-
- NvBlastFractureBuffers m_fractureBuffers;
- Array<uint8_t>::type m_fractureData;
-};
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// ExtImpactDamageManagerImpl
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-ExtImpactDamageManager* ExtImpactDamageManager::create(ExtPxManager* pxManager, ExtImpactSettings settings)
-{
- return NVBLAST_NEW(ExtImpactDamageManagerImpl) (pxManager, settings);
-}
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// onContact callback call
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-void ExtImpactDamageManagerImpl::onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, uint32_t nbPairs)
-{
- if (pairHeader.flags & physx::PxContactPairHeaderFlag::eREMOVED_ACTOR_0 ||
- pairHeader.flags & physx::PxContactPairHeaderFlag::eREMOVED_ACTOR_1 ||
- pairHeader.actors[0] == nullptr ||
- pairHeader.actors[1] == nullptr)
- {
- return;
- }
-
- PxRigidActor* rigidActor0 = pairHeader.actors[0];
- PxRigidActor* rigidActor1 = pairHeader.actors[1];
-
- ExtPxActor* actors[2];
-
- if (m_usePxUserData)
- {
- actors[0] = (ExtPxActor*)rigidActor0->userData;
- actors[1] = (ExtPxActor*)rigidActor1->userData;
- }
- else
- {
- PxRigidDynamic* rigidDynamic0 = rigidActor0->is<PxRigidDynamic>();
- PxRigidDynamic* rigidDynamic1 = rigidActor1->is<PxRigidDynamic>();
- actors[0] = rigidDynamic0 ? m_pxManager->getActorFromPhysXActor(*rigidDynamic0) : nullptr;
- actors[1] = rigidDynamic1 ? m_pxManager->getActorFromPhysXActor(*rigidDynamic1) : nullptr;
- }
-
-
- // check one of them is blast actor
- if (actors[0] == nullptr && actors[1] == nullptr)
- {
- return;
- }
-
- // self-collision check
- if (actors[0] != nullptr && actors[1] != nullptr)
- {
- if (&actors[0]->getFamily() == &actors[1]->getFamily() && !m_settings.isSelfCollissionEnabled)
- return;
- }
-
- for (uint32_t pairIdx = 0; pairIdx < nbPairs; pairIdx++)
- {
- const PxContactPair& currentPair = pairs[pairIdx];
-
- if (currentPair.flags & physx::PxContactPairFlag::eREMOVED_SHAPE_0 ||
- currentPair.flags & physx::PxContactPairFlag::eREMOVED_SHAPE_1 ||
- currentPair.shapes[0] == nullptr ||
- currentPair.shapes[1] == nullptr)
- {
- continue;
- }
-
- float masses[2] = { 0, 0 };
- {
- for (int i = 0; i < 2; ++i)
- {
- PxRigidDynamic* rigidDynamic = pairHeader.actors[i]->is<physx::PxRigidDynamic>();
- if (rigidDynamic)
- {
- if (!(rigidDynamic->getRigidBodyFlags() & physx::PxRigidBodyFlag::eKINEMATIC))
- {
- masses[i] = rigidDynamic->getMass();
- }
- }
- }
- };
-
- float reducedMass;
- if (masses[0] == 0.0f)
- {
- reducedMass = masses[1];
- }
- else if (masses[1] == 0.0f)
- {
- reducedMass = masses[0];
- }
- else
- {
- reducedMass = masses[0] * masses[1] / (masses[0] + masses[1]);
- }
-
-
- PxVec3 destructibleForces[2] = { PxVec3(0.0f), PxVec3(0.0f) };
- PxVec3 avgContactPosition = PxVec3(0.0f);
- PxVec3 avgContactNormal = PxVec3(0.0f);
- uint32_t numContacts = 0;
-
- m_pairPointBuffer.resize(currentPair.contactCount);
- uint32_t numContactsInStream = currentPair.contactCount > 0 ? currentPair.extractContacts(m_pairPointBuffer.begin(), currentPair.contactCount) : 0;
-
- for (uint32_t contactIdx = 0; contactIdx < numContactsInStream; contactIdx++)
- {
- PxContactPairPoint& currentPoint = m_pairPointBuffer[contactIdx];
-
- const PxVec3& patchNormal = currentPoint.normal;
- const PxVec3& position = currentPoint.position;
- PxVec3 velocities[2] = { PxVec3(0.0f), PxVec3(0.0f) };
- for (int i = 0; i < 2; ++i)
- {
- PxRigidBody* rigidBody = pairHeader.actors[i]->is<physx::PxRigidBody>();
- if (rigidBody)
- {
- velocities[i] = physx::PxRigidBodyExt::getVelocityAtPos(*rigidBody, position);
- }
- }
-
- const PxVec3 velocityDelta = velocities[0] - velocities[1];
- if (velocityDelta.magnitudeSquared() >= MIN_IMPACT_VELOCITY_SQUARED || reducedMass == 0.0f) // If reduced mass == 0, this is kineamtic vs. kinematic. Generate damage.
- {
- for (int i = 0; i < 2; ++i)
- {
- if (actors[i])
- {
- // this is not really physically correct, but at least its deterministic...
- destructibleForces[i] += (patchNormal * patchNormal.dot(velocityDelta)) * reducedMass * (i ? 1.0f : -1.0f);
- }
- }
- avgContactPosition += position;
- avgContactNormal += patchNormal;
- numContacts++;
- }
- }
-
- if (numContacts)
- {
- avgContactPosition /= (float)numContacts;
- avgContactNormal.normalize();
- for (uint32_t i = 0; i < 2; i++)
- {
- const PxVec3 force = destructibleForces[i] / (float)numContacts;
- ExtPxActor* actor = actors[i];
- if (actor != nullptr)
- {
- if (!force.isZero())
- {
- queueImpactDamage(actor, force, avgContactPosition, currentPair.shapes[i]);
- }
- else if (reducedMass == 0.0f) // Handle kinematic vs. kinematic
- {
- // holy molly
- }
- }
- }
- }
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// ExtImpactDamageManager damage processing
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-void ExtImpactDamageManagerImpl::applyDamage()
-{
- const auto damageFn = m_settings.damageFunction;
- const auto damageFnData = m_settings.damageFunctionData;
-
- for (const ImpactDamageData& data : m_impactDamageBuffer)
- {
- PxTransform t(data.actor->getPhysXActor().getGlobalPose().getInverse());
- PxVec3 force = t.rotate(data.force);
- PxVec3 position = t.transform(data.position);
-
- if (!damageFn || !damageFn(damageFnData, data.actor, data.shape, position, force))
- {
- damageActor(data.actor, data.shape, position, force);
- }
- }
- m_impactDamageBuffer.clear();
-}
-
-void ExtImpactDamageManagerImpl::ensureBuffersSize(ExtPxActor* actor)
-{
- const TkAsset* tkAsset = actor->getTkActor().getAsset();
- const uint32_t chunkCount = tkAsset->getChunkCount();
- const uint32_t bondCount = tkAsset->getBondCount();
-
- m_fractureBuffers.bondFractureCount = bondCount;
- m_fractureBuffers.chunkFractureCount = chunkCount;
- m_fractureData.resize((uint32_t)(m_fractureBuffers.bondFractureCount*sizeof(NvBlastBondFractureData) + m_fractureBuffers.chunkFractureCount*sizeof(NvBlastChunkFractureData))); // chunk count + bond count
- m_fractureBuffers.chunkFractures = reinterpret_cast<NvBlastChunkFractureData*>(m_fractureData.begin());
- m_fractureBuffers.bondFractures = reinterpret_cast<NvBlastBondFractureData*>(&m_fractureData.begin()[m_fractureBuffers.chunkFractureCount*sizeof(NvBlastChunkFractureData)]);
-}
-
-void ExtImpactDamageManagerImpl::damageActor(ExtPxActor* actor, PxShape* /*shape*/, PxVec3 position, PxVec3 force)
-{
- ensureBuffersSize(actor);
-
- const float damage = m_settings.hardness > 0.f ? force.magnitude() / m_settings.hardness : 0.f;
-
- const NvBlastExtMaterial* material = actor->getFamily().getMaterial();
- if (!material)
- {
- return;
- }
-
- float normalizedDamage = material->getNormalizedDamage(damage);
- if (normalizedDamage == 0.f || normalizedDamage < m_settings.damageThresholdMin)
- {
- return;
- }
- normalizedDamage = PxClamp<float>(normalizedDamage, 0, m_settings.damageThresholdMax);
-
- const PxVec3 normal = force.getNormalized();
- const float minDistance = m_settings.damageRadiusMax * normalizedDamage;
- const float maxDistance = minDistance * PxClamp<float>(m_settings.damageFalloffRadiusFactor, 1, 32);
-
- NvBlastExtProgramParams programParams(nullptr);
- programParams.material = material;
- programParams.accelerator = actor->getFamily().getPxAsset().getAccelerator();
- NvBlastDamageProgram program;
-
- if (m_settings.shearDamage)
- {
- NvBlastExtShearDamageDesc desc = {
- normalizedDamage,
- { normal[0], normal[1], normal[2] },
- { position[0], position[1], position[2] },
- minDistance,
- maxDistance
- };
-
- programParams.damageDesc = &desc;
-
- program.graphShaderFunction = NvBlastExtShearGraphShader;
- program.subgraphShaderFunction = NvBlastExtShearSubgraphShader;
-
- NvBlastFractureBuffers fractureEvents = m_fractureBuffers;
- actor->getTkActor().generateFracture(&fractureEvents, program, &programParams);
- actor->getTkActor().applyFracture(nullptr, &fractureEvents);
- }
- else
- {
- NvBlastExtImpactSpreadDamageDesc desc = {
- normalizedDamage,
- { position[0], position[1], position[2] },
- minDistance,
- maxDistance
- };
-
- programParams.damageDesc = &desc;
-
- program.graphShaderFunction = NvBlastExtImpactSpreadGraphShader;
- program.subgraphShaderFunction = NvBlastExtImpactSpreadSubgraphShader;
-
- NvBlastFractureBuffers fractureEvents = m_fractureBuffers;
- actor->getTkActor().generateFracture(&fractureEvents, program, &programParams);
- actor->getTkActor().applyFracture(nullptr, &fractureEvents);
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// Filter Shader
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-PxFilterFlags ExtImpactDamageManager::FilterShader(
- PxFilterObjectAttributes attributes0,
- PxFilterData filterData0,
- PxFilterObjectAttributes attributes1,
- PxFilterData filterData1,
- PxPairFlags& pairFlags,
- const void* constantBlock,
- uint32_t constantBlockSize)
-{
- PX_UNUSED(constantBlock);
- PX_UNUSED(constantBlockSize);
- // let triggers through
- if (PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1))
- {
- pairFlags = PxPairFlag::eTRIGGER_DEFAULT;
- return PxFilterFlags();
- }
-
- if ((PxFilterObjectIsKinematic(attributes0) || PxFilterObjectIsKinematic(attributes1)) &&
- (PxGetFilterObjectType(attributes0) == PxFilterObjectType::eRIGID_STATIC || PxGetFilterObjectType(attributes1) == PxFilterObjectType::eRIGID_STATIC))
- {
- return PxFilterFlag::eSUPPRESS;
- }
-
- // use a group-based mechanism if the first two filter data words are not 0
- uint32_t f0 = filterData0.word0 | filterData0.word1;
- uint32_t f1 = filterData1.word0 | filterData1.word1;
- if (f0 && f1 && !(filterData0.word0&filterData1.word1 || filterData1.word0&filterData0.word1))
- return PxFilterFlag::eSUPPRESS;
-
- // determine if we should suppress notification
- const bool suppressNotify = ((filterData0.word3 | filterData1.word3) & ExtPxManager::LEAF_CHUNK) != 0;
-
- pairFlags = PxPairFlag::eCONTACT_DEFAULT;
- if (!suppressNotify)
- {
- pairFlags = pairFlags
- | PxPairFlag::eNOTIFY_CONTACT_POINTS
- | PxPairFlag::eNOTIFY_THRESHOLD_FORCE_PERSISTS
- | PxPairFlag::eNOTIFY_THRESHOLD_FORCE_FOUND
- | PxPairFlag::eNOTIFY_TOUCH_FOUND
- | PxPairFlag::eNOTIFY_TOUCH_PERSISTS;
- }
-
- // eSOLVE_CONTACT is invalid with kinematic pairs
- if (PxFilterObjectIsKinematic(attributes0) && PxFilterObjectIsKinematic(attributes1))
- {
- pairFlags &= ~PxPairFlag::eSOLVE_CONTACT;
- }
-
- return PxFilterFlags();
-}
-
-} // namespace Blast
-} // namespace Nv
+// 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) 2016-2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "NvBlastExtImpactDamageManager.h"
+#include "NvBlastExtPxManager.h"
+#include "NvBlastExtPxFamily.h"
+#include "NvBlastExtPxActor.h"
+#include "NvBlastExtPxAsset.h"
+#include "NvBlastExtPxListener.h"
+
+#include "NvBlastAssert.h"
+
+#include "NvBlastExtDamageShaders.h"
+#include "NvBlastArray.h"
+
+#include "PxRigidDynamic.h"
+#include "PxSimulationEventCallback.h"
+#include "PxRigidBodyExt.h"
+
+#include "NvBlastTkFramework.h"
+#include "NvBlastTkActor.h"
+#include "NvBlastTkFamily.h"
+#include "NvBlastTkAsset.h"
+
+
+namespace Nv
+{
+namespace Blast
+{
+
+using namespace physx;
+
+const float MIN_IMPACT_VELOCITY_SQUARED = 1.0f;
+
+
+class ExtImpactDamageManagerImpl final : public ExtImpactDamageManager
+{
+public:
+ ExtImpactDamageManagerImpl(ExtPxManager* pxManager, ExtImpactSettings settings)
+ : m_pxManager(pxManager), m_settings(settings), m_listener(this), m_usePxUserData(m_pxManager->isPxUserDataUsed())
+ {
+ NVBLAST_ASSERT_WITH_MESSAGE(pxManager != nullptr, "ExtImpactDamageManager creation: input ExtPxManager is nullptr.");
+ m_pxManager->subscribe(m_listener);
+
+ m_impactDamageBuffer.reserve(32);
+ }
+
+ ~ExtImpactDamageManagerImpl()
+ {
+ m_pxManager->unsubscribe(m_listener);
+ }
+
+ virtual void release() override
+ {
+ NVBLAST_DELETE(this, ExtImpactDamageManagerImpl);
+ }
+
+
+ //////// interface ////////
+
+ virtual void setSettings(const ExtImpactSettings& settings) override
+ {
+ m_settings = settings;
+ }
+
+ virtual void onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, uint32_t nbPairs) override;
+
+ virtual void applyDamage() override;
+
+
+ //////// public methods ////////
+
+ void queueImpactDamage(ExtPxActor* actor, PxVec3 force, PxVec3 position, PxShape* shape)
+ {
+ ImpactDamageData data = { actor, force, position, shape };
+ m_impactDamageBuffer.pushBack(data);
+ }
+
+
+private:
+ //////// physics manager listener ////////
+
+ class PxManagerListener : public ExtPxListener
+ {
+ public:
+ PxManagerListener(ExtImpactDamageManagerImpl* manager) : m_manager(manager) {}
+
+ virtual void onActorCreated(ExtPxFamily&, ExtPxActor&) override {}
+ virtual void onActorDestroyed(ExtPxFamily& family, ExtPxActor& actor) override
+ {
+ NV_UNUSED(family);
+
+ // filter out actor from queued buffer
+ auto& buffer = m_manager->m_impactDamageBuffer;
+ for (int32_t i = 0; i < (int32_t)buffer.size(); ++i)
+ {
+ if (buffer[i].actor == &actor)
+ {
+ buffer.replaceWithLast(i);
+ i--;
+ }
+ }
+ }
+ private:
+ ExtImpactDamageManagerImpl* m_manager;
+ };
+
+
+ //////// private methods ////////
+
+ void ensureBuffersSize(ExtPxActor* actor);
+ void damageActor(ExtPxActor* actor, PxShape* shape, PxVec3 position, PxVec3 force);
+
+
+ //////// data ////////
+
+ ExtPxManager* m_pxManager;
+ ExtImpactSettings m_settings;
+ PxManagerListener m_listener;
+ Array<PxContactPairPoint>::type m_pairPointBuffer;
+ bool m_usePxUserData;
+
+ struct ImpactDamageData
+ {
+ ExtPxActor* actor;
+ PxVec3 force;
+ PxVec3 position;
+ PxShape* shape;
+ };
+
+ Array<ImpactDamageData>::type m_impactDamageBuffer;
+
+ NvBlastFractureBuffers m_fractureBuffers;
+ Array<uint8_t>::type m_fractureData;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// ExtImpactDamageManagerImpl
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ExtImpactDamageManager* ExtImpactDamageManager::create(ExtPxManager* pxManager, ExtImpactSettings settings)
+{
+ return NVBLAST_NEW(ExtImpactDamageManagerImpl) (pxManager, settings);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// onContact callback call
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void ExtImpactDamageManagerImpl::onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, uint32_t nbPairs)
+{
+ if (pairHeader.flags & physx::PxContactPairHeaderFlag::eREMOVED_ACTOR_0 ||
+ pairHeader.flags & physx::PxContactPairHeaderFlag::eREMOVED_ACTOR_1 ||
+ pairHeader.actors[0] == nullptr ||
+ pairHeader.actors[1] == nullptr)
+ {
+ return;
+ }
+
+ PxRigidActor* rigidActor0 = pairHeader.actors[0];
+ PxRigidActor* rigidActor1 = pairHeader.actors[1];
+
+ ExtPxActor* actors[2];
+
+ if (m_usePxUserData)
+ {
+ actors[0] = (ExtPxActor*)rigidActor0->userData;
+ actors[1] = (ExtPxActor*)rigidActor1->userData;
+ }
+ else
+ {
+ PxRigidDynamic* rigidDynamic0 = rigidActor0->is<PxRigidDynamic>();
+ PxRigidDynamic* rigidDynamic1 = rigidActor1->is<PxRigidDynamic>();
+ actors[0] = rigidDynamic0 ? m_pxManager->getActorFromPhysXActor(*rigidDynamic0) : nullptr;
+ actors[1] = rigidDynamic1 ? m_pxManager->getActorFromPhysXActor(*rigidDynamic1) : nullptr;
+ }
+
+
+ // check one of them is blast actor
+ if (actors[0] == nullptr && actors[1] == nullptr)
+ {
+ return;
+ }
+
+ // self-collision check
+ if (actors[0] != nullptr && actors[1] != nullptr)
+ {
+ if (&actors[0]->getFamily() == &actors[1]->getFamily() && !m_settings.isSelfCollissionEnabled)
+ return;
+ }
+
+ for (uint32_t pairIdx = 0; pairIdx < nbPairs; pairIdx++)
+ {
+ const PxContactPair& currentPair = pairs[pairIdx];
+
+ if (currentPair.flags & physx::PxContactPairFlag::eREMOVED_SHAPE_0 ||
+ currentPair.flags & physx::PxContactPairFlag::eREMOVED_SHAPE_1 ||
+ currentPair.shapes[0] == nullptr ||
+ currentPair.shapes[1] == nullptr)
+ {
+ continue;
+ }
+
+ float masses[2] = { 0, 0 };
+ {
+ for (int i = 0; i < 2; ++i)
+ {
+ PxRigidDynamic* rigidDynamic = pairHeader.actors[i]->is<physx::PxRigidDynamic>();
+ if (rigidDynamic)
+ {
+ if (!(rigidDynamic->getRigidBodyFlags() & physx::PxRigidBodyFlag::eKINEMATIC))
+ {
+ masses[i] = rigidDynamic->getMass();
+ }
+ }
+ }
+ };
+
+ float reducedMass;
+ if (masses[0] == 0.0f)
+ {
+ reducedMass = masses[1];
+ }
+ else if (masses[1] == 0.0f)
+ {
+ reducedMass = masses[0];
+ }
+ else
+ {
+ reducedMass = masses[0] * masses[1] / (masses[0] + masses[1]);
+ }
+
+
+ PxVec3 destructibleForces[2] = { PxVec3(0.0f), PxVec3(0.0f) };
+ PxVec3 avgContactPosition = PxVec3(0.0f);
+ PxVec3 avgContactNormal = PxVec3(0.0f);
+ uint32_t numContacts = 0;
+
+ m_pairPointBuffer.resize(currentPair.contactCount);
+ uint32_t numContactsInStream = currentPair.contactCount > 0 ? currentPair.extractContacts(m_pairPointBuffer.begin(), currentPair.contactCount) : 0;
+
+ for (uint32_t contactIdx = 0; contactIdx < numContactsInStream; contactIdx++)
+ {
+ PxContactPairPoint& currentPoint = m_pairPointBuffer[contactIdx];
+
+ const PxVec3& patchNormal = currentPoint.normal;
+ const PxVec3& position = currentPoint.position;
+ PxVec3 velocities[2] = { PxVec3(0.0f), PxVec3(0.0f) };
+ for (int i = 0; i < 2; ++i)
+ {
+ PxRigidBody* rigidBody = pairHeader.actors[i]->is<physx::PxRigidBody>();
+ if (rigidBody)
+ {
+ velocities[i] = physx::PxRigidBodyExt::getVelocityAtPos(*rigidBody, position);
+ }
+ }
+
+ const PxVec3 velocityDelta = velocities[0] - velocities[1];
+ if (velocityDelta.magnitudeSquared() >= MIN_IMPACT_VELOCITY_SQUARED || reducedMass == 0.0f) // If reduced mass == 0, this is kineamtic vs. kinematic. Generate damage.
+ {
+ for (int i = 0; i < 2; ++i)
+ {
+ if (actors[i])
+ {
+ // this is not really physically correct, but at least its deterministic...
+ destructibleForces[i] += (patchNormal * patchNormal.dot(velocityDelta)) * reducedMass * (i ? 1.0f : -1.0f);
+ }
+ }
+ avgContactPosition += position;
+ avgContactNormal += patchNormal;
+ numContacts++;
+ }
+ }
+
+ if (numContacts)
+ {
+ avgContactPosition /= (float)numContacts;
+ avgContactNormal.normalize();
+ for (uint32_t i = 0; i < 2; i++)
+ {
+ const PxVec3 force = destructibleForces[i] / (float)numContacts;
+ ExtPxActor* actor = actors[i];
+ if (actor != nullptr)
+ {
+ if (!force.isZero())
+ {
+ queueImpactDamage(actor, force, avgContactPosition, currentPair.shapes[i]);
+ }
+ else if (reducedMass == 0.0f) // Handle kinematic vs. kinematic
+ {
+ // holy molly
+ }
+ }
+ }
+ }
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// ExtImpactDamageManager damage processing
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void ExtImpactDamageManagerImpl::applyDamage()
+{
+ const auto damageFn = m_settings.damageFunction;
+ const auto damageFnData = m_settings.damageFunctionData;
+
+ for (const ImpactDamageData& data : m_impactDamageBuffer)
+ {
+ PxTransform t(data.actor->getPhysXActor().getGlobalPose().getInverse());
+ PxVec3 force = t.rotate(data.force);
+ PxVec3 position = t.transform(data.position);
+
+ if (!damageFn || !damageFn(damageFnData, data.actor, data.shape, position, force))
+ {
+ damageActor(data.actor, data.shape, position, force);
+ }
+ }
+ m_impactDamageBuffer.clear();
+}
+
+void ExtImpactDamageManagerImpl::ensureBuffersSize(ExtPxActor* actor)
+{
+ const TkAsset* tkAsset = actor->getTkActor().getAsset();
+ const uint32_t chunkCount = tkAsset->getChunkCount();
+ const uint32_t bondCount = tkAsset->getBondCount();
+
+ m_fractureBuffers.bondFractureCount = bondCount;
+ m_fractureBuffers.chunkFractureCount = chunkCount;
+ m_fractureData.resize((uint32_t)(m_fractureBuffers.bondFractureCount*sizeof(NvBlastBondFractureData) + m_fractureBuffers.chunkFractureCount*sizeof(NvBlastChunkFractureData))); // chunk count + bond count
+ m_fractureBuffers.chunkFractures = reinterpret_cast<NvBlastChunkFractureData*>(m_fractureData.begin());
+ m_fractureBuffers.bondFractures = reinterpret_cast<NvBlastBondFractureData*>(&m_fractureData.begin()[m_fractureBuffers.chunkFractureCount*sizeof(NvBlastChunkFractureData)]);
+}
+
+void ExtImpactDamageManagerImpl::damageActor(ExtPxActor* actor, PxShape* /*shape*/, PxVec3 position, PxVec3 force)
+{
+ ensureBuffersSize(actor);
+
+ const float damage = m_settings.hardness > 0.f ? force.magnitude() / m_settings.hardness : 0.f;
+
+ const NvBlastExtMaterial* material = actor->getFamily().getMaterial();
+ if (!material)
+ {
+ return;
+ }
+
+ float normalizedDamage = material->getNormalizedDamage(damage);
+ if (normalizedDamage == 0.f || normalizedDamage < m_settings.damageThresholdMin)
+ {
+ return;
+ }
+ normalizedDamage = PxClamp<float>(normalizedDamage, 0, m_settings.damageThresholdMax);
+
+ const PxVec3 normal = force.getNormalized();
+ const float minDistance = m_settings.damageRadiusMax * normalizedDamage;
+ const float maxDistance = minDistance * PxClamp<float>(m_settings.damageFalloffRadiusFactor, 1, 32);
+
+ NvBlastExtProgramParams programParams(nullptr);
+ programParams.material = material;
+ programParams.accelerator = actor->getFamily().getPxAsset().getAccelerator();
+ NvBlastDamageProgram program;
+
+ if (m_settings.shearDamage)
+ {
+ NvBlastExtShearDamageDesc desc = {
+ normalizedDamage,
+ { normal[0], normal[1], normal[2] },
+ { position[0], position[1], position[2] },
+ minDistance,
+ maxDistance
+ };
+
+ programParams.damageDesc = &desc;
+
+ program.graphShaderFunction = NvBlastExtShearGraphShader;
+ program.subgraphShaderFunction = NvBlastExtShearSubgraphShader;
+
+ NvBlastFractureBuffers fractureEvents = m_fractureBuffers;
+ actor->getTkActor().generateFracture(&fractureEvents, program, &programParams);
+ actor->getTkActor().applyFracture(nullptr, &fractureEvents);
+ }
+ else
+ {
+ NvBlastExtImpactSpreadDamageDesc desc = {
+ normalizedDamage,
+ { position[0], position[1], position[2] },
+ minDistance,
+ maxDistance
+ };
+
+ programParams.damageDesc = &desc;
+
+ program.graphShaderFunction = NvBlastExtImpactSpreadGraphShader;
+ program.subgraphShaderFunction = NvBlastExtImpactSpreadSubgraphShader;
+
+ NvBlastFractureBuffers fractureEvents = m_fractureBuffers;
+ actor->getTkActor().generateFracture(&fractureEvents, program, &programParams);
+ actor->getTkActor().applyFracture(nullptr, &fractureEvents);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Filter Shader
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+PxFilterFlags ExtImpactDamageManager::FilterShader(
+ PxFilterObjectAttributes attributes0,
+ PxFilterData filterData0,
+ PxFilterObjectAttributes attributes1,
+ PxFilterData filterData1,
+ PxPairFlags& pairFlags,
+ const void* constantBlock,
+ uint32_t constantBlockSize)
+{
+ PX_UNUSED(constantBlock);
+ PX_UNUSED(constantBlockSize);
+ // let triggers through
+ if (PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1))
+ {
+ pairFlags = PxPairFlag::eTRIGGER_DEFAULT;
+ return PxFilterFlags();
+ }
+
+ if ((PxFilterObjectIsKinematic(attributes0) || PxFilterObjectIsKinematic(attributes1)) &&
+ (PxGetFilterObjectType(attributes0) == PxFilterObjectType::eRIGID_STATIC || PxGetFilterObjectType(attributes1) == PxFilterObjectType::eRIGID_STATIC))
+ {
+ return PxFilterFlag::eSUPPRESS;
+ }
+
+ // use a group-based mechanism if the first two filter data words are not 0
+ uint32_t f0 = filterData0.word0 | filterData0.word1;
+ uint32_t f1 = filterData1.word0 | filterData1.word1;
+ if (f0 && f1 && !(filterData0.word0&filterData1.word1 || filterData1.word0&filterData0.word1))
+ return PxFilterFlag::eSUPPRESS;
+
+ // determine if we should suppress notification
+ const bool suppressNotify = ((filterData0.word3 | filterData1.word3) & ExtPxManager::LEAF_CHUNK) != 0;
+
+ pairFlags = PxPairFlag::eCONTACT_DEFAULT;
+ if (!suppressNotify)
+ {
+ pairFlags = pairFlags
+ | PxPairFlag::eNOTIFY_CONTACT_POINTS
+ | PxPairFlag::eNOTIFY_THRESHOLD_FORCE_PERSISTS
+ | PxPairFlag::eNOTIFY_THRESHOLD_FORCE_FOUND
+ | PxPairFlag::eNOTIFY_TOUCH_FOUND
+ | PxPairFlag::eNOTIFY_TOUCH_PERSISTS;
+ }
+
+ // eSOLVE_CONTACT is invalid with kinematic pairs
+ if (PxFilterObjectIsKinematic(attributes0) && PxFilterObjectIsKinematic(attributes1))
+ {
+ pairFlags &= ~PxPairFlag::eSOLVE_CONTACT;
+ }
+
+ return PxFilterFlags();
+}
+
+} // namespace Blast
+} // namespace Nv