如何通过GetProperties/PropertyInfo访问自定义Shader的属性与字段?
你遇到的核心问题是混淆了C#类的反射属性和Shader本身的属性:用objectToSave.GetType().GetProperties()拿到的是Unity Material这个C#类的固有属性,而你在编辑器里看到的Shader参数是属于关联的Shader资源的,和Material的C#类属性完全不是一回事。
正确的解决方案:直接读取Shader的属性列表
Unity提供了专门的API来访问Shader的属性,不管是内置Shader还是ShaderForge生成的自定义Shader,都可以用这套方法获取所有暴露的参数,然后通过Material实例拿到对应的值:
public void Save(Material materialToSave) { if (materialToSave == null || materialToSave.shader == null) return; Shader targetShader = materialToSave.shader; int propertyCount = targetShader.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { string propertyName = targetShader.GetPropertyName(i); // 运行时用公开API,编辑器可用ShaderUtil ShaderPropertyType propertyType = targetShader.GetPropertyType(i); // 根据属性类型获取对应的值 object propertyValue = null; switch (propertyType) { case ShaderPropertyType.Color: propertyValue = materialToSave.GetColor(propertyName); break; case ShaderPropertyType.Float: case ShaderPropertyType.Range: propertyValue = materialToSave.GetFloat(propertyName); break; case ShaderPropertyType.Vector: propertyValue = materialToSave.GetVector(propertyName); break; case ShaderPropertyType.Texture: propertyValue = materialToSave.GetTexture(propertyName); break; // 可根据需求扩展更多属性类型 } // 这里处理属性名和值,比如保存到文件或其他逻辑 Debug.Log($"属性名:{propertyName},类型:{propertyType},值:{propertyValue}"); } }
关键细节说明
为什么之前的反射方法会报错?
你用反射访问的_Color其实是Material类的封装属性,它内部会调用GetColor("_Color"),但如果当前Material的Shader没有_Color这个属性,这个调用就会抛出错误——因为反射不管Shader有没有这个属性,硬去访问Material类的这个属性了。ShaderForge自定义Shader的适配
ShaderForge生成的Shader本质上就是标准的Unity Shader,所有暴露的参数都会被Unity的Shader系统识别,所以上面的API完全适用,不需要额外处理。你在编辑器Material面板看到的所有参数,都会通过GetPropertyCount()和GetPropertyName()拿到。是否需要判断自定义Shader?
其实不需要专门判断,只要通过materialToSave.shader拿到当前关联的Shader,然后读取它的属性列表即可——不管是内置还是自定义Shader,这套逻辑都能正确获取对应的参数。
注意事项
- 如果是Unity 2020之前的版本,
Shader.GetPropertyType()可能不可用,此时在编辑器环境可以改用ShaderUtil.GetPropertyType(targetShader, i),但注意ShaderUtil属于内部工具类,运行时打包可能需要替换为兼容方案。
内容的提问来源于stack exchange,提问作者Juhana Pietari Lehtiniemi

