URP的后处理还是比较的复杂的,我在了解了一些URP的管线中参考视频【Free Bird/URP教学】6.URP后处理_哔哩哔哩_bilibili写出本篇的文章,共自己后面的学习和总结。
volume组件
在后处理的过程中,为了更好的操控后处理的效果,需要暴露一些参数和结果给用户,所以需要写一个脚本来添加这些数据:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class ColorTint : VolumeComponent
{
//【设置颜色参数】
public ColorParameter colorChange = new ColorParameter(Color.white, true);//如果有两个true,则为HDR设置
}
//这个是volume的设置,为volumecomponent组件添加color参数,并且colorTint和下面的参数都暴露出来
该脚本需要放置在volume的组件,下这里只是设置了一个颜色的参数:效果如下:
1.
ScriptableRendererFeature
这个是主要用来写目的的后处理的脚本的代码,主要通过ScriptableRendererFeature类和渲染类ScriptableRenderPass来实现,基本的渲染流程已经注释完成:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class ColorTintRenderFeature : ScriptableRendererFeature
{
[System.Serializable]
public class Settings
{
public RenderPassEvent renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;//在后处理前执行我们的颜色校正
public Shader shader;//汇入shader
}
public Settings settings = new Settings();//开放设置
ColorTintPass colorTintPass;//设置渲染pass
public override void Create()//新建pass
{
this.name = "ColorTintPass"; //名字,本身是public,可以显示在外面
colorTintPass = new ColorTintPass(RenderPassEvent.BeforeRenderingPostProcessing,settings.shader);//初始化
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)//Pass逻辑
{
renderer.EnqueuePass(colorTintPass);//汇入队列
}
public override void SetupRenderPasses(ScriptableRenderer renderer, in RenderingData renderingData)
{
colorTintPass.Setup(renderer.cameraColorTargetHandle);
}
//【执行pass】
public class ColorTintPass : ScriptableRenderPass
{
static readonly string k_RenderTag = "ColorTint Effects";//设置tags
static readonly int MainTexId = Shader.PropertyToID("_MainTex");//设置主贴图
static readonly int TempTargetId = Shader.PropertyToID("_TempTargetColorTint");//设置暂存贴图
ColorTint colorTint;//提供一个Volume传递位置
Material colorTintMaterial;//后处理使用材质
RenderTargetIdentifier currentTarget;//设置当前渲染目标
#region 设置渲染事件
public ColorTintPass(RenderPassEvent evt, Shader ColorTintShader)
{
renderPassEvent = evt;//设置渲染事件位置
var shader = ColorTintShader;//汇入shader
//不存在则返回
if (shader == null)
{
Debug.LogError("不存在ColorTint shader");
return;
}
colorTintMaterial = CoreUtils.CreateEngineMaterial(ColorTintShader);//新建材质
}
#endregion
#region 初始化
public void Setup(in RenderTargetIdentifier currentTarget)
{
this.currentTarget = currentTarget;
}
#endregion
#region 执行
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (colorTintMaterial == null)//材质是否存在
{
Debug.LogError("材质初始化失败");
return;
}
//摄像机关闭后处理
if (!renderingData.cameraData.postProcessEnabled)
{
return;
}
//【渲染设置】
var stack = VolumeManager.instance.stack;//传入volume数据
colorTint = stack.GetComponent<ColorTint>();//拿到我们的Volume
if (colorTint == null)
{
Debug.LogError("Volume组件获取失败");
return;
}
var cmd = CommandBufferPool.Get(k_RenderTag);//设置抬头
Render(cmd, ref renderingData);//设置渲染函数
context.ExecuteCommandBuffer(cmd);//执行函数
CommandBufferPool.Release(cmd);//释放
}
#endregion
#region 渲染
void Render(CommandBuffer cmd, ref RenderingData renderingData)
{
ref var cameraData = ref renderingData.cameraData;//汇入摄像机数据
var camera = cameraData.camera;//传入摄像机数据
var source = currentTarget;//当前渲染图片汇入
int destination = TempTargetId;//渲染目的地
colorTintMaterial.SetColor("_ColorTint", colorTint.colorChange.value);//汇入颜色校正,来自colorTnt的颜色值
cmd.SetGlobalTexture(MainTexId, source);//汇入当前渲染图片,把sourece给以maintexid
cmd.GetTemporaryRT(destination, cameraData.camera.scaledPixelWidth, cameraData.camera.scaledPixelHeight, 0, FilterMode.Trilinear, RenderTextureFormat.Default);//设置目标贴图
cmd.Blit(source, destination,colorTintMaterial,0);//设置后处理,渲染到暂是保存的纹理
cmd.Blit(destination, source, colorTintMaterial, 0);//传入颜色校正,0表示默认使用的着色器通道,采用的是双缓冲
}
#endregion
}
}
主要就是在feature中创建一个渲染的流程,和一个渲染的类,实现渲染。通过setting也暴露一部分的接口:
Shader "PostProcess/ColorTint"//名字开放位置
{
Properties
{
_MainTex ("Texture", 2D) = "white" {} //外部的输入的纹理
}
SubShader
{
Tags { "RenderPipeline"="UniversalPipeline" }
Cull Off ZWrite Off ZTest Always
Pass
{
HLSLPROGRAM
#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 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _ColorTint; //设置颜色校正位置
v2f vert (appdata v)
{
v2f o;
o.vertex = TransformObjectToHClip(v.vertex);//裁剪空间转换
o.uv = v.uv;
return o;
}
float4 frag (v2f i) : SV_Target
{
// sample the texture
float4 col = tex2D(_MainTex, i.uv) * _ColorTint; //进行颜色矫正
// apply fog
return col;
}
ENDHLSL
}
}
}
在该sahder代码拖入就可以实现了,需要说明的是,本版本使用的是urp14. 基本效果有: