Unity SRP从零搭建一套图形衬着管线 实践2
参照 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 绘制许多网格小球
创建一个空物体,挂上如下脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 生成1023个mesh和小球对象
/// </summary>
public class MeshBall : MonoBehaviour
{
static int baseColorId = Shader.PropertyToID(”_BaseColor”);
Mesh mesh = default;
Material material = default;
Matrix4x4[] matrices = new Matrix4x4;
Vector4[] baseColors = new Vector4;
MaterialPropertyBlock block;
void Awake()
{
for (int i=0;i<matrices.Length;i++)
{
//创建随机转换矩阵和颜色
matrices = Matrix4x4.TRS(Random.insideUnitSphere*10f, Quaternion.Euler(
Random.value * 360f, Random.value * 360f, Random.value * 360f
),
Vector3.one * Random.Range(0.5f, 1.5f));
baseColors = new Vector4(Random.value,Random.value,Random.value,Random.Range(0.5f, 1f));
}
}
void Update()
{
if (block == null)
{
//随机属性发送到着色器
block = new MaterialPropertyBlock();
block.SetVectorArray(baseColorId, baseColors);
}
//绘制网格实例
Graphics.DrawMeshInstanced(mesh,0,material,matrices,1023,block);
}
}
即可生成大量小球。
2.6 动态合批
使用如下代码打开批措置开关,即可开启合批和GPUInstance
//绘制设置,设置衬着的Shader Pass 和排序模式
var drawingSettings = new DrawingSettings(unlitShaderTagId, sortingSettings)
{
//设置衬着时批措置的使用状态
enableDynamicBatching = useDynamicBatching,
enableInstancing = useInstancing,
};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
页:
[1]