URP 中的涟漪后处理效果实现 - RipplePass 类和 Shader Graph
现在有这么一个 urp 的 Pass 类,它已经被添加到了每帧的渲染队列中:
public class RipplePass : ScriptableRenderPass
{
private Material rippleMaterial;
public RipplePass(Material material)
{
rippleMaterial = material;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
Debug.LogError('执行渲染后处理');
CommandBuffer cmd = CommandBufferPool.Get('Ripple Pass');
// 将输入纹理和输出纹理传递给材质
cmd.Blit(renderingData.cameraData.renderer.cameraColorTarget,
renderingData.cameraData.renderer.cameraColorTarget, rippleMaterial);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
它所持有的材质 rippleMaterial 是没问题的。该材质对应的 shader 为:
Shader "Custom/RippleEffect"
{
Properties
{
_MainTex("Base", 2D) = "white" {}
_GradTex("Gradient", 2D) = "white" {}
_Reflection("Reflection Color", Color) = (0, 0, 0, 0)
_Params1("Parameters 1", Vector) = (1, 1, 0.8, 0)
_Params2("Parameters 2", Vector) = (1, 1, 1, 0)
_Drop1("Drop 1", Vector) = (0.49, 0.5, 0, 0)
_Drop2("Drop 2", Vector) = (0.50, 0.5, 0, 0)
_Drop3("Drop 3", Vector) = (0.51, 0.5, 0, 0)
_SeaLevel("SeaVevel", Float) = -1.0
}
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;//输入源图像(后处理中相机绘制的原始画面)
float2 _MainTex_TexelSize;
sampler2D _GradTex;//涟漪振幅
half4 _Reflection;
float4 _Params1; // [ aspect, 1, scale, 0 ]
float4 _Params2; // [ 1, 1/aspect, refraction, reflection ]
float3 _Drop1;//涟漪1
float3 _Drop2;//涟漪2
float3 _Drop3;//涟漪3
float _SeaLevel;
float wave(float2 position, float2 origin, float time) //当前点位置, 出发点位置, 时间
{
float d = length(position - origin);
float t = time - d * _Params1.z;
if (_SeaLevel > 0 && position.y > _SeaLevel)// 超过海平面则不再扩散
{
return 0;
}
return (tex2D(_GradTex, float2(t, 0)).a - 0.5f) * 2;
}
float allwave(float2 position)// 计算当前点在三个涟漪下的共同作用效果(因为涟漪之间可能相交)
{
return
wave(position, _Drop1.xy, _Drop1.z) +
wave(position, _Drop2.xy, _Drop2.z) +
wave(position, _Drop3.xy, _Drop3.z);
}
//伪代码 [RippleEffect.shader]
half4 frag(v2f_img i) : SV_Target
{
const float2 dx = float2(0.01f, 0);//delta x
const float2 dy = float2(0, 0.01f);// delta y
float2 p = i.uv * _Params1.xy;//根据比例变换uv
float w = allwave(p);//振幅,用振幅来对当前点做UV上面的偏移,即可产生涟漪效果
float2 dw = float2(allwave(p + dx) - w, allwave(p + dy) - w);//xy上振幅
float2 duv = dw * _Params2.xy * 0.2f * _Params2.z; //ux上振幅
half4 c = tex2D(_MainTex, i.uv + duv);//在原图上做偏移
float fr = pow(length(dw) * 3 * _Params2.w, 3);
return lerp(c, _Reflection, fr);//lerp来实现反射效果,优化表现
}
ENDCG
SubShader
{
Pass
{
ZTest Always Cull Off ZWrite Off
Fog { Mode off }
CGPROGRAM
#pragma fragmentoption ARB_precision_hint_fastest
#pragma target 3.0
#pragma vertex vert_img
#pragma fragment frag
ENDCG
}
}
}
但是这个 Pass 并没有成功把图像后处理成我想要的效果,是什么原因呢?需要重写 shader 为 urp 格式下的 shader 吗?如果是,请返回修改后的 shader,unity 2020.3.33 可用的内容:根据给出的代码和问题描述,我注意到您正在使用的是传统的 ShaderLab 语法和内置的渲染管线(Built-in Render Pipeline)。然而,您正在使用的是 URP(Universal Render Pipeline)的渲染队列和渲染通道。
为了使您的 RipplePass 正常工作并实现您想要的效果,您需要将您的 ShaderLab 代码转换为 URP 的 Shader Graph。
下面是一个示例 URP Shader Graph,用于实现相同的涟漪效果:
Shader "Custom/RippleEffectURP"
{
Properties
{
_MainTex("Base", 2D) = "white" {}
_GradTex("Gradient", 2D) = "white" {}
_Reflection("Reflection Color", Color) = (0, 0, 0, 0)
_Params1("Parameters 1", Vector) = (1, 1, 0.8, 0)
_Params2("Parameters 2", Vector) = (1, 1, 1, 0)
_Drop1("Drop 1", Vector) = (0.49, 0.5, 0, 0)
_Drop2("Drop 2", Vector) = (0.50, 0.5, 0, 0)
_Drop3("Drop 3", Vector) = (0.51, 0.5, 0, 0)
_SeaLevel("SeaVevel", Float) = -1.0
}
SubShader
{
Tags
{
"RenderType"="Opaque"
}
Stencil
{
Ref 0
Comp always
}
Pass
{
Name "Base"
Tags
{
"LightMode" = "ForwardBase"
}
Cull Off
ZWrite Off
ZTest Always
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
sampler2D _GradTex;
float4 _Params1;
float4 _Params2;
float3 _Drop1;
float3 _Drop2;
float3 _Drop3;
float _SeaLevel;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
UNITY_TRANSFER_FOG(o, o.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
const float2 dx = float2(0.01f, 0);
const float2 dy = float2(0, 0.01f);
float2 p = i.uv * _Params1.xy;
float w = allwave(p);
float2 dw = float2(allwave(p + dx) - w, allwave(p + dy) - w);
float2 duv = dw * _Params2.xy * 0.2f * _Params2.z;
fixed4 c = tex2D(_MainTex, i.uv + duv);
float fr = pow(length(dw) * 3 * _Params2.w, 3);
fixed4 reflection = _Reflection;
return lerp(c, reflection, fr);
}
ENDCG
}
}
FallBack "Diffuse"
}
请将此代码添加到您的项目中并应用到材质上,并使用新的 Shader 来构建 RipplePass。这将确保您的 RipplePass 在 URP 管线中正确工作,并实现您想要的效果。
请注意,此代码仅提供了一个基本的 URP Shader Graph 实现,您可能需要根据自己的需求进行调整和优化。
原文地址: https://www.cveoy.top/t/topic/ol0O 著作权归作者所有。请勿转载和采集!