|
| 1 | +using System; |
| 2 | +using System.Reflection; |
| 3 | +using UnityEditor; |
| 4 | +using UnityEngine; |
| 5 | + |
| 6 | +namespace MeshTools |
| 7 | +{ |
| 8 | + |
| 9 | + public enum FbxRigType |
| 10 | + { |
| 11 | + |
| 12 | + MatchSource, |
| 13 | + Humanoid, |
| 14 | + Generic, |
| 15 | + Legacy, |
| 16 | + None, |
| 17 | + } |
| 18 | + |
| 19 | + internal static class FbxExporter |
| 20 | + { |
| 21 | + public static bool IsFbxPackageInstalled() |
| 22 | + { |
| 23 | + return Type.GetType( |
| 24 | + "UnityEditor.Formats.Fbx.Exporter.ModelExporter, Unity.Formats.Fbx.Editor") != null; |
| 25 | + } |
| 26 | + |
| 27 | + public static void TryExportFbx(GameObject go, string fbxPath) |
| 28 | + { |
| 29 | + |
| 30 | + var exporterType = Type.GetType( |
| 31 | + "UnityEditor.Formats.Fbx.Exporter.ModelExporter, Unity.Formats.Fbx.Editor"); |
| 32 | + if (exporterType == null) |
| 33 | + { |
| 34 | + Debug.LogWarning("FBX export skipped: Unity FBX Exporter package not installed. Install 'com.unity.formats.fbx' from Package Manager."); |
| 35 | + return; |
| 36 | + } |
| 37 | + |
| 38 | + try |
| 39 | + { |
| 40 | + var method = exporterType.GetMethod("ExportObject", |
| 41 | + BindingFlags.Public | BindingFlags.Static, |
| 42 | + null, |
| 43 | + new Type[] { typeof(string), typeof(UnityEngine.Object) }, |
| 44 | + null); |
| 45 | + if (method == null) |
| 46 | + { |
| 47 | + Debug.LogWarning("FBX export skipped: FBX Exporter found but ExportObject(string, Object) method signature missing."); |
| 48 | + return; |
| 49 | + } |
| 50 | + |
| 51 | + method.Invoke(null, new object[] { fbxPath, go }); |
| 52 | + } |
| 53 | + catch (Exception e) |
| 54 | + { |
| 55 | + Debug.LogWarning("FBX export threw: " + e.GetType().Name + " — " + e.Message); |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + |
| 60 | + public static ModelImporterAnimationType? DetectSourceRigType(GameObject source) |
| 61 | + { |
| 62 | + if (source == null) return null; |
| 63 | + |
| 64 | + var animator = source.GetComponentInChildren<Animator>(true); |
| 65 | + |
| 66 | + |
| 67 | + if (animator != null && animator.avatar != null) |
| 68 | + { |
| 69 | + var avatarPath = AssetDatabase.GetAssetPath(animator.avatar); |
| 70 | + var importer = AssetImporter.GetAtPath(avatarPath) as ModelImporter; |
| 71 | + if (importer != null) return importer.animationType; |
| 72 | + } |
| 73 | + |
| 74 | + foreach (var smr in source.GetComponentsInChildren<SkinnedMeshRenderer>(true)) |
| 75 | + { |
| 76 | + if (smr.sharedMesh == null) continue; |
| 77 | + var path = AssetDatabase.GetAssetPath(smr.sharedMesh); |
| 78 | + var importer = AssetImporter.GetAtPath(path) as ModelImporter; |
| 79 | + if (importer != null) return importer.animationType; |
| 80 | + } |
| 81 | + |
| 82 | + foreach (var mf in source.GetComponentsInChildren<MeshFilter>(true)) |
| 83 | + { |
| 84 | + if (mf.sharedMesh == null) continue; |
| 85 | + var path = AssetDatabase.GetAssetPath(mf.sharedMesh); |
| 86 | + var importer = AssetImporter.GetAtPath(path) as ModelImporter; |
| 87 | + if (importer != null) return importer.animationType; |
| 88 | + } |
| 89 | + |
| 90 | + |
| 91 | + if (animator != null && animator.avatar != null && animator.avatar.isValid) |
| 92 | + { |
| 93 | + return animator.avatar.isHuman |
| 94 | + ? ModelImporterAnimationType.Human |
| 95 | + : ModelImporterAnimationType.Generic; |
| 96 | + } |
| 97 | + |
| 98 | + return null; |
| 99 | + } |
| 100 | + |
| 101 | + |
| 102 | + public static bool SetRigTypeOnAsset(string fbxAssetPath, FbxRigType rigType, ModelImporterAnimationType fallbackIfNoSource = ModelImporterAnimationType.Generic) |
| 103 | + { |
| 104 | + if (string.IsNullOrEmpty(fbxAssetPath)) return false; |
| 105 | + |
| 106 | + AssetDatabase.ImportAsset(fbxAssetPath, ImportAssetOptions.ForceUpdate); |
| 107 | + |
| 108 | + var importer = AssetImporter.GetAtPath(fbxAssetPath) as ModelImporter; |
| 109 | + if (importer == null) |
| 110 | + { |
| 111 | + Debug.LogWarning("Rig type setup skipped: no ModelImporter at " + fbxAssetPath); |
| 112 | + return false; |
| 113 | + } |
| 114 | + |
| 115 | + ModelImporterAnimationType target; |
| 116 | + switch (rigType) |
| 117 | + { |
| 118 | + case FbxRigType.Humanoid: target = ModelImporterAnimationType.Human; break; |
| 119 | + case FbxRigType.Generic: target = ModelImporterAnimationType.Generic; break; |
| 120 | + case FbxRigType.Legacy: target = ModelImporterAnimationType.Legacy; break; |
| 121 | + case FbxRigType.None: target = ModelImporterAnimationType.None; break; |
| 122 | + default: target = fallbackIfNoSource; break; |
| 123 | + } |
| 124 | + |
| 125 | + if (importer.animationType != target) |
| 126 | + { |
| 127 | + importer.animationType = target; |
| 128 | + if (target == ModelImporterAnimationType.Human) |
| 129 | + { |
| 130 | + //Let Unity auto generate the avatar from this FBXs own skeleton |
| 131 | + importer.avatarSetup = ModelImporterAvatarSetup.CreateFromThisModel; |
| 132 | + } |
| 133 | + importer.SaveAndReimport(); |
| 134 | + } |
| 135 | + |
| 136 | + return true; |
| 137 | + } |
| 138 | + } |
| 139 | +} |
0 commit comments