深入URP之Shader篇1: URP Shader概述
Posted n5
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入URP之Shader篇1: URP Shader概述相关的知识,希望对你有一定的参考价值。
关于本系列
使用和学习研究Unity URP已经两年多了,最近也一直在做基于URP的项目的Shader优化工作。发现学习研究URP的Shader代码是理解URP渲染机制的一个非常好的方式,因为无论渲染管线如何架构,Unity内置的渲染机制如何设计,最终都要落在Shader代码上去将这一切渲染出来。在研读URP以及SRP Core的Shader代码的过程中,经常会有原来如此的感叹,这样会对Unity/URP的渲染机制有更清晰和更深刻的认识。另一方面,URP/SRP自带的Shader代码是我们学习写SRP自定义Shader的非常好的材料,URP Shader代码中会调用URP Shader Library和SRP Shader Library中的Shader代码,这些代码是Unity提炼出来的公共核心代码,很好的掌握它们的使用,可以让我们写自己的Shader更加轻松,并且增强Shader的可读性。本系列文章以分析URP自带的Shader代码为线索,并一路挖掘相关的Library代码,以及这背后的渲染机制。同时本系列文章也会用一定篇幅讲解如何编写自定义的Shader代码,并兼容于SRP Batcher和GPU Instancing。
URP Shader简介
我们知道,URP和HDRP都是基于SRP的,尽管现在可以使用Shader Graph编写Shader,但是手写Shader仍然是有一定的优势,特别是在性能方面,手写Shader可以更极致的优化,因此我们在项目中前期都是直接使用Shader Graph编写Shader,项目后期会改成手写Shader来提高性能。而在SRP中手写Shader,我们仍然使用的是Shader Lab,这个结构并没有太大的变化,但是SRP Shader中使用Shader Lab语言还是有几点不同。
- 首先,我们使用 HLSL 而不是 CG语言,尽管这不是强制的,但是HLSL是官方推荐的,并且URP的Shader都是HLSL编写的,包括Shader Library中的核心公共代码。因此在编写SRP Shader时,HLSL是最佳选择。
- SubShader的Tags,需要指定RenderPipeline,例如
"RenderPipeline" = "UniversalPipeline"
表示这是一个URP的Shader。
SubShader
Tags "RenderType" = "Opaque" "IgnoreProjector" = "True" "RenderPipeline" = "UniversalPipeline" "ShaderModel"="4.5"
- Pass的Tags中的LightMode和内置流水线不同,这是由于URP的渲染管线和内置管线不同,在内置管线中,LightMode表示了这个Pass处于管线中处理光照的哪个步骤,例如
ForwardBase
,ForwardAdd
分别是前向流水线中的主光照pass和附加逐像素光照pass。而URP中,我们经常使用的有SRPDefaultUnlit
,UniversalForward
,ShadowCaster
,DepthOnly
等pass。这些LightMode表示了管线中不同步骤(pass)使用的Shader Pass。具体可参考文档URP ShaderLab Pass tags - 为了兼容SRP Batcher,Shader需要采用一些特殊的写法。简单来说,就是对于Properties中的属性,需要放到特定的CBuffer中,这个CBuffer的名字为
UnityPerMaterial
。另外对于Unity的内置属性,要放到UnityPerDraw
的CBuffer中,且符合Unity的规则,这个我们在分析URP Shader代码时会看到。 - 再提一个,如果要支持GPU Instancing,Shader代码还要使用另外的一组宏来修改,使得可以支持Instancing。这组宏其实也是支持SRP Batcher的,这个会有一篇文章详细说明。
URP Shader框架
在结束本篇之前,我们来看一个简单的URP Shader框架,以便对于URP Shader的整体结构有一个具体的认识。
Shader "Custom/URPShaderTemplate"
Properties
_BaseMap ("Main Texture", 2D) = "white"
_BaseColor ("Tine Colour", Color) = (1, 1, 1, 1)
SubShader
Tags "RenderType"="Opaque"
"Queue"="Geometry"
"RenderPipeline"="UniversalPipeline"
HLSLINCLUDE
ENDHLSL
Pass
Name "Example"
Tags "LightMode"="UniversalForward"
HLSLPROGRAM
ENDHLSL
这个结构中包含了Properties, SubShader, Pass三件套,我们注意到HLSL代码除了是写在Pass中之外,还可以写在SubShader中,一般这儿会include一些公共代码。这个结构很简单,没有处理SRP Batcher兼容。下篇中,我们将分析真正的URP Shader: Unlit.shader。
基础的Unity URP Shader
Shader "BaseURPShader"
Properties
_Color("Color",COLOR)=(1,1,1,1)
_MainTex("MainTex",2D)="white"
SubShader
Tags
"RenderPipeline"="UniversalPipeline"//渲染管线标记,标注当前SubShader是给URP渲染管线使用的
"RenderType"="Opaque"//渲染方式为不透明
"UniversalMaterialType" = "Unlit"
"Queue"="Geometry"
Pass //主Pass
Name "Pass"
Tags
// LightMode: <None>
Cull Back
Blend One Zero
ZTest LEqual
ZWrite On
HLSLPROGRAM
#pragma target 4.5
//只在以下平台进行编译
//#pragma exclude_renderers gles gles3 glcore
//定义顶点着色器
#pragma vertex vert
//定义片段着色器
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
//顶点着色器的输入(模型的数据信息)类似于appdate
struct Attributes
float3 positionOS : POSITION;
float2 uv:TEXCOORD;
;
//顶点着色器输出
struct Varyings
float4 positionCS : SV_POSITION;
float2 uv:TEXCOORD0;
;
CBUFFER_START(UnityPerMaterial)
half4 _Color;
float4 _MainTex_ST;
TEXTURE2D(_MainTex);//纹理的定义,如果是编译到GLES2.0平台,则相当于sampler2D _MainTex;否则就相当于Texture2D _MainTex
SAMPLER(sampler_MainTex);//采样器的定义,如果是编译到GLES2.0平台,就相当于空,否则就相当于SamplerState sampler_MainTex
// SAMPLER(SamplerState_Point_Repeat);根据传入的名称选择采样模式,比如该传入的名称代表贴图采样的Wrap Mode为Repeat,Fiter Mode为Point
CBUFFER_END
//v2f vert(appdata v)
//顶点着色器
Varyings vert(Attributes v)
Varyings o = (Varyings)0;
float3 positionWS=TransformObjectToWorld(v.positionOS);
o.positionCS=TransformWorldToHClip(positionWS);
o.uv=TRANSFORM_TEX(v.uv,_MainTex);
return o;
//fixed4 frag(v2f i):SV_TARGET
//片断着色器
half4 frag(Varyings i) : SV_TARGET
half4 c;
half4 mainTex=SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv);
c=mainTex*_Color;
return c;
ENDHLSL
FallBack "Hidden/Shader Graph/FallbackError"
以上是关于深入URP之Shader篇1: URP Shader概述的主要内容,如果未能解决你的问题,请参考以下文章
Unity商业Shader渲染-URP-基于AmplifyShader Editor