URP 不透明/半透明物体的折射
折射
应用场景
- 水池
- 玻璃
- 热空气(热扭曲)
GrabPass + CubeMap
《Unity3D Shader入门精要》第十章介绍了,模拟实现折射效果有两种
- 使用cubemap: 我认为太麻烦.需要的贴图太多。也没有找到其他合适的使用场景,遂搁置。
- 使用GrabPass抓屏: 是一种比较简单也好理解的方式,抓屏,然后对抓到的贴图的坐标进行偏移。
详情可以参考 《Unity3D Shader入门精要》第十章
URP 下的热扭曲(Opaque)
按照以往的把build-in升级到urp渲染管线,只需要改改Tag、变量名字和类型。 谁知道程序一直报错。
URP摒弃了GrabPass, 找到了可以使用 _CameraOpaqueTexture 来获取不透明物体的绘制。
有了如下代码:
代码
Shader "URP/DistortionOpaque"
{
Properties {
_NoiseTex ("Noise Texture (RG)", 2D) = "white" {}
_HeatTime ("Heat Time", range (0,1)) = 0.1
_HeatForce ("Heat Force", range (0,0.1)) = 0.008
}
SubShader {
Tags { "Queue" = "Transparent" "RenderType" = "Transparent" "RenderPipeline"="UniversalPipeline"}
Blend SrcAlpha OneMinusSrcAlpha
//AlphaTest Greater .01
Cull Off
Lighting Off
//ZTest Off
ZWrite Off
Pass {
Tags { "LightMode" = "UniversalForward"}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct appdata_t {
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord: TEXCOORD0;
};
struct v2f {
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
float2 uvmain : TEXCOORD1;
};
float _HeatForce;
float _HeatTime;
float4 _NoiseTex_ST;
sampler2D _NoiseTex;
SAMPLER(_CameraOpaqueTexture);
v2f vert (appdata_t v)
{
v2f o;
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
o.vertex = vertexInput.positionCS;
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvmain = TRANSFORM_TEX( v.texcoord, _NoiseTex);
return o;
}
half4 frag( v2f i ) : SV_Target
{
//noise effect
half4 offsetColor1 = tex2D(_NoiseTex, i.uvmain + _Time.xz*_HeatTime);
half4 offsetColor2 = tex2D(_NoiseTex, i.uvmain - _Time.yx*_HeatTime);
half distortX = ((offsetColor1.r + offsetColor2.r) - 1) * _HeatForce;
half distorty = ((offsetColor1.g + offsetColor2.g) - 1) * _HeatForce;
half2 screenUV = (i.vertex.xy / _ScreenParams.xy)+ float2(distortX, distorty);
half4 col = tex2D(_CameraOpaqueTexture, screenUV);
col.a = 1.0f;
return col;
}
ENDHLSL
}
}
}
URP 下的热扭曲(Sprite)
- _CameraColorTexture 是场景渲染后生成的纹理截图,
- _CameraOpaqueTexture 是在不透明物体渲染后截图,所以截取不到透明物体。
上面的方法是不支持半透明物体的,但是我现在有个需求是需要支持 Sprite, Sprite是作为一个半透明物体,无法使用上面的方法。
网上解决抓取半透明物体的方法是使用 _AfterPostProcessTexture。 思路如下:
- 利用RendererFeatures新建一个渲染时机 ,并新建一种LightMode Tags = Grab的类型.
- 这样所有Tags是Grab的shader都会在后期处理完成之后在渲染。
设置管线
- Name: Render Object 名字
- Event: AfterRenderingPostProcessing 获取屏幕渲染出的一张图
- Queue & Layer Mask: 设置渲染所有层和叠加模式
- LightMode Tags: 设置标签
设置相机
- 勾选 Post Processing
- Stack添加子相机
在FrameDebug里我们可以看到俩个摄像机,第二个摄像机就是看到前面渲染效果
设置shader
复制上文中的shader, 然后修改贴图
SAMPLER(_AfterPostProcessTexture);
修改获取贴图纹理
half4 col = tex2D(_AfterPostProcessTexture, screenUV);
在Fram Debugger 中, Grab渲染层级下并没有参数 _AfterPostProcessTexture. 反而看到的是 _CameraColorAttachmentA, 在shader代码中相应的位置修改成后_CameraColorAttachmentA,发现能正常显示了。
- 我看到修改成_SourceTex和_CameraColorAttachmentA都能正常显示。
完整代码如下:
代码
Shader "URP/Distortion"
{
Properties {
_NoiseTex ("Noise Texture (RG)", 2D) = "white" {}
_HeatTime ("Heat Time", range (0,1)) = 0.1
_HeatForce ("Heat Force", range (0,0.1)) = 0.008
}
SubShader {
Tags { "Queue" = "Transparent" "RenderType" = "Transparent" "RenderPipeline"="UniversalPipeline"}
Blend SrcAlpha OneMinusSrcAlpha
//AlphaTest Greater .01
Cull Off
//Lighting Off
//ZTest Off
ZWrite Off
Pass {
//Tags { "LightMode" = "UniversalForward"}
Tags { "LightMode" = "Grab"}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct appdata_t {
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord: TEXCOORD0;
};
struct v2f {
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
float2 uvmain : TEXCOORD1;
};
float _HeatForce;
float _HeatTime;
float4 _NoiseTex_ST;
sampler2D _NoiseTex;
//SAMPLER(_CameraOpaqueTexture);
//SAMPLER(_AfterPostProcessTexture);
//SAMPLER(_CameraColorTexture);
//SAMPLER(_CameraColorAttachmentA);
SAMPLER(_SourceTex);
v2f vert (appdata_t v)
{
v2f o;
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
o.vertex = vertexInput.positionCS;
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvmain = TRANSFORM_TEX( v.texcoord, _NoiseTex);
return o;
}
half4 frag( v2f i ) : SV_Target
{
//noise effect
half4 offsetColor1 = tex2D(_NoiseTex, i.uvmain + _Time.xz*_HeatTime);
half4 offsetColor2 = tex2D(_NoiseTex, i.uvmain - _Time.yx*_HeatTime);
half distortX = ((offsetColor1.r + offsetColor2.r) - 1) * _HeatForce;
half distorty = ((offsetColor1.g + offsetColor2.g) - 1) * _HeatForce;
half2 screenUV = (i.vertex.xy / _ScreenParams.xy)+ float2(distortX, distorty);
half4 col = tex2D(_SourceTex, screenUV);
col.a = 1.0f;
return col;
}
ENDHLSL
}
}
}
参考
- 《U3D shader 入门精要》 10 章
- 不透明物体的热扭曲: https://www.bilibili.com/read/cv15512651
- 透明物体的热扭曲: https://zhuanlan.zhihu.com/p/364021217
- 扭曲效果: https://www.bilibili.com/read/cv15512651
- _CameraOpaqueTexture does not render any URP sprite: https://forum.unity.com/threads/scene-color-shadergraph-node-_cameraopaquetexture-with-urp-2d-lighting.757985/
--完--
- 原文作者: 留白
- 原文链接: https://zfunnily.github.io/2022/05/refraction/
- 更新时间:2024-04-16 01:01:05
- 本文声明:转载请标记原文作者及链接