mastertravels77 发表于 2022-1-23 07:02

Unity渲染管线综述

基础概念

图形API

[*]OpenGL与DirectX:用于渲染2D、3D矢量图形的API。
[*]简易流水线:重复执行一个任务,多个步骤执行完,才重新开始任务。
[*]并行流水线:重复执行一个任务,前一个步骤执行完,仍会继续进行。
[*]渲染空间:Gamma空间或线性空间。
语言类

[*]GLSL:OpenGL的跨平台(没有着色器编译器)的着色语言。
[*]HLSL:DirectX的着色语言。
[*]CG:NVIDIA的跨平台(编译成中间语言)的着色语言。
[*]Shader:GPU流水线上的可编程环节。告诉计算机如何绘制画面的程序。
[*]ShaderLab:Unity提供的编写Unity Shader的一种说明性语言。
[*]语义:映射参数的变量名。(如: float4 position : SV_POSTION)
信息类

[*]材质:色彩、纹理、光滑度、透明度、反射率、折射率、发光度等。
[*]纹理(贴图、映射):根据Kershaw的术语,通过将投影方程运用于空间中的点 ,从而得到一组称为参数空间值的关于纹理的数值。
[*]渲染图元:渲染所需的几何信息。
[*]渲染状态:定义场景网格怎样被渲染的信息(Blend,Stencil,DepthTest等)。
[*]片元:很多状态信息的数据集合,用于计算每个像素的最终颜色。
计算类

[*]着色:根据材质属性、光源信息,使用一个等式(光照模型)去计算:沿某个观察方向的出射度的过程。
[*]Draw Call:每次CPU准备数据并通知GPU的过程。消耗的是CPU,不是GPU。
[*]插值:根据已知数据点,来预测未知数据点值的方法。
<hr/>图形渲染管线

《Real-Time Rendering 3rd》 提炼总结 - 图形渲染管线 - 毛星云的文章 - 知乎
GPU渲染管线

《Real-Time Rendering 3rd》 提炼总结 - GPU渲染管线与可编程着色器 - 毛星云的文章 - 知乎
Unity - BuildIn渲染管线


[*]【教程】技术美术入门:渲染管线概述_哔哩哔哩_bilibili,以下图片均为此节截图,讲得非常好。



1.buildin渲染流程



2.1应用程序阶段:剔除、排序



2.2.1模型信息



2.2应用程序阶段:打包数据



3. GPU渲染管线流程



3.1.1顶点shader:综述



3.1.2顶点shader:拍照过程



3.2硬件操作阶段



3.3.1片元shader:综述



3.3.2片元shader:纹理技术



3.3.3片元shader:光照技术框架



3.4.1输出合并



3.4.2输出合并:深度测试



3.4.3输出合并:提前深度测试:优化



3.4.4输出合并:混合



<hr/>Scriptable Renderer Pipeline(可编程渲染管线)

在Unity通过C#脚本调用一系列API配置和执行渲染命令的方式来实现渲染流程, SRP将这些命令传递给Unity底层图形体系结构,然后再将指令发送给图形API。
为什么要用这个东西?

[*]SRP的性能比Builtin内置管线好。解决渲染性能问题(URP:PASS绘制,最大程度的减少SetPassCall;内置很容易打断合批)。
[*]SRP提供源码,容易控制,比较好扩展,让美术效果可定制(可控制),让渲染性能更容易优化。
[*]自带支持PBR渲染管线(也支持非PBR内容)。
[*]解决了内置渲染管线渲染层级问题(内置渲染管线只有修改Renderqueue,改了通常也不稳定)。
[*]减小Blit操作(Blit会进行一次全屏拷贝,相当的消耗性能和带宽),URP可以手动调用Blit。
[*]便于特效实现(扭曲一般只对不透明物体生效。火焰使用半透明,管线定制可以覆盖这些效果)。
着色器变体

[*]Shader不建议使用if(非常高的消耗),那我们需要if怎么办?Keywords(宏)。
[*]每一种宏组合就是这个shader的一个变体
[*]官方文档
[*]Shader变体收集与打包
[*]打包中裁剪Shader变体
SRP Batcher

[*]SRP Batcher工作原理探究 - Xshadow的文章 - 知乎
若要适配SRP Batcher,得满足以下几点:
1.渲染的对象要是Mesh或Skinned Mesh,不能是粒子
2.Shader的写法要适配。uniform的变量要放在UnityPerDraw或者UnityPerMaterial的CBUFFER中
3.不能使用MaterialPropertyBlocks
4.若有多pass,则必须每个Pass的CBUFFER_START中的内容一致


图片来源《黑暗之潮》技术分享

<hr/>URP渲染管线

推荐文章

[*]URP核心代码学习
[*]Unity通用渲染管线学习 - 徒花的文章 - 知乎
切换到URP渲染管线

选择SRP



[*]HDRP目前不支持移动平台
[*]URP支持移动平台也支持PC
[*]URP不支持表面着色器(如果是表面着色器写的,无法转成URP)
切换管线


设置质量参数


BuildIn批量切换成URP - Shader


定制URP的内置管线
使用RenderObject:通过实现好的RenderFeature和RenderPass,可以在不用任何代码的情况下进行定制。



《黑暗之潮》URP最终定制的渲染管线

使用RenderObject有什么用?

[*]解决半透明物体渲染的不确定性。
在透明物体之前去渲染地面的layer(单独使用一个RenderObject)。

[*]透明物体实现扭曲的效果。
将复制ColorTexture的时机挪到透明物体之后,用单独的Pass去渲染需要扭曲的特效。
变化

与内置渲染管线功能对比

[*]相机变化



[*]Shader变化





[*]参数介绍
怎么把BuildInShader转成URPShader?

ASE、ShaderGraph连的,可以直接切换,但是要调对参数。
要改代码的话,先执行这2步:

[*]先用Edit/RenderPipeLine/Universal Render Pipleline/Upgrade试试
[*]直接切换材质球的Shader为Lit
不得行,需要改Shader如下,自行尝试:

[*]CG关键字改成HLSL关键字(虽然可以用CG,但是要用Unity的HLSL库)
[*]FallBack改成:FallBack "Hidden/Universal Render Pipeline/FallbackError"
[*]SubShader:新增Tags{"RenderPipeline" = "UniversalPipeline"}
[*]Pass:Tags { "LightMode" = "ForwardBase" } 要改成 { "LightMode" = "UniversalForward" }(或其他更多模式)
[*]光照库替换
#include "Lighting.HLSLinc"
替换为

Tags{"LightMode" = "UniversalForward"}:
#include "LitInput.hlsl"
#include "LitForwardPass.hlsl"

Tags{"LightMode" = "ShadowCaster"}:
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl"

[*]查阅
内置结构体、函数
Packages/Universal RP/ShaderLibrary/Input
Packages/Universal RP/ShaderLibrary/Core

内置函数、矩阵
Packages/Universal RP/ShaderLibrary/UnityInput关于UI在Gamma空间工作,但使用了线性空间

3D美术需要在基于PBR的高清的线性空间下工作,但常规的UI美术平时习惯于在Gamma空间工作。
UI的美术不太适应线性空间的流程,也不太适用线性空间下的颜色在他们的自产工具里进行产出。(PS - Gamma转线性后,颜色差别很大)
但游戏内需要使用线性空间下的流程,所以为了解决冲突,进行了分辨率分离:
使用单独的场景摄像机在线性空间下绘制,然后与UI相机进行blend,最后输出到屏幕上。场景空间的相机最后需要进行Gamma校正,而UI相机本身就是Gamma空间,所以不需要校正。如何写一个同时兼容Build-in和URP的shader?(补全中)

UnityShader编程指南

基础渲染系列(二)——着色器(必读)
编写原则和经验

[*]不建议在编写Shader时,使用分支或者循环语句,会降低GPU并行处理操作
[*]从性能考虑,尽量把计算放在顶点着色器中去执行
[*]ShaderLab中函数和变量要先声明再调用
[*]避免重复绘制,尽可能设置渲染队列为不透明物体的渲染队列
[*]在Unity中,渲染队列小于2500(不透明)的对象,从前往后绘制;其他的队列的物体,从后往前绘制。
表面着色器

[*]Unity自创的着色器(Surf),顶点/片元着色器的子集
[*]自动实现光照模型,为我们处理很多光照细节
[*]代码量少,不需要Pass代码段。但渲染代价稍高(它在后面仍会转换成顶点/片元着色器)
[*]适合:光照数多
顶点/片元着色器

[*]代码量多,自己定义每个Pass需要使用的Shader,更灵活地控制渲染细节
[*]适合:光照数少、有很多自定义渲染效果
固定着色器
适配很旧的设备(iphone3)时才会用。
Cg/HLSL

内置变量
【变换矩阵】

模型空间 = 对象空间
投影空间 = 裁剪空间
相机空间 = 观察空间
M:模型矩阵
V:相机矩阵
P:投影矩阵

UNITY_MATRIX_MVP:模型空间->投影空间  

UNITY_MATRIX_MV:模型空间->相机空间

UNITY_MATRIX_V:世界空间->相机空间     

UNITY_MATRIX_P:相机空间->投影空间     

UNITY_MATRIX_VP:世界空间->投影空间  

_Object2World:模型空间->世界空间

_World2Object:世界空间->模型空间

UNITY_MATRIX_T_MV:UNITY_MATRIX_MV的转置矩阵

UNITY_MATRIX_IT_MV:UNITY_MATRIX_MV的逆转置矩阵

//unity5.6以前的写法
o.vertex = mul(UNITY_MATRIX_MVP,v.vertex);   

//unity5.6以后的写法
o.vertex = UnityObjectToClipPos(v.vertex);基础模板
Shader "Custom/MyShader" {//定义Shader的名字和位置
    Properties {//声明一些能在材质面板中调整的属性
      Name ("displayname", PropertyType) = value
    }
    SubShader {
        Tags{"name"="value"}
        //应用于所有Pass
       
        Pass{//每个Pass定义一次完整渲染流程(Pass过多会造成渲染性能低下)
        Tags{"name"="value"}
        //应用于此Pass
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
                struct a2v{
                        float4 vertex : POSITION;
                        float3 noraml : NORMAL;
                }
                struct v2f{
                        float4 pos : SV_POSITION;
                        float3 color : COLOR;
                }
                v2f vert(a2v a){
                       v2f v;
                       //code
                       return v;
                }
                fixed4 frag(v2f v) : SV_Target{
                       fixed4 f;
                       //code
                       return f;
                }
        ENDCG
        }
        Fallback "Diffuse" //以上都无法应用时,使用此Shader 或者 关闭
    }
}基础类型
Shader "Custom/MyShader" {
    Properties {
                //属性类型
                _Int("Int",Int) = 2
                _Float("Float",Float) = 1.5
                _Range("Range",Range(0.0,5.0)) = 3.0
               
                _Color("Color",Color) = (1,1,1,1)
                _Vector("Vector",Vector) = (2,3,6,1)
               
                _2D("2D",2D) = ""{}//花括号原本用来指定纹理属性,但在Unity5.0后被移除了
                _Cube("Cube",Cube) = "white"{}
                _3D("3D",3D) = "black"{}
    }
    SubShader {
                //标签类型
                Tags{"Queue"="Transparent+1"} //指定该物体属于哪一个渲染队列
                Tags{"RenderType"="Opaque"} //对着色器进行分类
                Tags("DisableBatching"="True"} //批处理
                Tags {"ForceNoShadowCasting"="True"} //投射阴影
                Tags{"IgnoreProjector"="True"} //半透明
                Tags{"CanUseSpriteAtlas"="False"} //Sprite图集
                Tags{"PreviewType"="Plane"} //预览类型
               
                //状态类型
                Cull Back / Front / Off 剔除模式
                ZTest Less Greater|LEqual| GEqual|Equal |NotEqual | Always 设置深度测试时使用的函数
                ZWrite On|Off 开启/关闭深度写入
                Blend Srcactor DstFactor 开启并设置混合模式
      
                Pass{
                //状态类型 同上
                //标签类型
                Tags{"LightMode"="ForwardBase"} //定义该Pass在Unity的渲染流水线中的角色
                Tags {"RequireOptions"="Soft Vegetation"} //满足某些条件时才渲染该Pass
                }
        }CGPROGRAM类型
Pass {
                CGPROGRAM
                //Unity内置文件
                UnityCG.cginc 包含了最常使用的帮助函数、宏和结构体等
                UnityShaderVariables.cginc编译UnityShader时,会自动包含。包含了许多内置的全局变量
                Lighting.cginc 包含了各种内置的光照模型;编写的是Surface Shader的话,会自动包含进来
                HLSLSupport.cginc 编译UnityShader时,会被自动包含。声明了很多用于跨平台编译的宏和定义
               
                //ShaderLal属性类型 与 CG变量类型 匹配关系
                Color,Vector - float4,half4,fixed4
                Range,Float - float,half,fixed
                2D - sampler2D
                Cube - samplerCube
                3D - sampler3D
               
                //3种精度
                float 最高精度,桌面GPU上 float = half = fixed
                half 中等精度,手机GPU上 half = fixed
                fixed 最低精度,尽量使用此类型(优化)
               
                //从应用阶段传递模型数据给顶点着色器时,Unity支持的常用语义
                POSITION 模型空间中的顶点位置,通常是float4类型
                NORMAL 顶点法线,通常是float3类型
                TANGENT 顶点切线,通常是float4类型
                TEXCOORDn 该顶点的纹理坐标,n=0表示第一组纹理坐标,依此类推。通常是float2或float4类型
                COLOR 顶点颜色,通常是fixed4或float4类型
                //其余的全部用half
               
                //从顶点着色器传递数据给片元着色器时,Unity使用的常用语义
                SV_POSITION 裁剪空间中的顶点坐标,结构体中必须包含一个用该语义修饰的变量
                COLOR0 通常用于输出第一组顶点颜色,但不是必需的
                COLOR1 通常用于输出第二组顶点颜色,但不是必需的
                TEXCOORD0~TEXCOORD7 通常用于输出纹理坐标,但不是必需的
               
                //片元着色器输出时Unity支持的常用语义
                SV_Target 输出值将会存储到渲染目标(render target)中
                ENDCG
        }<hr/>附录


[*]新版Unity shader库为什么用HLSL,而不用CG了? - 文礼的回答 - 知乎
调试


[*]在CGPROGRAM或HLSLPROGRAM内加入
[*] pragma enable_d3d11_debug_symbols
页: [1]
查看完整版本: Unity渲染管线综述