Blender导出模型在Unity游戏中无法正常动画的问题排查
问题描述
我正在为Unity游戏《Ultimate Epic Battle Simulator 2》制作带有人形预制动画的角色,使用Blender完成建模与绑定工作。遇到以下问题:
- 几周前模型在游戏中动画表现正常,现在完全无法播放动画,角色保持初始姿势滑动;移除腿部与髋部的父子关系后,仅髋部可动,四肢仍无动作。
- 网上下载的模型在游戏中动画正常,但将这类FBX模型导入Blender后,未经编辑直接保存再导出,就会出现同样的动画失效问题。
- 使用Mixamo进行绑定,此前部分绑定后的模型可正常动画,但目前来自Blender的模型即便经Mixamo绑定也无法正常播放动画。
- Root motion开关无影响,Unity动画检视器中动画显示正常,但游戏内存在动画失效问题。
疑问:该问题是Blender骨骼层级变更导致的,还是Blender或Unity中存在隐藏设置引发的?
开发者提供的模组代码
private void Update() { for (int i = 0; i < AllMeshes.Length; i++) { if (AllMeshes[i].Skinned != null/* || AllMeshes[i].MeshRenderer != null*/) { if (AllMeshes[i].Skinned != null) AllMeshes[i].mats = AllMeshes[i].Skinned.sharedMaterials; // if (AllMeshes[i].MeshRenderer != null) AllMeshes[i].mats = AllMeshes[i].MeshRenderer.sharedMaterials; } } if(AllMeshes.Length != LastArraycount) { if(AllMeshes.Length > LastArraycount) { for (int i = AllMeshes.Length - (AllMeshes.Length - LastArraycount); i < AllMeshes.Length; i++) { AllMeshes[i].RenderPriority = Priority.Med; } } LastArraycount = AllMeshes.Length; } if (SeperateSubMeshes) { SeperateSubMeshes = false; List<MeshProps> nm = new List<MeshProps>(); for (int i = 0; i < AllMeshes.Length; i++) { GameObject[] newobs = SeparateSubmeshes(AllMeshes[i].Skinned.gameObject); for (int s = 0; s < newobs.Length; s++) { MeshProps nmm = new MeshProps(); nmm.Skinned = newobs[s].GetComponent<SkinnedMeshRenderer>(); nm.Add(nmm); } } AllMeshes = nm.ToArray(); } } public GameObject[] SeparateSubmeshes(GameObject sourceObject) { SkinnedMeshRenderer sourceRenderer = sourceObject.GetComponent<SkinnedMeshRenderer>(); if (sourceRenderer == null) { Debug.LogWarning("No SkinnedMeshRenderer found on the source object."); return null; } Mesh sourceMesh = sourceRenderer.sharedMesh; Material[] sourceMaterials = sourceRenderer.sharedMaterials; if (sourceMesh == null || sourceMesh.subMeshCount <= 1) { Debug.LogWarning("No sub-meshes found to separate."); return null; } List<GameObject> createdObjects = new List<GameObject>(); for (int i = 0; i < sourceMesh.subMeshCount; i++) { GameObject newObject = new GameObject(sourceMesh.name + " Submesh "+i, typeof(SkinnedMeshRenderer)); newObject.transform.SetParent(sourceObject.transform.parent, false); newObject.transform.localPosition = Vector3.zero; newObject.transform.localRotation = Quaternion.identity; newObject.transform.localScale = Vector3.one; SkinnedMeshRenderer newRenderer = newObject.GetComponent<SkinnedMeshRenderer>(); Mesh newMesh = CreateMeshFromSubmesh(sourceMesh, i); newRenderer.sharedMesh = newMesh; newRenderer.sharedMaterials = new Material[] { sourceMaterials[i] }; newRenderer.bones = sourceRenderer.bones; newRenderer.rootBone = sourceRenderer.rootBone; createdObjects.Add(newObject); //SAVE MESH newMesh.name = transform.name + "-"+ newObject.name; #if UNITY_EDITOR AssetDatabase.CreateAsset(newMesh, "Assets"+"/"+SaveMeshFolder+"/"+ newMesh.name); AssetDatabase.SaveAssets(); #endif } return createdObjects.ToArray(); } private Mesh CreateMeshFromSubmesh(Mesh sourceMesh, int submeshIndex) { if (submeshIndex < 0 || submeshIndex >= sourceMesh.subMeshCount) { Debug.LogError("Invalid submesh index."); return null; } Mesh newMesh = new Mesh(); if (sourceMesh.triangles.Length > 150000) newMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; int[] sourceTriangles = sourceMesh.GetTriangles(submeshIndex); // Collect unique vertex indices from the submesh HashSet<int> uniqueIndices = new HashSet<int>(sourceTriangles); int[] newIndexRemap = new int[sourceMesh.vertexCount]; Vector3[] sourceVertices = sourceMesh.vertices; Vector2[] sourceUv = sourceMesh.uv; Vector3[] sourceNormals = sourceMesh.normals; Vector4[] sourceTangents = sourceMesh.tangents; BoneWeight[] sourceBoneWeights = sourceMesh.boneWeights; // Create new vertex attribute arrays Vector3[] vertices = new Vector3[uniqueIndices.Count]; Vector2[] uv = new Vector2[uniqueIndices.Count]; Vector3[] normals = new Vector3[uniqueIndices.Count]; Vector4[] tangents = new Vector4[uniqueIndices.Count]; BoneWeight[] boneWeights = new BoneWeight[uniqueIndices.Count]; int newIndex = 0; foreach (int vertexIndex in uniqueIndices) { newIndexRemap[vertexIndex] = newIndex; vertices[newIndex] = sourceVertices[vertexIndex]; uv[newIndex] = sourceUv[vertexIndex]; normals[newIndex] = sourceNormals[vertexIndex]; tangents[newIndex] = sourceTangents[vertexIndex]; boneWeights[newIndex] = sourceBoneWeights[vertexIndex]; newIndex++; } // Remap the triangles to the new vertex indices int[] triangles = new int[sourceTriangles.Length]; for (int i = 0; i < sourceTriangles.Length; i++) { triangles[i] = newIndexRemap[sourceTriangles[i]]; } newMesh.vertices = vertices; newMesh.uv = uv; newMesh.normals = normals; newMesh.tangents = tangents; newMesh.boneWeights = boneWeights; newMesh.triangles = triangles; newMesh.bindposes = sourceMesh.bindposes; newMesh.RecalculateBounds(); return newMesh; } private void OnDrawGizmos() { Gizmos.DrawWireCube(transform.position + (Vector3.up * collisionSettings.CollisionHeight * 0.5f), new Vector3(collisionSettings.CollisionWidth, collisionSettings.CollisionHeight, collisionSettings.CollisionWidth)); }
问题分析与解决方案
核心排查方向
Blender导出FBX的关键设置
- 导出前选中模型和骨骼,按
Ctrl+A应用位置、旋转、缩放所有变换,避免导入Unity后出现缩放偏移导致骨骼驱动失效。 - 导出FBX时,仅勾选选中的对象,取消勾选空物体,防止额外层级干扰骨骼结构;确保骨骼和网格选项处于勾选状态。
- 严格保持骨骼命名规范:UEBS2依赖标准人形骨骼命名(如
Hips、Spine、LeftArm等),不要修改Blender或Mixamo生成的默认骨骼名称,确保骨骼层级与Unity的Humanoid Rig完全匹配。
- 导出前选中模型和骨骼,按
Unity导入设置修正
- 导入FBX后,在Rig标签下设置Animation Type为
Humanoid,点击Configure检查骨骼映射:必须确保Hips被设为Root骨骼,所有骨骼映射无缺失。 - 取消勾选Optimize Game Objects选项,UEBS2的模组代码依赖原始骨骼层级,优化后会丢失骨骼引用导致动画无法驱动模型。
- 导入FBX后,在Rig标签下设置Animation Type为
模组代码相关验证
开发者提供的SeparateSubmeshes方法拆分Submesh时,已复制骨骼和绑定姿势,但需注意:- 拆分后的新Mesh需关闭Mesh Compression,避免压缩破坏骨骼权重和绑定数据。
- 启用
SeperateSubMeshes开关后,检查拆分后的SkinnedMeshRenderer的rootBone是否正确指向原始Hips骨骼,确保原始骨骼对象处于激活状态。
Mixamo绑定后的注意事项
- Mixamo下载FBX时,选择With Skin并同时勾选Animation和Skin选项,不要单独下载骨骼文件。
- 导入Blender后不要修改骨骼层级,直接应用所有变换后导出FBX,保持骨骼结构的完整性。
快速验证步骤
- 直接导入网上下载的正常模型到Unity,确认动画正常,作为基准对照。
- 将该基准模型导入Blender,不做任何编辑,应用所有变换后导出FBX,再导入Unity检查Rig设置,测试动画:若失效则说明Blender导出设置有误,需重新检查导出选项。
- 在Unity Play模式下,打开场景视图的Gizmos→骨骼选项:若骨骼动但模型不动,说明
SkinnedMeshRenderer的骨骼引用或绑定姿势异常;若骨骼也不动,说明动画控制器未正确挂载或骨骼层级不匹配。
内容的提问来源于stack exchange,提问作者The White Tortoise
相关产品推荐
相关产品推荐

