Unity Shader无_MainTex属性 访问mainTexture偶发报错排查
问题说明
运行时抛出错误:Shader doesn't have a texture property '_MainTex'
异常表现如下:
- 代码首次运行时完全正常,后续运行在如下代码行触发报错:
exampleTexture = (Texture2D)rend.material.mainTexture;
- 当前使用的自定义Shader未定义Unity标准主纹理属性
_MainTex,其Properties块定义如下:
Properties { _Example ("Example (R16)", 2D) = "black" {} _Color ("Color", Color) = (1, 1, 1, 1) }
- 核心疑问:首次执行代码无任何异常,后续运行才触发报错。
产生原因
这个现象是Unity材质系统的懒加载机制+内置API的固定绑定逻辑共同导致的:
Renderer.material是实例化材质属性,第一次访问这个属性时,Unity才会为当前渲染器克隆一份独立的材质实例(和共享材质sharedMaterial分离)。这个克隆过程是懒执行的,初始阶段材质和Shader的属性绑定校验还没完成,此时访问mainTexture,引擎找不到对应的_MainTex属性时只会静默返回null/默认占位纹理,不会抛出异常,所以第一次运行能正常走通流程。- 等后续帧引擎完成材质实例与Shader的绑定校验后,会严格按照Shader中声明的Properties列表做属性合法性检查。而
material.mainTexture是Unity为标准Shader预留的快捷访问API,它固定读写Shader中名为_MainTex的纹理属性,不会自动匹配你自定义的其他2D属性,此时检测到当前Shader没有声明_MainTex,就会直接抛出异常。
*补充:如果首次运行时你给mainTexture做过赋值,引擎会临时给材质实例挂载一个_MainTex的动态属性,等Shader重编译、场景重载、材质实例重置后这个临时属性被清除,再次访问时也会触发同样的报错。
解决方案
二选一即可,根据项目需求选择:
- 方案1:保留现有C#代码逻辑,修改Shader对齐Unity标准属性规范
直接在Shader的Properties块中补上_MainTex的声明即可,不需要改动原有_Example相关的渲染逻辑;如果不需要额外保留_Example属性,也可以直接把_Example重命名为_MainTex。补全声明的示例代码:Properties { _MainTex ("Base Texture", 2D) = "white" {} // 新增这一行即可 _Example ("Example (R16)", 2D) = "black" {} _Color ("Color", Color) = (1, 1, 1, 1) } - 方案2:保留现有Shader结构,修改C#代码通过自定义属性名访问纹理
弃用mainTexture这个固定绑定_MainTex的快捷API,改用通用的材质属性读写接口,直接操作你自定义的_Example纹理属性,修改后的代码示例:// 替换原有的rend.material.mainTexture读取逻辑 exampleTexture = (Texture2D)rend.material.GetTexture("_Example"); // 如果需要给纹理赋值,调用对应Set接口即可 // rend.material.SetTexture("_Example", targetTexture);
内容的提问来源于stack exchange,提问作者RavioliDish
相关产品推荐
相关产品推荐

