From 7115f60b91b5717d90f643fd692010905c7004db Mon Sep 17 00:00:00 2001 From: Bryan Galdrikian Date: Thu, 31 May 2018 11:36:08 -0700 Subject: Blast 1.1.3. See docs/release_notes.txt. --- .../physics/NvBlastExtImpactDamageManager.cpp | 978 ++++++++++----------- 1 file changed, 489 insertions(+), 489 deletions(-) mode change 100644 => 100755 sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp (limited to 'sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp') diff --git a/sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp b/sdk/extensions/physx/source/physics/NvBlastExtImpactDamageManager.cpp old mode 100644 new mode 100755 index 205c77e..7f86021 --- 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::type m_pairPointBuffer; - bool m_usePxUserData; - - struct ImpactDamageData - { - ExtPxActor* actor; - PxVec3 force; - PxVec3 position; - PxShape* shape; - }; - - Array::type m_impactDamageBuffer; - - NvBlastFractureBuffers m_fractureBuffers; - Array::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* rigidDynamic1 = rigidActor1->is(); - 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(); - 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(); - 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(m_fractureData.begin()); - m_fractureBuffers.bondFractures = reinterpret_cast(&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(normalizedDamage, 0, m_settings.damageThresholdMax); - - const PxVec3 normal = force.getNormalized(); - const float minDistance = m_settings.damageRadiusMax * normalizedDamage; - const float maxDistance = minDistance * PxClamp(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::type m_pairPointBuffer; + bool m_usePxUserData; + + struct ImpactDamageData + { + ExtPxActor* actor; + PxVec3 force; + PxVec3 position; + PxShape* shape; + }; + + Array::type m_impactDamageBuffer; + + NvBlastFractureBuffers m_fractureBuffers; + Array::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* rigidDynamic1 = rigidActor1->is(); + 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(); + 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(); + 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(m_fractureData.begin()); + m_fractureBuffers.bondFractures = reinterpret_cast(&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(normalizedDamage, 0, m_settings.damageThresholdMax); + + const PxVec3 normal = force.getNormalized(); + const float minDistance = m_settings.damageRadiusMax * normalizedDamage; + const float maxDistance = minDistance * PxClamp(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 -- cgit v1.2.3