1.MaterialPropertyBlock
定义:A block of material values to apply.(一块可以应用的材质属性)
Unity中所有的东西都是通过材质(material)来进行渲染的,材质又影响到合批。那么有没有一个方式又让物体用同一个材质渲染(可以合批),又可以让物体表现出不同的性质呢?那就要用到MaterialPropertyBlock
了。
Use it in situations where you want to draw multiple objects with the same material, but slightly different properties. For example, if you want to slightly change the color of each mesh drawn. Changing the render state is not supported.
当你想用相同的材质绘制多个对象,但每个对象属性略有不同的时候就可以使用MaterialPropertyBlock。例如稍微改变每个网格的颜色。但修改渲染状态不支持修改每个网格颜色。
Unity's terrain engine uses MaterialPropertyBlock to draw trees; all of them use the same material, but each tree has different color, scale & wind factor.
Unity 的地形引擎使用 MaterialPropertyBlock 绘制树木,它们都使用相同的材质,但每棵树都有不同的颜色、比例和风系数。
Note that this is not compatible with SRP Batcher. Using this in the Universal Render Pipeline (URP), High Definition Render Pipeline (HDRP) or a custom render pipeline based on the Scriptable Render Pipeline (SRP) will likely result in a drop in performance.
此外要注意的是,MaterialPropertyBlock与SRP Batcher不兼容,在URP/HDRP/SRP中使用可能会导致性能下降。(官方吐槽:谁知道你们自定义的管线支不支持我们MaterialPropertyBlock呀~)
从官方文档中很明白的就能看出来:
- Block是凌驾于Material之上的,比如你使用Block进行绘制颜色的时候,原本material上的颜色就会失效。
- 使用了Block可以实现相同材质表现出不一样的效果。
2.那么这个玩意儿到底怎么用呢?
Block可以用作绘制Mesh或者更改Renderer上的材质属性,材质本质上存储的是shader中使用的各种属性。
1 2 3 4 |
//更改Renderer上的Block Renderer.SetPropertyBlock //直接在mesh上绘制 Graphics.DrawMesh |
举个栗子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public class ExampleClass : MonoBehaviour { public Mesh mesh; private MeshRenderer meshRenderer; public Material material; private MaterialPropertyBlock block; private int colorID; void Start() { block = new MaterialPropertyBlock(); colorID = Shader.PropertyToID("_Color"); } void Update() { //Block有两种设置方式: //通过材质上的属性名设置 block.SetColor("_Color", Color.red); //通过提前获取属性ID进行设置 block.SetColor(colorID, Color.red); //直接在mesh上绘制 Graphics.DrawMesh(mesh, new Vector3(0, 0, 0), Quaternion.identity, material, 0, null, 0, block); //更改Renderer上的Block meshRenderer.SetPropertyBlock(block); } } |
3.我想获取上次设置的Block该咋办?
我在上一帧修改了很多Block属性,但是这一帧只想改变其中的某一项。
或者是上一帧A设置了一大堆Block属性进去,这一帧B要修改其中的某一项。
Unity提供了接口GetPropertyBlock
public void GetPropertyBlock(MaterialPropertyBlock properties);
public void GetPropertyBlock(MaterialPropertyBlock properties, int materialIndex);
但是这个函数明明叫Get,为什么返回值是个void呢?
Get per-Renderer or per-Material property block.
The retrieved properties are stored in the property block passed in through "properties". If no properties are set, the property block is cleared. In either case the property block you pass in is completely overwritten.
获取per-Renderer或per-Material属性块
把之前存储的属性通过参数properties进行恢复。如果之前没设置Block,就把properties清空。(这不就是个ref吗?)
不管怎样,你传进来的properties属性都会被完全覆盖(何必呢,为啥不加个ref呢?我瞄了一眼Block也不是结构体啊)