10.使用MaterialPropertyBlock

10.补充知识-如何使用MaterialPropertyBlock


10.1 知识点

MaterialPropertyBlock的作用

  • 在不复制、不改动共享材质资源的前提下,对某一个 Renderer 单独覆盖材质属性。
  • 主要作用:
    • 让同一材质的不同对象有不同的表现。
    • 不会产生新的材质,节约内存。
    • 并且如果和 GPU Instancing 的实例属性配合使用,可以做到表现不同 DrawCall 也不会增加。

注意

  • MaterialPropertyBlock 的本质是让单个渲染器(Renderer)覆写材质参数。
  • 从而避免新材质的实例化,从而节约一些内存,并且节约材质实例化和拷贝的开销。
  • 相当于一份材质,多份参数。
  • 具体它不和 DrawCall 的减少相关。
  • 我们需要将它和 GPU Instancing 的实例属性配合使用才能做到不增加 DrawCall 的目的。

如何使用MaterialPropertyBlock

主要目的

  • 能够在 C# 侧通过 MaterialPropertyBlock 设置材质属性,传递给 Shader。

主要思路

  • 创建 MaterialPropertyBlock 对象,通过 Renderer 的 API 获取和设置属性块。

主要步骤

  1. new 一个 MaterialPropertyBlock 对象。
  2. 通过 Renderer 中的 API GetPropertyBlock 获取属性块。
  3. 利用 MPB 中的 Set 相关方法设置属性块中的变量。
  4. 通过 Renderer 中的 API SetPropertyBlock 将属性块传回 Renderer。

注意

  • 属性块相关应用都是在 C# 侧完成的。
  • 通过 C# 传递相关参数给到 Shader 中。

具体操作

new 一个 MaterialPropertyBlock 对象
//1.new 一个MaterialPropertyBlock对象
materialPropertyBlock = new MaterialPropertyBlock();
通过 GetPropertyBlock 获取属性块
  • 通过 Renderer 中的 API GetPropertyBlock 获取属性块。
//2.通过Renderer中的API GetPropertyBlock获取属性块
Renderer renderer = this.GetComponentInChildren<Renderer>();
renderer.GetPropertyBlock(materialPropertyBlock);
利用 Set 方法设置属性块中的变量
  • 可以直接传字符串,也可以传 id。
  • 我们这样设置是因为我们在 Shader 中定义了 GPU 实例化属性缓冲区。
//3.利用MPB中的Set相关方法设置属性块中的变量 可以直接传字符串,也可以传id
materialPropertyBlock.SetVector("_Color", new Vector4(1, 1, 1, 1));
materialPropertyBlock.SetVector(_Pos_id, new Vector4(1, 1, 1, 1));
materialPropertyBlock.SetInt("_OffsetIndex", Random.Range(0, 50));

//注意 我们这样设置是因为我们在shader中定义了以下内容
// // ==================== GPU实例化属性缓冲区 ====================
// // 定义实例化参数组,每个物体实例可独立修改以下参数
// UNITY_INSTANCING_BUFFER_START(MrTao)
// // 实例化颜色:每个实例独立的颜色参数
// UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
// // 实例化位置:每个实例独立的位置偏移参数
// UNITY_DEFINE_INSTANCED_PROP(float4, _Pos)
// // 实例化偏移索引:用于区分不同实例的序号参数
// UNITY_DEFINE_INSTANCED_PROP(int, _OffsetIndex)
// UNITY_INSTANCING_BUFFER_END(MrTao)
通过 SetPropertyBlock 将属性块传回 Renderer
//4.通过Renderer中的API SetPropertyBlock将属性块传回Renderer
renderer.SetPropertyBlock(materialPropertyBlock);

10.2 知识点代码

MaterialPropertyBlockLearn.cs

using UnityEngine;

public class MaterialPropertyBlockLearn : MonoBehaviour
{
    private MaterialPropertyBlock materialPropertyBlock;

    int _Pos_id = Shader.PropertyToID("_Pos");
    
    void Start()
    {
        #region 知识点一 MaterialPropertyBlock的作用

        //在不复制、不改动共享材质资源的前提下
        //对某一个Renderer单独覆盖材质属性
        //主要作用:
        //让同一材质的不同对象有不同的表现
        //不会产生新的材质,节约内存
        //并且如果和GPU Instancing的实例属性配合使用
        //可以做到表现不同DrawCall也不会增加

        //注意:
        //MaterialPropertyBlock的本质是让当个渲染器(Renderer)覆写材质参数
        //从而避免新材质的实例化,从而节约一些内存,并且节约材质实例化和拷贝的开销
        //相当于一份材质,多份参数
        //具体它不和DrawCall的减少相关
        //我们需要将它和GPU Instancing的实例属性配合使用才能做到不增加DrawCall的目的

        #endregion

        #region 知识点二 如何使用MaterialPropertyBlock

        //1.new 一个MaterialPropertyBlock对象
        materialPropertyBlock = new MaterialPropertyBlock();
        
        //2.通过Renderer中的API GetPropertyBlock获取属性块
        Renderer renderer = this.GetComponentInChildren<Renderer>();
        renderer.GetPropertyBlock(materialPropertyBlock);
        
        //3.利用MPB中的Set相关方法设置属性块中的变量 可以直接传字符串,也可以现状id
        materialPropertyBlock.SetVector("_Color", new Vector4(1, 1, 1, 1));
        materialPropertyBlock.SetVector(_Pos_id, new Vector4(1, 1, 1, 1));
        materialPropertyBlock.SetInt("_OffsetIndex", Random.Range(0, 50));
        
        //注意 我们这样设置是因为我们在shader中定义了以下内容
        // // ==================== GPU实例化属性缓冲区 ====================
        // // 定义实例化参数组,每个物体实例可独立修改以下参数
        // UNITY_INSTANCING_BUFFER_START(MrTao)
        // // 实例化颜色:每个实例独立的颜色参数
        // UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
        // // 实例化位置:每个实例独立的位置偏移参数
        // UNITY_DEFINE_INSTANCED_PROP(float4, _Pos)
        // // 实例化偏移索引:用于区分不同实例的序号参数
        // UNITY_DEFINE_INSTANCED_PROP(int, _OffsetIndex)
        // UNITY_INSTANCING_BUFFER_END(MrTao)
        
        //4.通过Renderer中的API SetPropertyBlock将属性块传回Renderer
        renderer.SetPropertyBlock(materialPropertyBlock);

        //注意:
        //属性块相关应用都是在C#侧完成的
        //通过C#传递相关参数给到Shader中

        #endregion
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏