手写URP-Shader代码框架-无光照Shader框架
一、Unlit Shader Framework(书写整体框架)
一个框架需要有下面的整体框架外,还需要支持:
- 透明剔除
- 提出模式选择
- 阴影渲染
- 支持Depth Priming选项
1.1 整体代码结构如下
- 创建一个unity新场景basic (URP)
- 创建一个unlit shader (命名为ShaderFramework)
- 写好shader后右键create->material
- 然后拖拽到场景中的某个物体上

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| Shader "UrpFramework/Unlit" { Properties { _BaseMap("Base Map",2d) = "white"{} _BaseColor("Base Color",Color) = (1,1,1,1) } SubShader { Tags { "RenderPipeline" = "UniversalPipeline" "RenderType" = "Opaque" "Queue" = "Geometry" }
HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" CBUFFER_START(UnityPerMaterial) TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap); float4 _BaseMap_ST;
float4 _BaseColor; CBUFFER_END ENDHLSL
Pass { Name "Unlit"
HLSLPROGRAM
#pragma vertex UnlitPassVertex #pragma fragment UnlitPassFragment
struct Attributes { float4 positionOS :POSITION; float2 uv :TEXCOORD0; float4 color :COLOR; };
struct Varyings { float4 positionCS :SV_POSITION; float2 uv :TEXCOORD0; float4 color :COLOR; };
Varyings UnlitPassVertex(Attributes IN) { Varyings OUT = (Varyings)0;
VertexPositionInputs positionInputs = GetVertexPositionInputs(IN.positionOS.xyz);
OUT.positionCS = positionInputs.positionCS; OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap); OUT.color = IN.color;
return OUT; }
half4 UnlitPassFragment(Varyings IN) :SV_TARGET { half4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);
return baseMap * _BaseColor * IN.color; } ENDHLSL } } }
|
二、Alpha Test(透明剔除)
- ShaderFramework创建一个material 命名为Leaf
- unity场景中新建一个quad
- 将Leaf拖拽到quad上
2.1 透明剔除及代码(⭐)
未进行透明剔除时

- 剔除代码:
或
- 具体代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| half4 UnlitPassFragment(Varyings IN) :SV_TARGET { half4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);
if (baseMap.a < 0.5) discard;
return baseMap * _BaseColor * IN.color; }
|
- 方案二: clip(param) -当param值小于0 则剔除
1 2 3 4 5 6 7 8 9 10 11
| half4 UnlitPassFragment(Varyings IN) :SV_TARGET { half4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);
clip(baseMap.a-0.5)
return baseMap * _BaseColor * IN.color; }
|
- 剔除效果

2.2 增加剔除代码开关(变体)
避免同一个shader的不同材质都同时剔除或者不剔除
- 方法: 变体 配合 #ifdef #endif 使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| Properties { [Toggle(_ALPHATEST_ON)] _AlphaTestToggle("Alhpa Clipping", Float) = 0 _Cutoff("Alpha Cutoff", Float) = 0.5 }
shader {
HLSLINCLUDE float _Cutoff; ENDHLSL
Pass { #pragma shader_feature _ALPHATEST_ON
half4 UnlitPassFragment(Varyings IN) :SV_TARGET { half4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv);
#ifdef _ALPHATEST_ON clip(baseMap.a - _Cutoff); #endif
return baseMap * _BaseColor * IN.color; } } }
|
- 效果

三、Cull Mode(剔除模式)
- 目前树叶背面不可见

3.1 设置Cull Mode
方案: Cull xxx
1 2 3 4 5 6 7 8 9
| Properties { [Enum(Off,0,Front,1,Back,2)]_Cull("Cull Mode", Float) = 2.0 //设置枚举类型。不剔除、正面剔除、背面剔除 }
Pass { Cull [_Cull] }
|
3.2 效果

四、阴影渲染
先在unity场景中新建一个Plane
4.1 方法1:简单方法
- 最简单的方法就是直接使用Unity写好阴影的pass
1 2 3 4 5
| shader { UsePass "Universal Render Pipeline/Lit/ShadowCaster" }
|
4.2 方法2:新增pass
- 阴影计算比较复杂,作为框架的展示,可以调用unity写好的阴影的顶点着色器和片元着色器

- 注意
由于之前的代码将下面的内容写入到了HLSLINCLUDE中,但新增的pass中也定义了TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);,所以不能放到HLSLINCLUDE了。需要单独放到使用该变量的具体pass中,或者换名也可以
1
| TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);
|
直接看代码和注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| Pass { Name "ShadowCaster" Tags{"LightMode"="ShadowCaster"}
ZWrite On ZTest LEqual
ColorMask 0 Cull [_Cull]
HLSLPROGRAM #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBED0_CHANNEL_A
#pragma multi_compile_instancing
#pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
#pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl"
ENDHLSL }
|
4.3 两种方法的最终效果一致

五、Depth Priming (支持Depth Priming选项)
- Depth Priming本身用于优化物体渲染的性能。

- 如果编写的shader不支持Depth Priming选项,在设置选择时,则会导致物体看不见

5.1 Depth Priming 需要新建一个pass(DepthOnly)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| Pass { Name "DepthOnly" Tags{"LightMode"="DepthOnly"}
ZWrite On ZTest LEqual
ColorMask 0
HLSLPROGRAM #pragma vertex DepthOnlyVertex #pragma fragment DepthOnlyFragment
#pragma shader_feature _ALPHATEST_ON #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBED0_CHANNEL_A
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/Shaders/DepthOnlyPass.hlsl" ENDHLSL }
|
- 效果

5.2 支持MSAA等一些复杂的效果 新建一个pass -DepthNormals
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| Pass { Name "DepthNoramls" Tags{"LightMode"="DepthNormals"}
ZWrite On ZTest LEqual
HLSLPROGRAM #pragma vertex DepthNormalsVertex #pragma fragment DepthNormalsFragment
#pragma shader_feature_local _NORMAL_MAP #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBED0_CHANNEL_A
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/Shaders/DepthNormalsPass.hlsl" ENDHLSL }
|