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. --- samples/SampleBase/blast/BlastController.cpp | 1066 +++++++++++++------------- 1 file changed, 533 insertions(+), 533 deletions(-) mode change 100644 => 100755 samples/SampleBase/blast/BlastController.cpp (limited to 'samples/SampleBase/blast/BlastController.cpp') diff --git a/samples/SampleBase/blast/BlastController.cpp b/samples/SampleBase/blast/BlastController.cpp old mode 100644 new mode 100755 index c1e977e..e185922 --- a/samples/SampleBase/blast/BlastController.cpp +++ b/samples/SampleBase/blast/BlastController.cpp @@ -1,533 +1,533 @@ -// 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-2018 NVIDIA Corporation. All rights reserved. - - -#include "BlastController.h" -#include "BlastFamily.h" -#include "BlastAsset.h" -#include "BlastReplay.h" -#include "PhysXController.h" -#include "SampleTime.h" -#include "SampleProfiler.h" -#include "Utils.h" -#include "Renderer.h" - -#include "NvBlastExtPxTask.h" - -#include "NvBlast.h" -#include "NvBlastPxCallbacks.h" -#include "NvBlastExtPxManager.h" -#include "NvBlastExtPxFamily.h" -#include "NvBlastExtPxActor.h" -#include "NvBlastExtPxAsset.h" -#include "NvBlastExtSerialization.h" -#include "NvBlastExtTkSerialization.h" -#include "NvBlastExtPxSerialization.h" - -#include "NvBlastTkFramework.h" - -#include "PsString.h" -#include "PxTaskManager.h" -#include "PxDefaultCpuDispatcher.h" -#include "PxRigidBody.h" -#include "PxScene.h" -#include "PxRigidDynamic.h" -#include "PxDistanceJoint.h" - -#include -#include -#include - -#include "imgui.h" - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Joint creation -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static physx::PxJoint* createPxJointCallback(ExtPxActor* actor0, const physx::PxTransform& localFrame0, ExtPxActor* actor1, const physx::PxTransform& localFrame1, physx::PxPhysics& physics, TkJoint& joint) -{ - PxDistanceJoint* pxJoint = PxDistanceJointCreate(physics, actor0 ? &actor0->getPhysXActor() : nullptr, localFrame0, actor1 ? &actor1->getPhysXActor() : nullptr, localFrame1); - pxJoint->setMaxDistance(1.0f); - return pxJoint; -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Controller -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -BlastController::BlastController() -: m_eventCallback(nullptr), debugRenderMode(BlastFamily::DEBUG_RENDER_DISABLED), m_impactDamageEnabled(true), -m_impactDamageToStressEnabled(false), m_rigidBodyLimitEnabled(true), m_rigidBodyLimit(40000), m_blastAssetsSize(0), debugRenderScale(0.01f), -m_taskManager(nullptr), m_extGroupTaskManager(nullptr), m_damageDescBuffer(64 * 1024), m_damageParamsBuffer(1024) -{ - m_impactDamageToStressFactor = 0.01f; - m_draggingToStressFactor = 100.0f; -} - - -BlastController::~BlastController() -{ -} - -void BlastController::reinitialize() -{ - onSampleStop(); - onSampleStart(); -} - -void BlastController::onSampleStart() -{ - m_tkFramework = NvBlastTkFrameworkCreate(); - - m_replay = new BlastReplay(); - - m_taskManager = PxTaskManager::createTaskManager(NvBlastGetPxErrorCallback(), getPhysXController().getCPUDispatcher(), 0); - - TkGroupDesc gdesc; - gdesc.workerCount = m_taskManager->getCpuDispatcher()->getWorkerCount(); - m_tkGroup = m_tkFramework->createGroup(gdesc); - - m_extPxManager = ExtPxManager::create(getPhysXController().getPhysics(), *m_tkFramework, createPxJointCallback); - m_extPxManager->setActorCountLimit(m_rigidBodyLimitEnabled ? m_rigidBodyLimit : 0); - m_extImpactDamageManager = ExtImpactDamageManager::create(m_extPxManager, m_extImpactDamageManagerSettings); - m_eventCallback = new EventCallback(m_extImpactDamageManager); - - m_extGroupTaskManager = ExtGroupTaskManager::create(*m_taskManager); - m_extGroupTaskManager->setGroup(m_tkGroup); - - setImpactDamageEnabled(m_impactDamageEnabled, true); - - m_extSerialization = NvBlastExtSerializationCreate(); - if (m_extSerialization != nullptr) - { - NvBlastExtTkSerializerLoadSet(*m_tkFramework, *m_extSerialization); - NvBlastExtPxSerializerLoadSet(*m_tkFramework, getPhysXController().getPhysics(), getPhysXController().getCooking(), *m_extSerialization); - } -} - - -void BlastController::onSampleStop() -{ - getPhysXController().simualtionSyncEnd(); - - removeAllFamilies(); - - m_extImpactDamageManager->release(); - m_extPxManager->release(); - SAFE_DELETE(m_eventCallback); - - m_tkGroup->release(); - - delete m_replay; - - m_tkFramework->release(); - - if (m_extGroupTaskManager != nullptr) - { - m_extGroupTaskManager->release(); - m_extGroupTaskManager = nullptr; - } - - if (m_taskManager != nullptr) - { - m_taskManager->release(); - } -} - - -void BlastController::notifyPhysXControllerRelease() -{ - if (m_extGroupTaskManager != nullptr) - { - m_extGroupTaskManager->release(); - m_extGroupTaskManager = nullptr; - } - - if (m_taskManager != nullptr) - { - m_taskManager->release(); - m_taskManager = nullptr; - } -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Deffered/Immediate damage -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void BlastController::deferDamage(ExtPxActor *actor, BlastFamily& family, const NvBlastDamageProgram& program, const void* damageDesc, uint32_t damageDescSize) -{ - const void* bufferedDamageDesc = m_damageDescBuffer.push(damageDesc, damageDescSize); - PX_ASSERT_WITH_MESSAGE(bufferedDamageDesc, "Damage desc buffer exhausted."); - - NvBlastExtProgramParams programParams = { bufferedDamageDesc, &family.getMaterial(), actor->getFamily().getPxAsset().getAccelerator() }; - - const void* bufferedProgramParams = m_damageParamsBuffer.push(&programParams, sizeof(NvBlastExtProgramParams)); - PX_ASSERT_WITH_MESSAGE(bufferedProgramParams, "Damage params buffer exhausted."); - - if (bufferedDamageDesc && bufferedProgramParams) - { - actor->getTkActor().damage(program, bufferedProgramParams); - } -} - -NvBlastFractureBuffers& BlastController::getFractureBuffers(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.data()); - m_fractureBuffers.bondFractures = reinterpret_cast(&m_fractureData.data()[m_fractureBuffers.chunkFractureCount * sizeof(NvBlastChunkFractureData)]); - return m_fractureBuffers; -} - -void BlastController::immediateDamage(ExtPxActor *actor, BlastFamily& family, const NvBlastDamageProgram& program, const void* damageDesc) -{ - NvBlastExtProgramParams programParams = { damageDesc, &family.getMaterial(), actor->getFamily().getPxAsset().getAccelerator() }; - - NvBlastFractureBuffers& fractureEvents = getFractureBuffers(actor); - actor->getTkActor().generateFracture(&fractureEvents, program, &programParams); - actor->getTkActor().applyFracture(nullptr, &fractureEvents); -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Impact damage -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void BlastController::updateImpactDamage() -{ - if (m_impactDamageUpdatePending) - { - getPhysXController().getPhysXScene().setSimulationEventCallback(m_impactDamageEnabled ? m_eventCallback : nullptr); - refreshImpactDamageSettings(); - m_impactDamageUpdatePending = false; - } -} - -void BlastController::setImpactDamageEnabled(bool enabled, bool forceUpdate) -{ - if (m_impactDamageEnabled != enabled || forceUpdate) - { - m_impactDamageEnabled = enabled; - m_impactDamageUpdatePending = true; - } -} - -bool BlastController::customImpactDamageFunction(void* data, ExtPxActor* actor, physx::PxShape* shape, physx::PxVec3 position, physx::PxVec3 force) -{ - return reinterpret_cast(data)->stressDamage(actor, position, force); -} - -bool BlastController::stressDamage(ExtPxActor *actor, physx::PxVec3 position, physx::PxVec3 force) -{ - if (actor->getTkActor().getGraphNodeCount() > 1) - { - void* userData = actor->getFamily().userData; - if (userData) - { - ExtPxStressSolver* solver = reinterpret_cast(userData); - solver->getSolver().addForce(*actor->getTkActor().getActorLL(), position, force * m_impactDamageToStressFactor); - return true; - } - } - - return false; -} - -void BlastController::refreshImpactDamageSettings() -{ - m_extImpactDamageManagerSettings.damageFunction = m_impactDamageToStressEnabled ? customImpactDamageFunction : nullptr; - m_extImpactDamageManagerSettings.damageFunctionData = this; - m_extImpactDamageManager->setSettings(m_extImpactDamageManagerSettings); -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Stress -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void BlastController::updateDraggingStress() -{ - auto physxController = getPhysXController(); - auto actor = physxController.getDraggingActor(); - if (actor) - { - ExtPxActor* pxActor = m_extPxManager->getActorFromPhysXActor(*actor); - if (pxActor && pxActor->getTkActor().getGraphNodeCount() > 1 && pxActor->getPhysXActor().getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC) - { - void* userData = pxActor->getFamily().userData; - if (userData) - { - ExtPxStressSolver* solver = reinterpret_cast(userData); - PxTransform t(pxActor->getPhysXActor().getGlobalPose().getInverse()); - PxVec3 dragVector = t.rotate(physxController.getDragVector()); - const float factor = dragVector.magnitudeSquared() * m_draggingToStressFactor; - solver->getSolver().addForce(*pxActor->getTkActor().getActorLL(), physxController.getDragActorHookLocalPoint(), dragVector.getNormalized() * factor); - } - } - } -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Stats -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -uint32_t BlastController::getActorCount() const -{ - return std::accumulate(m_families.begin(), m_families.end(), (uint32_t)0, [](uint32_t sum, const BlastFamilyPtr& a) - { - return sum += a->getActorCount(); - }); -} - -uint32_t BlastController::getTotalVisibleChunkCount() const -{ - return std::accumulate(m_families.begin(), m_families.end(), (uint32_t)0, [](uint32_t sum, const BlastFamilyPtr& a) - { - return sum += a->getTotalVisibleChunkCount(); - }); -} - -size_t BlastController::getFamilySize() const -{ - return std::accumulate(m_families.begin(), m_families.end(), (size_t)0, [](size_t sum, const BlastFamilyPtr& a) - { - return sum += a->getFamilySize(); - }); -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Time -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -const double Time::s_secondsPerTick = Time::getTickDuration(); - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Controller events -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void BlastController::Animate(double dt) -{ - PROFILER_SCOPED_FUNCTION(); - - PROFILER_BEGIN("Apply Impact Damage"); - m_extImpactDamageManager->applyDamage(); - PROFILER_END(); - - updateDraggingStress(); - - fillDebugRender(); - - getPhysXController().simualtionSyncEnd(); - - updateImpactDamage(); - - Time blastTime; - for (uint32_t i = 0; i < m_families.size(); ++i) - { - if (m_families[i]) - { - m_families[i]->updatePreSplit(dt); - } - } - - m_replay->update(); - - PROFILER_BEGIN("Tk Group Process/Sync"); - -#if 1 - - m_extGroupTaskManager->process(); - m_extGroupTaskManager->wait(); - -#else // process group on main thread - - m_tkGroup->process(); - -#endif - - m_damageParamsBuffer.clear(); - m_damageDescBuffer.clear(); - - PROFILER_END(); - - getPhysXController().simulationBegin(dt); - - TkGroupStats gstats; - m_tkGroup->getStats(gstats); - - this->m_lastBlastTimers.blastDamageMaterial = NvBlastTicksToSeconds(gstats.timers.material); - this->m_lastBlastTimers.blastDamageFracture = NvBlastTicksToSeconds(gstats.timers.fracture); - this->m_lastBlastTimers.blastSplitIsland = NvBlastTicksToSeconds(gstats.timers.island); - this->m_lastBlastTimers.blastSplitPartition = NvBlastTicksToSeconds(gstats.timers.partition); - this->m_lastBlastTimers.blastSplitVisibility = NvBlastTicksToSeconds(gstats.timers.visibility); - - for (uint32_t i = 0; i < m_families.size(); ++i) - { - if (m_families[i]) - { - m_families[i]->updateAfterSplit(dt); - } - } -} - - -void BlastController::drawUI() -{ - // impact damage - bool impactEnabled = getImpactDamageEnabled(); - if (ImGui::Checkbox("Impact Damage", &impactEnabled)) - { - setImpactDamageEnabled(impactEnabled); - } - { - bool refresh = false; - refresh |= ImGui::Checkbox("Use Shear Damage", &m_extImpactDamageManagerSettings.shearDamage); - refresh |= ImGui::DragFloat("Material Hardness", &m_extImpactDamageManagerSettings.hardness); - refresh |= ImGui::DragFloat("Damage Radius (Max)", &m_extImpactDamageManagerSettings.damageRadiusMax); - refresh |= ImGui::DragFloat("Damage Threshold (Min)", &m_extImpactDamageManagerSettings.damageThresholdMin, 1.0f, 0.0f, 1.0f); - refresh |= ImGui::DragFloat("Damage Threshold (Max)", &m_extImpactDamageManagerSettings.damageThresholdMax, 1.0f, 0.0f, 1.0f); - refresh |= ImGui::DragFloat("Damage Falloff Radius Factor", &m_extImpactDamageManagerSettings.damageFalloffRadiusFactor, 1.0f, 0.0f, 32.0f); - refresh |= ImGui::Checkbox("Impact Damage To Stress Solver", &m_impactDamageToStressEnabled); - - if (refresh) - { - refreshImpactDamageSettings(); - } - } - - ImGui::DragFloat("Impact Damage To Stress Factor", &m_impactDamageToStressFactor, 0.001f, 0.0f, 1000.0f, "%.4f"); - ImGui::DragFloat("Dragging To Stress Factor", &m_draggingToStressFactor, 0.1f, 0.0f, 1000.0f, "%.3f"); - - ImGui::Checkbox("Limit Rigid Body Count", &m_rigidBodyLimitEnabled); - if (m_rigidBodyLimitEnabled) - { - ImGui::DragInt("Rigid Body Limit", (int*)&m_rigidBodyLimit, 100, 1000, 100000); - } - m_extPxManager->setActorCountLimit(m_rigidBodyLimitEnabled ? m_rigidBodyLimit : 0); -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// actor management -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -BlastFamilyPtr BlastController::spawnFamily(BlastAsset* blastAsset, const BlastAsset::ActorDesc& desc) -{ - BlastFamilyPtr actor = blastAsset->createFamily(getPhysXController(), *m_extPxManager, desc); - m_families.push_back(actor); - recalculateAssetsSize(); - m_replay->addFamily(&actor->getFamily()->getTkFamily()); - return actor; -} - -void BlastController::removeFamily(BlastFamilyPtr actor) -{ - m_replay->removeFamily(&actor->getFamily()->getTkFamily()); - m_families.erase(std::remove(m_families.begin(), m_families.end(), actor), m_families.end()); - recalculateAssetsSize(); - getPhysXController().resetDragging(); -} - -void BlastController::removeAllFamilies() -{ - while (!m_families.empty()) - { - removeFamily(m_families.back()); - } - m_replay->reset(); -} - -void BlastController::recalculateAssetsSize() -{ - std::set uniquedAssets; - m_blastAssetsSize = 0; - for (uint32_t i = 0; i < m_families.size(); ++i) - { - if (uniquedAssets.find(&m_families[i]->getBlastAsset()) == uniquedAssets.end()) - { - m_blastAssetsSize += m_families[i]->getBlastAsset().getBlastAssetSize(); - uniquedAssets.insert(&m_families[i]->getBlastAsset()); - } - } -} - -bool BlastController::overlap(const PxGeometry& geometry, const PxTransform& pose, std::function hitCall) -{ - PROFILER_SCOPED_FUNCTION(); - - bool anyHit = false; - for (uint32_t i = 0; i < m_families.size(); ++i) - { - if (m_families[i]) - { - anyHit |= m_families[i]->overlap(geometry, pose, hitCall); - } - } - return anyHit; -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// debug render -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void BlastController::fillDebugRender() -{ - PROFILER_SCOPED_FUNCTION(); - - m_debugRenderBuffer.clear(); - - if (debugRenderMode != BlastFamily::DEBUG_RENDER_DISABLED) - { - getPhysXController().getPhysXScene().setVisualizationParameter(PxVisualizationParameter::eSCALE, 1); - for (uint32_t i = 0; i < m_families.size(); ++i) - { - m_families[i]->fillDebugRender(m_debugRenderBuffer, debugRenderMode, debugRenderScale); - } - } - else - { - getPhysXController().getPhysXScene().setVisualizationParameter(PxVisualizationParameter::eSCALE, 0); - } - - getRenderer().queueRenderBuffer(&m_debugRenderBuffer); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// 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-2018 NVIDIA Corporation. All rights reserved. + + +#include "BlastController.h" +#include "BlastFamily.h" +#include "BlastAsset.h" +#include "BlastReplay.h" +#include "PhysXController.h" +#include "SampleTime.h" +#include "SampleProfiler.h" +#include "Utils.h" +#include "Renderer.h" + +#include "NvBlastExtPxTask.h" + +#include "NvBlast.h" +#include "NvBlastPxCallbacks.h" +#include "NvBlastExtPxManager.h" +#include "NvBlastExtPxFamily.h" +#include "NvBlastExtPxActor.h" +#include "NvBlastExtPxAsset.h" +#include "NvBlastExtSerialization.h" +#include "NvBlastExtTkSerialization.h" +#include "NvBlastExtPxSerialization.h" + +#include "NvBlastTkFramework.h" + +#include "PsString.h" +#include "PxTaskManager.h" +#include "PxDefaultCpuDispatcher.h" +#include "PxRigidBody.h" +#include "PxScene.h" +#include "PxRigidDynamic.h" +#include "PxDistanceJoint.h" + +#include +#include +#include + +#include "imgui.h" + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Joint creation +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static physx::PxJoint* createPxJointCallback(ExtPxActor* actor0, const physx::PxTransform& localFrame0, ExtPxActor* actor1, const physx::PxTransform& localFrame1, physx::PxPhysics& physics, TkJoint& joint) +{ + PxDistanceJoint* pxJoint = PxDistanceJointCreate(physics, actor0 ? &actor0->getPhysXActor() : nullptr, localFrame0, actor1 ? &actor1->getPhysXActor() : nullptr, localFrame1); + pxJoint->setMaxDistance(1.0f); + return pxJoint; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Controller +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +BlastController::BlastController() +: m_eventCallback(nullptr), debugRenderMode(BlastFamily::DEBUG_RENDER_DISABLED), m_impactDamageEnabled(true), +m_impactDamageToStressEnabled(false), m_rigidBodyLimitEnabled(true), m_rigidBodyLimit(40000), m_blastAssetsSize(0), debugRenderScale(0.01f), +m_taskManager(nullptr), m_extGroupTaskManager(nullptr), m_damageDescBuffer(64 * 1024), m_damageParamsBuffer(1024) +{ + m_impactDamageToStressFactor = 0.01f; + m_draggingToStressFactor = 100.0f; +} + + +BlastController::~BlastController() +{ +} + +void BlastController::reinitialize() +{ + onSampleStop(); + onSampleStart(); +} + +void BlastController::onSampleStart() +{ + m_tkFramework = NvBlastTkFrameworkCreate(); + + m_replay = new BlastReplay(); + + m_taskManager = PxTaskManager::createTaskManager(NvBlastGetPxErrorCallback(), getPhysXController().getCPUDispatcher(), 0); + + TkGroupDesc gdesc; + gdesc.workerCount = m_taskManager->getCpuDispatcher()->getWorkerCount(); + m_tkGroup = m_tkFramework->createGroup(gdesc); + + m_extPxManager = ExtPxManager::create(getPhysXController().getPhysics(), *m_tkFramework, createPxJointCallback); + m_extPxManager->setActorCountLimit(m_rigidBodyLimitEnabled ? m_rigidBodyLimit : 0); + m_extImpactDamageManager = ExtImpactDamageManager::create(m_extPxManager, m_extImpactDamageManagerSettings); + m_eventCallback = new EventCallback(m_extImpactDamageManager); + + m_extGroupTaskManager = ExtGroupTaskManager::create(*m_taskManager); + m_extGroupTaskManager->setGroup(m_tkGroup); + + setImpactDamageEnabled(m_impactDamageEnabled, true); + + m_extSerialization = NvBlastExtSerializationCreate(); + if (m_extSerialization != nullptr) + { + NvBlastExtTkSerializerLoadSet(*m_tkFramework, *m_extSerialization); + NvBlastExtPxSerializerLoadSet(*m_tkFramework, getPhysXController().getPhysics(), getPhysXController().getCooking(), *m_extSerialization); + } +} + + +void BlastController::onSampleStop() +{ + getPhysXController().simualtionSyncEnd(); + + removeAllFamilies(); + + m_extImpactDamageManager->release(); + m_extPxManager->release(); + SAFE_DELETE(m_eventCallback); + + m_tkGroup->release(); + + delete m_replay; + + m_tkFramework->release(); + + if (m_extGroupTaskManager != nullptr) + { + m_extGroupTaskManager->release(); + m_extGroupTaskManager = nullptr; + } + + if (m_taskManager != nullptr) + { + m_taskManager->release(); + } +} + + +void BlastController::notifyPhysXControllerRelease() +{ + if (m_extGroupTaskManager != nullptr) + { + m_extGroupTaskManager->release(); + m_extGroupTaskManager = nullptr; + } + + if (m_taskManager != nullptr) + { + m_taskManager->release(); + m_taskManager = nullptr; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Deffered/Immediate damage +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastController::deferDamage(ExtPxActor *actor, BlastFamily& family, const NvBlastDamageProgram& program, const void* damageDesc, uint32_t damageDescSize) +{ + const void* bufferedDamageDesc = m_damageDescBuffer.push(damageDesc, damageDescSize); + PX_ASSERT_WITH_MESSAGE(bufferedDamageDesc, "Damage desc buffer exhausted."); + + NvBlastExtProgramParams programParams = { bufferedDamageDesc, &family.getMaterial(), actor->getFamily().getPxAsset().getAccelerator() }; + + const void* bufferedProgramParams = m_damageParamsBuffer.push(&programParams, sizeof(NvBlastExtProgramParams)); + PX_ASSERT_WITH_MESSAGE(bufferedProgramParams, "Damage params buffer exhausted."); + + if (bufferedDamageDesc && bufferedProgramParams) + { + actor->getTkActor().damage(program, bufferedProgramParams); + } +} + +NvBlastFractureBuffers& BlastController::getFractureBuffers(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.data()); + m_fractureBuffers.bondFractures = reinterpret_cast(&m_fractureData.data()[m_fractureBuffers.chunkFractureCount * sizeof(NvBlastChunkFractureData)]); + return m_fractureBuffers; +} + +void BlastController::immediateDamage(ExtPxActor *actor, BlastFamily& family, const NvBlastDamageProgram& program, const void* damageDesc) +{ + NvBlastExtProgramParams programParams = { damageDesc, &family.getMaterial(), actor->getFamily().getPxAsset().getAccelerator() }; + + NvBlastFractureBuffers& fractureEvents = getFractureBuffers(actor); + actor->getTkActor().generateFracture(&fractureEvents, program, &programParams); + actor->getTkActor().applyFracture(nullptr, &fractureEvents); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Impact damage +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastController::updateImpactDamage() +{ + if (m_impactDamageUpdatePending) + { + getPhysXController().getPhysXScene().setSimulationEventCallback(m_impactDamageEnabled ? m_eventCallback : nullptr); + refreshImpactDamageSettings(); + m_impactDamageUpdatePending = false; + } +} + +void BlastController::setImpactDamageEnabled(bool enabled, bool forceUpdate) +{ + if (m_impactDamageEnabled != enabled || forceUpdate) + { + m_impactDamageEnabled = enabled; + m_impactDamageUpdatePending = true; + } +} + +bool BlastController::customImpactDamageFunction(void* data, ExtPxActor* actor, physx::PxShape* shape, physx::PxVec3 position, physx::PxVec3 force) +{ + return reinterpret_cast(data)->stressDamage(actor, position, force); +} + +bool BlastController::stressDamage(ExtPxActor *actor, physx::PxVec3 position, physx::PxVec3 force) +{ + if (actor->getTkActor().getGraphNodeCount() > 1) + { + void* userData = actor->getFamily().userData; + if (userData) + { + ExtPxStressSolver* solver = reinterpret_cast(userData); + solver->getSolver().addForce(*actor->getTkActor().getActorLL(), position, force * m_impactDamageToStressFactor); + return true; + } + } + + return false; +} + +void BlastController::refreshImpactDamageSettings() +{ + m_extImpactDamageManagerSettings.damageFunction = m_impactDamageToStressEnabled ? customImpactDamageFunction : nullptr; + m_extImpactDamageManagerSettings.damageFunctionData = this; + m_extImpactDamageManager->setSettings(m_extImpactDamageManagerSettings); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Stress +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastController::updateDraggingStress() +{ + auto physxController = getPhysXController(); + auto actor = physxController.getDraggingActor(); + if (actor) + { + ExtPxActor* pxActor = m_extPxManager->getActorFromPhysXActor(*actor); + if (pxActor && pxActor->getTkActor().getGraphNodeCount() > 1 && pxActor->getPhysXActor().getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC) + { + void* userData = pxActor->getFamily().userData; + if (userData) + { + ExtPxStressSolver* solver = reinterpret_cast(userData); + PxTransform t(pxActor->getPhysXActor().getGlobalPose().getInverse()); + PxVec3 dragVector = t.rotate(physxController.getDragVector()); + const float factor = dragVector.magnitudeSquared() * m_draggingToStressFactor; + solver->getSolver().addForce(*pxActor->getTkActor().getActorLL(), physxController.getDragActorHookLocalPoint(), dragVector.getNormalized() * factor); + } + } + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Stats +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +uint32_t BlastController::getActorCount() const +{ + return std::accumulate(m_families.begin(), m_families.end(), (uint32_t)0, [](uint32_t sum, const BlastFamilyPtr& a) + { + return sum += a->getActorCount(); + }); +} + +uint32_t BlastController::getTotalVisibleChunkCount() const +{ + return std::accumulate(m_families.begin(), m_families.end(), (uint32_t)0, [](uint32_t sum, const BlastFamilyPtr& a) + { + return sum += a->getTotalVisibleChunkCount(); + }); +} + +size_t BlastController::getFamilySize() const +{ + return std::accumulate(m_families.begin(), m_families.end(), (size_t)0, [](size_t sum, const BlastFamilyPtr& a) + { + return sum += a->getFamilySize(); + }); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Time +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const double Time::s_secondsPerTick = Time::getTickDuration(); + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Controller events +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastController::Animate(double dt) +{ + PROFILER_SCOPED_FUNCTION(); + + PROFILER_BEGIN("Apply Impact Damage"); + m_extImpactDamageManager->applyDamage(); + PROFILER_END(); + + updateDraggingStress(); + + fillDebugRender(); + + getPhysXController().simualtionSyncEnd(); + + updateImpactDamage(); + + Time blastTime; + for (uint32_t i = 0; i < m_families.size(); ++i) + { + if (m_families[i]) + { + m_families[i]->updatePreSplit(dt); + } + } + + m_replay->update(); + + PROFILER_BEGIN("Tk Group Process/Sync"); + +#if 1 + + m_extGroupTaskManager->process(); + m_extGroupTaskManager->wait(); + +#else // process group on main thread + + m_tkGroup->process(); + +#endif + + m_damageParamsBuffer.clear(); + m_damageDescBuffer.clear(); + + PROFILER_END(); + + getPhysXController().simulationBegin(dt); + + TkGroupStats gstats; + m_tkGroup->getStats(gstats); + + this->m_lastBlastTimers.blastDamageMaterial = NvBlastTicksToSeconds(gstats.timers.material); + this->m_lastBlastTimers.blastDamageFracture = NvBlastTicksToSeconds(gstats.timers.fracture); + this->m_lastBlastTimers.blastSplitIsland = NvBlastTicksToSeconds(gstats.timers.island); + this->m_lastBlastTimers.blastSplitPartition = NvBlastTicksToSeconds(gstats.timers.partition); + this->m_lastBlastTimers.blastSplitVisibility = NvBlastTicksToSeconds(gstats.timers.visibility); + + for (uint32_t i = 0; i < m_families.size(); ++i) + { + if (m_families[i]) + { + m_families[i]->updateAfterSplit(dt); + } + } +} + + +void BlastController::drawUI() +{ + // impact damage + bool impactEnabled = getImpactDamageEnabled(); + if (ImGui::Checkbox("Impact Damage", &impactEnabled)) + { + setImpactDamageEnabled(impactEnabled); + } + { + bool refresh = false; + refresh |= ImGui::Checkbox("Use Shear Damage", &m_extImpactDamageManagerSettings.shearDamage); + refresh |= ImGui::DragFloat("Material Hardness", &m_extImpactDamageManagerSettings.hardness); + refresh |= ImGui::DragFloat("Damage Radius (Max)", &m_extImpactDamageManagerSettings.damageRadiusMax); + refresh |= ImGui::DragFloat("Damage Threshold (Min)", &m_extImpactDamageManagerSettings.damageThresholdMin, 1.0f, 0.0f, 1.0f); + refresh |= ImGui::DragFloat("Damage Threshold (Max)", &m_extImpactDamageManagerSettings.damageThresholdMax, 1.0f, 0.0f, 1.0f); + refresh |= ImGui::DragFloat("Damage Falloff Radius Factor", &m_extImpactDamageManagerSettings.damageFalloffRadiusFactor, 1.0f, 0.0f, 32.0f); + refresh |= ImGui::Checkbox("Impact Damage To Stress Solver", &m_impactDamageToStressEnabled); + + if (refresh) + { + refreshImpactDamageSettings(); + } + } + + ImGui::DragFloat("Impact Damage To Stress Factor", &m_impactDamageToStressFactor, 0.001f, 0.0f, 1000.0f, "%.4f"); + ImGui::DragFloat("Dragging To Stress Factor", &m_draggingToStressFactor, 0.1f, 0.0f, 1000.0f, "%.3f"); + + ImGui::Checkbox("Limit Rigid Body Count", &m_rigidBodyLimitEnabled); + if (m_rigidBodyLimitEnabled) + { + ImGui::DragInt("Rigid Body Limit", (int*)&m_rigidBodyLimit, 100, 1000, 100000); + } + m_extPxManager->setActorCountLimit(m_rigidBodyLimitEnabled ? m_rigidBodyLimit : 0); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// actor management +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +BlastFamilyPtr BlastController::spawnFamily(BlastAsset* blastAsset, const BlastAsset::ActorDesc& desc) +{ + BlastFamilyPtr actor = blastAsset->createFamily(getPhysXController(), *m_extPxManager, desc); + m_families.push_back(actor); + recalculateAssetsSize(); + m_replay->addFamily(&actor->getFamily()->getTkFamily()); + return actor; +} + +void BlastController::removeFamily(BlastFamilyPtr actor) +{ + m_replay->removeFamily(&actor->getFamily()->getTkFamily()); + m_families.erase(std::remove(m_families.begin(), m_families.end(), actor), m_families.end()); + recalculateAssetsSize(); + getPhysXController().resetDragging(); +} + +void BlastController::removeAllFamilies() +{ + while (!m_families.empty()) + { + removeFamily(m_families.back()); + } + m_replay->reset(); +} + +void BlastController::recalculateAssetsSize() +{ + std::set uniquedAssets; + m_blastAssetsSize = 0; + for (uint32_t i = 0; i < m_families.size(); ++i) + { + if (uniquedAssets.find(&m_families[i]->getBlastAsset()) == uniquedAssets.end()) + { + m_blastAssetsSize += m_families[i]->getBlastAsset().getBlastAssetSize(); + uniquedAssets.insert(&m_families[i]->getBlastAsset()); + } + } +} + +bool BlastController::overlap(const PxGeometry& geometry, const PxTransform& pose, std::function hitCall) +{ + PROFILER_SCOPED_FUNCTION(); + + bool anyHit = false; + for (uint32_t i = 0; i < m_families.size(); ++i) + { + if (m_families[i]) + { + anyHit |= m_families[i]->overlap(geometry, pose, hitCall); + } + } + return anyHit; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// debug render +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BlastController::fillDebugRender() +{ + PROFILER_SCOPED_FUNCTION(); + + m_debugRenderBuffer.clear(); + + if (debugRenderMode != BlastFamily::DEBUG_RENDER_DISABLED) + { + getPhysXController().getPhysXScene().setVisualizationParameter(PxVisualizationParameter::eSCALE, 1); + for (uint32_t i = 0; i < m_families.size(); ++i) + { + m_families[i]->fillDebugRender(m_debugRenderBuffer, debugRenderMode, debugRenderScale); + } + } + else + { + getPhysXController().getPhysXScene().setVisualizationParameter(PxVisualizationParameter::eSCALE, 0); + } + + getRenderer().queueRenderBuffer(&m_debugRenderBuffer); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3