URP的多Pass和Features用法

news/2024/10/18 7:49:05/

回到目录

大家好,我是阿赵。这里用一个传统的描边例子来说明一下,URP下怎么使用多Pass和Features。

一、传统多Pass描边

最常用的制作描边方法,就是写多一个Cull Front的Pass,然后通过法线方向扩展顶点,模拟描边的效果。
如果用HLSL来写,代码会是这样的:

Shader "azhao/UnlitOutlineBase"
{Properties{_MainTex ("Texture", 2D) = "white" {}_outlineLen("outlineLen",float) = 0.02}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{Cull BackHLSLPROGRAM#pragma vertex vert#pragma fragment frag#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/core.hlsl"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 pos : SV_POSITION;};CBUFFER_START(UnityPerMaterial)sampler2D _MainTex;float4 _MainTex_ST;CBUFFER_ENDv2f vert (appdata v){v2f o;VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);o.pos = vertexInput.positionCS;o.uv = TRANSFORM_TEX(v.uv, _MainTex);return o;}half4 frag (v2f i) : SV_Target{// sample the texturehalf4 col = tex2D(_MainTex, i.uv);return col;}ENDHLSL}Pass{Cull FrontHLSLPROGRAM#pragma vertex vert#pragma fragment frag#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/core.hlsl"struct appdata{float4 vertex : POSITION;float3 normal :NORMAL;};struct v2f{float4 pos : SV_POSITION;};CBUFFER_START(UnityPerMaterial)float _outlineLen;CBUFFER_ENDv2f vert(appdata v){v2f o;float4 pos = mul(UNITY_MATRIX_MV, v.vertex);float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);normal.z = -0.5;pos = pos + float4(normalize(normal), 0) * _outlineLen;o.pos = mul(UNITY_MATRIX_P, pos);return o;}half4 frag(v2f i) : SV_Target{return half4(0,0,0,1);}ENDHLSL}}
}

在非URP的情况下,这个Shader可以正常的显示描边:
在这里插入图片描述

二、在URP下的多Pass情况

接下来,我们把项目改成URP渲染,具体方法可以参考之前的文章
Unity里URP项目的介绍和创建

切换完成后,会发现刚才那个shader不能正常显示描边了
在这里插入图片描述

这是因为,URP本身不鼓励在一个Shader里面写多Pass,所以如果不指定LightMode的情况下,只有第一个Pass生效,其他的Pass都不会生效。
知道了原因之后,那么给Pass加上Tags,应该就能解决这个问题。

Shader "azhao/UnlitOutlineMulPass"
{Properties{_MainTex ("Texture", 2D) = "white" {}_outlineLen("outlineLen",float) = 0.2}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{Tags{ "LightMode" = "LightweightForward" }Cull BackHLSLPROGRAM#pragma vertex vert#pragma fragment frag#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/core.hlsl"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 pos : SV_POSITION;};CBUFFER_START(UnityPerMaterial)sampler2D _MainTex;float4 _MainTex_ST;CBUFFER_ENDv2f vert (appdata v){v2f o;VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);o.pos = vertexInput.positionCS;o.uv = TRANSFORM_TEX(v.uv, _MainTex);return o;}half4 frag (v2f i) : SV_Target{// sample the texturehalf4 col = tex2D(_MainTex, i.uv);return col;}ENDHLSL}Pass{Tags{ "LightMode" = "SRPDefaultUnlit" }Cull FrontHLSLPROGRAM#pragma vertex vert#pragma fragment frag#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/core.hlsl"struct appdata{float4 vertex : POSITION;float3 normal :NORMAL;};struct v2f{float4 pos : SV_POSITION;};CBUFFER_START(UnityPerMaterial)float _outlineLen;CBUFFER_ENDv2f vert(appdata v){v2f o;float4 pos = mul(UNITY_MATRIX_MV, v.vertex);float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);normal.z = -0.5;pos = pos + float4(normalize(normal), 0) * _outlineLen;o.pos = mul(UNITY_MATRIX_P, pos);return o;}half4 frag(v2f i) : SV_Target{return half4(0,0,0,1);}ENDHLSL}}
}

可以看到,在第一个Pass加的是

Tags{ "LightMode" = "LightweightForward" }

而在第二个Pass加的是

Tags{ "LightMode" = "SRPDefaultUnlit" }

从URP的代码看

    m_ShaderTagIdList.Add(new ShaderTagId("UniversalForward"));m_ShaderTagIdList.Add(new ShaderTagId("LightweightForward"));m_ShaderTagIdList.Add(new ShaderTagId("SRPDefaultUnlit"));

应该来说,用UniversalForward、LightweightForward或者SRPDefaultUnlit都是可以的。
加完Tags之后,刚才那个Shader在URP渲染管线下,也能正常的渲染出描边了。

三、使用URP的Features

之前说过,URP本身并不鼓励在Shader里面写多Pass。这是因为URP的中心思想都是尽量用同一个Pass渲染尽量多的东西。所以其实我们通过Tags来强制开启多Pass,本身也不太符合URP的思想。
为了解决这个问题,URP提供了一个叫做Features的功能。
在这里插入图片描述

接下来我们就来用一下这个功能。

回到URP的Asset_Renderer文件的设置项,增加一个叫做outline的Feature
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在新建的Feature里面,指定了需要渲染的Layer,我这里新建了一个叫做outline的Layer。然后把刚才用于渲染带描边的小球的多个Pass的材质球拖到Overrides里面,然后指定Pass Index为1。
指定材质球并指定Pass这一步,其实是可以在一个多Pass的Shader里面指定用哪一个Pass作为这个Feature的渲染。
如果我们不用之前的Shader,单纯写一个只有一个描边Pass的Shader,也是可以的,比如

Shader "azhao/UnlitOutlineOnly"
{Properties{_MainTex ("Texture", 2D) = "white" {}_outlineLen("outlineLen",float) = 0.2}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{Cull FrontHLSLPROGRAM#pragma vertex vert#pragma fragment frag#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/core.hlsl"struct appdata{float4 vertex : POSITION;float3 normal :NORMAL;};struct v2f{float4 pos : SV_POSITION;};CBUFFER_START(UnityPerMaterial)float _outlineLen;CBUFFER_ENDv2f vert(appdata v){v2f o;float4 pos = mul(UNITY_MATRIX_MV, v.vertex);float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);normal.z = -0.5;pos = pos + float4(normalize(normal), 0) * _outlineLen;o.pos = mul(UNITY_MATRIX_P, pos);return o;}half4 frag(v2f i) : SV_Target{return half4(0,0,0,1);}ENDHLSL}}
}

那么Feature里面的设置就是
在这里插入图片描述

然后,回到小球身上,随便给一个默认的材质球给小球就行了,然后把小球的Layer设置成刚才新建的outline。这个时候
在这里插入图片描述

可以看到,小球是使用了默认的材质去渲染,只是额外叠加了一个描边的效果。
这样的处理就很符合URP的思想了,指定一个层,不管这个层原来的Shader是怎样显示的,都统一额外的用一个Pass,用于显示描边。


http://www.ppmy.cn/news/79758.html

相关文章

Python实现ACO蚁群优化算法优化随机森林分类模型(RandomForestClassifier算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蚁群优化算法(Ant Colony Optimization, ACO)是一种源于大自然生物世界的新的仿生进化算法&#xff0c…

机试打卡 -05 接雨水(动态规划栈)

我的思路:依次计算每一列能接收的雨水量。 关键点:如何计算得到每一列所能接收到的雨水量? 某一列能够接收到的雨水量,取决于其左右两侧最高的柱子。仅有当左右两侧的柱子均高于该列的高度,该列才可收到雨水&#x…

数组题目总结 -- 花式遍历

目录 一. 反转字符串中的单词思路和代码:I. 博主的做法II. 东哥的做法III. 其他做法1IV. 其他做法2 二. 旋转图像思路和代码:I. 博主的做法II. 东哥的做法 三. 旋转图像(逆时针旋转90)思路和代码:I. 博主和东哥的做法 …

es 二、核心概念

目录 Nrt cluster集群概念 node节点 Document 文档 Index 索引 Field字段 Type 类型 shard分片 Replica shard副本 数据库和es概念对比 Nrt 写入一秒后就能搜到 cluster集群概念 一台机器启动一个实例即可,多个组成 node节点 一个实例一个节点 Documen…

深度学习基础篇之卷积神经网络(CNN)

一、CNN的基本结构 首先我们来看CNN的解百纳结构,一个常见的图像识别CNN模型如下图: 从图中可以看出最左边的图像就是模型的输入层,在计算机中就是若干个矩阵,这点与DNN类似。 接着是卷积层(Convolution Layer&…

【正点原子STM32连载】 第十六章 外部中断实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

1)实验平台:正点原子stm32f103战舰开发板V4 2)平台购买地址:https://detail.tmall.com/item.htm?id609294757420 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html 第十六…

C++ new和delete详解

文章目录 1、 C C C内存分布2、 C C C内存管理方式3、 n e w new new 和 d e l e t e delete delete 底层实现4、定位 n e w new new表达式(了解)5、 m a l l o c 、 f r e e 和 n e w 、 d e l e t e malloc、free和new、delete malloc、free和new、de…

Java学习路线(11)——常用API

一、Object与Objects Object 概念: Java对象的总类。 方法: 方法说明String toString()默认返回当前对象在堆内存中的地址:类全名内存地址Boolean equals(Object o)比较对象的地址是否相同 toString() StudentExtend student new Stude…