原實現如下:
private void createOne(string path)
{
StaticSkin skin = Utils.ReadSkins(path);
Mesh mesh = Utils.BuildMeshBySkin(skin);
string mp = meshPath + "/" + skin.name + ".asset";
AssetDatabase.CreateAsset(mesh, mp);
GameObject go = new GameObject(skin.name);
MeshRenderer render = go.AddComponent<MeshRenderer>();
render.sharedMaterials = new UnityEngine.Material[skin.Materials.Length];
for (int i = 0; i < render.sharedMaterials.Length; ++i)
{
string materialName = skin.Materials[i].Texture;
if (string.IsNullOrEmpty(materialName) == false)
{
Debug.Log("[" + materialName + "]");
int idx = materialName.LastIndexOf('.');
materialName = materialName.Substring(0, idx) + ".mat";
UnityEngine.Material mat = AssetDatabase.LoadAssetAtPath<UnityEngine.Material>(materialPath + "/" + materialName);
render.sharedMaterials[i] = mat;
}
}
MeshFilter mf = go.GetComponent<MeshFilter>();
if (mf == null)
mf = go.AddComponent<MeshFilter>();
mf.sharedMesh = mesh;
PrefabUtility.SaveAsPrefabAsset(go, prefabPath + "/" + skin.name + ".prefab");
DestroyImmediate(go);
}
但是發現代碼執行過後,Prefab中引用的Material全是none,模型顯示默認顏色紅色
裏面關鍵一行的錯誤在
render.sharedMaterials[i] = mat;
這裏Material數組需要一次性賦值,不能逐個賦值,所以代碼改成這樣:
private void createOne(string path)
{
StaticSkin skin = Utils.ReadSkins(path);
Mesh mesh = Utils.BuildMeshBySkin(skin);
string mp = meshPath + "/" + skin.name + ".asset";
AssetDatabase.CreateAsset(mesh, mp);
GameObject go = new GameObject(skin.name);
MeshRenderer render = go.AddComponent<MeshRenderer>();
UnityEngine.Material[] sharedMaterials = new UnityEngine.Material[skin.Materials.Length];
for(int i = 0; i < sharedMaterials.Length; ++i)
{
string materialName = skin.Materials[i].Texture;
if(string.IsNullOrEmpty(materialName) == false)
{
Debug.Log("[" + materialName + "]");
int idx = materialName.LastIndexOf('.');
materialName = materialName.Substring(0, idx) + ".mat";
UnityEngine.Material mat = AssetDatabase.LoadAssetAtPath<UnityEngine.Material>(materialPath + "/" + materialName);
sharedMaterials[i] = mat;
}
}
render.sharedMaterials = sharedMaterials;
MeshFilter mf = go.GetComponent<MeshFilter>();
if(mf == null)
mf = go.AddComponent<MeshFilter>();
mf.sharedMesh = mesh;
PrefabUtility.SaveAsPrefabAsset(go, prefabPath + "/" + skin.name + ".prefab");
DestroyImmediate(go);
}
這段代碼中,單獨創建了一個數組UnityEngine.Material[] sharedMaterials,然後爲這個數組填充數據,最後一次性將數組傳入 Renderer
render.sharedMaterials = sharedMaterials;
原因是這樣:
sharedMaterials是個屬性,也就是我們說的get/set,我們可以寫如下僞代碼
public class Renderer
{
private Material[] shareMats;
public Material[] sharedMaterials
{
get { retrun shareMats; }
set
{
shareMats = value;
// 做一些底層必要的操作
}
}
}
從這份僞代碼中看到,如果我們使用renderer.sharedMaterials[i] = mat;
雖然把材質放進去了,但是實際上只執行了get方法,set方法卻沒有執行,註釋所代表的的那些“”底層必要的操作“”自然無法執行,這就導致你設置進去的材質不生效
而使用rendere.sharedMaterials = mats;
則會執行set方法而不是get方法,這樣,內部一些操作就會正常執行,所以材質就有效了。