diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index 0cb8cf5ccd..14e1f26bdd 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -83,10 +83,10 @@ namespace AZ // Update RenderActorInstance world bounding box // The bounding box is moving with the actor instance. // The entity and actor transforms are kept in sync already. - m_worldAABB = AZ::Aabb::CreateFromMinMax(m_actorInstance->GetAABB().GetMin(), m_actorInstance->GetAABB().GetMax()); + m_worldAABB = m_actorInstance->GetAabb(); // Update RenderActorInstance local bounding box - // NB: computing the local bbox from the world bbox makes the local bbox artifically larger than it should be + // NB: computing the local bbox from the world bbox makes the local bbox artificially larger than it should be // instead EMFX should support getting the local bbox from the actor instance directly m_localAABB = m_worldAABB.GetTransformedAabb(m_transformInterface->GetWorldTM().GetInverse()); @@ -107,9 +107,8 @@ namespace AZ { if (debugOptions.m_drawAABB) { - const MCore::AABB emfxAabb = m_actorInstance->GetAABB(); - const AZ::Aabb azAabb = AZ::Aabb::CreateFromMinMax(emfxAabb.GetMin(), emfxAabb.GetMax()); - auxGeom->DrawAabb(azAabb, AZ::Color(0.0f, 1.0f, 1.0f, 1.0f), RPI::AuxGeomDraw::DrawStyle::Line); + const AZ::Aabb& aabb = m_actorInstance->GetAabb(); + auxGeom->DrawAabb(aabb, AZ::Color(0.0f, 1.0f, 1.0f, 1.0f), RPI::AuxGeomDraw::DrawStyle::Line); } if (debugOptions.m_drawSkeleton) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp index a21b618b91..52a4ec6a0b 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp @@ -1063,11 +1063,10 @@ namespace CommandSystem continue; } - MCore::AABB newAABB; - actorInstance->SetStaticBasedAABB(actor->GetStaticAABB()); // this is needed as the CalcStaticBasedAABB uses the current AABB as starting point - actorInstance->CalcStaticBasedAABB(&newAABB); - actorInstance->SetStaticBasedAABB(newAABB); - //actorInstance->UpdateVisualizeScale(); + actorInstance->SetStaticBasedAabb(actor->GetStaticAabb()); // this is needed as the CalcStaticBasedAabb uses the current AABB as starting point + AZ::Aabb newAabb; + actorInstance->CalcStaticBasedAabb(&newAabb); + actorInstance->SetStaticBasedAabb(newAabb); const float factor = (float)MCore::Distance::GetConversionFactor(beforeUnitType, targetUnitType); actorInstance->SetVisualizeScale(actorInstance->GetVisualizeScale() * factor); diff --git a/Gems/EMotionFX/Code/EMotionFX/Exporters/ExporterLib/Exporter/NodeExport.cpp b/Gems/EMotionFX/Code/EMotionFX/Exporters/ExporterLib/Exporter/NodeExport.cpp index a9010fb524..79861be4b8 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Exporters/ExporterLib/Exporter/NodeExport.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Exporters/ExporterLib/Exporter/NodeExport.cpp @@ -18,21 +18,6 @@ namespace ExporterLib { - void WriteObbToNodeChunk(EMotionFX::FileFormat::Actor_Node& nodeChunk, const MCore::OBB& obb) - { - AZ::Transform obbMatrix = obb.GetTransformation(); - obbMatrix.GetBasisX().StoreToFloat3(nodeChunk.mOBB); - nodeChunk.mOBB[3] = 0.0f; - obbMatrix.GetBasisY().StoreToFloat3(nodeChunk.mOBB + 4); - nodeChunk.mOBB[7] = 0.0f; - obbMatrix.GetBasisZ().StoreToFloat3(nodeChunk.mOBB + 8); - nodeChunk.mOBB[11] = 0.0f; - nodeChunk.mOBB[12] = 0.0f; - nodeChunk.mOBB[13] = 0.0f; - nodeChunk.mOBB[14] = 0.0f; - nodeChunk.mOBB[15] = 1.0f; - } - void SaveNode(MCore::Stream* file, EMotionFX::Actor* actor, EMotionFX::Node* node, MCore::Endian::EEndianType targetEndianType) { MCORE_ASSERT(file); @@ -47,7 +32,7 @@ namespace ExporterLib const uint32 numChilds = node->GetNumChildNodes(); const EMotionFX::Transform& transform = actor->GetBindPose()->GetLocalSpaceTransform(nodeIndex); AZ::PackedVector3f position = AZ::PackedVector3f(transform.mPosition); - AZ::Quaternion rotation = transform.mRotation.GetNormalized();; + AZ::Quaternion rotation = transform.mRotation.GetNormalized(); #ifndef EMFX_SCALE_DISABLED AZ::PackedVector3f scale = AZ::PackedVector3f(transform.mScale); @@ -56,14 +41,13 @@ namespace ExporterLib #endif // create the node chunk and copy over the information - EMotionFX::FileFormat::Actor_Node nodeChunk; - memset(&nodeChunk, 0, sizeof(EMotionFX::FileFormat::Actor_Node)); + EMotionFX::FileFormat::Actor_Node2 nodeChunk; + memset(&nodeChunk, 0, sizeof(EMotionFX::FileFormat::Actor_Node2)); CopyVector(nodeChunk.mLocalPos, position); CopyQuaternion(nodeChunk.mLocalQuat, rotation); CopyVector(nodeChunk.mLocalScale, scale); - //nodeChunk.mImportanceFactor = FLT_MAX;//importance; nodeChunk.mNumChilds = numChilds; nodeChunk.mParentIndex = parentIndex; @@ -98,10 +82,6 @@ namespace ExporterLib nodeChunk.mNodeFlags &= ~EMotionFX::Node::ENodeFlags::FLAG_CRITICAL; } - // OBB - WriteObbToNodeChunk(nodeChunk, actor->GetNodeOBB(node->GetNodeIndex())); - - // log the node chunk information MCore::LogDetailedInfo("- Node: name='%s' index=%i", actor->GetSkeleton()->GetNode(nodeIndex)->GetName(), nodeIndex); if (parentIndex == MCORE_INVALIDINDEX32) @@ -140,19 +120,13 @@ namespace ExporterLib ConvertUnsignedInt(&nodeChunk.mNumChilds, targetEndianType); ConvertUnsignedInt(&nodeChunk.mSkeletalLODs, targetEndianType); - for (uint32 j = 0; j < 16; ++j) - { - ConvertFloat(&nodeChunk.mOBB[j], targetEndianType); - } - // write it - file->Write(&nodeChunk, sizeof(EMotionFX::FileFormat::Actor_Node)); + file->Write(&nodeChunk, sizeof(EMotionFX::FileFormat::Actor_Node2)); // write the name of the node and parent SaveString(node->GetName(), file, targetEndianType); } - void SaveNodes(MCore::Stream* file, EMotionFX::Actor* actor, MCore::Endian::EEndianType targetEndianType) { uint32 i; @@ -167,10 +141,10 @@ namespace ExporterLib // chunk information EMotionFX::FileFormat::FileChunk chunkHeader; chunkHeader.mChunkID = EMotionFX::FileFormat::ACTOR_CHUNK_NODES; - chunkHeader.mVersion = 1; + chunkHeader.mVersion = 2; // get the nodes chunk size - chunkHeader.mSizeInBytes = sizeof(EMotionFX::FileFormat::Actor_Nodes) + numNodes * sizeof(EMotionFX::FileFormat::Actor_Node); + chunkHeader.mSizeInBytes = sizeof(EMotionFX::FileFormat::Actor_Nodes2) + numNodes * sizeof(EMotionFX::FileFormat::Actor_Node2); for (i = 0; i < numNodes; i++) { chunkHeader.mSizeInBytes += GetStringChunkSize(actor->GetSkeleton()->GetNode(i)->GetName()); @@ -181,23 +155,15 @@ namespace ExporterLib file->Write(&chunkHeader, sizeof(EMotionFX::FileFormat::FileChunk)); // nodes chunk - EMotionFX::FileFormat::Actor_Nodes nodesChunk; + EMotionFX::FileFormat::Actor_Nodes2 nodesChunk; nodesChunk.mNumNodes = numNodes; nodesChunk.mNumRootNodes = actor->GetSkeleton()->GetNumRootNodes(); - nodesChunk.mStaticBoxMin.mX = actor->GetStaticAABB().GetMin().GetX(); - nodesChunk.mStaticBoxMin.mY = actor->GetStaticAABB().GetMin().GetY(); - nodesChunk.mStaticBoxMin.mZ = actor->GetStaticAABB().GetMin().GetZ(); - nodesChunk.mStaticBoxMax.mX = actor->GetStaticAABB().GetMax().GetX(); - nodesChunk.mStaticBoxMax.mY = actor->GetStaticAABB().GetMax().GetY(); - nodesChunk.mStaticBoxMax.mZ = actor->GetStaticAABB().GetMax().GetZ(); // endian conversion and write it ConvertUnsignedInt(&nodesChunk.mNumNodes, targetEndianType); ConvertUnsignedInt(&nodesChunk.mNumRootNodes, targetEndianType); - ConvertFileVector3(&nodesChunk.mStaticBoxMin, targetEndianType); - ConvertFileVector3(&nodesChunk.mStaticBoxMax, targetEndianType); - file->Write(&nodesChunk, sizeof(EMotionFX::FileFormat::Actor_Nodes)); + file->Write(&nodesChunk, sizeof(EMotionFX::FileFormat::Actor_Nodes2)); // write the nodes for (uint32 n = 0; n < numNodes; n++) 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/Pipeline/RCExt/Actor/ActorGroupExporter.cpp b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp index bf79fbf05c..a498ed2cb7 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp @@ -48,7 +48,8 @@ namespace EMotionFX AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - serializeContext->Class()->Version(2); + // Increasing the version number of the actor group exporter will make sure all actor products will be force re-generated. + serializeContext->Class()->Version(3); } } diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/Camera.h b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/Camera.h index 0c7b19384e..6a95621b0d 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/Camera.h +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/Camera.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include "MCommonConfig.h" diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp index 6301b0d7e3..9c0a4af895 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp @@ -198,7 +198,7 @@ namespace MCommon // render the current bounding box of the given actor instance - void RenderUtil::RenderAABB(const MCore::AABB& box, const MCore::RGBAColor& color, bool directlyRender) + void RenderUtil::RenderAabb(const AZ::Aabb& box, const MCore::RGBAColor& color, bool directlyRender) { AZ::Vector3 min = box.GetMin(); AZ::Vector3 max = box.GetMax(); @@ -238,26 +238,28 @@ namespace MCommon // render selection gizmo around the given AABB - void RenderUtil::RenderSelection(const MCore::AABB& box, const MCore::RGBAColor& color, bool directlyRender) + void RenderUtil::RenderSelection(const AZ::Aabb& box, const MCore::RGBAColor& color, bool directlyRender) { - //const Vector3 center = box.CalcMiddle(); - const AZ::Vector3 min = box.GetMin();// + (box.GetMin()-center).Normalized()*0.005f; - const AZ::Vector3 max = box.GetMax();// + (box.GetMax()-center).Normalized()*0.005f; - const float scale = box.CalcRadius() * 0.1f; + const AZ::Vector3& min = box.GetMin(); + const AZ::Vector3& max = box.GetMax(); + const float radius = AZ::Vector3(box.GetMax() - box.GetMin()).GetLength() * 0.5f; + const float scale = radius * 0.1f; const AZ::Vector3 up = AZ::Vector3(0.0f, 1.0f, 0.0f) * scale; const AZ::Vector3 right = AZ::Vector3(1.0f, 0.0f, 0.0f) * scale; const AZ::Vector3 front = AZ::Vector3(0.0f, 0.0f, 1.0f) * scale; // generate our vertices - AZ::Vector3 p[8]; - p[0].Set(min.GetX(), min.GetY(), min.GetZ()); - p[1].Set(max.GetX(), min.GetY(), min.GetZ()); - p[2].Set(max.GetX(), min.GetY(), max.GetZ()); - p[3].Set(min.GetX(), min.GetY(), max.GetZ()); - p[4].Set(min.GetX(), max.GetY(), min.GetZ()); - p[5].Set(max.GetX(), max.GetY(), min.GetZ()); - p[6].Set(max.GetX(), max.GetY(), max.GetZ()); - p[7].Set(min.GetX(), max.GetY(), max.GetZ()); + const AZStd::array p + { + AZ::Vector3{min.GetX(), min.GetY(), min.GetZ()}, + AZ::Vector3{max.GetX(), min.GetY(), min.GetZ()}, + AZ::Vector3{max.GetX(), min.GetY(), max.GetZ()}, + AZ::Vector3{min.GetX(), min.GetY(), max.GetZ()}, + AZ::Vector3{min.GetX(), max.GetY(), min.GetZ()}, + AZ::Vector3{max.GetX(), max.GetY(), min.GetZ()}, + AZ::Vector3{max.GetX(), max.GetY(), max.GetZ()}, + AZ::Vector3{min.GetX(), max.GetY(), max.GetZ()}, + }; // render the box RenderLine(p[0], p[0] + up, color); @@ -304,46 +306,29 @@ namespace MCommon { mNodeBasedAABB = true; mMeshBasedAABB = true; - mCollisionMeshBasedAABB = true; mStaticBasedAABB = true; mStaticBasedColor = MCore::RGBAColor(0.0f, 0.7f, 0.7f); mNodeBasedColor = MCore::RGBAColor(1.0f, 0.0f, 0.0f); - mCollisionMeshBasedColor = MCore::RGBAColor(0.0f, 0.7f, 0.0f); mMeshBasedColor = MCore::RGBAColor(0.0f, 0.0f, 0.7f); } // render the given types of AABBs of a actor instance - void RenderUtil::RenderAABBs(EMotionFX::ActorInstance* actorInstance, const AABBRenderSettings& renderSettings, bool directlyRender) + void RenderUtil::RenderAabbs(EMotionFX::ActorInstance* actorInstance, const AABBRenderSettings& renderSettings, bool directlyRender) { - // get the current LOD level const uint32 lodLevel = actorInstance->GetLODLevel(); - // handle the collision mesh based AABB - if (renderSettings.mCollisionMeshBasedAABB) - { - // calculate the collision mesh based AABB - MCore::AABB box; - actorInstance->CalcCollisionMeshBasedAABB(lodLevel, &box); - - // render the aabb - if (box.CheckIfIsValid()) - { - RenderAABB(box, renderSettings.mCollisionMeshBasedColor); - } - } - // handle the node based AABB if (renderSettings.mNodeBasedAABB) { // calculate the node based AABB - MCore::AABB box; - actorInstance->CalcNodeBasedAABB(&box); + AZ::Aabb box; + actorInstance->CalcNodeBasedAabb(&box); // render the aabb - if (box.CheckIfIsValid()) + if (box.IsValid()) { - RenderAABB(box, renderSettings.mNodeBasedColor); + RenderAabb(box, renderSettings.mNodeBasedColor); } } @@ -351,26 +336,26 @@ namespace MCommon if (renderSettings.mMeshBasedAABB) { // calculate the mesh based AABB - MCore::AABB box; - actorInstance->CalcMeshBasedAABB(lodLevel, &box); + AZ::Aabb box; + actorInstance->CalcMeshBasedAabb(lodLevel, &box); // render the aabb - if (box.CheckIfIsValid()) + if (box.IsValid()) { - RenderAABB(box, renderSettings.mMeshBasedColor); + RenderAabb(box, renderSettings.mMeshBasedColor); } } if (renderSettings.mStaticBasedAABB) { // calculate the static based AABB - MCore::AABB box; - actorInstance->CalcStaticBasedAABB(&box); + AZ::Aabb box; + actorInstance->CalcStaticBasedAabb(&box); // render the aabb - if (box.CheckIfIsValid()) + if (box.IsValid()) { - RenderAABB(box, renderSettings.mStaticBasedColor); + RenderAabb(box, renderSettings.mStaticBasedColor); } } @@ -420,77 +405,6 @@ namespace MCommon } } - - // render object orientated bounding boxes for all enabled nodes inside the actor instance - void RenderUtil::RenderOBBs(EMotionFX::ActorInstance* actorInstance, const AZStd::unordered_set* visibleJointIndices, const AZStd::unordered_set* selectedJointIndices, const MCore::RGBAColor& color, const MCore::RGBAColor& selectedColor, bool directlyRender) - { - AZ::Vector3 p[8]; - - // get the actor it is an instance from - const EMotionFX::Actor* actor = actorInstance->GetActor(); - const EMotionFX::Skeleton* skeleton = actor->GetSkeleton(); - const EMotionFX::Pose* pose = actorInstance->GetTransformData()->GetCurrentPose(); - - // iterate through all enabled nodes - MCore::RGBAColor tempColor; - const uint32 numEnabled = actorInstance->GetNumEnabledNodes(); - for (uint32 i = 0; i < numEnabled; ++i) - { - const EMotionFX::Node* joint = skeleton->GetNode(actorInstance->GetEnabledNode(i)); - const AZ::u32 jointIndex = joint->GetNodeIndex(); - - if (!visibleJointIndices || visibleJointIndices->empty() || - (visibleJointIndices->find(jointIndex) != visibleJointIndices->end())) - { - const MCore::OBB& obb = actor->GetNodeOBB(jointIndex); - EMotionFX::Transform worldTransform = pose->GetWorldSpaceTransform(jointIndex); - - // skip the OBB if it isn't valid - if (obb.CheckIfIsValid() == false) - { - continue; - } - - // check if the current bone is selected and set the color according to it - if (selectedJointIndices && selectedJointIndices->find(jointIndex) != selectedJointIndices->end()) - { - tempColor = selectedColor; - } - else - { - tempColor = color; - } - - obb.CalcCornerPoints(p); - for (uint32 a = 0; a < 8; a++) - { - p[a] = worldTransform.TransformPoint(p[a]); - } - - // render - RenderLine(p[0], p[1], tempColor); - RenderLine(p[1], p[2], tempColor); - RenderLine(p[2], p[3], tempColor); - RenderLine(p[0], p[3], tempColor); - - RenderLine(p[1], p[5], tempColor); - RenderLine(p[3], p[7], tempColor); - RenderLine(p[2], p[6], tempColor); - RenderLine(p[0], p[4], tempColor); - - RenderLine(p[4], p[5], tempColor); - RenderLine(p[4], p[7], tempColor); - RenderLine(p[6], p[7], tempColor); - RenderLine(p[6], p[5], tempColor); - } - } - - if (directlyRender) - { - RenderLines(); - } - } - // render wireframe mesh void RenderUtil::RenderWireframe(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, const MCore::RGBAColor& color, bool directlyRender, float offsetScale) { @@ -1639,7 +1553,7 @@ namespace MCommon // calculate the intersection points with the ground plane and create an AABB around those // if there is no intersection point then use the ray target as point, which is the projection onto the far plane basically - MCore::AABB aabb; + AZ::Aabb aabb = AZ::Aabb::CreateNull(); AZ::Vector3 intersectionPoint; const AZ::Plane groundPlane = AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3(0.0f, 0.0f, 1.0f), AZ::Vector3::CreateZero()); for (AZ::u32 i = 0; i < 4; ++i) @@ -1649,7 +1563,7 @@ namespace MCommon corners[i] = intersectionPoint; } - aabb.Encapsulate(corners[i]); + aabb.AddPoint(corners[i]); } // set the grid start and end values @@ -1665,9 +1579,9 @@ namespace MCommon // get aabb which includes all actor instances - MCore::AABB RenderUtil::CalcSceneAABB() + AZ::Aabb RenderUtil::CalcSceneAabb() { - MCore::AABB finalAABB; + AZ::Aabb finalAABB = AZ::Aabb::CreateNull(); // get the number of actor instances and iterate through them const uint32 numActorInstances = EMotionFX::GetActorManager().GetNumActorInstances(); @@ -1685,17 +1599,17 @@ namespace MCommon actorInstance->UpdateMeshDeformers(0.0f); // get the mesh based bounding box - MCore::AABB boundingBox; - actorInstance->CalcMeshBasedAABB(actorInstance->GetLODLevel(), &boundingBox); + AZ::Aabb boundingBox; + actorInstance->CalcMeshBasedAabb(actorInstance->GetLODLevel(), &boundingBox); // in case there aren't any meshes, use the node based bounding box - if (boundingBox.CheckIfIsValid() == false) + if (!boundingBox.IsValid()) { - actorInstance->CalcNodeBasedAABB(&boundingBox); + actorInstance->CalcNodeBasedAabb(&boundingBox); } // make sure the actor instance is covered in our world bounding box - finalAABB.Encapsulate(boundingBox); + finalAABB.AddAabb(boundingBox); } return finalAABB; diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.h b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.h index 8b1cd30b6c..f63d41e812 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.h +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.h @@ -6,10 +6,9 @@ * */ -#ifndef __MCOMMON_RENDERUTIL_H -#define __MCOMMON_RENDERUTIL_H +#pragma once -// include required headers +#include #include #include #include @@ -111,7 +110,7 @@ namespace MCommon * Render tangents and bitangents of the mesh. * @param mesh A pointer to the mesh which will be rendered. * @param worldTM The world space transformation matrix of the node to which the given mesh belongs to. - * @param scale This parameter controls the length of the tangents and bitangentss. The default size of the tangents and bitangents is one unit. + * @param scale This parameter controls the length of the tangents and bitangents. The default size of the tangents and bitangents is one unit. * @param colorTangents The color of the tangents. * @param mirroredBitangentColor The color of the mirrored bitangents, so the ones that have a w value of -1. * @param colorBitangent The color of the face bitangents. @@ -127,7 +126,7 @@ namespace MCommon * @param directlyRender Will call the RenderLines() function internally in case it is set to true. If false * you have to make sure to call RenderLines() manually at the end of your custom render frame function. */ - void RenderAABB(const MCore::AABB& box, const MCore::RGBAColor& color, bool directlyRender = false); + void RenderAabb(const AZ::Aabb& box, const MCore::RGBAColor& color, bool directlyRender = false); /** * Render a selection gizmo around the given axis aligned bounding box. @@ -136,7 +135,7 @@ namespace MCommon * @param directlyRender Will call the RenderLines() function internally in case it is set to true. If false * you have to make sure to call RenderLines() manually at the end of your custom render frame function. */ - void RenderSelection(const MCore::AABB& box, const MCore::RGBAColor& color, bool directlyRender = false); + void RenderSelection(const AZ::Aabb& box, const MCore::RGBAColor& color, bool directlyRender = false); /** * The render settings used to enable the different AABB types of an actor instance. @@ -152,11 +151,9 @@ namespace MCommon bool mNodeBasedAABB; /**< Enable in case you want to render the node based AABB (default=true). */ bool mMeshBasedAABB; /**< Enable in case you want to render the mesh based AABB (default=true). */ - bool mCollisionMeshBasedAABB; /**< Enable in case you want to render the collision mesh based AABB (default=true). */ bool mStaticBasedAABB; /**< Enable in case you want to render the static based AABB (default=true). */ MCore::RGBAColor mNodeBasedColor; /**< The color of the node based AABB. */ MCore::RGBAColor mMeshBasedColor; /**< The color of the mesh based AABB. */ - MCore::RGBAColor mCollisionMeshBasedColor; /**< The color of the collision mesh based AABB. */ MCore::RGBAColor mStaticBasedColor; /**< The color of the static based AABB. */ }; @@ -168,19 +165,7 @@ namespace MCommon * @param directlyRender Will call the RenderLines() function internally in case it is set to true. If false * you have to make sure to call RenderLines() manually at the end of your custom render frame function. */ - void RenderAABBs(EMotionFX::ActorInstance* actorInstance, const AABBRenderSettings& renderSettings = AABBRenderSettings(), bool directlyRender = false); - - /** - * Render OBB for all enabled nodes inside the actor instance. - * @param actorInstance A pointer to the actor instance which will be rendered. - * @param[in] visibleJointIndices List of visible joint indices. nullptr in case all joints should be rendered. - * @param[in] selectedJointIndices List of selected joint indices. nullptr in case selection should not be considered. - * @param[in] color The color of the OBBs. - * @param[in] selectedColor The color of the selected OBBs. - * @param[in] directlyRender Will call the RenderLines() function internally in case it is set to true. If false - * you have to make sure to call RenderLines() manually at the end of your custom render frame function. - */ - void RenderOBBs(EMotionFX::ActorInstance* actorInstance, const AZStd::unordered_set* visibleJointIndices = nullptr, const AZStd::unordered_set* selectedJointIndices = nullptr, const MCore::RGBAColor& color = MCore::RGBAColor(1.0f, 1.0f, 0.0f, 1.0f), const MCore::RGBAColor& selectedColor = MCore::RGBAColor(1.0f, 0.647f, 0.0f), bool directlyRender = false); + void RenderAabbs(EMotionFX::ActorInstance* actorInstance, const AABBRenderSettings& renderSettings = AABBRenderSettings(), bool directlyRender = false); /** * Render a simple line based skeleton for all enabled nodes of the actor instance. @@ -615,7 +600,7 @@ namespace MCommon * Calculate the aabb which includes all actor instances. * @return The aabb which includes all actor instances. */ - MCore::AABB CalcSceneAABB(); + AZ::Aabb CalcSceneAabb(); struct TrajectoryPathParticle { @@ -722,7 +707,7 @@ namespace MCommon /** * Change the shape of a given arrow head util mesh. This method can be used to adjust an already allocated arrow head util mesh. - * For example this can be usedful if you need to change the radius or the height of an arrow head. + * For example this can be useful if you need to change the radius or the height of an arrow head. * @param mesh A pointer to the arrow head util mesh. Note that this mesh has to be created using CreateArrowHead(). * @param height The height of the arrow head from the base to the head. * @param radius The radius of the base of the arrow head. @@ -735,7 +720,7 @@ namespace MCommon * @param radius The radius of the sphere. * @return A pointer to the newly created util sphere mesh. */ - static UtilMesh* CreateSphere(float radius, uint32 numSegments = 8); + static UtilMesh* CreateSphere(float radius, uint32 numSegments = 5); /** * Create an util mesh we can use to render cubes. @@ -831,6 +816,3 @@ namespace MCommon static uint32 mNumMaxTriangleVertices; /**< The maximum capacity of the triangle vertex buffer */ }; } // namespace MCommon - - -#endif diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RotateManipulator.h b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RotateManipulator.h index c6d719ae7c..5443bad219 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RotateManipulator.h +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RotateManipulator.h @@ -8,7 +8,7 @@ #pragma once -// include the Core system +#include #include #include #include diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/ScaleManipulator.h b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/ScaleManipulator.h index 8cfd3ec541..6d2f167893 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/ScaleManipulator.h +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/ScaleManipulator.h @@ -8,7 +8,7 @@ #pragma once -// include the Core system +#include #include #include #include "MCommonConfig.h" diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/TranslateManipulator.h b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/TranslateManipulator.h index 362f6c19be..7bc0bacfe0 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/TranslateManipulator.h +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/TranslateManipulator.h @@ -9,7 +9,7 @@ #ifndef __MCOMMON_TRANSLATEMANIPULATOR_H #define __MCOMMON_TRANSLATEMANIPULATOR_H -// include the Core system +#include #include #include #include "MCommonConfig.h" diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp index 833f8a14f3..68b9d62e8e 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() { } @@ -97,6 +91,7 @@ namespace EMotionFX mID = MCore::GetIDGenerator().GenerateID(); mUnitType = GetEMotionFX().GetUnitType(); mFileUnitType = mUnitType; + m_staticAabb = AZ::Aabb::CreateNull(); mUsedForVisualization = false; mDirtyFlag = false; @@ -148,7 +143,7 @@ namespace EMotionFX result->mMotionExtractionNode = mMotionExtractionNode; result->mUnitType = mUnitType; result->mFileUnitType = mFileUnitType; - result->mStaticAABB = mStaticAABB; + result->m_staticAabb = m_staticAabb; result->mRetargetRootNode = mRetargetRootNode; result->mInvBindPoseTransforms = mInvBindPoseTransforms; result->m_optimizeSkeleton = m_optimizeSkeleton; @@ -187,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(); @@ -997,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() { @@ -1352,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) { @@ -1387,11 +1368,6 @@ namespace EMotionFX mSkeleton->GetBindPose()->ForceUpdateFullModelSpacePose(); mSkeleton->GetBindPose()->ZeroMorphWeights(); - if (generateOBBs) - { - UpdateNodeBindPoseOBBs(0); - } - if (!GetHasMirrorInfo()) { AllocateNodeMirrorInfos(); @@ -1405,10 +1381,6 @@ namespace EMotionFX m_simulatedObjectSetup->InitAfterLoad(this); - // build the static axis aligned bounding box by creating an actor instance (needed to perform cpu skinning mesh deforms and mesh scaling etc) - // then copy it over to the actor - UpdateStaticAABB(); - // rescale all content if needed if (convertUnitType) { @@ -1526,6 +1498,10 @@ namespace EMotionFX mMorphSetups[i] = nullptr; } } + + // build the static axis aligned bounding box by creating an actor instance (needed to perform cpu skinning mesh deforms and mesh scaling etc) + // then copy it over to the actor + UpdateStaticAabb(); } m_isReady = true; @@ -1534,16 +1510,13 @@ namespace EMotionFX } // update the static AABB (very heavy as it has to create an actor instance, update mesh deformers, calculate the mesh based bounds etc) - void Actor::UpdateStaticAABB() + void Actor::UpdateStaticAabb() { - if (!mStaticAABB.CheckIfIsValid()) - { - ActorInstance* actorInstance = ActorInstance::Create(this, nullptr, mThreadIndex); - //actorInstance->UpdateMeshDeformers(0.0f); - //actorInstance->UpdateStaticBasedAABBDimensions(); - actorInstance->GetStaticBasedAABB(&mStaticAABB); - actorInstance->Destroy(); - } + ActorInstance* actorInstance = ActorInstance::Create(this, nullptr, mThreadIndex); + actorInstance->UpdateMeshDeformers(0.0f); + actorInstance->UpdateStaticBasedAabbDimensions(); + actorInstance->GetStaticBasedAabb(&m_staticAabb); + actorInstance->Destroy(); } @@ -1885,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) @@ -1903,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) { @@ -1934,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) @@ -1946,7 +1916,6 @@ namespace EMotionFX void Actor::DeleteAllNodes() { mSkeleton->RemoveAllNodes(); - mNodeInfos.clear(); AZStd::vector& lodLevels = m_meshLodData.m_lodLevels; for (LODLevel& lodLevel : lodLevels) @@ -2206,14 +2175,14 @@ namespace EMotionFX #endif } - const MCore::AABB& Actor::GetStaticAABB() const + const AZ::Aabb& Actor::GetStaticAabb() const { - return mStaticAABB; + return m_staticAabb; } - void Actor::SetStaticAABB(const MCore::AABB& box) + void Actor::SetStaticAabb(const AZ::Aabb& aabb) { - mStaticAABB = box; + m_staticAabb = aabb; } //--------------------------------- @@ -2265,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) { @@ -2413,17 +2306,9 @@ 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 - mStaticAABB.SetMin(mStaticAABB.GetMin() * scaleFactor); - mStaticAABB.SetMax(mStaticAABB.GetMax() * scaleFactor); + m_staticAabb.SetMin(m_staticAabb.GetMin() * scaleFactor); + m_staticAabb.SetMax(m_staticAabb.GetMax() * scaleFactor); // update mesh data for all LOD levels const uint32 numLODs = GetNumLODLevels(); diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h index 6c3ab6bf29..faf5b6b94d 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h @@ -16,15 +16,14 @@ #include #include #include +#include #include #include // include MCore related files -#include #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; @@ -781,9 +769,9 @@ namespace EMotionFX void ResizeTransformData(); void CopyTransformsFrom(const Actor* other); - const MCore::AABB& GetStaticAABB() const; - void SetStaticAABB(const MCore::AABB& box); - void UpdateStaticAABB(); // VERY heavy operation, you shouldn't call this ever (internally creates an actor instance, updates mesh deformers, calcs a mesh based aabb, destroys the actor instance again) + const AZ::Aabb& GetStaticAabb() const; + void SetStaticAabb(const AZ::Aabb& aabb); + void UpdateStaticAabb(); // VERY heavy operation, you shouldn't call this ever (internally creates an actor instance, updates mesh deformers, calcs a mesh based aabb, destroys the actor instance again) void SetThreadIndex(uint32 index) { mThreadIndex = index; } uint32 GetThreadIndex() const { return mThreadIndex; } @@ -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. */ @@ -985,7 +913,7 @@ namespace EMotionFX uint32 mRetargetRootNode; /**< The retarget root node, which controls the height displacement of the character. This is most likely the hip or pelvis node. */ uint32 mID; /**< The unique identification number for the actor. */ uint32 mThreadIndex; /**< The thread number we are running on, which is a value starting at 0, up to the number of threads in the job system. */ - MCore::AABB mStaticAABB; /**< The static AABB. */ + AZ::Aabb m_staticAabb; /**< The static AABB. */ bool mDirtyFlag; /**< The dirty flag which indicates whether the user has made changes to the actor since the last file save operation. */ bool mUsedForVisualization; /**< Indicates if the actor is used for visualization specific things and is not used as a normal in-game actor. */ bool m_optimizeSkeleton; /**< Indicates if we should perform/ */ diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.cpp index b2091f967f..b80aab3c50 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.cpp @@ -67,7 +67,7 @@ namespace EMotionFX mMotionSamplingTimer = 0.0f; mTrajectoryDelta.IdentityWithZeroScale(); - mStaticAABB.Init(); + m_staticAabb = AZ::Aabb::CreateNull(); mAnimGraphInstance = nullptr; @@ -137,15 +137,15 @@ namespace EMotionFX UpdateDependencies(); // update the static based AABB dimensions - mStaticAABB = mActor->GetStaticAABB(); - if (mStaticAABB.CheckIfIsValid() == false) + m_staticAabb = mActor->GetStaticAabb(); + if (!m_staticAabb.IsValid()) { UpdateMeshDeformers(0.0f, true); // TODO: not really thread safe because of shared meshes, although it probably will output correctly - UpdateStaticBasedAABBDimensions(); + UpdateStaticBasedAabbDimensions(); } // update the bounds - UpdateBounds(0, mBoundsUpdateType, 1); + UpdateBounds(/*lodLevel=*/0, mBoundsUpdateType); // register it GetActorManager().RegisterActorInstance(this); @@ -254,12 +254,12 @@ namespace EMotionFX UpdateAttachments(); // update the attachment parent matrices // update the bounds when needed - if (GetBoundsUpdateEnabled() && mBoundsUpdateType != BOUNDS_MESH_BASED) + if (GetBoundsUpdateEnabled()) { mBoundsUpdatePassedTime += timePassedInSeconds; if (mBoundsUpdatePassedTime >= mBoundsUpdateFrequency) { - UpdateBounds(mLODLevel, BOUNDS_NODE_BASED, mBoundsUpdateItemFreq); + UpdateBounds(mLODLevel, mBoundsUpdateType, mBoundsUpdateItemFreq); mBoundsUpdatePassedTime = 0.0f; } } @@ -354,7 +354,7 @@ namespace EMotionFX } // update the bounds when needed - if (GetBoundsUpdateEnabled() && mBoundsUpdateType != BOUNDS_MESH_BASED) + if (GetBoundsUpdateEnabled()) { mBoundsUpdatePassedTime += timePassedInSeconds; if (mBoundsUpdatePassedTime >= mBoundsUpdateFrequency) @@ -407,18 +407,6 @@ namespace EMotionFX stack->Update(this, node, timePassedInSeconds, processDisabledDeformers); } } - - // Update the bounds when we are set to use mesh based bounds. - if (GetBoundsUpdateEnabled() && - GetBoundsUpdateType() == BOUNDS_MESH_BASED) - { - mBoundsUpdatePassedTime += timePassedInSeconds; - if (mBoundsUpdatePassedTime >= mBoundsUpdateFrequency) - { - UpdateBounds(mLODLevel, mBoundsUpdateType, mBoundsUpdateItemFreq); - mBoundsUpdatePassedTime = 0.0f; - } - } } // Update the mesh morph deformers, which updates the vertex positions on the CPU, so performing CPU morphing. @@ -439,18 +427,6 @@ namespace EMotionFX stack->UpdateByModifierType(this, node, timePassedInSeconds, MorphMeshDeformer::TYPE_ID, true, processDisabledDeformers); } } - - // Update the bounds when we are set to use mesh based bounds. - if (GetBoundsUpdateEnabled() && - GetBoundsUpdateType() == BOUNDS_MESH_BASED) - { - mBoundsUpdatePassedTime += timePassedInSeconds; - if (mBoundsUpdatePassedTime >= mBoundsUpdateFrequency) - { - UpdateBounds(mLODLevel, mBoundsUpdateType, mBoundsUpdateItemFreq); - mBoundsUpdatePassedTime = 0.0f; - } - } } void ActorInstance::PostPhysicsUpdate(float timePassedInSeconds) @@ -639,118 +615,40 @@ namespace EMotionFX { // calculate the static based AABB case BOUNDS_STATIC_BASED: - CalcStaticBasedAABB(&mAABB); + CalcStaticBasedAabb(&m_aabb); break; // based on the world space positions of the nodes (least accurate, but fastest) case BOUNDS_NODE_BASED: - CalcNodeBasedAABB(&mAABB, itemFrequency); - break; - - // based on the world space positions of the vertices of the collision meshes (faster and more accurate than mesh based) - case BOUNDS_COLLISIONMESH_BASED: - CalcCollisionMeshBasedAABB(geomLODLevel, &mAABB, itemFrequency); + CalcNodeBasedAabb(&m_aabb, itemFrequency); break; // based on the world space positions of the vertices of the meshes (most accurate) case BOUNDS_MESH_BASED: - CalcMeshBasedAABB(geomLODLevel, &mAABB, itemFrequency); - break; - - // based on the world space positions of the vertices of the meshes (most accurate) - case BOUNDS_NODEOBB_BASED: - CalcNodeOBBBasedAABB(&mAABB, itemFrequency); - break; - - case BOUNDS_NODEOBBFAST_BASED: - CalcNodeOBBBasedAABBFast(&mAABB, itemFrequency); + UpdateMeshDeformers(0.0f); + CalcMeshBasedAabb(geomLODLevel, &m_aabb, itemFrequency); break; // when we're dealing with an unspecified bounding volume update method default: MCore::LogInfo("*** EMotionFX::ActorInstance::UpdateBounds() - Unknown boundsType specified! (%d) ***", (uint32)boundsType); } - } - // calculate the axis aligned bounding box that contains the object oriented boxes of all nodes - void ActorInstance::CalcNodeOBBBasedAABBFast(MCore::AABB* outResult, uint32 nodeFrequency) - { - // init the axis aligned bounding box - outResult->Init(); - - const Pose* pose = mTransformData->GetCurrentPose(); - const Skeleton* skeleton = mActor->GetSkeleton(); - - // for all nodes, encapsulate the world space positions - uint16 nodeNr; - const uint32 numNodes = GetNumEnabledNodes(); - for (uint32 i = 0; i < numNodes; i += nodeFrequency) + // Expand the bounding volume by a tolerance area in case set. + if (!AZ::IsClose(m_boundsExpandBy, 0.0f)) { - nodeNr = GetEnabledNode(i); - Node* node = skeleton->GetNode(nodeNr); - if (node->GetIncludeInBoundsCalc()) - { - const MCore::OBB& obb = mActor->GetNodeOBB(nodeNr); - if (obb.CheckIfIsValid() == false) - { - continue; - } - - // calculate the corner points of the node in local space - AZ::Vector3 minPoint, maxPoint; - obb.CalcMinMaxPoints(&minPoint, &maxPoint); - - // encapsulate the results in the AABB box - const Transform worldTransform = pose->GetWorldSpaceTransform(nodeNr); - outResult->Encapsulate(worldTransform.TransformPoint(minPoint)); - outResult->Encapsulate(worldTransform.TransformPoint(maxPoint)); - } - } - } - - // more accurate node obb based method that uses the 8 corner points of the obb - void ActorInstance::CalcNodeOBBBasedAABB(MCore::AABB* outResult, uint32 nodeFrequency) - { - // init the axis aligned bounding box - outResult->Init(); - - const Pose* pose = mTransformData->GetCurrentPose(); - const Skeleton* skeleton = mActor->GetSkeleton(); - - // for all nodes, encapsulate the world space positions - AZ::Vector3 cornerPoints[8]; - uint16 nodeNr; - const uint32 numNodes = GetNumEnabledNodes(); - for (uint32 i = 0; i < numNodes; i += nodeFrequency) - { - nodeNr = GetEnabledNode(i); - Node* node = skeleton->GetNode(nodeNr); - if (node->GetIncludeInBoundsCalc()) - { - const MCore::OBB& obb = mActor->GetNodeOBB(nodeNr); - if (obb.CheckIfIsValid() == false) - { - continue; - } - - // calculate the 8 corner points - obb.CalcCornerPoints(cornerPoints); - - const Transform worldTransform = pose->GetWorldSpaceTransform(nodeNr); - - // encapsulate all OBB world space corner points inside the AABB - for (uint32 p = 0; p < 8; ++p) - { - outResult->Encapsulate(worldTransform.TransformPoint(cornerPoints[p])); - } - } + const AZ::Vector3 center = m_aabb.GetCenter(); + const AZ::Vector3 halfExtents = m_aabb.GetExtents() * 0.5f; + const AZ::Vector3 scaledHalfExtents = halfExtents * (1.0f + m_boundsExpandBy); + m_aabb.SetMin(center - scaledHalfExtents); + m_aabb.SetMax(center + scaledHalfExtents); } } // calculate the axis aligned bounding box based on the world space positions of the nodes - void ActorInstance::CalcNodeBasedAABB(MCore::AABB* outResult, uint32 nodeFrequency) + void ActorInstance::CalcNodeBasedAabb(AZ::Aabb* outResult, uint32 nodeFrequency) { - outResult->Init(); + *outResult = AZ::Aabb::CreateNull(); const Pose* pose = mTransformData->GetCurrentPose(); const Skeleton* skeleton = mActor->GetSkeleton(); @@ -763,16 +661,15 @@ namespace EMotionFX nodeNr = GetEnabledNode(i); if (skeleton->GetNode(nodeNr)->GetIncludeInBoundsCalc()) { - outResult->Encapsulate(pose->GetWorldSpaceTransform(nodeNr).mPosition); + outResult->AddPoint(pose->GetWorldSpaceTransform(nodeNr).mPosition); } } } // calculate the AABB that contains all world space vertices of all meshes - void ActorInstance::CalcMeshBasedAABB(uint32 geomLODLevel, MCore::AABB* outResult, uint32 vertexFrequency) + void ActorInstance::CalcMeshBasedAabb(uint32 geomLODLevel, AZ::Aabb* outResult, uint32 vertexFrequency) { - // init the axis aligned bounding box - outResult->Init(); + *outResult = AZ::Aabb::CreateNull(); const Pose* pose = mTransformData->GetCurrentPose(); const Skeleton* skeleton = mActor->GetSkeleton(); @@ -800,52 +697,9 @@ namespace EMotionFX const Transform worldTransform = pose->GetMeshNodeWorldSpaceTransform(geomLODLevel, nodeNr); // calculate and encapsulate the mesh bounds inside the total mesh box - MCore::AABB meshBox; - mesh->CalcAABB(&meshBox, worldTransform, vertexFrequency); - outResult->Encapsulate(meshBox); - } - } - - void ActorInstance::CalcCollisionMeshBasedAABB(uint32 geomLODLevel, MCore::AABB* outResult, uint32 vertexFrequency) - { - // init the axis aligned bounding box - outResult->Init(); - - const Pose* pose = mTransformData->GetCurrentPose(); - const Skeleton* skeleton = mActor->GetSkeleton(); - - // for all nodes, encapsulate the world space positions - uint16 nodeNr; - const uint32 numNodes = GetNumEnabledNodes(); - for (uint32 i = 0; i < numNodes; ++i) - { - nodeNr = GetEnabledNode(i); - Node* node = skeleton->GetNode(nodeNr); - - // skip nodes without collision meshes - Mesh* mesh = mActor->GetMesh(geomLODLevel, nodeNr); - if (mesh == nullptr) - { - continue; - } - - if (mesh->GetIsCollisionMesh() == false) - { - continue; - } - - // if this node should be excluded - if (node->GetIncludeInBoundsCalc() == false) - { - continue; - } - - const Transform worldTransform = pose->GetMeshNodeWorldSpaceTransform(geomLODLevel, nodeNr); - - // calculate and encapsulate the mesh bounds inside the total mesh box - MCore::AABB meshBox; - mesh->CalcAABB(&meshBox, worldTransform, vertexFrequency); - outResult->Encapsulate(meshBox); + AZ::Aabb meshBox; + mesh->CalcAabb(&meshBox, worldTransform, vertexFrequency); + outResult->AddAabb(meshBox); } } @@ -1567,111 +1421,45 @@ namespace EMotionFX } // update the static based aabb dimensions - void ActorInstance::UpdateStaticBasedAABBDimensions() + void ActorInstance::UpdateStaticBasedAabbDimensions() { - // backup the transform Transform orgTransform = GetLocalSpaceTransform(); - //------------------------------------- - - // reset position and scale SetLocalSpacePosition(AZ::Vector3::CreateZero()); + EMFX_SCALECODE(SetLocalSpaceScale(AZ::Vector3(1.0f, 1.0f, 1.0f));) - EMFX_SCALECODE( - SetLocalSpaceScale(AZ::Vector3(1.0f, 1.0f, 1.0f));) + UpdateTransformations(0.0f, true); + UpdateMeshDeformers(0.0f); - // rotate over x, y and z axis - AZ::Vector3 boxMin(FLT_MAX, FLT_MAX, FLT_MAX); - AZ::Vector3 boxMax(-FLT_MAX, -FLT_MAX, -FLT_MAX); - for (uint32 axis = 0; axis < 3; axis++) + // calculate the aabb of this + if (mActor->CheckIfHasMeshes(0)) { - for (uint32 i = 0; i < 360; i += 45) // steps of 45 degrees - { - // rotate a given amount of degrees over the axis we are currently testing - AZ::Vector3 axisVector(0.0f, 0.0f, 0.0f); - axisVector.SetElement(axis, 1.0f); - const float angle = static_cast(i); - SetLocalSpaceRotation(MCore::CreateFromAxisAndAngle(axisVector, MCore::Math::DegreesToRadians(angle))); - - UpdateTransformations(0.0f, true); - UpdateMeshDeformers(0.0f); - - // calculate the aabb of this - if (mActor->CheckIfHasMeshes(0)) - { - CalcMeshBasedAABB(0, &mStaticAABB); - } - else - { - CalcNodeBasedAABB(&mStaticAABB); - } - - // find the minimum and maximum - const AZ::Vector3& curMin = mStaticAABB.GetMin(); - const AZ::Vector3& curMax = mStaticAABB.GetMax(); - if (curMin.GetX() < boxMin.GetX()) - { - boxMin.SetX(curMin.GetX()); - } - if (curMin.GetY() < boxMin.GetY()) - { - boxMin.SetY(curMin.GetY()); - } - if (curMin.GetZ() < boxMin.GetZ()) - { - boxMin.SetZ(curMin.GetZ()); - } - if (curMax.GetX() > boxMax.GetX()) - { - boxMax.SetX(curMax.GetX()); - } - if (curMax.GetY() > boxMax.GetY()) - { - boxMax.SetY(curMax.GetY()); - } - if (curMax.GetZ() > boxMax.GetZ()) - { - boxMax.SetZ(curMax.GetZ()); - } - } + CalcMeshBasedAabb(0, &m_staticAabb); + } + else + { + CalcNodeBasedAabb(&m_staticAabb); } - mStaticAABB.SetMin(boxMin); - mStaticAABB.SetMax(boxMax); - - /* - // calculate the center point of the box - const AZ::Vector3 center = mStaticAABB.CalcMiddle(); - - // find the maximum of the width, height and depth - const float maxDim = MCore::Max3( mStaticAABB.CalcWidth(), mStaticAABB.CalcHeight(), mStaticAABB.CalcDepth() ) * 0.5f; - - // make width, height and depth the same as its maximum - mStaticAABB.SetMin( center + AZ::Vector3(-maxDim, -maxDim, -maxDim) ); - mStaticAABB.SetMax( center + AZ::Vector3( maxDim, maxDim, maxDim) ); - */ - //------------------------------------- - - // restore the transform mLocalTransform = orgTransform; } // calculate the moved static based aabb - void ActorInstance::CalcStaticBasedAABB(MCore::AABB* outResult) + void ActorInstance::CalcStaticBasedAabb(AZ::Aabb* outResult) { if (GetIsSkinAttachment()) { - mSelfAttachment->GetAttachToActorInstance()->CalcStaticBasedAABB(outResult); + mSelfAttachment->GetAttachToActorInstance()->CalcStaticBasedAabb(outResult); return; } - *outResult = mStaticAABB; + *outResult = m_staticAabb; EMFX_SCALECODE( - outResult->SetMin(mStaticAABB.GetMin() * mWorldTransform.mScale); - outResult->SetMax(mStaticAABB.GetMax() * mWorldTransform.mScale);) + outResult->SetMin(m_staticAabb.GetMin() * mWorldTransform.mScale); + outResult->SetMax(m_staticAabb.GetMax() * mWorldTransform.mScale);) outResult->Translate(mWorldTransform.mPosition); } - // adjust the animgraph instance + // adjust the anim graph instance void ActorInstance::SetAnimGraphInstance(AnimGraphInstance* instance) { mAnimGraphInstance = instance; @@ -1774,29 +1562,29 @@ namespace EMotionFX SetFlag(BOOL_BOUNDSUPDATEENABLED, enable); } - void ActorInstance::SetStaticBasedAABB(const MCore::AABB& aabb) + void ActorInstance::SetStaticBasedAabb(const AZ::Aabb& aabb) { - mStaticAABB = aabb; + m_staticAabb = aabb; } - void ActorInstance::GetStaticBasedAABB(MCore::AABB* outAABB) + void ActorInstance::GetStaticBasedAabb(AZ::Aabb* outAabb) { - *outAABB = mStaticAABB; + *outAabb = m_staticAabb; } - const MCore::AABB& ActorInstance::GetStaticBasedAABB() const + const AZ::Aabb& ActorInstance::GetStaticBasedAabb() const { - return mStaticAABB; + return m_staticAabb; } - const MCore::AABB& ActorInstance::GetAABB() const + const AZ::Aabb& ActorInstance::GetAabb() const { - return mAABB; + return m_aabb; } - void ActorInstance::SetAABB(const MCore::AABB& aabb) + void ActorInstance::SetAabb(const AZ::Aabb& aabb) { - mAABB = aabb; + m_aabb = aabb; } uint32 ActorInstance::GetNumAttachments() const @@ -2018,23 +1806,20 @@ namespace EMotionFX mVisualizeScale = 0.0f; UpdateMeshDeformers(0.0f); - MCore::AABB box; - CalcCollisionMeshBasedAABB(0, &box); - if (box.CheckIfIsValid()) + AZ::Aabb box = AZ::Aabb::CreateNull(); + + CalcNodeBasedAabb(&box); + if (box.IsValid()) { - mVisualizeScale = MCore::Max(mVisualizeScale, box.CalcRadius()); + const float boxRadius = AZ::Vector3(box.GetMax() - box.GetMin()).GetLength() * 0.5f; + mVisualizeScale = MCore::Max(mVisualizeScale, boxRadius); } - CalcNodeBasedAABB(&box); - if (box.CheckIfIsValid()) + CalcMeshBasedAabb(0, &box); + if (box.IsValid()) { - mVisualizeScale = MCore::Max(mVisualizeScale, box.CalcRadius()); - } - - CalcMeshBasedAABB(0, &box); - if (box.CheckIfIsValid()) - { - mVisualizeScale = MCore::Max(mVisualizeScale, box.CalcRadius()); + const float boxRadius = AZ::Vector3(box.GetMax() - box.GetMin()).GetLength() * 0.5f; + mVisualizeScale = MCore::Max(mVisualizeScale, boxRadius); } mVisualizeScale *= 0.01f; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.h b/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.h index 3567175d6d..4488a1386f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.h @@ -60,9 +60,6 @@ namespace EMotionFX { BOUNDS_NODE_BASED = 0, /**< Calculate the bounding volumes based on the world space node positions. */ BOUNDS_MESH_BASED = 1, /**< Calculate the bounding volumes based on the world space vertex positions. */ - BOUNDS_COLLISIONMESH_BASED = 2, /**< Calculate the bounding volumes based on the world space collision mesh vertex positions. */ - BOUNDS_NODEOBB_BASED = 3, /**< Calculate the bounding volumes based on the oriented bounding boxes of the nodes. Uses all 8 corner points of the individual node OBB boxes. */ - BOUNDS_NODEOBBFAST_BASED = 4, /**< Calculate the bounding volumes based on the oriented bounding boxes of the nodes. Uses the min and max point of the individual node OBB boxes. This is less accurate but faster. */ BOUNDS_STATIC_BASED = 5 /**< Calculate the bounding volumes based on an approximate box, based on the mesh bounds, and move this box along with the actor instance position. */ }; @@ -348,6 +345,14 @@ namespace EMotionFX */ EBoundsType GetBoundsUpdateType() const; + /** + * Get the normalized percentage that the calculated bounding box is expanded with. + * This can be used to add a tolerance area to the calculated bounding box to avoid clipping the character too early. + * A static bounding box together with the expansion is the recommended way for maximum performance. + * @result A value of 1.0 means that the calculated bounding box won't be expanded at all, while 2.0 means it is twice the size. + */ + float GetExpandBoundsBy() const { return m_boundsExpandBy; } + /** * Get the bounding volume auto-update item frequency. * A value of 1 would mean every node or vertex will be taken into account in the bounds calculation. @@ -376,11 +381,19 @@ namespace EMotionFX /** * Set the bounding volume auto-update type. * This can be either based on the node's world space positions, the mesh vertex world space positions, or the - * collision mesh vertex world space postitions. + * collision mesh vertex world space positions. * @param bType The bounding volume update type. */ void SetBoundsUpdateType(EBoundsType bType); + /** + * Set the normalized percentage that the calculated bounding box should be expanded with. + * This can be used to add a tolerance area to the calculated bounding box to avoid clipping the character too early. + * A static bounding box together with the expansion is the recommended way for maximum performance. + * @param[in] expandBy A value of 1.0 means that the calculated bounding box won't be expanded at all, while 2.0 means it will be twice the size. + */ + void SetExpandBoundsBy(float expandBy) { m_boundsExpandBy = expandBy; } + /** * Set the bounding volume auto-update item frequency. * A value of 1 would mean every node or vertex will be taken into account in the bounds calculation. @@ -420,11 +433,11 @@ namespace EMotionFX * This function is generally only executed once, when creating the actor instance. * The CalcStaticBasedAABB function then simply translates this box along with the actor instance's position. */ - void UpdateStaticBasedAABBDimensions(); + void UpdateStaticBasedAabbDimensions(); - void SetStaticBasedAABB(const MCore::AABB& aabb); - void GetStaticBasedAABB(MCore::AABB* outAABB); - const MCore::AABB& GetStaticBasedAABB() const; + void SetStaticBasedAabb(const AZ::Aabb& aabb); + void GetStaticBasedAabb(AZ::Aabb* outAabb); + const AZ::Aabb& GetStaticBasedAabb() const; /** * Calculate an axis aligned bounding box that can be used as static AABB. It is static in the way that the volume does not change. It can however be translated as it will move @@ -434,7 +447,7 @@ namespace EMotionFX * If there are no meshes present, a widened node based box will be used instead as basis. * @param outResult The resulting bounding box, moved along with the actor instance's position. */ - void CalcStaticBasedAABB(MCore::AABB* outResult); + void CalcStaticBasedAabb(AZ::Aabb* outResult); /** * Calculate the axis aligned bounding box based on the world space positions of the nodes. @@ -442,7 +455,7 @@ namespace EMotionFX * @param nodeFrequency This will include every "nodeFrequency"-th node. So a value of 1 will include all nodes. A value of 2 would * process every second node, meaning that half of the nodes will be skipped. A value of 4 would process every 4th node, etc. */ - void CalcNodeBasedAABB(MCore::AABB* outResult, uint32 nodeFrequency = 1); + void CalcNodeBasedAabb(AZ::Aabb* outResult, uint32 nodeFrequency = 1); /** * Calculate the axis aligned bounding box based on the world space vertex coordinates of the meshes. @@ -452,43 +465,7 @@ namespace EMotionFX * @param vertexFrequency This includes every "vertexFrequency"-th vertex. So for example a value of 2 would skip every second vertex and * so will process half of the vertices. A value of 4 would process only each 4th vertex, etc. */ - void CalcMeshBasedAABB(uint32 geomLODLevel, MCore::AABB* outResult, uint32 vertexFrequency = 1); - - /** - * Calculate the axis aligned bounding box based on the world space vertex coordinates of the collision meshes. - * If the actor has no collision meshes, the created box will be invalid. - * @param geomLODLevel The geometry LOD level to calculate the box for. - * @param outResult The AABB where this method should store the resulting box in. - * @param vertexFrequency This includes every "vertexFrequency"-th vertex. So for example a value of 2 would skip every second vertex and - * so will process half of the vertices. A value of 4 would process only each 4th vertex, etc. - */ - void CalcCollisionMeshBasedAABB(uint32 geomLODLevel, MCore::AABB* outResult, uint32 vertexFrequency = 1); - - /** - * Calculate the axis aligned bounding box that contains the object oriented boxes of all nodes. - * The OBB (oriented bounding box) of each node is calculated by fitting an OBB to its mesh. - * The OBB of nodes that act as bones and have no meshes themselves are fit to the set of vertices that are influenced by the given bone. - * This method will give more accurate results than the CalcNodeBasedAABB method in trade for a bit lower performance. - * Also one big advantage of this method is that you can use these bounds for hit detection, without having artists setup collision meshes. - * @param outResult The AABB where this method should store the resulting box in. - * @param nodeFrequency This will include every "nodeFrequency"-th node. So a value of 1 will include all nodes. A value of 2 would - * process every second node, meaning that half of the nodes will be skipped. A value of 4 would process every 4th node, etc. - */ - void CalcNodeOBBBasedAABB(MCore::AABB* outResult, uint32 nodeFrequency = 1); - - /** - * Calculate the axis aligned bounding box that contains the object oriented boxes of all nodes. - * The OBB (oriented bounding box) of each node is calculated by fitting an OBB to its mesh. - * The OBB of nodes that act as bones and have no meshes themselves are fit to the set of vertices that are influenced by the given bone. - * This method will give more accurate results than the CalcNodeBasedAABB method in trade for a bit lower performance. - * Also one big advantage of this method is that you can use these bounds for hit detection, without having artists setup collision meshes. - * NOTE: this is a faster variant from the CalcNodeOBBBasedAABB method. The difference is that this method only transforms the min and max point of the box in local space. - * Therefore it is less accurate, but it might still be enough. The original CalcNodeOBBBasedAABB method calculates the 8 corner points of the node obb boxes. - * @param outResult The AABB where this method should store the resulting box in. - * @param nodeFrequency This will include every "nodeFrequency"-th node. So a value of 1 will include all nodes. A value of 2 would - * process every second node, meaning that half of the nodes will be skipped. A value of 4 would process every 4th node, etc. - */ - void CalcNodeOBBBasedAABBFast(MCore::AABB* outResult, uint32 nodeFrequency = 1); + void CalcMeshBasedAabb(uint32 geomLODLevel, AZ::Aabb* outResult, uint32 vertexFrequency = 1); /** * Get the axis aligned bounding box. @@ -496,14 +473,14 @@ namespace EMotionFX * That method is also called automatically when the bounds auto-update feature is enabled. * @result The axis aligned bounding box. */ - const MCore::AABB& GetAABB() const; + const AZ::Aabb& GetAabb() const; /** * Set the axis aligned bounding box. * Please beware that this box will get automatically overwritten when automatic bounds update is enabled. * @param aabb The axis aligned bounding box to store. */ - void SetAABB(const MCore::AABB& aabb); + void SetAabb(const AZ::Aabb& aabb); //------------------------------------------------------------------------------------------- @@ -887,8 +864,8 @@ namespace EMotionFX private: TransformData* mTransformData; /**< The transformation data for this instance. */ - MCore::AABB mAABB; /**< The axis aligned bounding box. */ - MCore::AABB mStaticAABB; /**< A static pre-calculated bounding box, which we can move along with the position of the actor instance, and use for visibility checks. */ + AZ::Aabb m_aabb; /**< The axis aligned bounding box. */ + AZ::Aabb m_staticAabb; /**< A static pre-calculated bounding box, which we can move along with the position of the actor instance, and use for visibility checks. */ Transform mLocalTransform = Transform::CreateIdentity(); Transform mWorldTransform = Transform::CreateIdentity(); @@ -907,7 +884,7 @@ namespace EMotionFX MotionSystem* mMotionSystem; /**< The motion system, that handles all motion playback and blending etc. */ AnimGraphInstance* mAnimGraphInstance; /**< A pointer to the anim graph instance, which can be nullptr when there is no anim graph instance. */ AZStd::unique_ptr m_ragdollInstance; - MCore::Mutex mLock; /**< The multithread lock. */ + MCore::Mutex mLock; /**< The multi-thread lock. */ void* mCustomData; /**< A pointer to custom data for this actor. This could be a pointer to your engine or game object for example. */ AZ::Entity* m_entity; /**< The entity to which the actor instance belongs to. */ float mBoundsUpdateFrequency; /**< The bounds update frequency. Which is a time value in seconds. */ @@ -920,7 +897,8 @@ namespace EMotionFX uint32 mBoundsUpdateItemFreq; /**< The bounds update item counter step size. A value of 1 means every vertex/node, a value of 2 means every second vertex/node, etc. */ uint32 mID; /**< The unique identification number for the actor instance. */ uint32 mThreadIndex; /**< The thread index. This specifies the thread number this actor instance is being processed in. */ - EBoundsType mBoundsUpdateType; /**< The bounds update type (node based, mesh based or colliison mesh based). */ + EBoundsType mBoundsUpdateType; /**< The bounds update type (node based, mesh based or collision mesh based). */ + float m_boundsExpandBy = 0.25f; /**< Expand bounding box by normalized percentage. (Default: 25% greater than the calculated bounding box) */ uint8 mNumAttachmentRefs; /**< Specifies how many actor instances use this actor instance as attachment. */ uint8 mBoolFlags; /**< Boolean flags. */ diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/BlendTreeRotationMath2Node.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/BlendTreeRotationMath2Node.cpp index d01a6e5f0d..1f15333561 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/BlendTreeRotationMath2Node.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/BlendTreeRotationMath2Node.cpp @@ -105,7 +105,6 @@ namespace EMotionFX } // If both x and y inputs have connections - //MCore::Quaternion x = MCore::AzQuatToEmfxQuat(m_defaultValue); AZ::Quaternion x = m_defaultValue; AZ::Quaternion y = x; if (mConnections.size() == 2) diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ActorFileFormat.h b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ActorFileFormat.h index b8a5cc9616..402c70c8a1 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ActorFileFormat.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ActorFileFormat.h @@ -108,7 +108,7 @@ namespace EMotionFX // a node header // (not aligned) - struct Actor_Node + struct Actor_Node2 { FileQuaternion mLocalQuat; // the local rotation (before hierarchy) FileVector3 mLocalPos; // the local translation (before hierarchy) @@ -117,7 +117,6 @@ namespace EMotionFX uint32 mParentIndex;// parent node number, or 0xFFFFFFFF in case of a root node uint32 mNumChilds; // the number of child nodes uint8 mNodeFlags; // #1 bit boolean specifies whether we have to include this node in the bounds calculation or not - float mOBB[16]; // followed by: // string : node name (the unique name of the node) @@ -200,14 +199,11 @@ namespace EMotionFX // uint16 [mNumNodes] }; - // (aligned) - struct Actor_Nodes + struct Actor_Nodes2 { uint32 mNumNodes; uint32 mNumRootNodes; - FileVector3 mStaticBoxMin; - FileVector3 mStaticBoxMax; // followed by Actor_Node4[mNumNodes] or Actor_NODE5[mNumNodes] (for v2) }; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp index 3cec3b599c..9f6429abd7 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp @@ -355,12 +355,9 @@ namespace EMotionFX return mLoggingActive; } - //================================================================================================= - - // a chunk that contains all nodes in one chunk - bool ChunkProcessorActorNodes::Process(MCore::File* file, Importer::ImportParameters& importParams) + bool ChunkProcessorActorNodes2::Process(MCore::File* file, Importer::ImportParameters& importParams) { const MCore::Endian::EEndianType endianType = importParams.mEndianType; Actor* actor = importParams.mActor; @@ -369,28 +366,12 @@ namespace EMotionFX MCORE_ASSERT(actor); Skeleton* skeleton = actor->GetSkeleton(); - FileFormat::Actor_Nodes nodesHeader; - file->Read(&nodesHeader, sizeof(FileFormat::Actor_Nodes)); + FileFormat::Actor_Nodes2 nodesHeader; + file->Read(&nodesHeader, sizeof(FileFormat::Actor_Nodes2)); // convert endian MCore::Endian::ConvertUnsignedInt32(&nodesHeader.mNumNodes, endianType); MCore::Endian::ConvertUnsignedInt32(&nodesHeader.mNumRootNodes, endianType); - MCore::Endian::ConvertFloat(&nodesHeader.mStaticBoxMin.mX, endianType); - MCore::Endian::ConvertFloat(&nodesHeader.mStaticBoxMin.mY, endianType); - MCore::Endian::ConvertFloat(&nodesHeader.mStaticBoxMin.mZ, endianType); - MCore::Endian::ConvertFloat(&nodesHeader.mStaticBoxMax.mX, endianType); - MCore::Endian::ConvertFloat(&nodesHeader.mStaticBoxMax.mY, endianType); - MCore::Endian::ConvertFloat(&nodesHeader.mStaticBoxMax.mZ, endianType); - - // convert endian and coord system of the static box - AZ::Vector3 boxMin(nodesHeader.mStaticBoxMin.mX, nodesHeader.mStaticBoxMin.mY, nodesHeader.mStaticBoxMin.mZ); - AZ::Vector3 boxMax(nodesHeader.mStaticBoxMax.mX, nodesHeader.mStaticBoxMax.mY, nodesHeader.mStaticBoxMax.mZ); - - // build the box and set it - MCore::AABB staticBox; - staticBox.SetMin(boxMin); - staticBox.SetMax(boxMax); - actor->SetStaticAABB(staticBox); // pre-allocate space for the nodes actor->SetNumNodes(nodesHeader.mNumNodes); @@ -410,8 +391,8 @@ namespace EMotionFX for (uint32 n = 0; n < nodesHeader.mNumNodes; ++n) { // read the node header - FileFormat::Actor_Node nodeChunk; - file->Read(&nodeChunk, sizeof(FileFormat::Actor_Node)); + FileFormat::Actor_Node2 nodeChunk; + file->Read(&nodeChunk, sizeof(FileFormat::Actor_Node2)); // read the node name const char* nodeName = SharedHelperData::ReadString(file, importParams.mSharedData, endianType); @@ -420,7 +401,6 @@ namespace EMotionFX MCore::Endian::ConvertUnsignedInt32(&nodeChunk.mParentIndex, endianType); MCore::Endian::ConvertUnsignedInt32(&nodeChunk.mSkeletalLODs, endianType); MCore::Endian::ConvertUnsignedInt32(&nodeChunk.mNumChilds, endianType); - MCore::Endian::ConvertFloat(&nodeChunk.mOBB[0], endianType, 16); // show the name of the node, the parent and the number of children if (GetLogging()) @@ -453,11 +433,6 @@ namespace EMotionFX ConvertScale(&scale, endianType); ConvertQuaternion(&rot, endianType); - // make sure the input data is normalized - // TODO: this isn't really needed as we already normalized? - //rot.FastNormalize(); - //scaleRot.FastNormalize(); - // set the local transform Transform bindTransform; bindTransform.mPosition = pos; @@ -503,23 +478,6 @@ namespace EMotionFX skeleton->AddRootNode(nodeIndex); } - // OBB - AZ::Matrix4x4 obbMatrix4x4 = AZ::Matrix4x4::CreateFromRowMajorFloat16(nodeChunk.mOBB); - - const AZ::Vector3 obbCenter = obbMatrix4x4.GetTranslation(); - const AZ::Vector3 obbExtents = obbMatrix4x4.GetRowAsVector3(3); - - // initialize the OBB - MCore::OBB obb; - obb.SetCenter(obbCenter); - obb.SetExtents(obbExtents); - - // need to transpose to go from row major to column major - const AZ::Matrix3x3 obbMatrix3x3 = AZ::Matrix3x3::CreateFromMatrix4x4(obbMatrix4x4).GetTranspose(); - const AZ::Transform obbTransform = AZ::Transform::CreateFromMatrix3x3AndTranslation(obbMatrix3x3, obbExtents); - obb.SetTransformation(obbTransform); - actor->SetNodeOBB(nodeIndex, obb); - if (GetLogging()) { MCore::LogDetailedInfo(" - Position: x=%f, y=%f, z=%f", diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.h b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.h index 306e4af0c8..56822c6940 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.h @@ -256,7 +256,6 @@ namespace EMotionFX virtual ~ChunkProcessor(); }; - //------------------------------------------------------------------------------------------------- /** @@ -287,7 +286,7 @@ namespace EMotionFX EMFX_CHUNKPROCESSOR(ChunkProcessorActorInfo3, FileFormat::ACTOR_CHUNK_INFO, 3) EMFX_CHUNKPROCESSOR(ChunkProcessorActorProgMorphTarget, FileFormat::ACTOR_CHUNK_STDPROGMORPHTARGET, 1) EMFX_CHUNKPROCESSOR(ChunkProcessorActorNodeGroups, FileFormat::ACTOR_CHUNK_NODEGROUPS, 1) - EMFX_CHUNKPROCESSOR(ChunkProcessorActorNodes, FileFormat::ACTOR_CHUNK_NODES, 1) + EMFX_CHUNKPROCESSOR(ChunkProcessorActorNodes2, FileFormat::ACTOR_CHUNK_NODES, 2) EMFX_CHUNKPROCESSOR(ChunkProcessorActorProgMorphTargets, FileFormat::ACTOR_CHUNK_STDPMORPHTARGETS, 1) EMFX_CHUNKPROCESSOR(ChunkProcessorActorProgMorphTargets2, FileFormat::ACTOR_CHUNK_STDPMORPHTARGETS, 2) EMFX_CHUNKPROCESSOR(ChunkProcessorActorNodeMotionSources, FileFormat::ACTOR_CHUNK_NODEMOTIONSOURCES, 1) diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/Importer.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/Importer.cpp index 67cbb91c06..82da9ccd86 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/Importer.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/Importer.cpp @@ -352,7 +352,7 @@ namespace EMotionFX } // post create init - actor->PostCreateInit(actorSettings.mMakeGeomLODsCompatibleWithSkeletalLODs, false, actorSettings.mUnitTypeConvert); + actor->PostCreateInit(actorSettings.mMakeGeomLODsCompatibleWithSkeletalLODs, actorSettings.mUnitTypeConvert); } // close the file and return a pointer to the actor we loaded @@ -846,7 +846,7 @@ namespace EMotionFX RegisterChunkProcessor(aznew ChunkProcessorActorInfo3()); RegisterChunkProcessor(aznew ChunkProcessorActorProgMorphTarget()); RegisterChunkProcessor(aznew ChunkProcessorActorNodeGroups()); - RegisterChunkProcessor(aznew ChunkProcessorActorNodes()); + RegisterChunkProcessor(aznew ChunkProcessorActorNodes2()); RegisterChunkProcessor(aznew ChunkProcessorActorProgMorphTargets()); RegisterChunkProcessor(aznew ChunkProcessorActorProgMorphTargets2()); RegisterChunkProcessor(aznew ChunkProcessorActorNodeMotionSources()); diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp index 993426f4c4..3ece1e24af 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp @@ -1372,20 +1372,17 @@ namespace EMotionFX } - void Mesh::CalcAABB(MCore::AABB* outBoundingBox, const Transform& transform, uint32 vertexFrequency) + void Mesh::CalcAabb(AZ::Aabb* outBoundingBox, const Transform& transform, uint32 vertexFrequency) { MCORE_ASSERT(vertexFrequency >= 1); + *outBoundingBox = AZ::Aabb::CreateNull(); - // init the bounding box - outBoundingBox->Init(); - - // get the position data AZ::Vector3* positions = (AZ::Vector3*)FindVertexData(ATTRIB_POSITIONS); const uint32 numVerts = GetNumVertices(); for (uint32 i = 0; i < numVerts; i += vertexFrequency) { - outBoundingBox->Encapsulate(transform.TransformPoint(positions[i])); + outBoundingBox->AddPoint(transform.TransformPoint(positions[i])); } } diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.h b/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.h index f9a9f960ce..cb929dc7db 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.h @@ -9,6 +9,7 @@ #pragma once #include "EMotionFXConfig.h" +#include #include #include #include @@ -571,7 +572,7 @@ namespace EMotionFX * @param vertexFrequency This is the for loop increase counter value. A value of 1 means every vertex will be processed * while a value of 2 means every second vertex, etc. The value must be 1 or higher. */ - void CalcAABB(MCore::AABB* outBoundingBox, const Transform& transform, uint32 vertexFrequency = 1); + void CalcAabb(AZ::Aabb* outBoundingBox, const Transform& transform, uint32 vertexFrequency = 1); /** * The mesh type used to indicate if a mesh is either static, like a cube or building, cpu deformed, if it needs to be processed on the CPU, or GPU deformed if it can be processed fully on the GPU. diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Node.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Node.cpp index 2aa6b796ab..8ab7fa540d 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Node.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Node.cpp @@ -98,7 +98,6 @@ namespace EMotionFX result->mChildIndices = mChildIndices; //result->mImportanceFactor = mImportanceFactor; result->mNodeFlags = mNodeFlags; - result->mOBB = mOBB; result->mSemanticNameID = mSemanticNameID; // copy the node attributes diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp index ef74cf466f..274edd36ce 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp @@ -55,8 +55,6 @@ namespace EMStudio const char* RenderOptions::s_nodeAABBColorOptionName = "nodeAABBColor"; const char* RenderOptions::s_staticAABBColorOptionName = "staticAABBColor"; const char* RenderOptions::s_meshAABBColorOptionName = "meshAABBColor"; - const char* RenderOptions::s_collisionMeshAABBColorOptionName = "collisionMeshAABBColor"; - const char* RenderOptions::s_OBBsColorOptionName = "OBBsColor"; const char* RenderOptions::s_lineSkeletonColorOptionName = "lineSkeletonColor_v2"; const char* RenderOptions::s_skeletonColorOptionName = "skeletonColor"; const char* RenderOptions::s_selectionColorOptionName = "selectionColor"; @@ -108,8 +106,6 @@ namespace EMStudio , m_nodeAABBColor(1.0f, 0.0f, 0.0f, 1.0f) , m_staticAABBColor(0.0f, 0.7f, 0.7f, 1.0f) , m_meshAABBColor(0.0f, 0.0f, 0.7f, 1.0f) - , m_collisionMeshAABBColor(0.0f, 0.7f, 0.0f, 1.0f) - , m_OBBsColor(1.0f, 1.0f, 0.0f, 1.0f) , m_lineSkeletonColor(0.33333f, 1.0f, 0.0f, 1.0f) , m_skeletonColor(0.19f, 0.58f, 0.19f, 1.0f) , m_selectionColor(1.0f, 1.0f, 1.0f, 1.0f) @@ -169,8 +165,6 @@ namespace EMStudio SetNodeAABBColor(other.GetNodeAABBColor()); SetStaticAABBColor(other.GetStaticAABBColor()); SetMeshAABBColor(other.GetMeshAABBColor()); - SetCollisionMeshAABBColor(other.GetCollisionMeshAABBColor()); - SetOBBsColor(other.GetOBBsColor()); SetLineSkeletonColor(other.GetLineSkeletonColor()); SetSkeletonColor(other.GetSkeletonColor()); SetSelectionColor(other.GetSelectionColor()); @@ -206,9 +200,7 @@ namespace EMStudio settings->setValue(s_nodeAABBColorOptionName, ColorToString(m_nodeAABBColor)); settings->setValue(s_staticAABBColorOptionName, ColorToString(m_staticAABBColor)); settings->setValue(s_meshAABBColorOptionName, ColorToString(m_meshAABBColor)); - settings->setValue(s_collisionMeshAABBColorOptionName, ColorToString(m_collisionMeshAABBColor)); settings->setValue(s_collisionMeshColorOptionName, ColorToString(m_collisionMeshColor)); - settings->setValue(s_OBBsColorOptionName, ColorToString(m_OBBsColor)); settings->setValue(s_lineSkeletonColorOptionName, ColorToString(m_lineSkeletonColor)); settings->setValue(s_skeletonColorOptionName, ColorToString(m_skeletonColor)); settings->setValue(s_selectionColorOptionName, ColorToString(m_selectionColor)); @@ -275,9 +267,7 @@ namespace EMStudio options.m_nodeAABBColor = StringToColor(settings->value(s_nodeAABBColorOptionName, ColorToString(options.m_nodeAABBColor)).toString()); options.m_staticAABBColor = StringToColor(settings->value(s_staticAABBColorOptionName, ColorToString(options.m_staticAABBColor)).toString()); options.m_meshAABBColor = StringToColor(settings->value(s_meshAABBColorOptionName, ColorToString(options.m_meshAABBColor)).toString()); - options.m_collisionMeshAABBColor = StringToColor(settings->value(s_collisionMeshAABBColorOptionName, ColorToString(options.m_collisionMeshAABBColor)).toString()); options.m_collisionMeshColor = StringToColor(settings->value(s_collisionMeshColorOptionName, ColorToString(options.m_collisionMeshColor)).toString()); - options.m_OBBsColor = StringToColor(settings->value(s_OBBsColorOptionName, ColorToString(options.m_OBBsColor)).toString()); options.m_lineSkeletonColor = StringToColor(settings->value(s_lineSkeletonColorOptionName, ColorToString(options.m_lineSkeletonColor)).toString()); options.m_skeletonColor = StringToColor(settings->value(s_skeletonColorOptionName, ColorToString(options.m_skeletonColor)).toString()); options.m_selectionColor = StringToColor(settings->value(s_selectionColorOptionName, ColorToString(options.m_selectionColor)).toString()); @@ -393,8 +383,6 @@ namespace EMStudio ->Field(s_nodeAABBColorOptionName, &RenderOptions::m_nodeAABBColor) ->Field(s_staticAABBColorOptionName, &RenderOptions::m_staticAABBColor) ->Field(s_meshAABBColorOptionName, &RenderOptions::m_meshAABBColor) - ->Field(s_collisionMeshAABBColorOptionName, &RenderOptions::m_collisionMeshAABBColor) - ->Field(s_OBBsColorOptionName, &RenderOptions::m_OBBsColor) ->Field(s_lineSkeletonColorOptionName, &RenderOptions::m_lineSkeletonColor) ->Field(s_skeletonColorOptionName, &RenderOptions::m_skeletonColor) ->Field(s_selectionColorOptionName, &RenderOptions::m_selectionColor) @@ -552,12 +540,6 @@ namespace EMStudio ->DataElement(AZ::Edit::UIHandlers::Default, &RenderOptions::m_meshAABBColor, "Mesh based AABB color", "Color for the runtime-updated AABB calculated based on the deformed meshes.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &RenderOptions::OnMeshAABBColorChangedCallback) - ->DataElement(AZ::Edit::UIHandlers::Default, &RenderOptions::m_collisionMeshAABBColor, "CollisionMesh based AABB color", - "Color for the runtime-updated AABB calculated based on the deformed collision meshes.") - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &RenderOptions::OnCollisionMeshAABBColorChangedCallback) - ->DataElement(AZ::Edit::UIHandlers::Default, &RenderOptions::m_OBBsColor, "Joint OBB color", - "Color used for the pre-calculated joint oriented bounding boxes.") - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &RenderOptions::OnOBBsColorChangedCallback) ->DataElement(AZ::Edit::UIHandlers::Default, &RenderOptions::m_lineSkeletonColor, "Line based skeleton color", "Line-based skeleton color.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &RenderOptions::OnLineSkeletonColorChangedCallback) @@ -903,24 +885,6 @@ namespace EMStudio } } - void RenderOptions::SetCollisionMeshAABBColor(const AZ::Color& collisionMeshAABBColor) - { - if (!collisionMeshAABBColor.IsClose(m_collisionMeshAABBColor)) - { - m_collisionMeshAABBColor = collisionMeshAABBColor; - OnCollisionMeshAABBColorChangedCallback(); - } - } - - void RenderOptions::SetOBBsColor(const AZ::Color& OBBsColor) - { - if (!OBBsColor.IsClose(m_OBBsColor)) - { - m_OBBsColor = OBBsColor; - OnOBBsColorChangedCallback(); - } - } - void RenderOptions::SetLineSkeletonColor(const AZ::Color& lineSkeletonColor) { if (!lineSkeletonColor.IsClose(m_lineSkeletonColor)) @@ -1258,16 +1222,6 @@ namespace EMStudio PluginOptionsNotificationsBus::Event(s_meshAABBColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_meshAABBColorOptionName); } - void RenderOptions::OnCollisionMeshAABBColorChangedCallback() const - { - PluginOptionsNotificationsBus::Event(s_collisionMeshAABBColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_collisionMeshAABBColorOptionName); - } - - void RenderOptions::OnOBBsColorChangedCallback() const - { - PluginOptionsNotificationsBus::Event(s_OBBsColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_OBBsColorOptionName); - } - void RenderOptions::OnLineSkeletonColorChangedCallback() const { PluginOptionsNotificationsBus::Event(s_lineSkeletonColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_lineSkeletonColorOptionName); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h index 1df1a023c8..60f7aa1291 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h @@ -59,8 +59,6 @@ namespace EMStudio static const char* s_nodeAABBColorOptionName; static const char* s_staticAABBColorOptionName; static const char* s_meshAABBColorOptionName; - static const char* s_collisionMeshAABBColorOptionName; - static const char* s_OBBsColorOptionName; static const char* s_lineSkeletonColorOptionName; static const char* s_skeletonColorOptionName; static const char* s_selectionColorOptionName; @@ -191,12 +189,6 @@ namespace EMStudio AZ::Color GetMeshAABBColor() const { return m_meshAABBColor; } void SetMeshAABBColor(const AZ::Color& meshAABBColor); - AZ::Color GetCollisionMeshAABBColor() const { return m_collisionMeshAABBColor; } - void SetCollisionMeshAABBColor(const AZ::Color& collisionMeshAABBColor); - - AZ::Color GetOBBsColor() const { return m_OBBsColor; } - void SetOBBsColor(const AZ::Color& OBBsColor); - AZ::Color GetLineSkeletonColor() const { return m_lineSkeletonColor; } void SetLineSkeletonColor(const AZ::Color& lineSkeletonColor); @@ -303,8 +295,6 @@ namespace EMStudio void OnNodeAABBColorChangedCallback() const; void OnStaticAABBColorChangedCallback() const; void OnMeshAABBColorChangedCallback() const; - void OnCollisionMeshAABBColorChangedCallback() const; - void OnOBBsColorChangedCallback() const; void OnLineSkeletonColorChangedCallback() const; void OnSkeletonColorChangedCallback() const; void OnSelectionColorChangedCallback() const; @@ -361,8 +351,6 @@ namespace EMStudio AZ::Color m_nodeAABBColor; AZ::Color m_staticAABBColor; AZ::Color m_meshAABBColor; - AZ::Color m_collisionMeshAABBColor; - AZ::Color m_OBBsColor; AZ::Color m_lineSkeletonColor; AZ::Color m_skeletonColor; AZ::Color m_selectionColor; diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp index 182314f2a6..ef281b8301 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp @@ -266,8 +266,7 @@ namespace EMStudio return; } - MCore::AABB aabb; - aabb.Init(); + AZ::Aabb aabb = AZ::Aabb::CreateNull(); const EMotionFX::Actor* actor = actorInstance->GetActor(); const EMotionFX::Skeleton* skeleton = actor->GetSkeleton(); @@ -276,21 +275,20 @@ namespace EMStudio for (const EMotionFX::Node* joint : joints) { const AZ::Vector3 jointPosition = pose->GetWorldSpaceTransform(joint->GetNodeIndex()).mPosition; - - aabb.Encapsulate(jointPosition); + aabb.AddPoint(jointPosition); const AZ::u32 childCount = joint->GetNumChildNodes(); for (AZ::u32 i = 0; i < childCount; ++i) { EMotionFX::Node* childJoint = skeleton->GetNode(joint->GetChildIndex(i)); const AZ::Vector3 childPosition = pose->GetWorldSpaceTransform(childJoint->GetNodeIndex()).mPosition; - aabb.Encapsulate(childPosition); + aabb.AddPoint(childPosition); } } - if (aabb.CheckIfIsValid()) + if (aabb.IsValid()) { - aabb.Widen(aabb.CalcRadius()); + aabb.Expand(AZ::Vector3(aabb.GetExtents().GetLength() * 0.5f)); bool isFollowModeActive = false; for (const RenderViewWidget* viewWidget : m_viewWidgets) @@ -619,35 +617,30 @@ namespace EMStudio EMotionFX::ActorInstance* actorInstance = EMotionFX::ActorInstance::Create(mActor); actorInstance->UpdateMeshDeformers(0.0f, true); - MCore::AABB aabb; - actorInstance->CalcMeshBasedAABB(0, &aabb); + AZ::Aabb aabb; + actorInstance->CalcMeshBasedAabb(0, &aabb); - if (aabb.CheckIfIsValid() == false) + if (!aabb.IsValid()) { - actorInstance->CalcNodeOBBBasedAABB(&aabb); + actorInstance->CalcNodeBasedAabb(&aabb); } - if (aabb.CheckIfIsValid() == false) - { - actorInstance->CalcNodeBasedAABB(&aabb); - } - - mCharacterHeight = aabb.CalcHeight(); + mCharacterHeight = aabb.GetExtents().GetZ(); mOffsetFromTrajectoryNode = aabb.GetMin().GetY() + (mCharacterHeight * 0.5f); actorInstance->Destroy(); // scale the normals down to 1% of the character size, that looks pretty nice on all models - mNormalsScaleMultiplier = aabb.CalcRadius() * 0.01f; + const float radius = AZ::Vector3(aabb.GetMax() - aabb.GetMin()).GetLength() * 0.5f; + mNormalsScaleMultiplier = radius * 0.01f; } // zoom to characters void RenderPlugin::ViewCloseup(bool selectedInstancesOnly, RenderWidget* renderWidget, float flightTime) { - const MCore::AABB sceneAABB = GetSceneAABB(selectedInstancesOnly); - - if (sceneAABB.CheckIfIsValid()) + const AZ::Aabb sceneAabb = GetSceneAabb(selectedInstancesOnly); + if (sceneAabb.IsValid()) { // in case the given view widget parameter is nullptr apply it on all view widgets if (!renderWidget) @@ -655,13 +648,13 @@ namespace EMStudio for (RenderViewWidget* viewWidget : m_viewWidgets) { RenderWidget* current = viewWidget->GetRenderWidget(); - current->ViewCloseup(sceneAABB, flightTime); + current->ViewCloseup(sceneAabb, flightTime); } } // only apply it to the given view widget else { - renderWidget->ViewCloseup(sceneAABB, flightTime); + renderWidget->ViewCloseup(sceneAabb, flightTime); } } } @@ -882,9 +875,9 @@ namespace EMStudio // get the AABB containing all actor instances in the scene - MCore::AABB RenderPlugin::GetSceneAABB(bool selectedInstancesOnly) + AZ::Aabb RenderPlugin::GetSceneAabb(bool selectedInstancesOnly) { - MCore::AABB finalAABB; + AZ::Aabb finalAabb = AZ::Aabb::CreateNull(); CommandSystem::SelectionList& selection = GetCommandManager()->GetCurrentSelection(); if (mUpdateCallback) @@ -922,20 +915,28 @@ namespace EMStudio } // get the mesh based AABB - MCore::AABB aabb; - actorInstance->CalcMeshBasedAABB(0, &aabb); + AZ::Aabb aabb = AZ::Aabb::CreateNull(); + actorInstance->CalcMeshBasedAabb(0, &aabb); // get the node based AABB - if (aabb.CheckIfIsValid() == false) + if (!aabb.IsValid()) { - actorInstance->CalcNodeBasedAABB(&aabb); + actorInstance->CalcNodeBasedAabb(&aabb); } // make sure the actor instance is covered in our global bounding box - finalAABB.Encapsulate(aabb); + if (aabb.IsValid()) + { + finalAabb.AddAabb(aabb); + } } - return finalAABB; + if (!finalAabb.IsValid()) + { + finalAabb.Set(AZ::Vector3(-1.0f, -1.0f, 0.0f), AZ::Vector3(1.0f, 1.0f, 0.0f)); + } + + return finalAabb; } @@ -1155,24 +1156,19 @@ namespace EMStudio settings.mNodeBasedColor = renderOptions->GetNodeAABBColor(); settings.mStaticBasedColor = renderOptions->GetStaticAABBColor(); settings.mMeshBasedColor = renderOptions->GetMeshAABBColor(); - settings.mCollisionMeshBasedColor = renderOptions->GetCollisionMeshAABBColor(); - renderUtil->RenderAABBs(actorInstance, settings); + renderUtil->RenderAabbs(actorInstance, settings); } - if (widget->GetRenderFlag(RenderViewWidget::RENDER_OBB)) - { - renderUtil->RenderOBBs(actorInstance, &visibleJointIndices, &selectedJointIndices, renderOptions->GetOBBsColor(), renderOptions->GetSelectedObjectColor()); - } if (widget->GetRenderFlag(RenderViewWidget::RENDER_LINESKELETON)) { const MCommon::Camera* camera = widget->GetRenderWidget()->GetCamera(); const AZ::Vector3& cameraPos = camera->GetPosition(); - MCore::AABB aabb; - actorInstance->CalcNodeBasedAABB(&aabb); - const AZ::Vector3 aabbMid = aabb.CalcMiddle(); - const float aabbRadius = aabb.CalcRadius(); + AZ::Aabb aabb; + actorInstance->CalcNodeBasedAabb(&aabb); + const AZ::Vector3 aabbMid = aabb.GetCenter(); + const float aabbRadius = AZ::Vector3(aabb.GetMax() - aabb.GetMin()).GetLength() * 0.5f; const float camDistance = fabs((cameraPos - aabbMid).GetLength()); // Avoid rendering too big joint spheres when zooming in onto a joint. @@ -1185,7 +1181,7 @@ namespace EMStudio // Scale the joint spheres based on the character's extents, to avoid really large joint spheres // on small characters and too small spheres on large characters. static const float baseRadius = 0.005f; - const float jointSphereRadius = aabb.CalcRadius() * scaleMultiplier * baseRadius; + const float jointSphereRadius = aabbRadius * scaleMultiplier * baseRadius; renderUtil->RenderSimpleSkeleton(actorInstance, &visibleJointIndices, &selectedJointIndices, renderOptions->GetLineSkeletonColor(), renderOptions->GetSelectedObjectColor(), jointSphereRadius); @@ -1268,8 +1264,8 @@ namespace EMStudio // render the selection if (renderOptions->GetRenderSelectionBox() && EMotionFX::GetActorManager().GetNumActorInstances() != 1 && GetCurrentSelection()->CheckIfHasActorInstance(actorInstance)) { - MCore::AABB aabb = actorInstance->GetAABB(); - aabb.Widen(aabb.CalcRadius() * 0.005f); + AZ::Aabb aabb = actorInstance->GetAabb(); + aabb.Expand(AZ::Vector3(0.005f)); renderUtil->RenderSelection(aabb, renderOptions->GetSelectionColor()); } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.h index 68cabbefa3..7fa0a880d0 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.h @@ -154,7 +154,7 @@ namespace EMStudio MCORE_INLINE CommandSystem::SelectionList* GetCurrentSelection() const { return mCurrentSelection; } MCORE_INLINE MCommon::RenderUtil* GetRenderUtil() const { return mRenderUtil; } - MCore::AABB GetSceneAABB(bool selectedInstancesOnly); + AZ::Aabb GetSceneAabb(bool selectedInstancesOnly); MCommon::RenderUtil::TrajectoryTracePath* FindTracePath(EMotionFX::ActorInstance* actorInstance); void ResetSelectedTrajectoryPaths(); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderUpdateCallback.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderUpdateCallback.cpp index 4c032cb2ea..6de228fa52 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderUpdateCallback.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderUpdateCallback.cpp @@ -170,15 +170,10 @@ namespace EMStudio settings.mNodeBasedColor = renderOptions->GetNodeAABBColor(); settings.mStaticBasedColor = renderOptions->GetStaticAABBColor(); settings.mMeshBasedColor = renderOptions->GetMeshAABBColor(); - settings.mCollisionMeshBasedColor = renderOptions->GetCollisionMeshAABBColor(); - renderUtil->RenderAABBs(actorInstance, settings); + renderUtil->RenderAabbs(actorInstance, settings); } - if (widget->GetRenderFlag(RenderViewWidget::RENDER_OBB)) - { - renderUtil->RenderOBBs(actorInstance, &visibleJointIndices, &selectedJointIndices, renderOptions->GetOBBsColor(), renderOptions->GetSelectedObjectColor()); - } if (widget->GetRenderFlag(RenderViewWidget::RENDER_LINESKELETON)) { renderUtil->RenderSimpleSkeleton(actorInstance, &visibleJointIndices, &selectedJointIndices, renderOptions->GetLineSkeletonColor(), renderOptions->GetSelectedObjectColor()); @@ -260,8 +255,8 @@ namespace EMStudio // render the selection if (renderOptions->GetRenderSelectionBox() && EMotionFX::GetActorManager().GetNumActorInstances() != 1 && mPlugin->GetCurrentSelection()->CheckIfHasActorInstance(actorInstance)) { - MCore::AABB aabb = actorInstance->GetAABB(); - aabb.Widen(aabb.CalcRadius() * 0.005f); + AZ::Aabb aabb = actorInstance->GetAabb(); + aabb.Expand(aabb.GetExtents() * 0.005f); renderUtil->RenderSelection(aabb, renderOptions->GetSelectionColor()); } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp index 76e1a1e7f3..55699c165f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp @@ -108,7 +108,6 @@ namespace EMStudio CreateViewOptionEntry(contextMenu, "Face Normals", RENDER_FACENORMALS); CreateViewOptionEntry(contextMenu, "Tangents", RENDER_TANGENTS); CreateViewOptionEntry(contextMenu, "Actor Bounding Boxes", RENDER_AABB); - CreateViewOptionEntry(contextMenu, "Joint OBBs", RENDER_OBB, false); CreateViewOptionEntry(contextMenu, "Collision Meshes", RENDER_COLLISIONMESHES, false); contextMenu->addSeparator(); CreateViewOptionEntry(contextMenu, "Line Skeleton", RENDER_LINESKELETON); @@ -233,7 +232,6 @@ namespace EMStudio SetRenderFlag(RENDER_TANGENTS, false); SetRenderFlag(RENDER_AABB, false); - SetRenderFlag(RENDER_OBB, false); SetRenderFlag(RENDER_COLLISIONMESHES, false); SetRenderFlag(RENDER_RAGDOLL_COLLIDERS, true); SetRenderFlag(RENDER_RAGDOLL_JOINTLIMITS, true); @@ -410,7 +408,6 @@ namespace EMStudio } // Override some settings as we removed those from the menu. - SetRenderFlag(RENDER_OBB, false); SetRenderFlag(RENDER_COLLISIONMESHES, false); SetRenderFlag(RENDER_TEXTURING, false); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.h index 74e5e0ce72..defdb0d2a7 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.h @@ -52,7 +52,6 @@ namespace EMStudio RENDER_VERTEXNORMALS = 6, RENDER_TANGENTS = 7, RENDER_AABB = 8, - RENDER_OBB = 9, RENDER_COLLISIONMESHES = 10, RENDER_SKELETON = 11, RENDER_LINESKELETON = 12, diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp index c74f693765..25ae2ba2d4 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp @@ -6,7 +6,6 @@ * */ -// include the required headers #include "RenderWidget.h" #include "RenderPlugin.h" #include @@ -21,6 +20,7 @@ #include "../EMStudioManager.h" #include "../MainWindow.h" #include +#include namespace EMStudio @@ -72,9 +72,8 @@ namespace EMStudio } // start view closeup flight - void RenderWidget::ViewCloseup(const MCore::AABB& aabb, float flightTime, uint32 viewCloseupWaiting) + void RenderWidget::ViewCloseup(const AZ::Aabb& aabb, float flightTime, uint32 viewCloseupWaiting) { - //LogError("ViewCloseup: AABB: Pos=(%.3f, %.3f, %.3f), Width=%.3f, Height=%.3f, Depth=%.3f", aabb.CalcMiddle().x, aabb.CalcMiddle().y, aabb.CalcMiddle().z, aabb.CalcWidth(), aabb.CalcHeight(), aabb.CalcDepth()); mViewCloseupWaiting = viewCloseupWaiting; mViewCloseupAABB = aabb; mViewCloseupFlightTime = flightTime; @@ -82,9 +81,8 @@ namespace EMStudio void RenderWidget::ViewCloseup(bool selectedInstancesOnly, float flightTime, uint32 viewCloseupWaiting) { - //LogError("ViewCloseup: AABB: Pos=(%.3f, %.3f, %.3f), Width=%.3f, Height=%.3f, Depth=%.3f", aabb.CalcMiddle().x, aabb.CalcMiddle().y, aabb.CalcMiddle().z, aabb.CalcWidth(), aabb.CalcHeight(), aabb.CalcDepth()); mViewCloseupWaiting = viewCloseupWaiting; - mViewCloseupAABB = mPlugin->GetSceneAABB(selectedInstancesOnly); + mViewCloseupAABB = mPlugin->GetSceneAabb(selectedInstancesOnly); mViewCloseupFlightTime = flightTime; } @@ -603,14 +601,15 @@ namespace EMStudio if (actor->CheckIfHasMeshes(actorInstance->GetLODLevel()) == false) { // calculate the node based AABB - MCore::AABB box; - actorInstance->CalcNodeBasedAABB(&box); + AZ::Aabb box; + actorInstance->CalcNodeBasedAabb(&box); // render the aabb - if (box.CheckIfIsValid()) + if (box.IsValid()) { + const MCore::AABB mcoreAabb(box.GetMin(), box.GetMax()); AZ::Vector3 ii, n; - if (ray.Intersects(box, &ii, &n)) + if (ray.Intersects(mcoreAabb, &ii, &n)) { selectedActorInstance = actorInstance; oldIntersectionPoint = ii; @@ -1169,8 +1168,7 @@ namespace EMStudio mViewCloseupWaiting--; if (mViewCloseupWaiting == 0) { - mCamera->ViewCloseup(mViewCloseupAABB, mViewCloseupFlightTime); - //mViewCloseupWaiting = 0; + mCamera->ViewCloseup(MCore::AABB(mViewCloseupAABB.GetMin(), mViewCloseupAABB.GetMax()), mViewCloseupFlightTime); } } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.h index b6776d43a4..10722f744a 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.h @@ -6,11 +6,10 @@ * */ -#ifndef __EMSTUDIO_RENDERWIDGET_H -#define __EMSTUDIO_RENDERWIDGET_H +#pragma once -// #if !defined(Q_MOC_RUN) +#include #include #include "../EMStudioConfig.h" #include @@ -117,7 +116,7 @@ namespace EMStudio MCORE_INLINE MCommon::Camera* GetCamera() const { return mCamera; } MCORE_INLINE CameraMode GetCameraMode() const { return mCameraMode; } MCORE_INLINE void SetSkipFollowCalcs(bool skipFollowCalcs) { mSkipFollowCalcs = skipFollowCalcs; } - void ViewCloseup(const MCore::AABB& aabb, float flightTime, uint32 viewCloseupWaiting = 5); + void ViewCloseup(const AZ::Aabb& aabb, float flightTime, uint32 viewCloseupWaiting = 5); void ViewCloseup(bool selectedInstancesOnly, float flightTime, uint32 viewCloseupWaiting = 5); void SwitchCamera(CameraMode mode); @@ -161,7 +160,7 @@ namespace EMStudio // used for closeup camera flights uint32 mViewCloseupWaiting; - MCore::AABB mViewCloseupAABB; + AZ::Aabb mViewCloseupAABB; float mViewCloseupFlightTime; // manipulator helper data @@ -175,6 +174,3 @@ namespace EMStudio int32 mPixelsMovedSinceRightClick; }; } // namespace EMStudio - - -#endif diff --git a/Gems/EMotionFX/Code/MCore/Source/OBB.cpp b/Gems/EMotionFX/Code/MCore/Source/OBB.cpp deleted file mode 100644 index 66c47e9475..0000000000 --- a/Gems/EMotionFX/Code/MCore/Source/OBB.cpp +++ /dev/null @@ -1,638 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -// include required headers -#include "OBB.h" -#include "AABB.h" - -#include -#include -#include -#include - -namespace MCore -{ - // check if the box contains a given point - bool OBB::Contains(const AZ::Vector3& p) const - { - // translate to box space - AZ::Vector3 relPoint = p - mCenter; - - // convert the box into box space and test each axis - float f = mRotation.GetBasisX().Dot(relPoint); - if (f >= mExtents.GetX() || f <= -mExtents.GetX()) - { - return false; - } - - f = mRotation.GetBasisY().Dot(relPoint); - if (f >= mExtents.GetY() || f <= -mExtents.GetY()) - { - return false; - } - - f = mRotation.GetBasisZ().Dot(relPoint); - if (f >= mExtents.GetZ() || f <= -mExtents.GetZ()) - { - return false; - } - - return true; - } - - - void OBB::Create(const AABB& aabb, const AZ::Transform& mat) - { - // calculate the center and extents - mCenter = aabb.CalcMiddle(); - mExtents = aabb.CalcExtents(); - - // transform the center - mCenter = mat.TransformPoint(mCenter); - - // set the rotation - mRotation = mat; - } - - - void OBB::Transform(const AZ::Transform& transMatrix) - { - mCenter = transMatrix.TransformPoint(mCenter); - mRotation = transMatrix * mRotation; - } - - - void OBB::Transformed(const AZ::Transform& transMatrix, OBB* outOBB) const - { - outOBB->mExtents = mExtents; - outOBB->mCenter = transMatrix.TransformPoint(mCenter); - outOBB->mRotation = transMatrix * mRotation; - } - - - bool OBB::CheckIfIsInside(const OBB& box) const - { - // make a 4x4 from the box & inverse it - AZ::Transform M0 = box.mRotation; - M0.SetTranslation(box.mCenter); - AZ::Transform M0Inv = M0.GetInverse(); - - // with our inversed 4x4, create box1 in space of box0 - OBB _1in0; - Transformed(M0Inv, &_1in0); - - // this should cancel out box0's rotation, i.e. it's now an AABB - - // the two boxes are in the same space so now we can compare them - // create the AABB of (box1 in space of box0) - const AZ::Transform& mtx = _1in0.mRotation; - - AZ::Vector3 transformedAxisX = mtx.GetUniformScale() * (mtx.GetRotation().GetConjugate().TransformVector(AZ::Vector3::CreateAxisX())); - AZ::Vector3 transformedAxisY = mtx.GetUniformScale() * (mtx.GetRotation().GetConjugate().TransformVector(AZ::Vector3::CreateAxisY())); - AZ::Vector3 transformedAxisZ = mtx.GetUniformScale() * (mtx.GetRotation().GetConjugate().TransformVector(AZ::Vector3::CreateAxisZ())); - - float f = transformedAxisX.GetAbs().Dot(mExtents) - box.mExtents.GetX(); - if (f > _1in0.mCenter.GetX()) - { - return false; - } - if (-f < _1in0.mCenter.GetX()) - { - return false; - } - - f = transformedAxisY.GetAbs().Dot(mExtents) - box.mExtents.GetY(); - if (f > _1in0.mCenter.GetY()) - { - return false; - } - if (-f < _1in0.mCenter.GetY()) - { - return false; - } - - f = transformedAxisZ.GetAbs().Dot(mExtents) - box.mExtents.GetZ(); - if (f > _1in0.mCenter.GetZ()) - { - return false; - } - if (-f < _1in0.mCenter.GetZ()) - { - return false; - } - - return true; - } - - - // calculate the corner points for the OBB - void OBB::CalcCornerPoints(AZ::Vector3* outPoints) const - { - MCORE_ASSERT(outPoints); - MCORE_ASSERT(CheckIfIsValid()); - - AZ::Vector3 right = MCore::GetRight(mRotation); - AZ::Vector3 up = MCore::GetUp(mRotation); - AZ::Vector3 forward = MCore::GetForward(mRotation); - - right *= mExtents.GetX(); - up *= mExtents.GetZ(); - forward *= mExtents.GetY(); - - // 7+------+6 - // /| /| - // / | / | - // / 4+---/--+5 - // 3+------+2 / - // | / | / - // |/ |/ - // 0+------+1 - - outPoints[0] = mCenter - right - up - forward; - outPoints[1] = mCenter + right - up - forward; - outPoints[2] = mCenter + right + up - forward; - outPoints[3] = mCenter - right + up - forward; - outPoints[4] = mCenter - right - up + forward; - outPoints[5] = mCenter + right - up + forward; - outPoints[6] = mCenter + right + up + forward; - outPoints[7] = mCenter - right + up + forward; - } - - - //---------------------------------------------------------------------------------------------------------- - - // calculate the 3 eigen vectors - void OBB::GetRealSymmetricEigenvectors(const float A[6], AZ::Vector3& v1, AZ::Vector3& v2, AZ::Vector3& v3) - { - // compute coefficients for cubic equation - const float c2 = A[0] + A[3] + A[5]; - const float a12sq = A[1] * A[1]; - const float a13sq = A[2] * A[2]; - const float a23sq = A[4] * A[4]; - const float a11a22 = A[0] * A[3]; - const float c1 = a11a22 - a12sq + A[0] * A[5] - a13sq + A[3] * A[5] - a23sq; - const float c0 = a11a22 * A[5] + 2.0f * A[1] * A[2] * A[4] - A[0] * a23sq - A[3] * a13sq - A[5] * a12sq; - - // compute intermediate values for root solving - const float c2sq = c2 * c2; - const float a = (3.0f * c1 - c2sq) / 3.0f; - const float b = (9.0f * c1 * c2 - 2.0f * c2sq * c2 - 27.f * c0) / 27.0f; - const float halfb = b * 0.5f; - const float halfb2 = halfb * halfb; - const float Q = halfb2 + a * a * a / 27.0f; - - // determine type of eigenspaces - if (Q > 1.0e-6f) - { - // one eigenvalue, use standard basis - v1.Set(1.0f, 0.0f, 0.0f); - v2.Set(0.0f, 1.0f, 0.0f); - v3.Set(0.0f, 0.0f, 1.0f); - return; - } - else - if (Q < -1.0e-6f) - { - // three distinct eigenvalues - - // intermediate terms - const float theta_3 = Math::ATan2(Math::Sqrt(-Q), -halfb) / 3.0f; - float rho = Math::Sqrt(halfb2 - Q); - const float c2_3 = c2 / 3.0f; - float rho_13 = powf(Math::Abs(rho), 1.0f / 3.0f); - if (rho < 0.0f) - { - rho_13 = -rho_13; - } - float ct_3, st_3; - const float sqrt3 = Math::Sqrt(3.0f); - ct_3 = Math::Cos(theta_3); - st_3 = Math::Sin(theta_3); - - // compute each eigenvalue and eigenvector - // sort from largest to smallest - float lambda1 = c2_3 + 2.0f * rho_13 * ct_3; - CalcSymmetricEigenVector(A, lambda1, v1); - - float lambda2 = c2_3 - rho_13 * (ct_3 + sqrt3 * st_3); - if (lambda2 > lambda1) - { - v2 = v1; - float temp = lambda2; - lambda2 = lambda1; - lambda1 = temp; - CalcSymmetricEigenVector(A, lambda2, v1); - } - else - { - CalcSymmetricEigenVector(A, lambda2, v2); - } - - float lambda3 = c2_3 - rho_13 * (ct_3 - sqrt3 * st_3); - if (lambda3 > lambda1) - { - v3 = v2; - v2 = v1; - CalcSymmetricEigenVector(A, lambda3, v1); - } - else - if (lambda3 > lambda2) - { - v3 = v2; - CalcSymmetricEigenVector(A, lambda3, v2); - } - else - { - CalcSymmetricEigenVector(A, lambda3, v3); - } - } - else - { - // two distinct eigenvalues - - // intermediate terms - float c2_3 = c2 / 3.0f; - float halfb_13 = Math::Pow(Math::Abs(halfb), 1.0f / 3.0f); - if (halfb < 0.0f) - { - halfb_13 = -halfb_13; - } - - // compute each eigenvalue and eigenvector - // sort from largest to smallest - float lambda1 = c2_3 + halfb_13; - CalcSymmetricEigenPair(A, lambda1, v1, v2); - - float lambda2 = c2_3 - 2.0f * halfb_13; - if (lambda2 > lambda1) - { - v3 = v2; - v2 = v1; - CalcSymmetricEigenVector(A, lambda2, v1); - } - else - { - CalcSymmetricEigenVector(A, lambda2, v3); - } - } - - v1.Normalize(); - v2.Normalize(); - v3.Normalize(); - - if ((v1.Cross(v2)).Dot(v3) < 0.0f) - { - v3 = -v3; - } - } - - - // calculate the eigen vector from a symmetric matrix in combination with a given eigen value - void OBB::CalcSymmetricEigenVector(const float A[6], float eigenValue, AZ::Vector3& v1) - { - const float m11 = A[0] - eigenValue; - const float m12 = A[1]; - const float m13 = A[2]; - const float m22 = A[3] - eigenValue; - const float m23 = A[4]; - const float m33 = A[5] - eigenValue; - - // compute cross product matrix, and find column with maximal entry - const float u11 = m22 * m33 - m23 * m23; - float max = Math::Abs(u11); - int c = 1; - const float u12 = m13 * m23 - m12 * m33; - if (Math::Abs(u12) > max) - { - max = Math::Abs(u12); - c = 2; - } - - const float u13 = m12 * m23 - m13 * m22; - if (Math::Abs(u13) > max) - { - max = Math::Abs(u13); - c = 3; - } - - const float u22 = m11 * m33 - m13 * m13; - if (Math::Abs(u22) > max) - { - max = Math::Abs(u22); - c = 2; - } - - const float u23 = m12 * m13 - m23 * m11; - if (Math::Abs(u23) > max) - { - max = Math::Abs(u23); - c = 3; - } - - const float u33 = m11 * m22 - m12 * m12; - if (Math::Abs(u33) > max) - { - max = Math::Abs(u33); - c = 3; - } - - // return column with maximal entry - if (c == 1) - { - v1.Set(u11, u12, u13); - } - else - if (c == 2) - { - v1.Set(u12, u22, u23); - } - else - { - v1.Set(u13, u23, u33); - } - } - - - //------------------------------------------------------------------------------- - // Given symmetric matrix A and eigenvalue l, returns eigenvector pair - // Assumes that order of eigenvalue is 2 - //------------------------------------------------------------------------------- - void OBB::CalcSymmetricEigenPair(const float A[6], float eigenValue, AZ::Vector3& v1, AZ::Vector3& v2) - { - // find maximal entry in M - const float m11 = A[0] - eigenValue; - float max = Math::Abs(m11); - int r = 1, c = 1; - if (Math::Abs(A[1]) > max) - { - max = Math::Abs(A[1]); - r = 1; - c = 2; - } - - if (Math::Abs(A[2]) > max) - { - max = Math::Abs(A[2]); - r = 1; - c = 3; - } - - const float m22 = A[3] - eigenValue; - if (Math::Abs(m22) > max) - { - max = Math::Abs(m22); - r = 2; - c = 2; - } - - if (Math::Abs(A[4]) > max) - { - max = Math::Abs(A[4]); - r = 2; - c = 3; - } - - const float m33 = A[5] - eigenValue; - if (Math::Abs(m33) > max) - { - r = 3; - c = 3; - } - - // compute eigenvectors for each case - if (r == 1) - { - if (c == 3) - { - v1.Set(A[2], 0.0f, -m11); - v2.Set(-A[1] * m11, m11 * m11 + A[2] * A[2], -A[1] * A[2]); - } - else - { - v1.Set(-A[1], m11, 0.0f); - v2.Set(-A[2] * m11, -A[2] * A[1], m11 * m11 + A[1] * A[1]); - } - } - else - if (r == 2) - { - v1.Set(0.0f, -A[4], m22); - v2.Set(m22 * m22 + A[4] * A[4], -A[1] * m22, -A[1] * A[4]); - } - else - if (r == 3) - { - v1.Set(0.0f, -m33, A[4]); - v2.Set(A[4] * A[4] + m33 * m33, -A[2] * A[4], -A[2] * m33); - } - } - - //----------------------- - - //------------------------------------------------------------------------------- - // Compute covariance matrix for set of points - // Returns centroid and unique values of matrix - //------------------------------------------------------------------------------- - void OBB::CovarianceMatrix(const AZ::Vector3* points, uint32 numPoints, AZ::Vector3& mean, float C[6]) - { - uint32 i; - - // compute mean - mean = points[0]; - for (i = 1; i < numPoints; ++i) - { - mean += points[i]; - } - - mean *= 1.0f / numPoints; - - // compute each element of matrix - memset(C, 0, sizeof(float) * 6); - for (i = 0; i < numPoints; ++i) - { - const AZ::Vector3 diff = points[i] - mean; - C[0] += diff.GetX() * diff.GetX(); - C[1] += diff.GetX() * diff.GetY(); - C[2] += diff.GetX() * diff.GetZ(); - C[3] += diff.GetY() * diff.GetY(); - C[4] += diff.GetY() * diff.GetZ(); - C[5] += diff.GetZ() * diff.GetZ(); - } - - // normalize the matrix values - float maxC = 0.0f; - for (i = 0; i < 6; ++i) - { - if (Math::Abs(C[i]) > maxC) - { - maxC = Math::Abs(C[i]); - } - } - for (i = 0; i < 6; ++i) - { - C[i] /= maxC; - } - } - - - // calc the best fit for a given x rotation slice - void OBB::InitFromPointsRange(const AZ::Vector3* points, uint32 numPoints, float xDegrees, float* outMinArea, AABB* outMinBox, AZ::Transform* outMinMatrix) - { - // calculate the x rotation matrix - AZ::Transform rotMatrix = AZ::Transform::CreateRotationX(Math::DegreesToRadians(xDegrees)); - - // try the same over the z axis - for (float z = -180.0f; z < 180.0f; z += 5.0f) - { - // calculate the final rotation matrix - rotMatrix = AZ::Transform::CreateRotationZ(Math::DegreesToRadians(z)) * rotMatrix; - - // calculate the inverse so we can transform the point set into space of this current rotation - AZ::Transform invMatrix = rotMatrix.GetInverse(); - - // rotate the points into the space of the current rotation - AABB box; - box.Init(); - for (uint32 i = 0; i < numPoints; ++i) - { - box.Encapsulate(invMatrix.TransformPoint(points[i])); - } - - // check if the surface area of this box is smaller than the smallest one we have - const float area = box.CalcSurfaceArea(); - if (area < *outMinArea) - { - *outMinArea = area; - *outMinBox = box; - *outMinMatrix = rotMatrix; - } - } - } - - - // Compute bounding box for set of points - void OBB::InitFromPoints(const AZ::Vector3* points, uint32 numPoints) - { - // if we have no points, just init - if (numPoints == 0) - { - Init(); - return; - } - - // some values we need - const uint32 MAX_NUM = (360 / 5) + 1; - AABB minBoxes[MAX_NUM]; - AZ::Transform minRotMatrices[MAX_NUM]; - float minAreas[MAX_NUM]; - for (uint32 i = 0; i < MAX_NUM; ++i) - { - minAreas[i] = FLT_MAX; - } - - - // try all rotation on the x axis (multithreaded) - AZ::JobCompletion jobCompletion; - uint32 index = 0; - for (float x = -180.0f; x < 180.0f; x += 5.0f) - { - MCORE_ASSERT(index < MAX_NUM); - - // create the job and add it - AZ::JobContext* jobContext = nullptr; - AZ::Job* job = AZ::CreateJobFunction([this, &minAreas, &minBoxes, &minRotMatrices, &numPoints, &points, x, index]() - { - InitFromPointsRange(points, numPoints, x, &minAreas[index], &minBoxes[index], &minRotMatrices[index]); - }, true, jobContext); - - job->SetDependent(&jobCompletion); - job->Start(); - - index++; - } - - jobCompletion.StartAndWaitForCompletion(); - - // find the real minimum value (single threaded lookup) - float minimumArea = FLT_MAX; - uint32 minimumIndex = 0; - for (uint32 i = 0; i < MAX_NUM; ++i) - { - if (minAreas[i] < minimumArea) - { - minimumArea = minAreas[i]; - minimumIndex = i; - } - } - - // update - mRotation = minRotMatrices[minimumIndex]; - mCenter = mRotation.TransformPoint(minBoxes[minimumIndex].CalcMiddle()); - mExtents = minBoxes[minimumIndex].CalcExtents(); - - /* - // compute covariance matrix - float C[6]; - CovarianceMatrix( points, numPoints, mCenter, C ); - - // get principle axes - Vector3 basis[3]; - GetRealSymmetricEigenvectors( C, basis[0], basis[1], basis[2] ); - - // init the min and max vectors - Vector3 minVec; - Vector3 maxVec; - minVec.Set(FLT_MAX, FLT_MAX, FLT_MAX); - maxVec.Set(-FLT_MAX, -FLT_MAX, -FLT_MAX); - - // find the min and max - for (uint32 i=0; i maxVec[j]) - maxVec[j] = length; - else - if (length < minVec[j]) - minVec[j] = length; - } - } - - // build the matrix from the calculated basis vectors - mRotation.Identity(); - mRotation.SetRow(0, basis[0]); - mRotation.SetRow(1, basis[1]); - mRotation.SetRow(2, basis[2]); - - // calculate the extents - mExtents = (maxVec - minVec) * 0.5f; - */ - } - - - // calculate the minimum and maximum point - void OBB::CalcMinMaxPoints(AZ::Vector3* outMin, AZ::Vector3* outMax) const - { - AZ::Transform rotation = mRotation; - rotation.SetTranslation(AZ::Vector3::CreateZero()); - AZ::Vector3 rotatedExtents = rotation.TransformPoint(mExtents); - *outMax = mCenter + rotatedExtents; - *outMin = mCenter - rotatedExtents; - - // +------+MAX - // /| /| - // / | / | - // / +---/--+ - // +------+ / - // | / | / - // |/ |/ - //MIN+------+ - } -} // namespace MCore diff --git a/Gems/EMotionFX/Code/MCore/Source/OBB.h b/Gems/EMotionFX/Code/MCore/Source/OBB.h deleted file mode 100644 index 64cf61fb20..0000000000 --- a/Gems/EMotionFX/Code/MCore/Source/OBB.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include "StandardHeaders.h" - - -namespace MCore -{ - // forward declarations - class AABB; - - - /** - * 3D Oriented Bounding Box (OBB) template. - * This is basically a AABB with an arbitrary rotation. - */ - class MCORE_API OBB - { - public: - /** - * The constructor. - * This automatically initializes the box. After initialization the box is invalid since it basically has no size yet. - * The IsValid() method will return false. - */ - MCORE_INLINE OBB() { Init(); } - - /** - * Construct the OBB from a given axis aligned bounding box and a transformation. - * @param aabb The axis aligned bounding box. - * @param transformation The transformation of the box. - */ - MCORE_INLINE OBB(const AABB& aabb, const AZ::Transform& transformation) { Create(aabb, transformation); } - - /** - * Construct the OBB from a center, extends and a rotation. - * @param center The center of the box. - * @param extents The extents of the box, which start at the center of the box. - * @param rot The matrix, representing the transformation of the box. - */ - MCORE_INLINE OBB(const AZ::Vector3& center, const AZ::Vector3& extents, const AZ::Transform& rot) - : mRotation(rot) - , mExtents(extents) - , mCenter(center) {} - - /** - * Reset the OBB with as center 0,0,0, infinite negative extents and no rotation. - * This makes the box an invalid box as well, because the extents have not been set. - */ - MCORE_INLINE void Init(); - - /** - * Initialize the box from a set of points. - * This uses the covariant matrix and eigen vectors to fit the box to the set of points. - * @param points The set of points to fit the box to. - * @param numPoints The number of points inside array specified as first parameter. - */ - void InitFromPoints(const AZ::Vector3* points, uint32 numPoints); - - /** - * Check if this box OBB contains a given point or not. - * @param p The point to check. - * @result Returns true when the point is inside this box, otherwise false is returned. - */ - bool Contains(const AZ::Vector3& p) const; - - /** - * Check if this OBB is inside another specified box. - * @param box The OBB to check. - * @result Returns true when this OBB is inside the box specified as parameter. - */ - bool CheckIfIsInside(const OBB& box) const; - - /** - * Create the OBB from a given AABB and a matrix. - * @param aabb The axis aligned bounding box. - * @param mat The matrix, which represents the orientation of the box. - */ - void Create(const AABB& aabb, const AZ::Transform& mat); - - /** - * Transform this OBB with a given matrix. - * This means the transformation specified as parameter will be applied to the current transformation of the OBB. - * So the transformation specified is NOT an absolute rotation, but a relative transformation. - * @param transMatrix The relative transformation matrix, to be applied to the current transformation. - */ - void Transform(const AZ::Transform& transMatrix); - - /** - * Calculate the transformed version of this OBB. - * @param rotMatrix The transformation matrix to be applied to the rotation of this OBB, so not an absolute rotation! - * @param outOBB A pointer to the OBB to fill with the rotated version of this OBB. - */ - void Transformed(const AZ::Transform& rotMatrix, OBB* outOBB) const; - - /** - * Check if this is a valid OBB or not. - * The box is only valid if the extents are non-negative. - * @result Returns true when the OBB is valid, otherwise false is returned. - */ - MCORE_INLINE bool CheckIfIsValid() const; - - /** - * Set the center of the box. - * @param center The new center of the box. - */ - MCORE_INLINE void SetCenter(const AZ::Vector3& center) { mCenter = center; } - - /** - * Set the extents of the box. - * @param extents The new extents of the box. - */ - MCORE_INLINE void SetExtents(const AZ::Vector3& extents) { mExtents = extents; } - - /** - * Set the transformation of the box. - * @param transform The new transformation of the box. - */ - MCORE_INLINE void SetTransformation(const AZ::Transform& transform) { mRotation = transform; } - - /** - * Get the center of the box. - * @result The center point of the box. - */ - MCORE_INLINE const AZ::Vector3& GetCenter() const { return mCenter; } - - /** - * Get the extents of the box. - * @result The extents of the box, which start at the center. - */ - MCORE_INLINE const AZ::Vector3& GetExtents() const { return mExtents; } - - /** - * Get the transformation of the box. - * @result The transformation of the box. - */ - MCORE_INLINE const AZ::Transform& GetTransformation() const { return mRotation; } - - /** - * Calculate the 8 corner points of the box. - * The layout is as follows: - *
-         *
-         *     7+------+6
-         *     /|     /|
-         *    / |    / |
-         *   / 4+---/--+5
-         * 3+------+2 /
-         *  | /    | /
-         *  |/     |/
-         * 0+------+1
-         *
-         * 
- * @param outPoints the array of at least 8 vectors to write the points in. - */ - void CalcCornerPoints(AZ::Vector3* outPoints) const; - - /** - * Calculate the rotated minimum and maximum points of the box. - * After rotation it is possible that the min point is not really the min anymore though. The same goes for max. - * But the main use for this method however is to quickly approximate an AABB from this OBB, without having to - * calculate all 8 corner points. - *
-         *
-         *        +------+MAX
-         *       /|     /|
-         *      / |    / |
-         *     /  +---/--+
-         *    +------+  /
-         *    | /    | /
-         *    |/     |/
-         * MIN+------+
-         *
-         * 
- * @param outMin The vector that we will write the minimum point to. - * @param outMax The vector that we will write the maximum point to. - */ - void CalcMinMaxPoints(AZ::Vector3* outMin, AZ::Vector3* outMax) const; - - private: - AZ::Transform mRotation; /**< The rotation of the box. */ // TODO: store the center inside the translation component and extents inside last column? - AZ::Vector3 mExtents; /**< The extents of the box. */ - AZ::Vector3 mCenter; /**< The center of the box. */ - - /** - * Calculate the three eigen vectors for a symmetric matrix. - * @param A The symmetric matrix values. - * @param v1 The first output eigen vector. - * @param v2 The second output eigen vector. - * @param v3 The third output eigen vector. - */ - void GetRealSymmetricEigenvectors(const float A[6], AZ::Vector3& v1, AZ::Vector3& v2, AZ::Vector3& v3); - - /** - * Calculate the eigen vector from a symmetric matrix. - * This assumes that the specified eigenvalue is of order 1. - * @param A The symmetric matrix values. - * @param eigenValue The eigen value. - * @param v1 The output eigen vector. - */ - void CalcSymmetricEigenVector(const float A[6], float eigenValue, AZ::Vector3& v1); - - /** - * Calculate the pair of eigen vectors from a symmetric matrix. - * This assumes that the specified eigen value is of order 2. - * @param A The symmetric matrix values. - * @param eigenValue The eigen value. - * @param v1 The first output eigen vector. - * @param v2 The second output eigen vector. - */ - void CalcSymmetricEigenPair(const float A[6], float eigenValue, AZ::Vector3& v1, AZ::Vector3& v2); - - /** - * Calculate the covariance matrix from a set of points. - * @param points The set of points to calculate the covariance matrix from. - * @param numPoints The number of points inside the specified set of points. - * @param mean The statistical mean will be output in this vector. - * @param C The covariance matrix values that will be written to. Since the matrix is symmetric we only output one triangle of the 3x3 matrix. - */ - void CovarianceMatrix(const AZ::Vector3 * points, uint32 numPoints, AZ::Vector3 & mean, float C[6]); - - void InitFromPointsRange(const AZ::Vector3* points, uint32 numPoints, float xDegrees, float* outMinArea, AABB* outMinBox, AZ::Transform* outMinMatrix); - }; - - // include the inline code -#include "OBB.inl" -} // namespace MCore diff --git a/Gems/EMotionFX/Code/MCore/Source/OBB.inl b/Gems/EMotionFX/Code/MCore/Source/OBB.inl deleted file mode 100644 index e8d82dd247..0000000000 --- a/Gems/EMotionFX/Code/MCore/Source/OBB.inl +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -// initialize the box -// this creates an invalid box (with negative extents) so the IsValid method will return false -MCORE_INLINE void OBB::Init() -{ - mCenter = AZ::Vector3::CreateZero(); - mExtents.Set(-FLT_MAX, -FLT_MAX, -FLT_MAX); - mRotation = AZ::Transform::CreateIdentity(); -} - - -// check if the OBB is valid -MCORE_INLINE bool OBB::CheckIfIsValid() const -{ - if (mExtents.GetX() < 0.0f) - { - return false; - } - if (mExtents.GetY() < 0.0f) - { - return false; - } - if (mExtents.GetZ() < 0.0f) - { - return false; - } - return true; -} - diff --git a/Gems/EMotionFX/Code/MCore/mcore_files.cmake b/Gems/EMotionFX/Code/MCore/mcore_files.cmake index b0d8a67ccd..43a41b4a11 100644 --- a/Gems/EMotionFX/Code/MCore/mcore_files.cmake +++ b/Gems/EMotionFX/Code/MCore/mcore_files.cmake @@ -101,9 +101,6 @@ set(FILES Source/MemoryTracker.cpp Source/MemoryTracker.h Source/MultiThreadManager.h - Source/OBB.cpp - Source/OBB.h - Source/OBB.inl Source/PlaneEq.cpp Source/PlaneEq.h Source/PlaneEq.inl diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp index 74133997e4..b033e46a87 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp @@ -58,27 +58,32 @@ namespace EMotionFX }; ////////////////////////////////////////////////////////////////////////// - void ActorComponent::BoundingBoxConfiguration::Set(ActorInstance* actor) const + void ActorComponent::BoundingBoxConfiguration::Set(ActorInstance* actorInstance) const { + actorInstance->SetExpandBoundsBy(m_expandBy * 0.01f); // Normalize percentage for internal use. (1% == 0.01f) + if (m_autoUpdateBounds) { - actor->SetupAutoBoundsUpdate(m_updateTimeFrequency, m_boundsType, m_updateItemFrequency); + actorInstance->SetupAutoBoundsUpdate(m_updateTimeFrequency, m_boundsType, m_updateItemFrequency); } else { - actor->SetBoundsUpdateType(m_boundsType); - actor->SetBoundsUpdateEnabled(false); + actorInstance->SetBoundsUpdateType(m_boundsType); + actorInstance->SetBoundsUpdateEnabled(false); } } - void ActorComponent::BoundingBoxConfiguration::SetAndUpdate(ActorInstance* actor) const + void ActorComponent::BoundingBoxConfiguration::SetAndUpdate(ActorInstance* actorInstance) const { - Set(actor); - const AZ::u32 freq = actor->GetBoundsUpdateEnabled() ? actor->GetBoundsUpdateItemFrequency() : 1; - actor->UpdateBounds(0, actor->GetBoundsUpdateType(), freq); + Set(actorInstance); + + const AZ::u32 updateFrequency = actorInstance->GetBoundsUpdateEnabled() ? actorInstance->GetBoundsUpdateItemFrequency() : 1; + const ActorInstance::EBoundsType boundUpdateType = actorInstance->GetBoundsUpdateType(); + + actorInstance->UpdateBounds(actorInstance->GetLODLevel(), boundUpdateType, updateFrequency); } - void ActorComponent::BoundingBoxConfiguration::Reflect(AZ::ReflectContext * context) + void ActorComponent::BoundingBoxConfiguration::Reflect(AZ::ReflectContext* context) { if (auto* serializeContext = azrtti_cast(context)) { @@ -105,10 +110,26 @@ namespace EMotionFX ->Field("m_autoUpdateBounds", &BoundingBoxConfiguration::m_autoUpdateBounds) ->Field("m_updateTimeFrequency", &BoundingBoxConfiguration::m_updateTimeFrequency) ->Field("m_updateItemFrequency", &BoundingBoxConfiguration::m_updateItemFrequency) + ->Field("expandBy", &BoundingBoxConfiguration::m_expandBy) ; } } + AZ::Crc32 ActorComponent::BoundingBoxConfiguration::GetVisibilityAutoUpdate() const + { + return m_boundsType != EMotionFX::ActorInstance::BOUNDS_STATIC_BASED ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide; + } + + AZ::Crc32 ActorComponent::BoundingBoxConfiguration::GetVisibilityAutoUpdateSettings() const + { + if (m_boundsType == EMotionFX::ActorInstance::BOUNDS_STATIC_BASED || m_autoUpdateBounds == false) + { + return AZ::Edit::PropertyVisibility::Hide; + } + + return AZ::Edit::PropertyVisibility::Show; + } + ////////////////////////////////////////////////////////////////////////// void ActorComponent::Configuration::Reflect(AZ::ReflectContext* context) { diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h index 0f36846a50..2bf85692be 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h @@ -45,24 +45,29 @@ namespace EMotionFX AZ_COMPONENT(ActorComponent, "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}"); friend class EditorActorComponent; - struct BoundingBoxConfiguration + class BoundingBoxConfiguration { + public: AZ_TYPE_INFO(BoundingBoxConfiguration, "{EBCFF975-00A5-4578-85C7-59909F52067C}"); BoundingBoxConfiguration() = default; - EMotionFX::ActorInstance::EBoundsType m_boundsType = EMotionFX::ActorInstance::BOUNDS_STATIC_BASED; - bool m_autoUpdateBounds = true; - float m_updateTimeFrequency = 0.f; - AZ::u32 m_updateItemFrequency = 1; + EMotionFX::ActorInstance::EBoundsType m_boundsType = EMotionFX::ActorInstance::BOUNDS_STATIC_BASED; + float m_expandBy = 25.0f; ///< Expand the bounding volume by the given percentage. + bool m_autoUpdateBounds = true; + float m_updateTimeFrequency = 0.0f; + AZ::u32 m_updateItemFrequency = 1; - // Set the bounding box configuration of the given actor instance to the parameters given by `this'. The actor instance must not be null (this is not checked). - void Set(ActorInstance* inst) const; + // Set the bounding box configuration of the given actor instance to the parameters given by 'this'. The actor instance must not be null (this is not checked). + void Set(ActorInstance* actorInstance) const; // Set the bounding box configuration, then update the bounds of the actor instance - void SetAndUpdate(ActorInstance* inst) const; + void SetAndUpdate(ActorInstance* actorInstance) const; static void Reflect(AZ::ReflectContext* context); + + AZ::Crc32 GetVisibilityAutoUpdate() const; + AZ::Crc32 GetVisibilityAutoUpdateSettings() const; }; /** diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp index efc5cbd9a2..160cbe8ee4 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp @@ -62,39 +62,40 @@ namespace EMotionFX { editContext->Class("Actor Bounding Box Config", "") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &ActorComponent::BoundingBoxConfiguration::m_boundsType, "Bounds type", - "The method used to compute the Actor bounding box. NOTE: ordered by least expensive to compute to most expensive to compute." - ) - ->EnumAttribute(ActorInstance::BOUNDS_STATIC_BASED, "Static bounds (source-asset bounds)") - ->EnumAttribute(ActorInstance::BOUNDS_NODE_BASED, "Bone position-based") - ->EnumAttribute(ActorInstance::BOUNDS_NODEOBB_BASED, "Bone local bounding box-based") - ->EnumAttribute(ActorInstance::BOUNDS_MESH_BASED, "Render mesh vertex position-based (VERY EXPENSIVE)") - - ->DataElement(0, &ActorComponent::BoundingBoxConfiguration::m_autoUpdateBounds, + "The method used to compute the Actor bounding box. NOTE: ordered by least expensive to compute to most expensive to compute.") + ->EnumAttribute(ActorInstance::BOUNDS_STATIC_BASED, "Static (Recommended)") + ->EnumAttribute(ActorInstance::BOUNDS_NODE_BASED, "Bone position-based") + ->EnumAttribute(ActorInstance::BOUNDS_MESH_BASED, "Mesh vertex-based (VERY EXPENSIVE)") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) + ->DataElement(AZ::Edit::UIHandlers::Default, &ActorComponent::BoundingBoxConfiguration::m_expandBy, + "Expand by", + "Percentage that the calculated bounding box should be automatically expanded with. " + "This can be used to add a tolerance area to the calculated bounding box to avoid clipping the character too early. " + "A static bounding box together with the expansion is the recommended way for maximum performance. (Default = 25%)") + ->Attribute(AZ::Edit::Attributes::Suffix, " %") + ->Attribute(AZ::Edit::Attributes::Min, -100.0f + AZ::Constants::Tolerance) + ->DataElement(AZ::Edit::UIHandlers::Default, &ActorComponent::BoundingBoxConfiguration::m_autoUpdateBounds, "Automatically update bounds?", - "If true, bounds are automatically updated based on some frequency. Otherwise bounds are computed only at creation or when triggered manually" - ) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) - - ->DataElement(0, &ActorComponent::BoundingBoxConfiguration::m_updateTimeFrequency, + "If true, bounds are automatically updated based on some frequency. Otherwise bounds are computed only at creation or when triggered manually") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) + ->Attribute(AZ::Edit::Attributes::Visibility, &ActorComponent::BoundingBoxConfiguration::GetVisibilityAutoUpdate) + ->DataElement(AZ::Edit::UIHandlers::Default, &ActorComponent::BoundingBoxConfiguration::m_updateTimeFrequency, "Update frequency", - "How often to update bounds automatically" - ) - ->Attribute(AZ::Edit::Attributes::Suffix, " Hz") - ->Attribute(AZ::Edit::Attributes::Min, 0.f) - ->Attribute(AZ::Edit::Attributes::Step, 0.001f) - ->Attribute(AZ::Edit::Attributes::Visibility, &ActorComponent::BoundingBoxConfiguration::m_autoUpdateBounds) - - ->DataElement(0, &ActorComponent::BoundingBoxConfiguration::m_updateItemFrequency, + "How often to update bounds automatically") + ->Attribute(AZ::Edit::Attributes::Suffix, " Hz") + ->Attribute(AZ::Edit::Attributes::Min, 0.0f) + ->Attribute(AZ::Edit::Attributes::Max, FLT_MAX) + ->Attribute(AZ::Edit::Attributes::Step, 0.1f) + ->Attribute(AZ::Edit::Attributes::Visibility, &ActorComponent::BoundingBoxConfiguration::GetVisibilityAutoUpdateSettings) + ->DataElement(AZ::Edit::UIHandlers::Default, &ActorComponent::BoundingBoxConfiguration::m_updateItemFrequency, "Update item skip factor", "How many items (bones or vertices) to skip when automatically updating bounds." - "
i.e. =1 uses every single item, =2 uses every 2nd item, =3 uses every 3rd item... " - ) - ->Attribute(AZ::Edit::Attributes::Suffix, " items") - ->Attribute(AZ::Edit::Attributes::Min, (AZ::u32)1) - ->Attribute(AZ::Edit::Attributes::Visibility, &ActorComponent::BoundingBoxConfiguration::m_autoUpdateBounds) + "
i.e. =1 uses every single item, =2 uses every 2nd item, =3 uses every 3rd item...") + ->Attribute(AZ::Edit::Attributes::Suffix, " items") + ->Attribute(AZ::Edit::Attributes::Min, (AZ::u32)1) + ->Attribute(AZ::Edit::Attributes::Visibility, &ActorComponent::BoundingBoxConfiguration::GetVisibilityAutoUpdateSettings) ; editContext->Class("Actor", "The Actor component manages an instance of an Actor") 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/Integration/CanAddActor.cpp b/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp index 3c529c93dd..9b18ca5862 100644 --- a/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp +++ b/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp @@ -40,7 +40,7 @@ namespace EMotionFX } // Ensure the Actor is correct - ASSERT_TRUE(GetActorManager().FindActorByName("rinactor")); + ASSERT_TRUE(GetActorManager().FindActorByName("rinActor")); EXPECT_EQ(GetActorManager().GetNumActors(), 1); } } // namespace EMotionFX 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/TestAssetCode/ActorFactory.h b/Gems/EMotionFX/Code/Tests/TestAssetCode/ActorFactory.h index 73519e079e..198fe4ce49 100644 --- a/Gems/EMotionFX/Code/Tests/TestAssetCode/ActorFactory.h +++ b/Gems/EMotionFX/Code/Tests/TestAssetCode/ActorFactory.h @@ -22,7 +22,7 @@ namespace EMotionFX actor->SetID(0); actor->GetSkeleton()->UpdateNodeIndexValues(0); actor->ResizeTransformData(); - actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/false, /*generateOBBs=*/false, /*convertUnitType=*/false); + actor->PostCreateInit(/*makeGeomLodsCompatibleWithSkeletalLODs=*/false, /*convertUnitType=*/false); return actor; } }; diff --git a/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor b/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor index 5a79fd5f48..20d4ffef85 100644 --- a/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor +++ b/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7db74f39a261bb70e1fdbdd546c337107809cdbdd1fc52568a0d30358b0f83d7 -size 30005 +oid sha256:55ecbc78a913c808cd007326b51dfc98b943b196b77fd6dc16aff0892b112e74 +size 16948 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();