Unity角色換裝問題
阿新 • • 發佈:2018-12-02
遊戲中經常涉及到角色換裝問題。
1.裝備模型中的每一套裝備都必須使用同一套骨骼,把單個骨骼資料儲存成Prefab,骨骼資料在Unity中以Transform形式存在
2.把模型中的每個部分都單獨儲存成prefab。
實現思路:
1.建立骨骼GameObject,把所有的裝備蒙皮資料合併到一個prefab中。
2.建立裝備GameObject,用來手機其中蒙皮資料,從而建立新的SkinedMeshRenderer。
收集資訊程式碼
// Collect information from meshes for (int i = 0; i < meshes.Length; i ++) { SkinnedMeshRenderer smr= meshes[i]; materials.AddRange(smr.materials); // Collect materials // Collect meshes for (int sub = 0; sub < smr.sharedMesh.subMeshCount; sub++) { CombineInstance ci = new CombineInstance(); ci.mesh = smr.sharedMesh; ci.subMeshIndex= sub; combineInstances.Add(ci); } // Collect bones for (int j = 0 ; j < smr.bones.Length; j ++) { int tBase = 0; for (tBase = 0; tBase < transforms.Count; tBase ++) {if (smr.bones[j].name.Equals(transforms[tBase].name)) { bones.Add(transforms[tBase]); break; } } } }
為新的骨骼生成SkinnedMeshRenderer。
// Create a new SkinnedMeshRenderer SkinnedMeshRenderer oldSKinned = skeleton.GetComponent<SkinnedMeshRenderer> (); if (oldSKinned != null) { GameObject.DestroyImmediate (oldSKinned); } SkinnedMeshRenderer r = skeleton.AddComponent<SkinnedMeshRenderer>(); r.sharedMesh = new Mesh(); r.sharedMesh.CombineMeshes(combineInstances.ToArray(), false, false);// Combine meshes r.bones = bones.ToArray();// Use new bones
掛載武器
Transform[] transforms = Instance.GetComponentsInChildren<Transform>(); foreach (Transform joint in transforms) { if (joint.name == "weapon_hand_r") {// find the joint (need the support of art designer) WeaponInstance.transform.parent = joint.gameObject.transform; break; } }
這裡涉及到一個優化,合併出來的新的skinned Mesh Renderer中有所有部位的materials,
這裡我們可以吧materials合併成一個,減少DrawCall,但是同樣會增加記憶體,在具體專案中,可以結合實際情況進行優化,
// merge materials if (combine) { newMaterial = new Material (Shader.Find ("Mobile/Diffuse")); oldUV = new List<Vector2[]>(); // merge the texture List<Texture2D> Textures = new List<Texture2D>(); for (int i = 0; i < materials.Count; i++) { Textures.Add(materials[i].GetTexture(COMBINE_DIFFUSE_TEXTURE) as Texture2D); } newDiffuseTex = new Texture2D(COMBINE_TEXTURE_MAX, COMBINE_TEXTURE_MAX, TextureFormat.RGBA32, true); Rect[] uvs = newDiffuseTex.PackTextures(Textures.ToArray(), 0); newMaterial.mainTexture = newDiffuseTex; // reset uv Vector2[] uva, uvb; for (int j = 0; j < combineInstances.Count; j++) { uva = (Vector2[])(combineInstances[j].mesh.uv); uvb = new Vector2[uva.Length]; for (int k = 0; k < uva.Length; k++) { uvb[k] = new Vector2((uva[k].x * uvs[j].width) + uvs[j].x, (uva[k].y * uvs[j].height) + uvs[j].y); } oldUV.Add(combineInstances[j].mesh.uv); combineInstances[j].mesh.uv = uvb; } }
此方式是參考網上分析,原作者GitHub:https://github.com/zouchunyi/UnityAvater