原实现如下:
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方法,这样,内部一些操作就会正常执行,所以材质就有效了。