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

本章将接着上一篇文章,在初步实现一个渲染管线后来创建自定义的shader。上一篇文章的链接

 https://blog.csdn.net/yinfourever/article/details/90516602。在本章中,将完成以下内容:

  • 写一个HLSL Shader
  • 定义constant buffer(常量缓冲区)
  • 使用 Render Pipeline Core Library
  • 支持动态合批和GPU instancing

本章最后实现的效果如下图,多个不同颜色球体,只需要一个draw call

256个球体,只需要一个draw call

1.Custom Unlit Shader

1.1Creating a Shader

创建一个Shader,删掉所有自带的默代码,写入以下代码。

将上一章创建的Unlit Opaque material指定为使用我们创建的这个新shader。

1.2 HLSL

Unity 新的SRP渲染管线使用HLSL,所以我们自定义的渲染管线也使用HLSL,我们使用HLSLPROGRAM and ENDHLSL

 一个Shader至少应该包含vertex函数(顶点shader部分)和fragment函数(片元shader部分)。我们命名UnlitPassVertex for the vertex function and UnlitPassFragment for the other。但具体代码我们不在这个文件中实现,而是分离到一个单独的hlsl文件中,在这里include进来。

 在生成的Unlit.hlsl文件中,我们使用#ifndef来避免多次引用。之后,我们声明Vertex函数的输入参数结构体和输出参数结构体

在vertex shader中,讲输入参数传递给输出参数,在fragment shader中,返回1,这样就完成了一个最简单的shader架构,虽然参数还是有错误的(position参数没有进行坐标变换处理直接从vertex shader传入到了fragment shader) 

1.3 Transformation Matrices

从模型空间到裁剪空间需要两步转换,我们先用unity_ObjectToWorld矩阵转换到世界坐标空间,再用unity_MatrixVP矩阵转换到裁剪空间。

 我们可以通过一个小技巧来提高运算的效率,将input的position信息,从三维向量补齐成四维,可以大大加快运算效率。

1.4 Constant Buffers

Unity没有直接提供MVP矩阵二是拆开成提供两个矩阵M和VP是因为VP矩阵在一帧中不会改变,可以重复利用。Unity将M矩阵和VP矩阵存入Constant Buffer中以提高运算效率,M矩阵存入的buffer为UnityPerDraw buffer, 也就是针对每个物体的绘制不会改变。VP矩阵则存入的是UnityPerFrame buffer,即每一帧VP矩阵并不会改变。Constant Buffer并不是所有平台都支持,目前OpenGL就不支持。

使用cbuffer keyworld来引入Constant buffer,constant buffer中还有很多其他的数据,暂时我们用不到,只使用这两个矩阵

1.5 Core Library

  因为constant buffer并不是支持所有平台,所以我们使用宏来代替直接cbuffer keyword,使用CBUFFER_START 和CBUFFER_END 这两个宏需要使用Core Library,通过package manager可以安装。  安装成功后,在hlsl代码中引入common.hlsl就可以使用这两个宏了。

1.6 Compilation Target Level

我们使用#pragma target 指定shader level为3.5 代替默认的2.5,我们不支持OpenGL ES2那些老设备。

 

1.7 Folder Structure

我们调整下文件目录结构,使引用的文件都放入ShaderLibrary文件夹

2 Dynamic Batching

 现在使用我们新创建的这个shader去渲染大量球体时,可以看到每个球体各自占用一个draw call。在fram debugger中我们可以看到提示没有合批的原因是我们没有开启动态合批。

 

我们根据提示,即使打开了player setting中的Dynamic Batching option选项,依然不会有效果,这是因为player setting中设置的是unity默认的渲染管线,而我们现在使用的是自定义的渲染管线,所以需要代码手动控制我们自己的这个管线开启合批功能。

开启后,我们发现合批依然没有成功,根据提示,是因为物体的定点数太多,超过了动态合批的限制300。 

把球体换成顶点数很少的方体,动态合批就成功了,可以看到只有一个draw call 

2.2 Colors

当使用不同的material时,是不能动态合批的,为了证明这一点,我们加入color属性。

 将color属性存入constant buffer中

复制一份之前的material,将复制的material中的color属性设置为其他颜色,我们可以看到合批结果为4个draw call。 这是因为对于每个material至少会产生一个draw call,unity中为了避免overdraw,会根绝空间位置信息分组渲染,对于每个material,往往会多于一个draw call。

debugger中可以看到提示不能合批的信息为使用了不同的material。 

2.3 Optional Batching

动态合批是一个提升渲染效率的好方法,但是并不是所有时候都有效,甚至会拖慢渲染效率。当场景中并不存在大量使用相同material的小mesh的时候,动态合批就没什么用了,反而每帧关于动态合批的运算会降低效率。我们在自定义的渲染管线中加入一个bool值,来作为是否开启动态合批的开关。

 在MyPipeline的构造函数中,传入是否开启动态合批的bool值

 在render函数中根据drawFlags设置动态合批是否开启

 3 GPU Instancing

除了动态合批外,GPU Instancing也可以用于减少draw call。通过GPU Instancing,CPU告诉GPU在一个draw call中,渲染特定的mesh和material的组合多次。这使得使用相同mesh和material的物体渲染时不再像动态合批需要重新组成一个新的后批后的大mesh,这也就移除了对mesh大小的限制。

3.1 Optional Instancing

和之前的动态合批一样,我们也引入一个bool值控制是否开启GPU Instancing

 

 3.2 Material Support

渲染管线开启了GPU Instancing还不够,还需要使得material支持GPU Instancing,通过添加#pragma multi_compile_instancing来产生shader 变体,一个支持GPU Instancing一个不支持。在Editor中material的设置中可以看到是否开启GPU Instancing选项。

3.3 Shader Support

当GPU Instancing开启时,GPU会使用相同的constant data渲染同一个mesh多次。但是因为每个物体的位置不同,所以M矩阵就不同。为了解决这个问题,会在constant buffer中存入一个数组,用于存储待渲染的物体的M矩阵。每一个instance根据自身的index,从数组中取用数据。

我们使用unity提供的UNITY_MATRIX_M这个宏,在core library中的这个宏可以支持instancing,在使用矩阵数组的时候可以取出对应的矩阵

 使用该宏需要引用UnityInstancing.hlsl这个文件。

 当时用Instancing时,物体的index或被gpu传入顶点数据中,UNITY_MATRIX_M这个宏需要使用这个index数据,我们将Index数据加入到Vertex shader函数的输入结构体中,在Vertex Shader的处理函数中使用UNITY_SETUP_INSTANCE_ID 这个宏来使其生效。

 

 除了 object-to-world matrices, 默认 world-to-object矩阵也存在了constant buffer中。但是目前我们没有需求使用他们,所以可以通过#pragma instancing_options assumeuniformscaling去掉他们提高性能 

3.4 Many Colors

之前我们想实现一个场景中多个颜色的物体只能使用多个material,但是如果使用类似存储M矩阵的方式操作color属性,就可以实现用一个matrial渲染多种颜色物体。

首先创建一个脚本,包含要使用的color数据。

 其次通过MaterialPropertyBlock函数创建一个MaterialPropertyBlock实体,通过它来设置material中的颜色。这些操作写入了OnValidate函数中,使得在editor中可以看到颜色变化效果。

 通过去掉局部变量,可以优化效率。

这时就可以用一个material渲染多种颜色了,但是到目前为止,每个物体都会产生draw call 

 3.5 Per-Instance Colors

像M矩阵处理的方式一样,我们也将color属性以数组形式存入constant buffer中,在使用时通过index从数组中取出。

不同于M矩阵Unity已经帮我们处理好了,color属性需要我们自己手动创建constant buffer并存入其中

在vertex shader函数的输出中,也要把index数据传递到fragment shader函数中。在fragment shdare的处理函数中,根据index取用color数据

这时,我们只需使用一个material就能实现多颜色物体的渲染了,并且可以实现合并draw call。但是要注意的是constant buffer能存储多少数据是有限制的,最大数量的Instance取决于每个instance需要多少数据,除此之外,不同平台最大限制也不同。同时instance draw call的合并依然也要求需要是相同的mesh和material,比如下图中的方形和圆形虽然使用相同的material,但因为mesh不同所以依然需要不同的draw call进行渲染。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246009.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tcp 三次握手与四次挥手_TCP三次握手与四次挥手详解

TCP报文结构源端口和目的端口:各占2个字节,分别写入源端口号和目的端口号。序号:占4个字节。序号使用mod运算。TCP是面向字节流的,在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。故该字段也叫做“报文段序号”。确认序…

网关和路由器的区别_5G工业路由器与5G DTU的区别介绍详解

5G工业路由器和5G DTU都是实现无线网络数据传输功能,而两者间的区别主要从使用方法、外观接口以及应用环境等方面区分,今天给大家介绍5G工业路由器和5G DTU的一些不同点。使用方法的不同:5G工业路由器:5G路由器可对以太网、现场总线通信协议进…

7628刷breed_自制各类路由原厂直刷Breed的文件,无需修改mac无需重刷无线

本帖最后由 showme99 于 2017-3-25 16:35 编辑在原厂页面直接选择相应的刷机文件刷机,文件很小256K,大约十秒左右就自动进入Breed后直接刷入dd-wrt,opentwrt,gargoyle等固件即可。无需在Breed里设置MAC地址,也无需刷入ART无线文件&#xff0c…

c语言获取系统剩余内存_C语言编程中的“堆”和“栈”七大不同之处

更多精彩,请点击上方蓝字关注我们!对于编程初学者来说会接触到一些难以理解的名称,比如堆(heap)、栈(stack)、堆栈(stack)等。初学开发过程中往往让人混淆不清。今天我们来谈谈堆和栈的具体区别,来帮助初学者理清思路。堆和栈的区…

sql between包括两端吗_SQL大全

作者:静默虚空排版:MarkerHub原文:https://juejin.im/post/5c7e524af265da2d914db18f本文针对关系型数据库的一般语法。限于篇幅,本文侧重说明用法,不会展开讲解特性、原理。一、基本概念数据库术语数据库(database) -…

python交互模式什么意思_Python中的交互模式是什么

让开发者能快速学习、测试 Python 的各种功能,Python 提供的“python”命令不仅能用于运行 Python 程序,也可作为一个交互式解释器一一开发者逐行输入 Python 代码,它逐行解释执行。 当输入“python”命令时,可以看到如下输出结果…

idea创建springboot项目+mybatis_Spring Boot + MyBatis 多模块项目搭建教程

Java后端,选择“”优质文章,及时送达作者 | 枫本非凡链接 | cnblogs.com/orzlin/p/9717399.html上篇 | IDEA 远程一键部署 Spring Boot 到 Docker一、前言最近公司项目准备开始重构,框架选定为SpringBootMybatis,本篇主要记录了在…

下载nodejs的mysql安装包下载安装_Node.js安装 下载

1、安装Node.jshttps://nodejs.org/en/安装步骤:点击安装包按提示进行安装Node.js 安装配置本章节我们将向大家介绍在 Windows 和 Linux 上安装 Node.js 的方法。本安装教程以 Node.js v4.4.3 LTS(长期支持版本)版本为例。你可以根据不同平台系统选择你需要的 Node.…

redistemplate注入为null_Windows DLL 注入技术

Windows DLL 注入技术 本文主要介绍四种常见的 Windows DLL 注入技术。分别为全局钩子、远线程钩子、突破 SESSION 0 隔离的远线程注入和 APC 注入。全局钩子注入Windows 中大部分应用是基于 Windows 的消息机制,Windows提供截获这些消息的钩子函数。根据钩子作用的…

nginx location 正则表达式匹配多个地址_就是要让你搞懂Nginx,这篇就够了!

Nginx 是一个高性能的 HTTP 和反向代理服务器,特点是占用内存少,并发能力强,事实上 Nginx 的并发能力确实在同类型的网页服务器中表现较好。Nginx 专为性能优化而开发,性能是其最重要的要求,十分注重效率,有…

mysql查询网址_bootstrap+flask+mysql实现网站查询

之前那篇文章是flaskredis的,如果用flaskmysql怎么实现呢?创建数据库:CREATE DATABASE web12306 DEFAULT CHARACTER SET utf8;创建表:CREATE TABLE web12306 (user_email varchar(100) NOT NULL DEFAULT ,user_pass varchar(100)…

dubbo官方文档_不可忽视的Dubbo线程池

问题描述线上突然出现Dubbo超时调用,时间刚好为Consumer端设置的超时时间。有好几个不同的接口都报超时了第1次调用超时,第2次(或第3次)重试调用非常快(正常水平)Dubbo调用超时的情况集中出现了3次&#xf…

python中比较重要的几个函数_Python 几个重要的内置函数 python中的内置函数和关键字需要背过吗...

python重要的几个内置函数用法python内置函数什么用忘不掉的是回忆,继续的是生活,错过的,就当是路过吧。来来往往身边出现很多人,总有一个位置,一直没有变。看看温暖的阳光,偶尔还是会想一想。Python内置函…

netty worker线程数量_Dubbo线程模型

Dubbo中线程池的应用还是比较广泛的,按照consumer端到provider的RPC的方向来看,consumer端的应用业务线程到netty线程、consuemr端dubbo业务线程池,到provider端的netty boss线程、worker线程和dubbo业务线程池等。这些线程各司其职相互配合&…

function click_click事件的累加问题解决

click事件的 累加问题解决:$判断是否隐藏:hidden.c>span 只包含儿子.c span 包含儿子和孙子data-*嵌入自定义数据 .data(to)获取数据remove是移除标签 delete删除数组元素each()函数$(".layui-table-total .layui-table-cell").each(functi…

知道python语言应用2020答案_热点:大学moocPython语言基础与应用答案

2020年智慧树网课答案为您详细解读azMisb热点:大学moocPython语言基础与应用答案的详情,题主的教授应该是想要同学们找出一个值得研究和讨论的theory,简单来说就是你论文探讨的中心。然后需要你们定topic,然后搜索大量靠谱的资料,…

timestamp 转换 date mysql_MySQL时间函数 | 时间戳和日期之间得转换

一、时间戳转日期select FROM_UNIXTIME(1606028010, %Y-%m-%d %H:%i:%s);二、日期转时间戳select unix_timestamp(2018-01-15 09:45:16);三、时间戳格式化十位时间戳转为固定格式(yyyy-MM-dd HH:mm:ss)日期1.格式规定%M 月名字(January……December)%W 星期名字(Sunday……Satu…

python是一种动态语言这意味着_Python如何能成为全球最受欢迎的编程语言?该不该学Python?...

全文共3304字,预计学习时长10分钟 图源:(Python logo courtesy of https 有一种语言在过去十年受喜爱度一路飙升,成为最受欢迎的一种编程语言,它是谁? 千呼万唤始出来,没错,它就是我们的老弟Pyt…

python处理csv文件案例_让繁琐的工作自动化——python处理CSV文件

让繁琐的工作自动化——python处理CSV文件CSV:CSV文件是一种简化的电子表格,不同于Excle(二进制文件),CSV是纯文本文件。1.环境python3.8pycharm2020.12.读取本期实例数据haha,18,10.0jiji,16,12.1lala,17,11.9papa,11,13.3首先导入csv模块&a…

python实现坐标求取_根据相机位姿求指定点的世界坐标及其python实现

Authorshaniadolphin求解目的本文将展示位姿估计的一种应用,即通过单目相机对环境进行测量。简单来说,本文的工作就是利用下面的两幅图,在已知P1、P2、P3、P4四点世界坐标的情况下,计算出其它点的世界坐标。如图所示,一…