diff --git a/Editor/Scripts/GLTFImporter.cs b/Editor/Scripts/GLTFImporter.cs index 44310c44b..f9cf1efcd 100644 --- a/Editor/Scripts/GLTFImporter.cs +++ b/Editor/Scripts/GLTFImporter.cs @@ -107,6 +107,7 @@ private static void EnsureShadersAreLoaded() [SerializeField] internal CameraImportOption _importCamera = CameraImportOption.ImportAndCameraDisabled; [SerializeField] internal AnimationMethod _importAnimations = AnimationMethod.Mecanim; [SerializeField] internal bool _mecanimHumanoidFlip = false; + [SerializeField] internal string _nonHumanoidRootNodeName; [SerializeField] internal bool _addAnimatorComponent = false; [SerializeField] internal bool _animationLoopTime = true; [SerializeField] internal bool _animationLoopPose = false; @@ -550,11 +551,17 @@ string GetUniqueName(string desiredName) // } // } - if (gltfScene && _importAnimations == AnimationMethod.MecanimHumanoid) + if (gltfScene) { - var avatar = HumanoidSetup.AddAvatarToGameObject(gltfScene, _mecanimHumanoidFlip); - if (avatar) - ctx.AddObjectToAsset("avatar", avatar); + Avatar avatar = null; + + if (_importAnimations == AnimationMethod.MecanimHumanoid) + avatar = HumanoidSetup.AddAvatarToGameObject(gltfScene, _mecanimHumanoidFlip); + else if (_importAnimations == AnimationMethod.Mecanim) + avatar = NonHumanoidSetup.AddAvatarToGameObject(gltfScene, false, _nonHumanoidRootNodeName); + + if (avatar) + ctx.AddObjectToAsset("avatar", avatar); } var renderers = gltfScene ? gltfScene.GetComponentsInChildren(true) : Array.Empty(); @@ -946,6 +953,7 @@ private void CreateGLTFScene(GLTFImportContext context, out GameObject scene, { DataLoader = new FileLoader(Path.GetDirectoryName(projectFilePath)), AnimationMethod = _importAnimations, + NonHumanoidRootNodeName = _nonHumanoidRootNodeName, AnimationLoopTime = _animationLoopTime, AnimationLoopPose = _animationLoopPose, ImportContext = context, diff --git a/Editor/Scripts/GLTFImporterInspector.cs b/Editor/Scripts/GLTFImporterInspector.cs index 74857c35c..38ea2e2cb 100644 --- a/Editor/Scripts/GLTFImporterInspector.cs +++ b/Editor/Scripts/GLTFImporterInspector.cs @@ -164,6 +164,14 @@ private void AnimationInspectorGUI() EditorGUILayout.PropertyField(flip, new GUIContent("Flip Forward", "Some formats like VRM have a different forward direction for Avatars. Enable this option if the animation looks inverted.")); EditorGUI.indentLevel--; } + else if (animationMethod.enumValueIndex == (int)AnimationMethod.Mecanim) + { + var rootNodeName = serializedObject.FindProperty(nameof(GLTFImporter._nonHumanoidRootNodeName)); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(rootNodeName, new GUIContent("Root Node Name", "Transform name of the root motion transform. If empty no root motion is defined and you must take care of avatar movement yourself.")); + EditorGUILayout.HelpBox("Enter just the name of the root node; not its path in hierarchy.", MessageType.Info); + EditorGUI.indentLevel--; + } if (hasAnimationData && anim.enumValueIndex > 0) { var loopTime = serializedObject.FindProperty(nameof(GLTFImporter._animationLoopTime)); diff --git a/Editor/Scripts/Internal/HumanoidSetup.cs b/Editor/Scripts/Internal/HumanoidSetup.cs index 76d950fcc..8b0af067e 100644 --- a/Editor/Scripts/Internal/HumanoidSetup.cs +++ b/Editor/Scripts/Internal/HumanoidSetup.cs @@ -106,4 +106,31 @@ static void _OpenEditor(MenuCommand command) } #endif } + + //todo: XtroTheArctic: I don't know how to add a new script file to a local package. We can fix this during PR phase. + internal static class NonHumanoidSetup + { + internal static Avatar AddAvatarToGameObject(GameObject gameObject, bool flipForward, string RootNode) + { + var previousRotation = gameObject.transform.rotation; + if (flipForward) + gameObject.transform.rotation *= Quaternion.Euler(0, 180, 0); + + Avatar avatar = AvatarBuilder.BuildGenericAvatar(gameObject, RootNode); + avatar.name = gameObject.name + "Avatar"; + + if (flipForward) + gameObject.transform.rotation = previousRotation; + + if (!avatar.isValid || avatar.isHuman) + { + Object.DestroyImmediate(avatar); + return null; + } + + var animator = gameObject.GetComponent(); + if (animator) animator.avatar = avatar; + return avatar; + } + } } diff --git a/Runtime/Scripts/GLTFSceneImporter.cs b/Runtime/Scripts/GLTFSceneImporter.cs index 1022a8850..818eb6cac 100644 --- a/Runtime/Scripts/GLTFSceneImporter.cs +++ b/Runtime/Scripts/GLTFSceneImporter.cs @@ -52,6 +52,7 @@ public class ImportOptions public AsyncCoroutineHelper AsyncCoroutineHelper = null; public bool ThrowOnLowMemory = true; public AnimationMethod AnimationMethod = AnimationMethod.Legacy; + public string NonHumanoidRootNodeName; public bool AnimationLoopTime = true; public bool AnimationLoopPose = false; public DeduplicateOptions DeduplicateResources = DeduplicateOptions.None; @@ -1392,7 +1393,7 @@ protected virtual async Task ConstructScene(GLTFScene scene, bool showSceneObj, } } - if (_options.AnimationMethod == AnimationMethod.MecanimHumanoid) + if (_options.AnimationMethod == AnimationMethod.MecanimHumanoid || _options.AnimationMethod == AnimationMethod.Mecanim && !string.IsNullOrEmpty(_options.NonHumanoidRootNodeName)) { var animator = sceneObj.GetComponent(); if (!animator) animator = sceneObj.AddComponent();