找回密码
 立即注册
查看: 190|回复: 0

Unity SRP从零搭建一套图形衬着管线 实践2

[复制链接]
发表于 2024-7-15 18:20 | 显示全部楼层 |阅读模式
参照 UWA上的一个教程:Unity SRP从零搭建一套图形衬着管线_UWA学堂 (uwa4d.com)
这是第二章节
以下图文均来自上面的教程,一些具体法式做了简略,参考教程即可,这里仅记录一些常识点。


1. Shader

SRP 只保留了对Unlit Shader的撑持,本节我们开始编写本身的Shader来衬着
Unity 内置的衬着管线着色器使用的是CG语言,和HLSL斗劲像,但是目前CG语言遏制更新很久了,基本已经被放弃,所以SRP使用了HLSL语言。
1.1 Unlit Shader

这个小节不涉及光照。参照教程创建Shader和hlsl文件。
Shader中include hlsl文件


HLSL文件里面加上
#ifndef CUSTOM_UNLIT_PASS_INCLUDED
#define CUSTOM_UNLIT_PASS_INCLUDED
#endif
我们一般通过#define指令定义一些标识符,在定义宏之前先判断一下是否认义过此标识符,如果定义过了,就跳过里面的所有代码不再执行,直接跳转到#endif末尾的代码。这样就能保证无论反复Include该HLSL文件多少次,只有第一次的Include是有效代码插入
1.2 着色器函数

先创建如下着色器


UnityInput.hlsl 文件存储Unity提供的一些尺度输入,定义一个模型空间到世界空间的转换矩阵。定义一个Common.hlsl文件存储,模型空间转到世界空间的方式。






上面顶点颠末模型转世界,世界转裁剪之后,网格显示正常了。


1.3 SRP 源码库

以上提及的在Common.hls定义的两空间转换方式斗劲常用,在安装的插件包Core RP Library中也有官方的库文件定义了这两个方式,所以我们把本身定义的TransformObjectToWorld和TransformWorldToHClip方式删除,替换为官方的,然后补全片元函数,这里代码较多就不贴了。 成果如下:


2.批措置

2.1 Draw Call 和Set Pass Call

命令缓冲区的命令有很多种类,而Draw Call就是此中一种,其它命令还有Set Pass Call等等。Set Pass Cal代表了我们常说的改变染状态,当切换材质或者切换同一材质中Shader的分歧Pass进行染时城市发一次Set Pass Cal。比如我们染1000个不异的物体和染1000个分歧的物体,虽然两者Draw Cal都是1000,但是前者Set Pass Cal为1,后者还是1000切换染状态在往比Draw Cal更耗时,所以这也是URP不再撑持多Pass的原因
可参考:Unity3D之DrawCalls、Batches和SetPassCalls的关系_Wei_Yuan_2012的博客-CSDN博客
2.2 SRP Batcher

SRP Batcher是一种新的批措置方式,它不会减少Draw Call的数量,但可以减少Set Pass Call的数量,并减少绘制调用命令的开销。CPU不需要每帧都给GPU发送衬着数据,如果这些数据没有发生变化则会保留在GPU内存中,每个绘制调用仅需包含一个指向正确内存位置的偏移量。
SRP Batcher是否会被打断的判断依据是Shader变种,即使物体之间使用了分歧的材质,但是使用的Shader变种不异就不会被打断,传统的批措置方式是要求使用同一材质为前提的。
SRP Batcher会在主存中将模型的坐标信息、材质信息、主光源暗影参数和非主光源暗影参数分袂保留到分歧的CBUFFER(常量缓中区)中,只有CBUFFER发生变化才会从头提交到GPU并保留。
如何判断Shader是否兼容 SRP Batcher,通过下面的属性看,当前的Shader是不兼容的


如下代码插手CBUFFER后,就可以兼容了






有关Cbuffer
【Unity】SRP底层衬着流程及道理 - 知乎 (zhihu.com)
hlsl 中使用的常量缓冲区(cbuffer)究竟是什么? | (1r1g.com)
使用  GraphicsSettings.useScriptableRenderPipelineBatching = true; 开启SRP合批
2.3 多种颜色

编写一个脚本使得同一个材质的物体能有分歧的颜色,否则默认是会颜色共享的。
参考:Unity材质属性块MaterialPropertyBlock - 简书 (jianshu.io)
我们新建如下脚本,挂在3个球体上:


会发现挂了脚本的SRP Batch 掉效了


2.4 GPU instancing

1)要撑持GPU Instancing,首先需要在Shader的Pass中添加#pragma multi_compile_instancing指令,然后在材质球上就能看到切换开关了,这时Unity会为我们的Shader生成两种变体,此时材质上也能看到开关了。


2)在Common.hlsl中插手
#include ”Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl”
3)改削顶点函数、片段函数


至此,4个球合并为1个DrawCall


一些说明
Unitylnstancing.hls通过从头定义一些宏去访谒实例的数据数组,它需要知道当前染对象的索引,该索引是通过顶点数据提供的。Unityinstancing.hlsl中定义了UNITY_VERTEX_INPUT_INSTANCE_ID宏来简化了这过程。
UNITY_VERTEX_INPUT_INSTANCE_ID 从顶点数据中获取当前衬着对象的索引
UNITY_INSTANCING_BUFFER_START
UNITY_DEFINE_INSTANCED_PROP
UNITY_SETUP_INSTANCE_ID
UNITY_TRANSFER_INSTANCE_ID
2.5 绘制许多网格小球

创建一个空物体,挂上如下脚本:
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. /// <summary>
  5. /// 生成1023个mesh和小球对象
  6. /// </summary>
  7. public class MeshBall : MonoBehaviour
  8. {
  9.     static int baseColorId = Shader.PropertyToID(”_BaseColor”);
  10.     [SerializeField]
  11.     Mesh mesh = default;
  12.     [SerializeField]
  13.     Material material = default;
  14.     Matrix4x4[] matrices = new Matrix4x4[1023];
  15.     Vector4[] baseColors = new Vector4[1023];
  16.     MaterialPropertyBlock block;
  17.     void Awake()
  18.     {
  19.         for (int i=0;i<matrices.Length;i++)
  20.         {
  21.             //创建随机转换矩阵和颜色
  22.             matrices[i] = Matrix4x4.TRS(Random.insideUnitSphere*10f, Quaternion.Euler(
  23.                     Random.value * 360f, Random.value * 360f, Random.value * 360f
  24.                 ),
  25.                 Vector3.one * Random.Range(0.5f, 1.5f));
  26.             baseColors[i] = new Vector4(Random.value,Random.value,Random.value,Random.Range(0.5f, 1f));
  27.         }
  28.     }
  29.      void Update()
  30.     {
  31.         if (block == null)
  32.         {
  33.             //随机属性发送到着色器
  34.             block = new MaterialPropertyBlock();
  35.             block.SetVectorArray(baseColorId, baseColors);
  36.         }   
  37.                  //绘制网格实例
  38.         Graphics.DrawMeshInstanced(mesh,0,material,matrices,1023,block);
  39.     }
  40. }
复制代码
即可生成大量小球。


2.6 动态合批

使用如下代码打开批措置开关,即可开启合批和GPUInstance
  1. //绘制设置,设置衬着的Shader Pass 和排序模式
  2. var drawingSettings = new DrawingSettings(unlitShaderTagId, sortingSettings)
  3. {
  4. //设置衬着时批措置的使用状态
  5. enableDynamicBatching = useDynamicBatching,
  6. enableInstancing = useInstancing,
  7.    };
复制代码
3.Alpha Blend 和 Alpha Test

3.1 Blend Modes


在Shader中设置混合模式,目前设置的是尺度的不透明混合模式




有关混合的参考:
Unity-ShaderLab:混合 - 哔哩哔哩 (bilibili.com)
注意透明物体衬着要封锁深度写入,否则得不到正确成果
最终参照如下配置


3.2 材质添加对纹理的撑持

增加如下代码






这块和以前的管线没啥大区别,直接贴出成果。


3.3 透明度测试 Alpha Test

附上代码






材质凡是使用透明度测试和透明度混合此中一个,而不是同时使用。透明度测试应使用在完全不透明的物体身上,除了被clip丢弃的片元外,其它片元会写入深度缓冲中。我们把混合模式设置成尺度不诱明物体的配置,然后开启深度写入,衬着队列设置为AlphaTest。


3.4 Shader Feature

使用shader feature可以让Unity按照分歧的定义条件或关键字编译多次,生成多个着色器变体。然后通过外部代码或者材质面板上的开关来启用某个关键字,加载对应的着色器变种版本来执行某些特定功能,是项目开发中斗劲常用的一种手段。下面我们添加一个控制透明度测试功能是否启用的开关。








3.5 逐对象的裁剪

还是通过MaterialPropertyBlock

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-23 17:32 , Processed in 0.103054 second(s), 28 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表