- 1 using UnityEngine;
- 2 using System.Collections.Generic;
- 3
- 4
- 5 public class CharacterCombine : MonoBehaviour
- 6 {
- 7 //目标物体(角色根物体)
- 8 public GameObject target;
- 9
- 10 //需要替换的部位(这里以body做示例)
- 11 public GameObject targetBody;
- 12
- 13 //用来替换上面部位的物体(这是一个独立的fbx文件,它里面可以包含多个子物体和贴图,但是必须有骨骼及蒙皮)
- 14 public GameObject bodyTest;
- 15
- 16
- 17 void Start()
- 18 {
- 19 //CombineTest();
- 20 }
- 21
- 22
- 23 public void CombineTest()
- 24 {
- 25Debug.Log("模型合并开始");
- 26
- 27 //为角色增加换装物体
- 28GameObject go = Instantiate(bodyTest);
- 29go.transform.parent = target.transform;
- 30
- 31 //禁用角色原来的body,这样就不会计算它的网格
- 32targetBody.SetActive(false);
- 33
- 34 //合并蒙皮网格和贴图,刷新骨骼
- 35 Combine(target.transform);
- 36
- 37 Destroy(go);
- 38 }
- 39
- 40
- 41 /// <summary>
- 42 /// 合并蒙皮网格,刷新骨骼
- 43 /// 注意:合并后的网格会使用同一个Material
- 44 /// </summary>
- 45 /// <param name="root">角色根物体</param>
- 46 public void Combine(Transform root)
- 47 {
- 48 floatstartTime = Time.realtimeSinceStartup;
- 49
- 50List combineInstances = newList();
- 51Material material =null;
- 52List boneList = newList();
- 53Transform[] transforms = root.GetComponentsInChildren();
- 54List textures = newList();
- 55
- 56 intwidth =0;
- 57 intheight =0;
- 58
- 59 intuvCount =0;
- 60
- 61List uvList = newList();
- 62
- 63 // 遍历所有蒙皮网格渲染器,以计算出所有需要合并的网格、UV、骨骼的信息
- 64 foreach(SkinnedMeshRenderer smrinroot.GetComponentsInChildren())
- 65 {
- 66 if(material ==null)
- 67 {
- 68material = Instantiate(smr.sharedMaterial);
- 69 }
- 70
- 71 for(intsub =0; sub < smr.sharedMesh.subMeshCount; sub++)
- 72 {
- 73CombineInstance ci =new CombineInstance();
- 74ci.mesh = smr.sharedMesh;
- 75ci.subMeshIndex = sub;
- 76 combineInstances.Add(ci);
- 77 }
- 78
- 79 uvList.Add(smr.sharedMesh.uv);
- 80uvCount += smr.sharedMesh.uv.Length;
- 81
- 82 if(smr.material.mainTexture !=null)
- 83 {
- 84textures.Add(smr.GetComponent().material.mainTexture as Texture2D);
- 85width += smr.GetComponent().material.mainTexture.width;
- 86height += smr.GetComponent().material.mainTexture.height;
- 87 }
- 88
- 89 foreach(Transform bonein smr.bones)
- 90 {
- 91 foreach(Transform itemin transforms)
- 92 {
- 93 if(item.name != bone.name)continue;
- 94 boneList.Add(item);
- 95 break;
- 96 }
- 97 }
- 98
- 99smr.gameObject.SetActive(false);
- 100 }
- 101
- 102 // 获取并配置角色所有的SkinnedMeshRenderer
- 103SkinnedMeshRenderer tempRenderer = root.gameObject.GetComponent();
- 104 if(!tempRenderer)
- 105 {
- 106tempRenderer = root.gameObject.AddComponent();
- 107 }
- 108
- 109tempRenderer.sharedMesh =new Mesh();
- 110
- 111 // 合并网格,刷新骨骼,附加材质
- 112tempRenderer.sharedMesh.CombineMeshes(combineInstances.ToArray(),true,false);
- 113tempRenderer.bones = boneList.ToArray();
- 114tempRenderer.material = material;
- 115
- 116Texture2D skinnedMeshAtlas =new Texture2D(get2Pow(width), get2Pow(height));
- 117Rect[] packingResult = skinnedMeshAtlas.PackTextures(textures.ToArray(),0);
- 118Vector2[] atlasUVs =new Vector2[uvCount];
- 119
- 120 // 因为将贴图都整合到了一张图片上,所以需要重新计算UV
- 121 intj =0;
- 122 for(inti =0; i < uvList.Count; i++)
- 123 {
- 124 foreach(Vector2 uvin uvList[i])
- 125 {
- 126atlasUVs[j].x = Mathf.Lerp(packingResult[i].xMin, packingResult[i].xMax, uv.x);
- 127atlasUVs[j].y = Mathf.Lerp(packingResult[i].yMin, packingResult[i].yMax, uv.y);
- 128j++;
- 129 }
- 130 }
- 131
- 132 // 设置贴图和UV
- 133tempRenderer.material.mainTexture = skinnedMeshAtlas;
- 134tempRenderer.sharedMesh.uv = atlasUVs;
- 135
- 136Debug.Log("合并耗时 : "+ (Time.realtimeSinceStartup - startTime) *1000+" ms");
- 137 }
- 138
- 139
- 140 /// <summary>
- 141 /// 获取最接近输入值的2的N次方的数,最大不会超过1024,例如输入320会得到512
- 142 /// </summary>
- 143 public intget2Pow(int into)
- 144 {
- 145 intouto =1;
- 146 for(inti =0; i <10; i++)
- 147 {
- 148outo *=2;
- 149 if(outo > into)
- 150 {
- 151 break;
- 152 }
- 153 }
- 154
- 155 return outo;
- 156 }
- 157}
来源: http://www.bubuko.com/infodetail-1969698.html