实例原文

Unity通用渲染管线(URP)系列(二)——Draw Calls(Shaders&Batches) - 知乎 (zhihu.com)

Draw Calls (catlikecoding.com)

编写简单的HLSL Shader

创建Shader: Custom RP/Unlit

声明其顶点着色器函数和片元着色器函数,声明颜色属性_BaseColor

Shader "Custom RP/Unlit"
{Properties{_BaseColor("Color", Color) = (1.0, 1.0, 1.0, 1.0)}SubShader{Pass{HLSLPROGRAM#pragma vertex UnlitPassVertex#pragma fragment UnlitPassFragment#include "UnlitPass.hlsl"ENDHLSL}}
}

在UnlitPass.hlsl中编写顶点着色器和片元着色器的具体定义

#ifndef CUSTOM_UNLIT_PASS_INCLUDE
#define CUSTOM_UNLIT_PASS_INCLUDE#include "../ShaderLibrary/Common.hlsl"float4 _BaseColor;float4 UnlitPassVertex(float3 positionOS : POSITION) : SV_POSITION
{float3 positionWS = TransformObjectToWorld(positionOS.xyz);return TransformWorldToHClip(positionWS);
}float4 UnlitPassFragment() : SV_TARGET
{return _BaseColor;
}#endif

其中在顶点着色器中做的是顶点位置空间变换,从模型空间转换到世界空间,再从世界空间转换到裁剪空间。

片元着色器返回定义的片元颜色。

在做空间变换时用到了unity_ObjectToWorld,unity_MatrixVP等矩阵及其逆矩阵,在UnityInput.hlsl中定义:

#ifndef CUSTOM_UNITY_INPUT_INCLUDED
#define CUSTOM_UNITY_INPUT_INCLUDEDfloat4x4 unity_ObjectToWorld;
float4x4 unity_WorldToObject;
real4 unity_WorldTransformParams;float4x4 unity_MatrixVP;
float4x4 unity_MatrixV;
float4x4 glstate_matrix_projection;#endif

在Common.hlsl中包含对实际调用转换方法的定义:

#ifndef CUSTOM_COMMON_INCLUDED
#define CUSTOM_COMMON_INCLUDED#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "UnityInput.hlsl"#define UNITY_MATRIX_M unity_ObjectToWorld
#define UNITY_MATRIX_I_M unity_WorldToObject
#define UNITY_MATRIX_V unity_MatrixV
#define UNITY_MATRIX_VP unity_MatrixVP
#define UNITY_MATRIX_P glstate_matrix_projection#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl"#endif

可以定位到对应的Core文件中看到顶点空间变换调用的函数代码SpaceTransform.hlsl:

float3 TransformObjectToWorld(float3 positionOS)
{return mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0)).xyz;
}float4x4 GetObjectToWorldMatrix()
{return UNITY_MATRIX_M;
}float4 TransformWorldToHClip(float3 positionWS)
{return mul(GetWorldToHClipMatrix(), float4(positionWS, 1.0));
}float4x4 GetWorldToHClipMatrix()
{return UNITY_MATRIX_VP;
}

批处理

SRP批处理器

它在GPU上缓存了材质属性,所有材质属性都需要在具体的存储缓冲区内定义,而不是在全局级别上定义。它通过将指定属性放入特定的常量内存缓冲区中来隔离它,尽管它仍可在全局级别访问。

并非所有平台(例如OpenGL ES 2.0)都支持常量缓冲区,因此,我们可以使用核心RP库中包含的CBUFFER_START和CBUFFER_END宏,而不是直接使用cbuffer。

在这个示例中,如果我们使用特定的一组值,则需要全部定义它们。对于转换组,即使我们不使用它,我们也需要包括float4 unity_LODFade。顺序无关紧要,但是Unity会将其直接放在unity_WorldToObject之后,因此我们也要这样做。

在渲染管线中开启SRP批处理程序,调用:

GraphicsSettings.useScriptableRenderPipelineBatching设置为true

唯一的限制是每种材质的内存布局需要相同,这是因为我们对所有材质都使用相同的着色器,每个着色器仅包含一个颜色属性。Unity不会比较材质的确切内存布局,它只是仅批处理使用完全相同的着色器变体的绘制调用。

GPU Instancing

还有一种合并DrawCall的方法,该方法适用于逐对象的材质属性。这就是所谓的GPU实例化(GPUInstancing),其工作原理是一次对具有相同网格物体的多个对象发出一次绘图调用。CPU收集所有每个对象的变换和材质属性,并将它们放入数组中,然后发送给GPU。然后,GPU遍历所有条目,并按提供顺序对其进行渲染。

在Unlit.shader文件中添加预编译指令,生成具有GPU实例化支持和不具有GPU实例化支持的两个变体。

在Common.hlsl中包括对GPU实例化的支持:

UnityInstancing.hlsl的作用是重新定义这些宏来访问实例数据数组。将输入结构修改为结构用作函数的输入参数,并将UNITY_VERTEX_INPUT_INSTANCE_ID放在属性中来添加它,然后在输入时,添加UNITY_SETUP_INSTANCE_ID(input); 在UnlitPassVertex的开头。这将从输入中提取索引,并将其存储在其他实例化宏所依赖的全局静态变量中。

struct Attribute
{float3 positionOS : POSITION;UNITY_VERTEX_INPUT_INSTANCE_ID
};float4 UnlitPassVertex(Attribute input) : SV_POSITION
{UNITY_SETUP_INSTANCE_ID(input);float3 positionWS = TransformObjectToWorld(input.positionOS);return TransformWorldToHClip(positionWS);
}

现在尚不支持逐实例的材质数据。如果要添加的话,通过用UNITY_INSTANCING_BUFFER_START替换CBUFFER_START以及用UNITY_INSTANCING_BUFFER_END替换CBUFFER_END来完成。

然后,将_BaseColor的定义替换为UNITY_DEFINE_INSTANCED_PROP(Float 4,_BaseColor)。

UNITY_INSTANCING_BUFFER_START(UnityPerMaterial)UNITY_DEFINE_INSTANCED_PROP(float4, _BaseColor)
UNITY_INSTANCING_BUFFER_END(UnityPerMaterial)

使用实例化时,我们现在还需要在UnlitPassFragment中提供实例索引。为了简单起见,我们将使用一个结构,通过UNITY_TRANSFER_INSTANCE_ID(input,output)使UnlitPassVertex输出位置和索引。复制索引(如果存在)。我们像Unity一样命名此结构Varying,因为它包含的数据在同一三角形的片段之间可能会有所不同。

将此结构作为参数添加到UnlitPassFragment。然后像以前一样使用UNITY_SETUP_INSTANCE_ID来使索引可用。现在需要通过UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial,_BaseColor)访问material属性。

struct Varyings {float4 positionCS : SV_POSITION;UNITY_VERTEX_INPUT_INSTANCE_ID
};Varyings UnlitPassVertex(Attributes input)
{Varyings output;UNITY_SETUP_INSTANCE_ID(input);UNITY_TRANSFER_INSTANCE_ID(input, output);float3 positionWS = TransformObjectToWorld(input.positionOS);output.positionCS = TransformWorldToHClip(positionWS);return output;
}float4 UnlitPassFragment(Varyings input) : SV_TARGET
{UNITY_SETUP_INSTANCE_ID(input);return UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _BaseColor);
}

请注意,基于目标平台以及每个实例需要提供的数据量,批处理大小是有限制的。如果超过此限制,那么最终将导致一批以上。此外,如果使用多种材质,分类仍可以拆分批次。

配置批处理

那种方式更好可能取决于很多因素,所以把它们处理成可配置的选项会更好。首先,添加布尔参数以控制是否将动态批处理和GUI实例化用于DrawVisibleGeometry,而不是对其进行硬编码。

相关代码如下:

创建透明和裁切的材质

Blend模式

不透明渲染和透明渲染之间的主要区别是,我们是替换之前绘制的任何内容还是与之前的结果结合以产生透视效果。可以通过设置源和目标混合模式来控制。这里的源是指现在绘制的内容,目标是先前绘制的内容,以及最终产生的结果。为此添加两个着色器属性:_SrcBlend和_DstBlend。它们是blend modes的枚举,我们可以使用的最佳类型是Float,默认情况下将源设置为1,将目标设置为零。

为了简化编辑,我们可以将Enum添加到properties中,并使用完全限定的UnityEngine.Rendering.BlendMode枚举类型作为参数。

可以在Pass块中使用Blend语句和两个模式来定义混合模式。想使用着色器属性,可以通过将其放在方括号内来访问它们。这是可编程着色器之前的远古语法。

不写入深度

纹理化

向着色器添加_BaseMap纹理属性

在UnlitPass.hlsl中的着色器属性之前执行:

使用名为TEXTURE2D的宏参数,将纹理传到GPU内存。

通过SAMPLER宏实现,在名称前添加了sampler。用来匹配Unity自动提供的采样器状态。

TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);

在UnityPerMaterial缓冲区中添加提供纹理的平铺和偏移属性,但附加了_ST,代表缩放和平移等。

定义纹理坐标:

在片元着色器函数中,添加baseUV的定义

修改顶点着色器中复制纹理坐标,

float4 baseST = UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _BaseMap_ST);
output.baseUV = input.baseUV * baseST.xy + baseST.zw;

在片元着色器中,通过使用SAMPLE_TEXTURE2D宏对纹理,采样器状态和坐标作为参数,对纹理进行采样。最终颜色是通过乘法相结合的纹理和单一颜色。

Alpha裁剪

完成此操作的通常方法是定义一个截止阈值。alpha值低于此阈值的片段将被丢弃,而所有其他片段将保留。添加一个_Cutoff属性,默认情况下将其设置为0.5。由于alpha始终位于零和1之间,因此我们可以使用Range(0.0,1.0)作为其类型。

同样将其添加到UnlitPass.hlsl的材质属性中。

通过调用UnlitPassFragment中的clip函数来丢弃片段。如果我们传递的值为零或更小,它将中止并丢弃该片段。因此,将最终的alpha值(可通过a或w属性访问)减去截止阈值传递给它。

添加一个控制着色器裁剪的关键字的Toggle属性,我们将使用_CLIPPING。属性本身的名称无关紧要,因此只需使用_Clipping。

将#pragma shader_feature _CLIPPING添加到其Pass中的指令中。

它将生成一个或两个变体,可以使代码以定义为条件:

Unity SRP系列——DrawCalls相关推荐

  1. bat比较有意思的代码_腾讯开源的 Unity全系列 代码逻辑热修复方案--InjectFix

    InjectFix 腾讯开源的 Unity 代码逻辑热修复方案 Unity代码逻辑热修复 可用于Unity业务的bug修复,支持Unity全系列,全平台. 几个亮点 直接在Unity工程上修改C#即可 ...

  2. Unity SRP自定义渲染管线 -- 1.Custom Pipeline

    该篇是对Catlike Coding这篇文章的概要总结,本人能力有限,如果有不正确的地方欢迎指正  https://catlikecoding.com/unity/tutorials/scriptab ...

  3. Unity SRP Batcher的工作原理

    抓手 根据我的理解总结,SRP Batcher就是 1.把调用draw call前,一大堆CPU的设置工作给一口气处理了,增加了效率. 2.把材质的属性数据直接永久放入到显卡的CBUFFER里,那只要 ...

  4. unity两个项目合并 同名_从实际项目升级中关于 Unity SRP 的一些评测

    Untiy 推出SRP 已经接近一年了,其中官方宣称 LWRP 在2018年年底时已经处于 production ready 既随时可以做产品了,于是改名为URP, 不过 HDRP 还需要2019.4 ...

  5. Unity SRP自定义渲染管线 -- 2.Custom Shaders

    本章将接着上一篇文章,在初步实现一个渲染管线后来创建自定义的shader.上一篇文章的链接 https://blog.csdn.net/yinfourever/article/details/9051 ...

  6. Unity SRP自定义渲染管线 -- 3.Lights

    Lights Single-Pass Forward Rendering 实现 diffuse shading. 支持 directional(方向光), point(点光源), and spotli ...

  7. Unity SRP初识之URP

    URP是Unity基于SRP提供的兼顾表现与性能的渲染管线.URP前身命名为LWRP(轻量级渲染管线),后更名为URP. URP已包含在新建工程的工程模板中 URP使用简化的基于物理的照明和材质来实现 ...

  8. Catlike Coding Unity教程系列 中文翻译 Basics篇(一)Game Objects and Scripts

    游戏对象和脚本 原文地址:https://catlikecoding.com/unity/tutorials/basics/game-objects-and-scripts/ 本次教程的主要内容: 用 ...

  9. Unity SRP URP HDRP 的区别

    https://blog.csdn.net/weixin_41622043/article/details/107623694 1.Build-In Render 内置渲染器(默认)兼容太多,反而不能 ...

最新文章

  1. %3cphp和%3c php_关于 PHP 表单安全性
  2. 详细分析 apache httpd 反向代理的用法
  3. 魔兽世界美服部落人数最多服务器,魔兽世界全球服务器最新人口普查,其实并没有你想象的那么少...
  4. 手机轮廓光怎么拍_摄影技巧:怎么拍影子?手机拍照教程
  5. SpringMVC与Mybatis整合---SpringMVC学习笔记(六)
  6. Visual Studio:error MSB8020
  7. 通过 Continual Learning 提高 ML.NET 模型准确性并增强性能
  8. iptables禁止端口和开放端口
  9. vim python补全_转:VIM python 自动补全插件:pydiction
  10. ev3编码软件linux,机器人编程软件下载 乐高ev3机器人编程软件(LEGO MINDSTORMS EV3 Home Edition)V1.3.1 中文安装版 下载-脚本之家...
  11. linux下mysql命令大全_linux下mysql命令大全
  12. 2.Zigbee串口发送
  13. Ciprian Manolescu 解决了三角解剖猜想
  14. Spring Security系列(一)——登录认证基本配置
  15. 大数据学习的第一课-大数据概论和技术原理
  16. cad lisp程序大集_cad lisp程序
  17. excel中表格行高最大值是多少?如果超过了怎么调整?
  18. gpedit.msc 打不开
  19. Python中的虚拟变量(dummy variables)
  20. Spring Cloud Alibaba微服务架构实战教程—07集成knife4j生成Api文档

热门文章

  1. ROS掉包侠修炼计划
  2. ZedBoard+Vivado(一)——纯PL实现流水灯
  3. 关于光猫连接无线路由设置问题
  4. chart.js 饼图显示百分比_干货收藏 | 用matplotlib和Pyecharts花式绘制饼图
  5. 字体属性-参数图解-基线
  6. 了解一下chirp,扫频信号的生成
  7. Java库和框架之间到底有什么区别?
  8. PostgreSQL使用Navicat连接pgsql时出现authentication method 10 not supported的解决办法
  9. 全球名校AI课程库(43)| 李宏毅 · 机器学习(深度学习)课程『Machine Learning』
  10. launcher3 修改文件夹图标九宫格显示