Unity人物換裝 合併網格材質骨骼
阿新 • • 發佈:2019-01-07
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
struct meshT
{
public Mesh _mesh;
public Transform[] _transform;
public Material _material;
///換裝併合併網格
/// </summary>
public class MeshMergeDome2 : MonoBehaviour
{
public static MeshMergeDome2 _intance;
private void Awake()
{
_intance = this;
}
public string loadName;
//生成人物得位置
private Transform StartPos;
private GameObject gamePlayerObj;
Dictionary<string, meshT> meshDic = new Dictionary<string, meshT>();
Dictionary<string, meshT> meshTs = new Dictionary<string, meshT>();
private string rootNamne;
Material[] material;
Transform[] _transform;
/// <summary>
/// 初始化
/// </summary>
private void Start()
{
//尋找生成位置
StartPos = GameObject.FindGameObjectWithTag("StartPos").transform;
//載入人物
gamePlayerObj = Instantiate(Resources.Load<GameObject>(loadName), StartPos.position, Quaternion.identity);
SkinnedMeshRenderer[] skinnedMeshRenderers = gamePlayerObj.GetComponentsInChildren<SkinnedMeshRenderer>();
for (int i = 0; i < skinnedMeshRenderers.Length; i++)
{
meshDic.Add(skinnedMeshRenderers[i].name, new meshT() { _mesh = skinnedMeshRenderers[i].sharedMesh, _transform = skinnedMeshRenderers[i].bones, _material = skinnedMeshRenderers[i].sharedMaterial,/*_transform1 = gamePlayerObj.transform.worldToLocalMatrix * skinnedMeshRenderers[i].transform.localToWorldMatrix*/ });
Destroy(skinnedMeshRenderers[i].gameObject);
}
List<Transform> boneList = new List<Transform>();
Transform[] transforms = gamePlayerObj.transform.Find("Female_Hips").GetComponentsInChildren<Transform>();
foreach (KeyValuePair<string, meshT> item in meshDic)
{
string name = item.Key.Split('-')[0];
if (name != rootNamne)
{
meshTs.Add(name, item.Value);
for (int i = 0; i < item.Value._transform.Length; i++)
{
boneList.Add(item.Value._transform[i]);
}
rootNamne = name;
}
}
CombineInstance[] combineInstances = new CombineInstance[meshTs.Count];
List<meshT> mesh = new List<meshT>();
foreach (var item in meshTs)
{
mesh.Add(item.Value);
}
material = new Material[mesh.Count];
_transform = new Transform[mesh.Count];
List<Vector2[]> uvList = new List<Vector2[]>();//uv座標
int uvCount = 0;
for (int i = 0; i < mesh.Count; i++)
{
uvList.Add(mesh[i]._mesh.uv);//儲存uv座標
uvCount += mesh[i]._mesh.uv.Length;
material[i] = mesh[i]._material;
combineInstances[i].mesh = mesh[i]._mesh;
}
List<Texture2D> textures = new List<Texture2D>();
int width = 0;
int height = 0;
//儲存圖片資訊
foreach (Material item in material)
{
if (item.mainTexture != null)
{
textures.Add(item.mainTexture as Texture2D);
width += item.mainTexture.width;
height += item.mainTexture.height;
}
}
SkinnedMeshRenderer skinned = gamePlayerObj.AddComponent<SkinnedMeshRenderer>();
// 設定貼圖和UV
skinned.sharedMesh = new Mesh();
skinned.sharedMesh.CombineMeshes(combineInstances, true, false); //不在意的矩陣的變換
skinned.bones = boneList.ToArray();
skinned.material = material[0];
//建立一個空的圖片
Texture2D skinnedMeshAtlas = new Texture2D(get2Pow(width), get2Pow(height));
Rect[] packingResult = skinnedMeshAtlas.PackTextures(textures.ToArray(), 0);
Vector2[] atlasUVs = new Vector2[uvCount];
// 因為將貼圖都整合到了一張圖片上,所以需要重新計算UV
int j = 0;
for (int i = 0; i < uvList.Count; i++)
{
foreach (Vector2 uv in uvList[i])
{
atlasUVs[j].x = Mathf.Lerp(packingResult[i].xMin, packingResult[i].xMax, uv.x);
atlasUVs[j].y = Mathf.Lerp(packingResult[i].yMin, packingResult[i].yMax, uv.y);
j++;
}
}
skinned.material.mainTexture = skinnedMeshAtlas;
skinned.sharedMesh.uv = atlasUVs;
//MergeMesh(skinned, combineInstances, boneList);
}
/// <summary>
/// 合併網格、材質、骨骼
/// </summary>
/// <param name="skinned"></param>
/// <param name="combineInstances"></param>
/// <param name="boneList"></param>
void MergeMesh(SkinnedMeshRenderer skinned, CombineInstance[] combineInstances, List<Transform> boneList)
{
skinned.sharedMesh = new Mesh();
skinned.sharedMesh.CombineMeshes(combineInstances, false, false); //不在意的矩陣的變換
skinned.materials = material;
skinned.bones = boneList.ToArray();
}
public void UpdateMesh(string meshName)
{
string UpdateName = "";
/// <summary>
/// 當前的人物換裝資訊
/// </summary>
Dictionary<string, meshT> currmesh = meshTs;
foreach (KeyValuePair<string, meshT> item in currmesh)
{
string name = item.Key.Split('-')[0];
if (name == meshName.Split('-')[0])
{
UpdateName = item.Key;
}
}
currmesh[UpdateName] = meshDic[meshName];
List<Transform> boneList = new List<Transform>();
foreach (KeyValuePair<string, meshT> item in currmesh)
{
for (int i = 0; i < item.Value._transform.Length; i++)
{
boneList.Add(item.Value._transform[i]);
}
}
CombineInstance[] combineInstances = new CombineInstance[meshTs.Count];
List<meshT> mesh = new List<meshT>();
foreach (var item in currmesh)
{
mesh.Add(item.Value);
}
List<Vector2[]> uvList = new List<Vector2[]>();//uv座標
int uvCount = 0;
for (int i = 0; i < mesh.Count; i++)
{
uvList.Add(mesh[i]._mesh.uv);//儲存uv座標
uvCount += mesh[i]._mesh.uv.Length;
material[i] = mesh[i]._material;
combineInstances[i].mesh = mesh[i]._mesh;
}
material = new Material[mesh.Count];
_transform = new Transform[mesh.Count];
for (int i = 0; i < mesh.Count; i++)
{
material[i] = mesh[i]._material;
combineInstances[i].mesh = mesh[i]._mesh;
}
List<Texture2D> textures = new List<Texture2D>();
int width = 0;
int height = 0;
//儲存圖片資訊
foreach (Material item in material)
{
if (item.mainTexture != null)
{
textures.Add(item.mainTexture as Texture2D);
width += item.mainTexture.width;
height += item.mainTexture.height;
}
}
SkinnedMeshRenderer skinned = gamePlayerObj.GetComponent<SkinnedMeshRenderer>();
skinned.sharedMesh = new Mesh();
skinned.sharedMesh.CombineMeshes(combineInstances, true, false); //不在意的矩陣的變換
skinned.bones = boneList.ToArray();
skinned.material = material[0];
//建立一個空的圖片
Texture2D skinnedMeshAtlas = new Texture2D(get2Pow(width), get2Pow(height));
Rect[] packingResult = skinnedMeshAtlas.PackTextures(textures.ToArray(), 0);
Vector2[] atlasUVs = new Vector2[uvCount];
// 因為將貼圖都整合到了一張圖片上,所以需要重新計算UV
int j = 0;
for (int i = 0; i < uvList.Count; i++)
{
foreach (Vector2 uv in uvList[i])
{
atlasUVs[j].x = Mathf.Lerp(packingResult[i].xMin, packingResult[i].xMax, uv.x);
atlasUVs[j].y = Mathf.Lerp(packingResult[i].yMin, packingResult[i].yMax, uv.y);
j++;
}
}
skinned.material.mainTexture = skinnedMeshAtlas;
skinned.sharedMesh.uv = atlasUVs;
//MergeMesh(skinned, combineInstances, boneList);
}
/// <summary>
/// 獲取最接近輸入值的2的N次方的數,最大不會超過1024,例如輸入320會得到512
/// </summary>
public int get2Pow(int into)
{
int outo = 1;
for (int i = 0; i < 10; i++)
{
outo *= 2;
if (outo > into)
{
break;
}
}
return outo;
}
using System.Collections.Generic;
using UnityEngine;
struct meshT
{
public Mesh _mesh;
public Transform[] _transform;
public Material _material;
}
/// <summary>///換裝併合併網格
/// </summary>
public class MeshMergeDome2 : MonoBehaviour
{
public static MeshMergeDome2 _intance;
private void Awake()
{
_intance = this;
}
public string loadName;
//生成人物得位置
private Transform StartPos;
private GameObject gamePlayerObj;
Dictionary<string, meshT> meshDic = new Dictionary<string, meshT>();
Dictionary<string, meshT> meshTs = new Dictionary<string, meshT>();
private string rootNamne;
Material[] material;
Transform[] _transform;
/// <summary>
/// 初始化
/// </summary>
private void Start()
{
//尋找生成位置
StartPos = GameObject.FindGameObjectWithTag("StartPos").transform;
//載入人物
gamePlayerObj = Instantiate(Resources.Load<GameObject>(loadName), StartPos.position, Quaternion.identity);
SkinnedMeshRenderer[] skinnedMeshRenderers = gamePlayerObj.GetComponentsInChildren<SkinnedMeshRenderer>();
for (int i = 0; i < skinnedMeshRenderers.Length; i++)
{
meshDic.Add(skinnedMeshRenderers[i].name, new meshT() { _mesh = skinnedMeshRenderers[i].sharedMesh, _transform = skinnedMeshRenderers[i].bones, _material = skinnedMeshRenderers[i].sharedMaterial,/*_transform1 = gamePlayerObj.transform.worldToLocalMatrix * skinnedMeshRenderers[i].transform.localToWorldMatrix*/ });
Destroy(skinnedMeshRenderers[i].gameObject);
}
List<Transform> boneList = new List<Transform>();
Transform[] transforms = gamePlayerObj.transform.Find("Female_Hips").GetComponentsInChildren<Transform>();
foreach (KeyValuePair<string, meshT> item in meshDic)
{
string name = item.Key.Split('-')[0];
if (name != rootNamne)
{
meshTs.Add(name, item.Value);
for (int i = 0; i < item.Value._transform.Length; i++)
{
boneList.Add(item.Value._transform[i]);
}
rootNamne = name;
}
}
CombineInstance[] combineInstances = new CombineInstance[meshTs.Count];
List<meshT> mesh = new List<meshT>();
foreach (var item in meshTs)
{
mesh.Add(item.Value);
}
material = new Material[mesh.Count];
_transform = new Transform[mesh.Count];
List<Vector2[]> uvList = new List<Vector2[]>();//uv座標
int uvCount = 0;
for (int i = 0; i < mesh.Count; i++)
{
uvList.Add(mesh[i]._mesh.uv);//儲存uv座標
uvCount += mesh[i]._mesh.uv.Length;
material[i] = mesh[i]._material;
combineInstances[i].mesh = mesh[i]._mesh;
}
List<Texture2D> textures = new List<Texture2D>();
int width = 0;
int height = 0;
//儲存圖片資訊
foreach (Material item in material)
{
if (item.mainTexture != null)
{
textures.Add(item.mainTexture as Texture2D);
width += item.mainTexture.width;
height += item.mainTexture.height;
}
}
SkinnedMeshRenderer skinned = gamePlayerObj.AddComponent<SkinnedMeshRenderer>();
// 設定貼圖和UV
skinned.sharedMesh = new Mesh();
skinned.sharedMesh.CombineMeshes(combineInstances, true, false); //不在意的矩陣的變換
skinned.bones = boneList.ToArray();
skinned.material = material[0];
//建立一個空的圖片
Texture2D skinnedMeshAtlas = new Texture2D(get2Pow(width), get2Pow(height));
Rect[] packingResult = skinnedMeshAtlas.PackTextures(textures.ToArray(), 0);
Vector2[] atlasUVs = new Vector2[uvCount];
// 因為將貼圖都整合到了一張圖片上,所以需要重新計算UV
int j = 0;
for (int i = 0; i < uvList.Count; i++)
{
foreach (Vector2 uv in uvList[i])
{
atlasUVs[j].x = Mathf.Lerp(packingResult[i].xMin, packingResult[i].xMax, uv.x);
atlasUVs[j].y = Mathf.Lerp(packingResult[i].yMin, packingResult[i].yMax, uv.y);
j++;
}
}
skinned.material.mainTexture = skinnedMeshAtlas;
skinned.sharedMesh.uv = atlasUVs;
//MergeMesh(skinned, combineInstances, boneList);
}
/// <summary>
/// 合併網格、材質、骨骼
/// </summary>
/// <param name="skinned"></param>
/// <param name="combineInstances"></param>
/// <param name="boneList"></param>
void MergeMesh(SkinnedMeshRenderer skinned, CombineInstance[] combineInstances, List<Transform> boneList)
{
skinned.sharedMesh = new Mesh();
skinned.sharedMesh.CombineMeshes(combineInstances, false, false); //不在意的矩陣的變換
skinned.materials = material;
skinned.bones = boneList.ToArray();
}
public void UpdateMesh(string meshName)
{
string UpdateName = "";
/// <summary>
/// 當前的人物換裝資訊
/// </summary>
Dictionary<string, meshT> currmesh = meshTs;
foreach (KeyValuePair<string, meshT> item in currmesh)
{
string name = item.Key.Split('-')[0];
if (name == meshName.Split('-')[0])
{
UpdateName = item.Key;
}
}
currmesh[UpdateName] = meshDic[meshName];
List<Transform> boneList = new List<Transform>();
foreach (KeyValuePair<string, meshT> item in currmesh)
{
for (int i = 0; i < item.Value._transform.Length; i++)
{
boneList.Add(item.Value._transform[i]);
}
}
CombineInstance[] combineInstances = new CombineInstance[meshTs.Count];
List<meshT> mesh = new List<meshT>();
foreach (var item in currmesh)
{
mesh.Add(item.Value);
}
List<Vector2[]> uvList = new List<Vector2[]>();//uv座標
int uvCount = 0;
for (int i = 0; i < mesh.Count; i++)
{
uvList.Add(mesh[i]._mesh.uv);//儲存uv座標
uvCount += mesh[i]._mesh.uv.Length;
material[i] = mesh[i]._material;
combineInstances[i].mesh = mesh[i]._mesh;
}
material = new Material[mesh.Count];
_transform = new Transform[mesh.Count];
for (int i = 0; i < mesh.Count; i++)
{
material[i] = mesh[i]._material;
combineInstances[i].mesh = mesh[i]._mesh;
}
List<Texture2D> textures = new List<Texture2D>();
int width = 0;
int height = 0;
//儲存圖片資訊
foreach (Material item in material)
{
if (item.mainTexture != null)
{
textures.Add(item.mainTexture as Texture2D);
width += item.mainTexture.width;
height += item.mainTexture.height;
}
}
SkinnedMeshRenderer skinned = gamePlayerObj.GetComponent<SkinnedMeshRenderer>();
skinned.sharedMesh = new Mesh();
skinned.sharedMesh.CombineMeshes(combineInstances, true, false); //不在意的矩陣的變換
skinned.bones = boneList.ToArray();
skinned.material = material[0];
//建立一個空的圖片
Texture2D skinnedMeshAtlas = new Texture2D(get2Pow(width), get2Pow(height));
Rect[] packingResult = skinnedMeshAtlas.PackTextures(textures.ToArray(), 0);
Vector2[] atlasUVs = new Vector2[uvCount];
// 因為將貼圖都整合到了一張圖片上,所以需要重新計算UV
int j = 0;
for (int i = 0; i < uvList.Count; i++)
{
foreach (Vector2 uv in uvList[i])
{
atlasUVs[j].x = Mathf.Lerp(packingResult[i].xMin, packingResult[i].xMax, uv.x);
atlasUVs[j].y = Mathf.Lerp(packingResult[i].yMin, packingResult[i].yMax, uv.y);
j++;
}
}
skinned.material.mainTexture = skinnedMeshAtlas;
skinned.sharedMesh.uv = atlasUVs;
//MergeMesh(skinned, combineInstances, boneList);
}
/// <summary>
/// 獲取最接近輸入值的2的N次方的數,最大不會超過1024,例如輸入320會得到512
/// </summary>
public int get2Pow(int into)
{
int outo = 1;
for (int i = 0; i < 10; i++)
{
outo *= 2;
if (outo > into)
{
break;
}
}
return outo;
}
}
效果: