在URP中我们可以插入自己的RenderFeature来实现一些特殊的效果。
首先我们需要创建两个C#类,分别继承ScriptableRendererFeature
、ScriptableRenderPass
。
这里我创建了TestRenderFeature
和TestPass
。
我在TestRenderFeature
的Create
方法中初始化TestPass
,在AddRenderPasses
中调用renderer.EnqueuePass(_testPass);
执行相关的渲染操作。
TestRenderFeature.cs
public class TestRenderFeature : ScriptableRendererFeature
{
public Material _material;
private TestPass _testPass;
public override void Create()
{
if (_material== null)
{
Debug.LogError("material can't be null");
}
_testPass=new TestPass (_material);
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
renderer.EnqueuePass(_testPass);
}
}
TestPass.cs
public class TestPass : ScriptableRenderPass
{
const string m_ProfilerTag = "Test Pass";
private Material material;
public TestPass (Material material)
{
this.material = material;
renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
// 设置Pass插入的位置
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (material == null)
return;
var camera = renderingData.cameraData.camera;
var cmd = CommandBufferPool.Get(m_ProfilerTag);
/
//以下为绘制全屏四边面的代码
/
cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, material);
cmd.SetViewProjectionMatrices(camera.worldToCameraMatrix, camera.projectionMatrix);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
Shader相关代码
使用GetPositionInput
,传入屏幕坐标、屏幕尺寸的倒数、原始深度、UNITY_MATRIX_I_VP、UNITY_MATRIX_V,返回一个PositionInputs类型的结构体,结构体内包含世界空间坐标(positionWS)、归一化的屏幕坐标positionNDC
、线性深度linearDepth
。
这个函数定义在com.unity.render-pipelines.core\ShaderLibrary\Common.hlsl
,我使用的版本为8.2.0
Pass
{
ZTest Always
ZWrite Off
//用HLSL吧
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
//记得引入这个头文件
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = TransformObjectToHClip(v.vertex);
//uv直接传过去即可
o.uv=v.uv;
return o;
}
float4 frag (v2f i) : SV_Target
{
float depth = LoadSceneDepth(i.uv*_ScreenParams.xy);
//PositionInputs GetPositionInput(float2 positionSS, float2 invScreenSize, float deviceDepth,float4x4 invViewProjMatrix, float4x4 viewMatrix)
//这里的i.uv实际上相当于归一化的屏幕坐标,让它乘以屏幕尺寸得到未归一化的屏幕坐标
PositionInputs inputs= GetPositionInput(i.uv * _ScreenParams.xy, _ScreenParams.zw-1, depth,
UNITY_MATRIX_I_VP,UNITY_MATRIX_V);
return float4(min(inputs.positionWS.x,1),min(inputs.positionWS.y,1),min(inputs.positionWS.z,1),1);
}
ENDHLSL
}