Explorar el Código

Fix the root motion extraction rotation problem (#10954)

* Fix the root motion extraction rotation problem

Signed-off-by: rhhong <[email protected]>

* CR feedback

Signed-off-by: rhhong <[email protected]>
Roman hace 3 años
padre
commit
966848d7d3

+ 21 - 0
Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp

@@ -179,6 +179,11 @@ namespace AZ::Render
             RenderTrajectoryPath(debugDisplay, instance, renderActorSettings.m_trajectoryHeadColor, renderActorSettings.m_trajectoryPathColor);
         }
 
+        if (CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::RootMotion))
+        {
+            RenderRootMotion(debugDisplay, instance, AZ::Colors::Red);
+        }
+
         // Render vertex normal, face normal, tagent and wireframe.
         const bool renderVertexNormals = CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::VertexNormals);
         const bool renderFaceNormals = CheckBitsAny(renderFlags, EMotionFX::ActorRenderFlags::FaceNormals);
@@ -1209,4 +1214,20 @@ namespace AZ::Render
             oldRight = vertices[3];
         }
     }
+
+    void AtomActorDebugDraw::RenderRootMotion(AzFramework::DebugDisplayRequests* debugDisplay,
+        const EMotionFX::ActorInstance* actorInstance,
+        const AZ::Color& rootColor)
+    {
+        const AZ::Transform actorTransform = actorInstance->GetWorldSpaceTransform().ToAZTransform();
+
+        // Render two circle around the character position.
+        debugDisplay->SetColor(rootColor);
+        debugDisplay->DrawCircle(actorTransform.GetTranslation(), 1.0f);
+        debugDisplay->DrawCircle(actorTransform.GetTranslation(), 0.05f);
+
+        // Render the character facing direction.
+        const AZ::Vector3 forward = actorTransform.GetBasisY();
+        debugDisplay->DrawArrow(actorTransform.GetTranslation(), actorTransform.GetTranslation() + forward);
+    }
 } // namespace AZ::Render

+ 4 - 0
Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h

@@ -107,6 +107,10 @@ namespace AZ::Render
             const EMotionFX::ActorInstance* actorInstance,
             const AZ::Color& headColor,
             const AZ::Color& pathColor);
+        void RenderRootMotion(
+            AzFramework::DebugDisplayRequests* debugDisplay,
+            const EMotionFX::ActorInstance* actorInstance,
+            const AZ::Color& rootColor);
         // Return a non-owning trajectory path pointer.
         TrajectoryTracePath* FindTrajectoryPath(const EMotionFX::ActorInstance* actorInstance);
         EMotionFX::Mesh* m_currentMesh = nullptr; //!< A pointer to the mesh whose world space positions are in the pre-calculated positions buffer.

+ 1 - 0
Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp

@@ -93,6 +93,7 @@ namespace EMStudio
 
             contextMenu->addSeparator();
             CreateViewOptionEntry(contextMenu, "Motion Extraction", EMotionFX::ActorRenderFlagIndex::MOTIONEXTRACTION);
+            CreateViewOptionEntry(contextMenu, "Root Motion", EMotionFX::ActorRenderFlagIndex::ROOTMOTION);
             CreateViewOptionEntry(contextMenu, "Debug Rendering", EMotionFX::ActorRenderFlagIndex::EMFX_DEBUG);
         }
 

+ 11 - 2
Gems/EMotionFX/Code/EMotionFX/Source/MotionData/NonUniformMotionData.cpp

@@ -1238,12 +1238,21 @@ namespace EMotionFX
                 const float x = transitionZeroXAxis ? m_jointData[sampleJointDataIndex].m_positionTrack.m_values[i].GetX() : 0;
                 const float y = transitionZeroYAxis ? m_jointData[sampleJointDataIndex].m_positionTrack.m_values[i].GetY() : 0;
                 const float z = m_jointData[sampleJointDataIndex].m_positionTrack.m_values[i].GetZ();
-
                 m_jointData[sampleJointDataIndex].m_positionTrack.m_values[i].Set(x, y, z);
 
                 if (extractRotation)
                 {
-                    m_jointData[sampleJointDataIndex].m_rotationTrack.m_values[i].FromQuaternion(AZ::Quaternion::CreateIdentity());
+                    const AZ::Quaternion sampleJointRotation = m_jointData[sampleJointDataIndex].m_rotationTrack.m_values[i].ToQuaternion();
+
+                    // Final root rotation only keeps the rotation around Z-axis
+                    const AZ::Vector3 rootRotEuler = AZ::ConvertQuaternionToEulerRadians(sampleJointRotation);
+                    const AZ::Quaternion finalRootRotation = AZ::ConvertEulerRadiansToQuaternion(AZ::Vector3(0, 0, rootRotEuler.GetZ()));
+
+                    // Calculate the final sample rotation
+                    const AZ::Quaternion finalSampleRotation = finalRootRotation.GetInverseFull() * sampleJointRotation;
+
+                    m_jointData[rootJointDataIndex].m_rotationTrack.m_values[i].FromQuaternion(finalRootRotation);
+                    m_jointData[sampleJointDataIndex].m_rotationTrack.m_values[i].FromQuaternion(finalSampleRotation);
                 }
             }
         }

+ 4 - 2
Gems/EMotionFX/Code/Source/Integration/Rendering/RenderFlag.h

@@ -40,7 +40,8 @@ namespace EMotionFX
         SIMULATEDOBJECT_COLLIDERS = 21,
         SIMULATEJOINTS = 22,
         EMFX_DEBUG = 23,
-        NUM_RENDERFLAGINDEXES = 24
+        ROOTMOTION = 24,
+        NUM_RENDERFLAGINDEXES = 25
     };
 
     //! A set of combinable flags which indicate which render option in turned on for the actor.
@@ -70,7 +71,8 @@ namespace EMotionFX
         (ClothColliders, AZ_BIT(ActorRenderFlagIndex::CLOTH_COLLIDERS)),
         (SimulatedObjectColliders, AZ_BIT(ActorRenderFlagIndex::SIMULATEDOBJECT_COLLIDERS)),
         (SimulatedJoints, AZ_BIT(ActorRenderFlagIndex::SIMULATEJOINTS)),
-        (EmfxDebug, AZ_BIT(ActorRenderFlagIndex::EMFX_DEBUG))
+        (EmfxDebug, AZ_BIT(ActorRenderFlagIndex::EMFX_DEBUG)),
+        (RootMotion, AZ_BIT(ActorRenderFlagIndex::ROOTMOTION))
     );
 
     AZ_DEFINE_ENUM_BITWISE_OPERATORS(ActorRenderFlags);