根据经验,我们知道这是正常的,到安卓手机就会正常。但还是很影响调试体验。
我们想弄一个脚本,在编辑器状态自动找到它的着色器的编辑器版本,重新指定。不同的资源会使用不同的着色器,必须根据资源身上的着色器名字找到编辑器下的版本。
我们不想给所有预制体挂一遍脚本,所以在实例化资源时加上这个脚本。需要把Instantiate封装一下,整个项目克隆预制体不再使用原生Instantiate。封装版本里面执行一个事件。
问题就是怎么从AB包物体的材质的着色器得到这个着色器在编辑器的版本。
尝试AssetDatabase.GetAssetPath获得物体实例的着色器的编辑器路径
cs
public static void AssignEditorShader(GameObject go)
{
Renderer[] renderers = go.GetComponentsInChildren<Renderer>();
foreach (Renderer renderer in renderers)
{
foreach (var mat in renderer.sharedMaterials)
{
string path= AssetDatabase.GetAssetPath(mat.shader);
Debug.Log($"{go}的着色器在{path}");
全部返回了空。AB包加载的预制体和克隆体的着色器和编辑器的已经不是一个对象。

实现
那么我们通过着色器名字的匹配。弄一个SO,记录用到的着色器列表,生成字典。
cs
public static event Action<GameObject> OnCloneGlobal;
public static GameObject CloneStatic(GameObject prefab)
{
if (prefab == null)
{
Debug.LogError($"资源为空!");
return null;
}
if (!(prefab is GameObject))
{
Debug.LogError($"不是GO,无法克隆");
return null;
}
GameObject go = UnityEngine.Object.Instantiate(prefab);
OnCloneGlobal?.Invoke(go);
return go;
}
cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace MyFarm
{
public class ReassignShader:MonoBehaviour
{
[ContextMenu("打印着色器名字")]
void PrintShaders()
{
Renderer[]renderers = GetComponentsInChildren<Renderer>();
foreach (Renderer renderer in renderers)
{
foreach (var mat in renderer.sharedMaterials)
{
Debug.Log(mat.shader.name);
}
}
}
#if UNITY_EDITOR
static ShaderRecorderSO _shaderRecorderSO;
static Dictionary<string, Shader> _shaderDic;
static Dictionary<string, Shader> shaderDic
{
get
{
if(_shaderDic == null)
{
_shaderRecorderSO = AssetDatabase.LoadAssetAtPath<ShaderRecorderSO>
("Assets/New Shader Recorder SO.asset");
if(_shaderRecorderSO == null)
{
Debug.LogError("加载着色器盘失败");
return null;
}
_shaderDic = new();
foreach(var shader in _shaderRecorderSO.shaders)
{
shaderDic[shader.name] = shader;
}
}
return _shaderDic;
}
}
public static void AssignEditorShader(GameObject go)
{
Renderer[] renderers = go.GetComponentsInChildren<Renderer>();
foreach (Renderer renderer in renderers)
{
foreach (var mat in renderer.sharedMaterials)
{
string shaderName= mat.shader.name;
if (shaderDic.ContainsKey(shaderName))
{
mat.shader = shaderDic[shaderName];
}
else
{
Debug.LogError($"着色器{shaderName}在SO里不存在");
}
}
}
}
#endif
}
}
cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MyFW;
namespace MyFarm
{
[CreateAssetMenu(menuName = "MyFarm/着色器记录")]
public class ShaderRecorderSO : ScriptableObject
{
public List<Shader> shaders;
}
}
cs
#if UNITY_EDITOR
MyResInfo.OnCloneGlobal += ReassignShader.AssignEditorShader;
#endif