伏雨朝寒悉不胜,那能还傍杏花行。去年高摘斗轻盈。漫惹炉烟双袖紫,空将酒晕一衫青。人间何处问多情。 ———— 纳兰容若
PostPossessing in URP
这是一篇写了很久但是没有放上来的文章,最近正好可以整理一下下。 查了半天,都找不到很方便可以在urp管线的volume上挂shader的直接有效的方法,后面发现是通过render feature实现的,虽然灵活(可以控制绘制层以实现遮挡的效果)但是终究会很麻烦,本文主要实现两部分,urp的后处理效果标准做法(renderfeature)和urp的后处理工具扩展
首先写一个目录,在当下URP的后处理的方法可以总结为 1、建立一个volume,挂上一个component,其中的profile就是一个集成我们后处理效果的东西,当然别忘了开相机的postpossessing 2、建立后处理面板控制器,继承VolumeComponent,IPostProcessComponent类 3、建立renderfeature类实现和管线结合的类方法,ScriptableRendererFeature.建立PostProcessPass类,ScriptableRenderPass,一切后处理就是一个pass的事儿 4、Shader链接上去 5、配置管线,建立一个URP的instance然后加上renderfeature
Render feature
Renderer Feature可让我们向URP Renderer添加额外的渲染通道,支持我们进行Asset资产配置来重写从而可以自定义渲染的顺序、渲染的对象、材质等等。很显然,就是让它的管线变得一点点不一样呗。具体在哪我们可以看到我们只需要右键新建render feature然后在管线加入就行
我们新建一个renderfeature,可以看到我们的 Scriptable Renderer Feature 由两个类 CustomRenderPassFeature 与 CustomRenderPass 组成,CustomRenderPassFeature 类继承自 ScriptableRendererFeature,CustomRenderPass 类继承自 ScriptableRenderPass
如果我们需要对renderfeature在我们的URP实例设置中暴露出调参数的接口,就写一个renderfeature的setting类,打上[System.Serializable]的tag并实例化(但是感觉并不是很方便,so没什么必要)
CustomRenderPassFeature
Render Feature 可以在渲染管线的某个时间点增加一个 Pass 或者多个 Pass 我们打开scriptable render feature的定义,里面的功能主要就是初始化我们的feature用的,就不过多赘述,我们主要实现的是creat()和addrenderpass方法,Creat函数初始化feature的资源,然后设置renderer(每一个相机设置一次)还决定了feature的插入位置(默认after opaue)后者则负责 Render Pass 加到 Renderer 里面。下面就是创建过程。
public class ZoomBlurRenderFeature : ScriptableRendererFeature
{
ZoomBlurPass zoomBlurPass;
public override void Create()
{
zoomBlurPass = new ZoomBlurPass(RenderPassEvent.BeforeRenderingPostProcessing);
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
zoomBlurPass.Setup(renderer.cameraColorTarget);
renderer.EnqueuePass(zoomBlurPass);
}
}
CustomRenderPass
我们回到scriptableevent的父类,看到大概有这些渲染顺序可以让我们插入。
而在renderpass里面定义的几个重要的方法后续要用到我们的feature上 Configure() 在执行渲染过程之前,Renderer 将调用此方法。如果需要配置渲染目标及其清除状态,并创建临时渲染目标纹理,那就要重写这个方法。如果渲染过程未重写这个方法,则该渲染过程将渲染到激活状态下 Camera 的渲染目标。我们这里是不需要重写这个方法的,因为我们就拿的原始Camera的target Execute() 是这个类的核心方法,定义我们的执行规则;包含渲染逻辑,设置渲染状态,绘制渲染器或绘制程序网格,调度计算等等。可以参考下面的代码,里面就是最经典的Graphic类里的代码了。 FrameCleanup() 可用于释放通过此过程创建的分配资源。完成渲染相机后调用。就可以使用此回调释放此渲染过程创建的所有资源。 Setup()方法则是为了在RenderFeature中初始化调用,Renderer可以拿到RT。
Start Coding
首先创建一个volumecomponent的脚本,继承volomecomponent类和IPostProcessComponent类,是一个非常框架化的写法,共同实现面板功能(至于后者tile兼容的函数到底是什么意思我还没查到)【btw,c#里面的=>是lambda运算符,相当于委托右边产生返回值给左边】这里的参数在完成写法之后就可以暴露在面板上。
然后像是和在上面的那个一样,建立Render Feature类,主要是为RenderPass埋下基础。写好了这个之后写上就加上一个RenderPass的类,第一个Tag上用在CommandBufferPool中的,FrameDebugger就能看到这个效果,后面就是一些构造函数
public ZoomBlurPass(RenderPassEvent evt)
{
renderPassEvent = evt;
var shader = Shader.Find("PostEffect/ZoomBlur");
if (shader == null)
{
Debug.LogError("Shader not found.");
return;
}
zoomBlurMaterial = CoreUtils.CreateEngineMaterial(shader);
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (zoomBlurMaterial == null)
{
Debug.LogError("Material not created.");
return;
}
if (!renderingData.cameraData.postProcessEnabled) return;
var stack = VolumeManager.instance.stack;
zoomBlur = stack.GetComponent<ZoomBlur>();
if (zoomBlur == null) { return; }
if (!zoomBlur.IsActive()) { return; }
var cmd = CommandBufferPool.Get(k_RenderTag);
Render(cmd, ref renderingData);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public void Setup(in RenderTargetIdentifier currentTarget)
{
this.currentTarget = currentTarget;
}
void Render(CommandBuffer cmd, ref RenderingData renderingData)
{
ref var cameraData = ref renderingData.cameraData;
var source = currentTarget;
int destination = TempTargetId;
var w = cameraData.camera.scaledPixelWidth;
var h = cameraData.camera.scaledPixelHeight;
zoomBlurMaterial.SetFloat(FocusPowerId, zoomBlur.focusPower.value);
zoomBlurMaterial.SetInt(FocusDetailId, zoomBlur.focusDetail.value);
zoomBlurMaterial.SetVector(FocusScreenPositionId, zoomBlur.focusScreenPosition.value);
zoomBlurMaterial.SetInt(ReferenceResolutionXId, zoomBlur.referenceResolutionX.value);
int shaderPass = 0;
cmd.SetGlobalTexture(MainTexId, source);
cmd.GetTemporaryRT(destination, w, h, 0, FilterMode.Point, RenderTextureFormat.Default);
cmd.Blit(source, destination);
cmd.Blit(destination, source, zoomBlurMaterial, shaderPass);
}
然后我们总结:这也太麻烦了,如果要做两个后处理暴露面板还需要再加一个renderfeature,这也意味着,如果我要开RT,都是独立的RT,没有办法互用,需要blit很多次,消耗也是大的,但是我们知道,URP自带的后处理是很方便的,那么如果我们让我们写的shader可以被那里直接很方便的调用呢?
扩展参考 https://www.jianshu.com/p/b9cd6bb4c4aa?ivk_sa=1024320u rf参考 https://zhuanlan.zhihu.com/p/373273390
cmrmrjupdq2024-11-13 07:00
独家揭秘:传奇私服刷怪技巧,怪物名字变色攻略,一夜称霸全服!:https://501h.com/lianji/2024-09-15/35381.html
xyprmtuuhc2024-11-24 04:32
《人民英雄国语》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/130207.html
falrdbfxcl2024-11-24 09:28
《我本善良》香港剧高清在线免费观看:https://www.jgz518.com/xingkong/141295.html
grbznavqkc2024-11-26 02:58
《游击队的姑娘》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/20371.html
phvhzepuze2024-12-04 04:56
《来来往往》国产剧高清在线免费观看:https://www.jgz518.com/xingkong/30837.html