Unity Editor 代码中创建Prefab时无法关联Material(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>();
        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方法,这样,内部一些操作就会正常执行,所以材质就有效了。

Unity中,使用代码生成预制体(Prefab)主要有以下几种方法: 1. **脚本动态创建**:你可以编写C#脚本,在运行创建新的GameObject,并将其转换为Prefab。这通常是通过`Instantiate`或`ScriptableObject.CreateInstance`等Unity提供的API来实现的。例如: ```csharp GameObject newObj = new GameObject("New Prefab"); PrefabAsset prefab = PrefabUtility.CreateEmptyPrefab("Path/To/NewPrefab.prefab"); PrefabUtility.SaveAsPrefabAsset(newObj.transform.position, prefab); ``` 2. **序列化字段创建**:如果想要基于某个预设的配置或数据生成Prefab,可以在剧本中设置一个公共类,包含所需组件和属性,并在该类实例化保存为Prefab。在编辑器中,选择该类并右键单击“Create Prefab”会自动创建一个Prefab。 3. **Unity Editor Tools扩展**:有一些第三方工具如Unity Asset Tools包允许开发者编写插件,扩展Unity的编辑器功能,以便更复杂地生成Prefab,比如基于用户交互或特定条件的Prefab。 4. **使用Mecanim StateMachine**:如果你需要根据状态机生成预制体,Unity的Mecanim系统可以配合使用,创建不同的动画状态并在需要的候生成对应的Prefab。 5. **C# ScriptableObjects**:利用ScriptableObject和其变体(如AnimatorController、Material等),可以在设计创建预设并生成Prefab。 每种方法都有其适用场景,选择哪种取决于具体的项目需求和个人喜好。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值