材质脚本控制
脚本中开启 HDR Color
1 | [//添加HDR类型的颜色条 ] |
材质属性
材质属性在 C# 代码中通过 MaterialProperty 类进行表示。
要访问 HLSL 代码中定义的变量,可以调用 Material.GetFloat、Material.SetFloat。还有其他类似的方法;请参阅材质 API 文档以获取完整列表。使用这些 API 访问 HLSL 变量时,变量是否为材质属性并不重要。
在 Unity 编辑器中,可以控制材质属性在 Inspector 窗口中的显示方式。为此,最简单的方法是使用 MaterialPropertyDrawer。对于更复杂的需求,可以使用 MaterialEditor、MaterialProperty 和 ShaderGUI 类。有关为着色器创建自定义 GUI 的更多信息,请参阅 ShaderLab:分配自定义编辑器。
方法名称 | 用途 |
---|---|
SetColor | 更改材质的颜色 |
SetFloat | 设置浮点值 |
SetInteger | 在材质中设置整数值 |
SetTexture | 为材质分配新纹理 |
1 | // 设置贴图 |
material 和 shader
1 直接设置 Material 文件
使用 unity 编辑器直接定位包含目标 shader 的 Material,并在脚本中访问。所有引入该 Material 的物体都会发生改变.
1,在脚本中建立公共 Material 参数
2,将脚本绑定到某物体上
3,在 unity edtor 中找到包含 Shader 的 Material 文件并拖拽到刚才的脚本对应参数上
1 | public class shaderController : MonoBehaviour |
2 设置资源中的 Material 文件
直接设置 Material 文件中的 Shader,所有引入该 Material 的物体都会发生改变
目标 Material 必须在 Asset/Resources 文件夹下。
1 | public class shaderController : MonoBehaviour |
3 通过指定 shader 设置
该设置只会影响带有当前新建的 Material 的物体,不会影响其他带有该 shader 的物体。
1,读取 shader 资源
2,在内存中创建 Material 并设置相关参数
3,将新建的 Material 赋给目标物体
1 | public class shaderController : MonoBehaviour |
4 通过目标物体直接设置,影响所有的物体
该设置会影响所有引用与该物体相同 Material 的物体
1,获取目标物体
2,获取物体 sharedMaterial 属性
3,设置
1 | public class shaderController : MonoBehaviour |
5 通过目标物体直接设置,只影响当前的物体
该设置只会影响当前设置 Material 的物体
1,获取目标物体
2,获取物体 Material 属性
3,设置
1 | public class shaderController : MonoBehaviour |
注意
如果设置无效要注意以下问题
- 目标 shader 的渲染器路径是否有重名。
- 如果是通过资源文件读取,需要确保它在 Asset/Resources 文件夹下
- 区分 material 和 share material 的区别。实际上直接设置 material 等于实例化了一个新的 materaial 并赋给对象,如果不手动销毁,这个新的 material 会一直在内存中驻留。而 sharematerial 则是修改已有的 material,但这个修改会改变所有引用了该 material 的对象。这点务必搞清楚。
脚本控制
子着色器标签
Material.GetTag
:读取子着色器标签
1 | // 将此附加到具有渲染器组件的游戏对象 |
修改 Queue 标签
1 | public Shader shader; |
Pass
Material.FindPass
:返回通道 passName 的索引,如果不存在,则为 -1
Material.GetPassName
返回索引 pass
处的着色器通道的名称。如果通道不存在,则它返回空字符串。
ShaderData. Pass. Name:此通道的名称
注意:Material.GetShaderPassEnabled 和 Material.SetShaderPassEnabled 不按名称引用通道;而是使用 LightMode 标签的值引用通道。
Pass 专用 Tags:
Shader.FindPassTagValue
:获取 Tag 值,适用于 Unity 的预定义 Pass 标签,以及您创建的自定义通道标签。
注意:有几个 API 可以直接与 LightMode 通道标签一起使用。有关更多信息,请参阅[[ https://docs.unity3d.com/cn/2022.3/Manual/SL-PassTags.html# 脚本使用 LightMode 标签]( https://docs.unity3d.com/cn/2022.3/Manual/SL-PassTags.html#lightmode-tag-scripts ]]。
LightMode 标签:
Material.SetShaderPassEnabled and ShaderTagId use the value of the LightMode
tag to determine how Unity handles a given Pass.
在可编程渲染管线中,您可以为 LightMode
标签创建自定义值。然后,通过配置一个 DrawingSettings 结构,您可以使用这些自定义值来确定在给定 ScriptableRenderContext.DrawRenderers 调用期间要绘制哪些通道。有关更多信息和代码示例,请参阅在自定义可编程渲染管线中创建一个简单的渲染循环。
材质属性
API
Shader.Find
通过 Shader.Find (name)
可以获得指定名字的 shader,需要注意的是 name 为 Shader 脚本中第一行定义 Shader 的全名,如 Unlit/Texture,Legacy Shaders/Diffuse 等。
如果 shader 没有被引用包含进发布工程,那么 Shader. Find 将不会获得目标 shader。
可以通过以下几种方式把需要的 shader 引用到工程中:
- 通过场景中的材质球引用,这样就会把引用的 shader 也一道打包了
- 在 Project Settings–>Graphics 下,把 shader 添加进 Always Included Shaders 中,手动太慢,可以使用代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24[ ]
public static void TestIncludedShader()
{
string[] myShaders = new string[1]{
"Legacy Shaders/Diffuse"
};
SerializedObject graphicsSettings = new SerializedObject (AssetDatabase.LoadAllAssetsAtPath ("ProjectSettings/GraphicsSettings.asset") [0]);
SerializedProperty it = graphicsSettings.GetIterator ();
SerializedProperty dataPoint;
while (it.NextVisible(true)) {
if (it.name == "m_AlwaysIncludedShaders") {
it.ClearArray();
for (int i = 0; i < myShaders.Length; i++) {
it.InsertArrayElementAtIndex(i);
dataPoint = it.GetArrayElementAtIndex (i);
dataPoint.objectReferenceValue = Shader.Find(myShaders[i]);
}
graphicsSettings.ApplyModifiedProperties ();
}
}
} - 把 shader 放到 Resources 目录下
注意
在热更项目中,通常会把 shader 通过引用的方式打成包,然后通过 AssetBundle.LoadAllAssets()
的方式引入到工程中。这种方式引用的 Shader 无法使用 Shader.Find 获取到的。
MaterialPropertyBlock
1 | public class Test : MonoBehaviour |
1 | public class MeshBall : MonoBehaviour |
对于实例化出来的模型,我们改变它身上的颜色值或者贴图之类,Unity 是会把它当前使用的 ShareMaterial 复制一份实例出来,以做到不同对象身上的材质互不影响的改变参数。但这样做会导致如果使用的对象很多,就会产生很多材质的实例的问题,这样会对内存有一定的消耗。
在场景里面生成了多个 cube,然后用代码改变他们的颜色:
给每一个 cube 随机一种颜色,然后用传统的 material. color 来设置颜色。
结果会是这样,各个 cube 的颜色变化了。
从 Profiler 里面看看内存,会发现场景内存里面,有很多的 InstanceMat(Instance)。这就是生成出来的材质实例。
接下来改一下代码,使用 MaterialPropertyBlock 来作为设置颜色的手段:
可以看到我们会先 new 一个 MaterialPropertyBlock,然后给它赋值,最后用 Renderer. SetPropertyBlock 方式给 MeshRender 设置属性。
运行时,可以看到运行的结果和之前的写法是一样的。
再从 Profiler 里面看看内存。
这次可以看到,并没有生成任何的 Material 的实例出来。