diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorBuilder.cpp b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorBuilder.cpp index 35d38dd359..0c5916f684 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorBuilder.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorBuilder.cpp @@ -272,7 +272,7 @@ namespace EMotionFX // Post create actor actor->SetUnitType(MCore::Distance::UNITTYPE_METERS); actor->SetFileUnitType(MCore::Distance::UNITTYPE_METERS); - actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/false, /*generateOBBs=*/false, /*convertUnitType=*/false); + actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/false, /*convertUnitType=*/false); // Only enable joints that are used for skinning (and their parents). // On top of that, enable all joints marked as critical joints. diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp index c55509e817..62bd8b32cb 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #include @@ -50,11 +49,6 @@ namespace EMotionFX { AZ_CLASS_ALLOCATOR_IMPL(Actor, ActorAllocator, 0) - Actor::NodeInfo::NodeInfo() - { - mOBB.Init(); - } - Actor::LODLevel::LODLevel() { } @@ -188,7 +182,6 @@ namespace EMotionFX result->mSkeleton = mSkeleton->Clone(); // clone lod data - result->mNodeInfos = mNodeInfos; const uint32 numNodes = mSkeleton->GetNumNodes(); const size_t numLodLevels = m_meshLodData.m_lodLevels.size(); @@ -998,18 +991,6 @@ namespace EMotionFX } } - // update the bounding volumes - void Actor::UpdateNodeBindPoseOBBs(uint32 lodLevel) - { - // for all nodes - const uint32 numNodes = mSkeleton->GetNumNodes(); - for (uint32 i = 0; i < numNodes; ++i) - { - CalcOBBFromBindPose(lodLevel, i); - } - } - - // remove all node groups void Actor::RemoveAllNodeGroups() { @@ -1353,9 +1334,8 @@ namespace EMotionFX } } - // post init - void Actor::PostCreateInit(bool makeGeomLodsCompatibleWithSkeletalLODs, bool generateOBBs, bool convertUnitType) + void Actor::PostCreateInit(bool makeGeomLodsCompatibleWithSkeletalLODs, bool convertUnitType) { if (mThreadIndex == MCORE_INVALIDINDEX32) { @@ -1388,11 +1368,6 @@ namespace EMotionFX mSkeleton->GetBindPose()->ForceUpdateFullModelSpacePose(); mSkeleton->GetBindPose()->ZeroMorphWeights(); - if (generateOBBs) - { - UpdateNodeBindPoseOBBs(0); - } - if (!GetHasMirrorInfo()) { AllocateNodeMirrorInfos(); @@ -1883,7 +1858,6 @@ namespace EMotionFX void Actor::SetNumNodes(uint32 numNodes) { mSkeleton->SetNumNodes(numNodes); - mNodeInfos.resize(numNodes); AZStd::vector& lodLevels = m_meshLodData.m_lodLevels; for (LODLevel& lodLevel : lodLevels) @@ -1901,7 +1875,6 @@ namespace EMotionFX mSkeleton->GetBindPose()->LinkToActor(this, Pose::FLAG_LOCALTRANSFORMREADY, false); // initialize the LOD data - mNodeInfos.emplace_back(); AZStd::vector& lodLevels = m_meshLodData.m_lodLevels; for (LODLevel& lodLevel : lodLevels) { @@ -1932,7 +1905,6 @@ namespace EMotionFX void Actor::RemoveNode(uint32 nr, bool delMem) { mSkeleton->RemoveNode(nr, delMem); - mNodeInfos.erase(mNodeInfos.begin() + nr); AZStd::vector& lodLevels = m_meshLodData.m_lodLevels; for (LODLevel& lodLevel : lodLevels) @@ -1944,7 +1916,6 @@ namespace EMotionFX void Actor::DeleteAllNodes() { mSkeleton->RemoveAllNodes(); - mNodeInfos.clear(); AZStd::vector& lodLevels = m_meshLodData.m_lodLevels; for (LODLevel& lodLevel : lodLevels) @@ -2263,82 +2234,6 @@ namespace EMotionFX return (stack->CheckIfHasDeformerOfType(SoftSkinDeformer::TYPE_ID) || stack->CheckIfHasDeformerOfType(DualQuatSkinDeformer::TYPE_ID)); } - - // calculate the OBB for a given node - void Actor::CalcOBBFromBindPose(uint32 lodLevel, uint32 nodeIndex) - { - AZStd::vector points; - - // if there is a mesh - Mesh* mesh = GetMesh(lodLevel, nodeIndex); - if (mesh) - { - // if the mesh is not skinned - if (mesh->FindSharedVertexAttributeLayer(SkinningInfoVertexAttributeLayer::TYPE_ID) == nullptr) - { - mesh->ExtractOriginalVertexPositions(points); - } - } - else // there is no mesh, so maybe this is a bone - { - const Transform& invBindPoseTransform = GetInverseBindPoseTransform(nodeIndex); - - // for all nodes inside the actor where this node belongs to - const uint32 numNodes = mSkeleton->GetNumNodes(); - for (uint32 n = 0; n < numNodes; ++n) - { - Mesh* loopMesh = GetMesh(lodLevel, n); - if (loopMesh == nullptr) - { - continue; - } - - // get the vertex positions in bind pose - const uint32 numVerts = loopMesh->GetNumVertices(); - points.reserve(numVerts * 2); - AZ::Vector3* positions = (AZ::Vector3*)loopMesh->FindOriginalVertexData(Mesh::ATTRIB_POSITIONS); - - SkinningInfoVertexAttributeLayer* skinLayer = (SkinningInfoVertexAttributeLayer*)loopMesh->FindSharedVertexAttributeLayer(SkinningInfoVertexAttributeLayer::TYPE_ID); - if (skinLayer) - { - // iterate over all skinning influences and see if this node number is used - // if so, add it to the list of points - const uint32* orgVertices = (uint32*)loopMesh->FindVertexData(Mesh::ATTRIB_ORGVTXNUMBERS); - for (uint32 v = 0; v < numVerts; ++v) - { - // get the original vertex number - const uint32 orgVtx = orgVertices[v]; - - // for all skinning influences for this vertex - const size_t numInfluences = skinLayer->GetNumInfluences(orgVtx); - for (size_t i = 0; i < numInfluences; ++i) - { - // get the node used by this influence - const uint32 nodeNr = skinLayer->GetInfluence(orgVtx, i)->GetNodeNr(); - - // if this is the same node as we are updating the bounds for, add the vertex position to the list - if (nodeNr == nodeIndex) - { - const AZ::Vector3 tempPos(positions[v]); - points.emplace_back(invBindPoseTransform.TransformPoint(tempPos)); - } - } // for all influences - } // for all vertices - } // if there is skinning info - } // for all nodes - } - - // init from the set of points - if (!points.empty()) - { - GetNodeOBB(nodeIndex).InitFromPoints(&points[0], static_cast(points.size())); - } - else - { - GetNodeOBB(nodeIndex).Init(); - } - } - // remove the mesh for a given node in a given LOD void Actor::RemoveNodeMeshForLOD(uint32 lodLevel, uint32 nodeIndex, bool destroyMesh) { @@ -2411,14 +2306,6 @@ namespace EMotionFX mInvBindPoseTransforms[i] = bindPose->GetModelSpaceTransform(i).Inversed(); } - // update node obbs - for (uint32 i = 0; i < numNodes; ++i) - { - MCore::OBB& box = GetNodeOBB(i); - box.SetExtents(box.GetExtents() * scaleFactor); - box.SetCenter(box.GetCenter() * scaleFactor); - } - // update static aabb m_staticAabb.SetMin(m_staticAabb.GetMin() * scaleFactor); m_staticAabb.SetMax(m_staticAabb.GetMax() * scaleFactor); diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h index 53cbe7e05a..1c1173a9a2 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h @@ -24,7 +24,6 @@ #include #include #include -#include #include // include required headers @@ -564,17 +563,6 @@ namespace EMotionFX */ void SetMorphSetup(uint32 lodLevel, MorphSetup* setup); - /** - * Update the oriented bounding volumes (OBB) of all the nodes inside this actor. - * This is a very heavy calculation and must NOT be performed on a per-frame basis but only as pre-process step. - * The OBBs of the nodes are already being calculated at export time, so you shouldn't really need to use this method. - * Only when the bind pose geometry has changed you can update the node OBBs by calling this method. - * For more information about how the bounds are calculated please see the Node::GetOBB() and Node::CalcOBBFromBindPose() methods. - * The calculations performed by this method are automatically spread over multiple threads to improve the performance. - * @param lodLevel The geometry LOD level to use while calculating the object oriented bounds per node. - */ - void UpdateNodeBindPoseOBBs(uint32 lodLevel); - /** * Get the number of node groups inside this actor object. * @result The number of node groups. @@ -758,7 +746,7 @@ namespace EMotionFX void MakeGeomLODsCompatibleWithSkeletalLODs(); void ReinitializeMeshDeformers(); - void PostCreateInit(bool makeGeomLodsCompatibleWithSkeletalLODs = true, bool generateOBBs = true, bool convertUnitType = true); + void PostCreateInit(bool makeGeomLodsCompatibleWithSkeletalLODs = true, bool convertUnitType = true); void AutoDetectMirrorAxes(); const MCore::Array& GetNodeMirrorInfos() const; @@ -808,57 +796,6 @@ namespace EMotionFX bool CheckIfHasMorphDeformer(uint32 lodLevel, uint32 nodeIndex) const; bool CheckIfHasSkinningDeformer(uint32 lodLevel, uint32 nodeIndex) const; - /** - * Calculate the object oriented box for a given LOD level. - * This will try to fit the tightest bounding box around the mesh of a node. - * If the node has no mesh and acts as bone inside skinning deformations the resulting box will contain - * all the vertices that are influenced by this given node/bone. - * Calculating this box is already done at export time. But you can use this to recalculate it if the mesh data changed. - * This method is relatively slow and not meant for per-frame calculations but only for preprocessing. - * You can use the GetOBB() method to retrieve the calculated box at any time. - * Nodes that do not have a mesh and not act as bone will have invalid OBB bounds, as they have no volume. You can check whether - * this is the case or not by using the MCore::OBB::IsValid() method. - * The box is stored in local space of the node. - * @param lodLevel The geometry LOD level to generate the OBBs from. - * @param nodeIndex The node to calculate the OBB for. - */ - void CalcOBBFromBindPose(uint32 lodLevel, uint32 nodeIndex); - - /** - * Get the object oriented bounding box for this node. - * The box is in local space. In order to convert it into world space you have to multiply the corner points of the box - * with the world space matrix of this node. - * Nodes that do not have a mesh and do not act as bone will have invalid bounds. You can use the MCore::OBB::CheckIfIsValid() method to check if - * the bounds are valid bounds or not. If it is not, then it means there was nothing to calculate the box from. - * Object Oriented Boxes for the nodes are calculated at export time by using the Actor::UpdateNodeBindPoseOBBs() and Node::CalcOBBFromBindPose() methods. - * @param nodeIndex The index of the node to get the OBB for. - * @result The object oriented bounding box that has been calculated before already. - */ - MCore::OBB& GetNodeOBB(uint32 nodeIndex) { return mNodeInfos[nodeIndex].mOBB; } - - /** - * Get the object oriented bounding box for this node. - * The box is in local space. In order to convert it into world space you have to multiply the corner points of the box - * with the world space matrix of this node. - * Nodes that do not have a mesh and do not act as bone will have invalid bounds. You can use the MCore::OBB::CheckIfIsValid() method to check if - * the bounds are valid bounds or not. If it is not, then it means there was nothing to calculate the box from. - * Object Oriented Boxes for the nodes are calculated at export time by using the Actor::UpdateNodeBindPoseOBBs() and Node::CalcOBBFromBindPose() methods. - * @param nodeIndex The index of the node to get the OBB for. - * @result The object oriented bounding box that has been calculated before already. - */ - const MCore::OBB& GetNodeOBB(uint32 nodeIndex) const { return mNodeInfos[nodeIndex].mOBB; } - - /** - * Set the object oriented bounding box for this node. - * The box is in local space. In order to convert it into world space you have to multiply the corner points of the box - * with the world space matrix of this node. - * Nodes that do not have a mesh and do not act as bone will have invalid bounds. You can use the MCore::OBB::CheckIfIsValid() method to check if - * the bounds are valid bounds or not. If it is not, then it means there was nothing to calculate the box from. - * @param nodeIndex The index of the node to set the OBB for. - * @param obb The object oriented bounding box that has been calculated before already. - */ - void SetNodeOBB(uint32 nodeIndex, const MCore::OBB& obb) { mNodeInfos[nodeIndex].mOBB = obb; } - void RemoveNodeMeshForLOD(uint32 lodLevel, uint32 nodeIndex, bool destroyMesh = true); void SetNumNodes(uint32 numNodes); @@ -917,14 +854,6 @@ namespace EMotionFX Node* FindJointByMeshName(const AZStd::string_view meshName) const; - // per node info (shared between lods) - struct EMFX_API NodeInfo - { - MCore::OBB mOBB; - - NodeInfo(); - }; - // data per node, per lod struct EMFX_API NodeLODInfo { @@ -968,7 +897,6 @@ namespace EMotionFX Skeleton* mSkeleton; /**< The skeleton, containing the nodes and bind pose. */ MCore::Array mDependencies; /**< The dependencies on other actors (shared meshes and transforms). */ - AZStd::vector mNodeInfos; /**< The per node info, shared between lods. */ AZStd::string mName; /**< The name of the actor. */ AZStd::string mFileName; /**< The filename of the actor. */ MCore::Array mNodeMirrorInfos; /**< The array of node mirror info. */ diff --git a/Gems/EMotionFX/Code/Tests/AnimGraphFixture.cpp b/Gems/EMotionFX/Code/Tests/AnimGraphFixture.cpp index 31c5455571..ab9d91046b 100644 --- a/Gems/EMotionFX/Code/Tests/AnimGraphFixture.cpp +++ b/Gems/EMotionFX/Code/Tests/AnimGraphFixture.cpp @@ -45,7 +45,7 @@ namespace EMotionFX ConstructActor(); ASSERT_TRUE(m_actor) << "Construct actor did not build a valid actor."; m_actor->ResizeTransformData(); - m_actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/ false, /*generateOBBs=*/ false, /*convertUnitType=*/ false); + m_actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/ false, /*convertUnitType=*/ false); } { m_motionSet = aznew MotionSet("testMotionSet"); diff --git a/Gems/EMotionFX/Code/Tests/MorphTargetRuntimeTests.cpp b/Gems/EMotionFX/Code/Tests/MorphTargetRuntimeTests.cpp index 0f022b72ef..24afc7af47 100644 --- a/Gems/EMotionFX/Code/Tests/MorphTargetRuntimeTests.cpp +++ b/Gems/EMotionFX/Code/Tests/MorphTargetRuntimeTests.cpp @@ -84,7 +84,7 @@ namespace EMotionFX // Without this call, the bind pose does not know about newly added // morph target (mMorphWeights.GetLength() == 0) m_actor->ResizeTransformData(); - m_actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/false, /*generateOBBs=*/false, /*convertUnitType=*/false); + m_actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/false, /*convertUnitType=*/false); m_animGraph = AZStd::make_unique(); diff --git a/Gems/EMotionFX/Code/Tests/UI/CanMorphManyShapes.cpp b/Gems/EMotionFX/Code/Tests/UI/CanMorphManyShapes.cpp index 978532505b..ba24c501ab 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanMorphManyShapes.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanMorphManyShapes.cpp @@ -68,7 +68,7 @@ namespace EMotionFX // Without this call, the bind pose does not know about newly added morph target (mMorphWeights.GetLength() == 0) m_actor->ResizeTransformData(); - m_actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/false, /*generateOBBs=*/false, /*convertUnitType=*/false); + m_actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/false, /*convertUnitType=*/false); m_animGraph = AZStd::make_unique();