// 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-2020 NVIDIA Corporation. All rights reserved. #include "BlastFamilyModelSkinned.h" #include "RenderUtils.h" #include "Renderer.h" #include "SkinnedRenderMesh.h" #include "NvBlastExtPxAsset.h" #include "NvBlastExtPxActor.h" #include "NvBlastTkActor.h" #include "PxRigidDynamic.h" using namespace physx; BlastFamilyModelSkinned::BlastFamilyModelSkinned(PhysXController& physXController, ExtPxManager& pxManager, Renderer& renderer, const BlastAssetModelSkinned& blastAsset, const BlastAsset::ActorDesc& desc) : BlastFamily(physXController, pxManager, blastAsset), m_renderer(renderer), m_visibleActorsDirty(true) { // materials auto materials = blastAsset.getRenderMaterials(); const BlastModel& model = blastAsset.getModel(); // finalize (create) sub model auto finalizeSubModelFunction = [&](SubModel* subModel, std::vector& subModelMeshes, RenderMaterial& renderMaterial) { subModel->skinnedRenderMesh = new SkinnedRenderMesh(subModelMeshes); subModel->renderable = renderer.createRenderable(*subModel->skinnedRenderMesh, renderMaterial); subModel->renderable->setColor(getRandomPastelColor()); }; // create at least one submodel per every material (if mesh count is too high, more then one sub model per material to be created) SubModel* subModel = nullptr; std::vector subModelMeshes; subModelMeshes.reserve(model.chunks.size()); for (uint32_t materialIndex = 0; materialIndex < model.materials.size(); materialIndex++) { for (uint32_t chunkIndex = 0; chunkIndex < model.chunks.size(); chunkIndex++) { const BlastModel::Chunk& chunk = model.chunks[chunkIndex]; for (const BlastModel::Chunk::Mesh& mesh : chunk.meshes) { if (mesh.materialIndex == materialIndex) { // init new submodel? if (subModel == nullptr) { m_subModels.push_back(SubModel()); subModel = &m_subModels.back(); subModel->chunkIdToBoneMap.resize(model.chunks.size()); std::fill(subModel->chunkIdToBoneMap.begin(), subModel->chunkIdToBoneMap.end(), SubModel::INVALID_BONE_ID); subModelMeshes.clear(); } // add mesh to map and list subModel->chunkIdToBoneMap[chunkIndex] = (uint32_t)subModelMeshes.size(); subModelMeshes.push_back(&(mesh.mesh)); // mesh reached limit? if (subModelMeshes.size() == SkinnedRenderMesh::MeshesCountMax) { finalizeSubModelFunction(subModel, subModelMeshes, *materials[materialIndex]); subModel = nullptr; } } } } // finalize subModel for this material if (subModel && subModelMeshes.size() > 0) { finalizeSubModelFunction(subModel, subModelMeshes, *materials[materialIndex]); subModel = nullptr; } } // reserve for scratch m_visibleBones.reserve(model.chunks.size()); m_visibleBoneTransforms.reserve(model.chunks.size()); // initialize in position initialize(desc); } BlastFamilyModelSkinned::~BlastFamilyModelSkinned() { for (uint32_t subModelIndex = 0; subModelIndex < m_subModels.size(); subModelIndex++) { m_renderer.removeRenderable(m_subModels[subModelIndex].renderable); SAFE_DELETE(m_subModels[subModelIndex].skinnedRenderMesh); } } void BlastFamilyModelSkinned::onActorCreated(const ExtPxActor& actor) { m_visibleActors.insert(&actor); m_visibleActorsDirty = true; } void BlastFamilyModelSkinned::onActorUpdate(const ExtPxActor& actor) { } void BlastFamilyModelSkinned::onActorDestroyed(const ExtPxActor& actor) { m_visibleActors.erase(&actor); m_visibleActorsDirty = true; } void BlastFamilyModelSkinned::onUpdate() { // visible actors changed this frame? if (m_visibleActorsDirty) { for (const SubModel& model : m_subModels) { // pass visible chunks list to render mesh m_visibleBones.clear(); for (const ExtPxActor* actor : m_visibleActors) { const uint32_t* chunkIndices = actor->getChunkIndices(); uint32_t chunkCount = actor->getChunkCount(); for (uint32_t i = 0; i < chunkCount; ++i) { uint32_t chunkIndex = chunkIndices[i]; uint32_t boneIndex = model.chunkIdToBoneMap[chunkIndex]; if (boneIndex != SubModel::INVALID_BONE_ID) { m_visibleBones.push_back(boneIndex); } } } model.skinnedRenderMesh->updateVisibleMeshes(m_visibleBones); } m_visibleActorsDirty = false; } // update and pass chunk transforms const ExtPxChunk* chunks = m_blastAsset.getPxAsset()->getChunks(); const ExtPxSubchunk* subChunks = m_blastAsset.getPxAsset()->getSubchunks(); for (const SubModel& model : m_subModels) { m_visibleBoneTransforms.clear(); for (const ExtPxActor* actor : m_visibleActors) { const uint32_t* chunkIndices = actor->getChunkIndices(); uint32_t chunkCount = actor->getChunkCount(); for (uint32_t i = 0; i < chunkCount; ++i) { uint32_t chunkIndex = chunkIndices[i]; uint32_t boneIndex = model.chunkIdToBoneMap[chunkIndex]; if (boneIndex != SubModel::INVALID_BONE_ID) { m_visibleBoneTransforms.push_back(PxMat44(actor->getPhysXActor().getGlobalPose() * subChunks[chunks[chunkIndex].firstSubchunkIndex].transform)); } } } model.skinnedRenderMesh->updateVisibleMeshTransforms(m_visibleBoneTransforms); } }