标签:比较 end anti 宽高 for com font .com sha
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/6505561.html
游戏角色换装分为以下几步:
1.替换蒙皮网格
2.刷新骨骼
3.替换材质
上面这种是比较简单的换装,可以实现,但是一般我们为了降低游戏的Draw Call会合并模型的网格,这就需要我们重新计算UV,还要合并贴图和材质。这种复杂的实现分为以下几步:
1.替换蒙皮网格(或者直接替换模型换装部位的GameObject,因为合并的时候会合并所有的蒙皮网格,而不会关心它是否属于原来角色身体的一部分,而且如果需要替换的部位有多个配件拥有独立的网格和贴图,那这种方式都可以正常执行。我下面的代码就是直接替换了换装部位的GameObject)
2.合并所有蒙皮网格
3.刷新骨骼
4.附加材质(我下面是获取第一个材质作为默认材质)
5.合并贴图(贴图的宽高最好是2的N次方的值)
6.重新计算UV
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 { 25 Debug.Log("模型合并开始"); 26 27 //为角色增加换装物体 28 GameObject go = Instantiate(bodyTest); 29 go.transform.parent = target.transform; 30 31 //禁用角色原来的body,这样就不会计算它的网格 32 targetBody.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 float startTime = Time.realtimeSinceStartup; 49 50 List<CombineInstance> combineInstances = new List<CombineInstance>(); 51 Material material = null; 52 List<Transform> boneList = new List<Transform>(); 53 Transform[] transforms = root.GetComponentsInChildren<Transform>(); 54 List<Texture2D> textures = new List<Texture2D>(); 55 56 int width = 0; 57 int height = 0; 58 59 int uvCount = 0; 60 61 List<Vector2[]> uvList = new List<Vector2[]>(); 62 63 // 遍历所有蒙皮网格渲染器,以计算出所有需要合并的网格、UV、骨骼的信息 64 foreach (SkinnedMeshRenderer smr in root.GetComponentsInChildren<SkinnedMeshRenderer>()) 65 { 66 if (material == null) 67 { 68 material = Instantiate(smr.sharedMaterial); 69 } 70 71 for (int sub = 0; sub < smr.sharedMesh.subMeshCount; sub++) 72 { 73 CombineInstance ci = new CombineInstance(); 74 ci.mesh = smr.sharedMesh; 75 ci.subMeshIndex = sub; 76 combineInstances.Add(ci); 77 } 78 79 uvList.Add(smr.sharedMesh.uv); 80 uvCount += smr.sharedMesh.uv.Length; 81 82 if (smr.material.mainTexture != null) 83 { 84 textures.Add(smr.GetComponent<Renderer>().material.mainTexture as Texture2D); 85 width += smr.GetComponent<Renderer>().material.mainTexture.width; 86 height += smr.GetComponent<Renderer>().material.mainTexture.height; 87 } 88 89 foreach (Transform bone in smr.bones) 90 { 91 foreach (Transform item in transforms) 92 { 93 if (item.name != bone.name) continue; 94 boneList.Add(item); 95 break; 96 } 97 } 98 99 smr.gameObject.SetActive(false); 100 } 101 102 // 获取并配置角色所有的SkinnedMeshRenderer 103 SkinnedMeshRenderer tempRenderer = root.gameObject.GetComponent<SkinnedMeshRenderer>(); 104 if (!tempRenderer) 105 { 106 tempRenderer = root.gameObject.AddComponent<SkinnedMeshRenderer>(); 107 } 108 109 tempRenderer.sharedMesh = new Mesh(); 110 111 // 合并网格,刷新骨骼,附加材质 112 tempRenderer.sharedMesh.CombineMeshes(combineInstances.ToArray(), true, false); 113 tempRenderer.bones = boneList.ToArray(); 114 tempRenderer.material = material; 115 116 Texture2D skinnedMeshAtlas = new Texture2D(get2Pow(width), get2Pow(height)); 117 Rect[] packingResult = skinnedMeshAtlas.PackTextures(textures.ToArray(), 0); 118 Vector2[] atlasUVs = new Vector2[uvCount]; 119 120 // 因为将贴图都整合到了一张图片上,所以需要重新计算UV 121 int j = 0; 122 for (int i = 0; i < uvList.Count; i++) 123 { 124 foreach (Vector2 uv in uvList[i]) 125 { 126 atlasUVs[j].x = Mathf.Lerp(packingResult[i].xMin, packingResult[i].xMax, uv.x); 127 atlasUVs[j].y = Mathf.Lerp(packingResult[i].yMin, packingResult[i].yMax, uv.y); 128 j++; 129 } 130 } 131 132 // 设置贴图和UV 133 tempRenderer.material.mainTexture = skinnedMeshAtlas; 134 tempRenderer.sharedMesh.uv = atlasUVs; 135 136 Debug.Log("合并耗时 : " + (Time.realtimeSinceStartup - startTime) * 1000 + " ms"); 137 } 138 139 140 /// <summary> 141 /// 获取最接近输入值的2的N次方的数,最大不会超过1024,例如输入320会得到512 142 /// </summary> 143 public int get2Pow(int into) 144 { 145 int outo = 1; 146 for (int i = 0; i < 10; i++) 147 { 148 outo *= 2; 149 if (outo > into) 150 { 151 break; 152 } 153 } 154 155 return outo; 156 } 157 }
在执行上面的代码前,角色的每个部分都是单独的,并且是激活的状态。
执行后,角色所有的部位都隐藏了起来,因为它们的网格都合并到了Player_Girl这个角色根物体上。
标签:比较 end anti 宽高 for com font .com sha
原文地址:http://www.cnblogs.com/shamoyuu/p/6505561.html