unityURP管线学习+后处理

  • 一,前置知识
    • RenderPipeline
      • 默认管线RenderPipeline
      • Scriptable Render Pipeline可编程渲染管线
  • 二,URP渲染流程(代码向)
    • Render函数
      • RenderSingleCamera函数
        • 其中的InitializeRenderingData函数
        • 其中的ForwardRenderer类
          • ForwardRenderer下Setup函数(重点)
          • ForwardRenderer下Execute函数(重点)
          • RenderPassEvent字段大小:
  • 三,后处理
    • 3.1 RenderFeature后处理
    • 3.2 Volume后处理
      • 3.2.1urp自带后处理
      • 3.2.2拓展Volume后处理
  • 参考资料

一,前置知识

RenderPipeline

默认管线RenderPipeline

  • 一些流程是由代码控制开关的,比如Depth Texture这一步,如果设置了depthTextureMode,则会把所有LightMode为ShadowCaster的Pass执行一遍并存储到Depth Texture中。
  • 一些流程是由Shader 中的Tags { “LightMode” “RenderType” “Queue”}标注控制的。渲染时unity根据这些标签,吧Pass放在图中对应顺序运行,因此才可以实现透明物体的“先渲染不透明,再渲染透明”的操作。

Scriptable Render Pipeline可编程渲染管线

  • unity提供的自定义渲染方案,可以灵活根据需求定制。也就是说可以自己随意设定上述谁先谁后的渲染流程,以满足定制化需求。除此以外SRP还有SRP Batcher等优化。

  • 而URP就是Unity在SRP基础上定义出的一个适配大部分情况的管线。

二,URP渲染流程(代码向)

Render函数

com.unity.render-pipelines.universal@7.7.1/Runtime/UniversalRenderPipeline.cs

protected override void Render(ScriptableRenderContext renderContext, Camera[] cameras)
{//固定调用,表示一个相机即将开始渲染BeginFrameRendering(renderContext, cameras);//设置是否是线性空间、是否用SRPBatcherGraphicsSettings.lightsUseLinearIntensity = (QualitySettings.activeColorSpace == ColorSpace.Linear);GraphicsSettings.useScriptableRenderPipelineBatching = asset.useSRPBatcher;//设置没开环境反射时的默认SH、阴影颜色等SetupPerFrameShaderConstants();……SortCameras(cameras);//根据相机深度把相机排序for (int i = 0; i < cameras.Length; ++i){var camera = cameras[i];……if (IsGameCamera(camera)){//遍历主相机的CameraStack里的每一个Overlay相机,并全部渲染出来RenderCameraStack(renderContext, camera);}else{BeginCameraRendering(renderContext, camera);……//看当前相机是否在后期Volume内,如果在则触发对应的后期效果UpdateVolumeFramework(camera, null);//渲染一个相机(剪裁、设置渲染器、执行渲染器)RenderSingleCamera(renderContext, camera);//固定调用,表示一个相机已经结束渲染EndCameraRendering(renderContext, camera);}}EndFrameRendering(renderContext, cameras);
}
  • 这里包含了相机渲染常规流程,以后会常见到:
BeginCameraRendering(context, currCamera);//开始
UpdateVolumeFramework(currCamera, currCameraData);//如果有后处理则触发
//从相机的UniversalAdditionalCameraData里提取设置参数
InitializeCameraData(baseCamera, baseCameraAdditionalData, out var baseCameraData);
//渲染耽搁相机:剪裁、设置渲染器、执行渲染器
RenderSingleCamera(context, overlayCameraData, lastCamera, anyPostProcessingEnabled);
EndCameraRendering(context, currCamera);//结束

RenderSingleCamera函数

其中最关键的是RenderSingleCamera函数:

/// <summary>
/// 渲染一个相机,其过程主要包括剪裁、设置渲染器、执行渲染器三步。
/// </summary>
/// <param name="context">渲染上下文用于记录执行过程中的命令。</param>
/// <param name="cameraData">相机渲染数据,里面可能包含了继承自基础相机的一些参数</param>
/// <param name="anyPostProcessingEnabled">如果相机需要做后期效果处理则为true,否则为false.</param>
static void RenderSingleCamera(ScriptableRenderContext context, CameraData cameraData, bool anyPostProcessingEnabled)
{Camera camera = cameraData.camera;//获取当前相机的渲染器renderer,URP中默认使用的是ForwardRenderervar renderer = cameraData.renderer;if (renderer == null){Debug.LogWarning(string.Format("Trying to render {0} with an invalid renderer. Camera rendering will be skipped.", camera.name));return;}//获取相机视锥裁剪参数,保存在变量cullingParameters里if (!camera.TryGetCullingParameters(IsStereoEnabled(camera), out var cullingParameters))return;ScriptableRenderer.current = renderer;bool isSceneViewCamera = cameraData.isSceneViewCamera;//申请一个CommandBuffer来执行渲染命令ProfilingSampler sampler = (asset.debugLevel >= PipelineDebugLevel.Profiling) ? new ProfilingSampler(camera.name): _CameraProfilingSampler;CommandBuffer cmd = CommandBufferPool.Get(sampler.name);using (new ProfilingScope(cmd, sampler)){//重置渲染对象及执行状态,清空pass队列renderer.Clear(cameraData.renderType);//根据cameraData设置好cullingParameters,包含shadowDistance等renderer.SetupCullingParameters(ref cullingParameters, ref cameraData);context.ExecuteCommandBuffer(cmd);//执行渲染命令cmd.Clear();//清空CommandBuffer……//根据剪裁参数计算剪裁结果cullResults,后续要从cullResults中筛选要渲染的元素。var cullResults = context.Cull(ref cullingParameters);//用剪裁结果cullResults、灯光等可变数据 初始化渲染数据renderingDataInitializeRenderingData(asset, ref cameraData, ref cullResults, anyPostProcessingEnabled, out var renderingData);……//根据渲染数据renderingData,筛选需要的pass进队列renderer.Setup(context, ref renderingData);//执行队列中的渲染passrenderer.Execute(context, ref renderingData);}context.ExecuteCommandBuffer(cmd);CommandBufferPool.Release(cmd);context.Submit();ScriptableRenderer.current = null;
}

其中的InitializeRenderingData函数

static void InitializeRenderingData(UniversalRenderPipelineAsset settings, ref CameraData cameraData, ref CullingResults cullResults,bool anyPostProcessingEnabled, out RenderingData renderingData)
{//这里主要处理了要不要阴影,并且addlight里只支持SpotLight的阴影……renderingData.cullResults = cullResults;renderingData.cameraData = cameraData;//InitializeLightData(settings, visibleLights, mainLightIndex, out renderingData.lightData);InitializeShadowData(settings, visibleLights, mainLightCastShadows, additionalLightsCastShadows && !renderingData.lightData.shadeAdditionalLightsPerVertex, out renderingData.shadowData);……
}
  • InitializeLightData设置了最大灯光数maxPerObjectLights,GLES 2最多四盏,其余最多八盏,如下图。
  • InitializeShadowData看到:
    1. 默认光照在pipelineasset设置,特殊光照在光源的UniversalAdditionalLightData组件设置
    2. 屏幕空间阴影需要设备GLES 2以上才支持
    3. 阴影质量由shadowmap分辨率和cascade数共同决定

其中的ForwardRenderer类

ForwardRenderer继承于ScriptableRenderer,它维护了一个ScriptableRenderPass的列表,在每帧前王列表里新增pass,然后执行pass渲染画面,每帧结束再清空列表。它的渲染资源被序列化为ScriptableRendererData。

ScriptableRenderer里的核心函数Setup和Execute每帧都会执行,其中Setup会把要执行的pass加入列表,Execute将列表里的pass按渲染顺序分类提取并执行。

ForwardRenderer下Setup函数(重点)

主要是将需要的pass加入渲染队列中。

public override void Setup(ScriptableRenderContext context, ref RenderingData renderingData)
{……//1,渲染深度纹理的相机,只加入RenderFeature、不透明物体、天空盒、半透明物体的Passbool isOffscreenDepthTexture = cameraData.targetTexture != null && cameraData.targetTexture.format == RenderTextureFormat.Depth;if (isOffscreenDepthTexture){……for (int i = 0; i < rendererFeatures.Count; ++i){if(rendererFeatures[i].isActive)rendererFeatures[i].AddRenderPasses(this, ref renderingData);}EnqueuePass(m_RenderOpaqueForwardPass);EnqueuePass(m_DrawSkyboxPass);……EnqueuePass(m_RenderTransparentForwardPass);return;}//获取cameraData、UniversalRenderPipeline.asset、renderingData中的各种参数供判断用……// 2,如果需要ColorTexture就设置颜色缓冲为m_CameraColorAttachment;如果需要DepthTexture就设置深度缓冲为m_CameraDepthAttachment//需要渲染到ColorTexture的条件包括:打开MSAA、打开RenderScale、打开HDR、打开Post-Processing、打开渲染到OpaqueTexture、添加了自定义ScriptableRendererFeature等if (cameraData.renderType == CameraRenderType.Base){m_ActiveCameraColorAttachment = (createColorTexture) ? m_CameraColorAttachment : RenderTargetHandle.CameraTarget;m_ActiveCameraDepthAttachment = (createDepthTexture) ? m_CameraDepthAttachment : RenderTargetHandle.CameraTarget;……}else{m_ActiveCameraColorAttachment = m_CameraColorAttachment;m_ActiveCameraDepthAttachment = m_CameraDepthAttachment;}ConfigureCameraTarget(m_ActiveCameraColorAttachment.Identifier(), m_ActiveCameraDepthAttachment.Identifier());//3,将所有自定义的ScriptableRendererFeature加入到ScriptableRenderPass的队列中for (int i = 0; i < rendererFeatures.Count; ++i){if(rendererFeatures[i].isActive)rendererFeatures[i].AddRenderPasses(this, ref renderingData);}//4,将各种通用Pass根据各自条件加入到ScriptableRenderPass的队列中if (mainLightShadows)EnqueuePass(m_MainLightShadowCasterPass);if (additionalLightShadows)EnqueuePass(m_AdditionalLightsShadowCasterPass);if (requiresDepthPrepass){m_DepthPrepass.Setup(cameraTargetDescriptor, m_DepthTexture);EnqueuePass(m_DepthPrepass);}if (generateColorGradingLUT){m_ColorGradingLutPass.Setup(m_ColorGradingLut);EnqueuePass(m_ColorGradingLutPass);}EnqueuePass(m_RenderOpaqueForwardPass);……if (camera.clearFlags == CameraClearFlags.Skybox && (RenderSettings.skybox != null || cameraSkybox?.material != null) && !isOverlayCamera)EnqueuePass(m_DrawSkyboxPass);// 如果创建了DepthTexture,我们需要复制它,otherwise我们可以将它渲染到renderbufferif (!requiresDepthPrepass && renderingData.cameraData.requiresDepthTexture && createDepthTexture){m_CopyDepthPass.Setup(m_ActiveCameraDepthAttachment, m_DepthTexture);EnqueuePass(m_CopyDepthPass);}if (renderingData.cameraData.requiresOpaqueTexture){Downsampling downsamplingMethod = UniversalRenderPipeline.asset.opaqueDownsampling;m_CopyColorPass.Setup(m_ActiveCameraColorAttachment.Identifier(), m_OpaqueColor, downsamplingMethod);EnqueuePass(m_CopyColorPass);}……if (transparentsNeedSettingsPass)EnqueuePass(m_TransparentSettingsPass);EnqueuePass(m_RenderTransparentForwardPass);EnqueuePass(m_OnRenderObjectCallbackPass);……//5,如果是最后一个渲染的相机,则将一些需要最后Blit的Pass加入到ScriptableRenderPass的队列中。if (lastCameraInTheStack){// 后处理得到最终的渲染目标,不需要 final blit pass.if (applyPostProcessing){m_PostProcessPass.Setup(……);EnqueuePass(m_PostProcessPass);}if (renderingData.cameraData.captureActions != null){m_CapturePass.Setup(m_ActiveCameraColorAttachment);EnqueuePass(m_CapturePass);}……// 执行FXAA或者需要在AA之后做的后处理.if (applyFinalPostProcessing){m_FinalPostProcessPass.SetupFinalPass(sourceForFinalPass);EnqueuePass(m_FinalPostProcessPass);}// We need final blit to resolve to screenif (!cameraTargetResolved){m_FinalBlitPass.Setup(cameraTargetDescriptor, sourceForFinalPass);EnqueuePass(m_FinalBlitPass);}}else if (applyPostProcessing){m_PostProcessPass.Setup(……);EnqueuePass(m_PostProcessPass);}……
}

可以看到可用的pass有MainLightShadowCasterPass、AdditionalLightsShadowCasterPass,DepthPrePass,ScreenSpaceShadowResolvePass,ColorGradingLutPass,RenderOpaqueForwardPass,DrawSkyboxPass,CopyDepthPass,CopyColorPass,TransparentForwardPass,RenderObjectCallbackPass,PostProcessPass,CapturePass,FinalPostProcessPass,FinalBlitPass等等。

  • 注意这里比默认管线多了CopyColor和CopyDepth两个步骤(水面折射时抓取color用,但无法多重折射)
ForwardRenderer下Execute函数(重点)

用于执行各个队列里的pass

public void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{……//1,把m_ActiveRenderPassQueue中的pass进行排序.SortStable(m_ActiveRenderPassQueue);……//2,按照每个pass的renderPassEvent字段大小把ScriptableRenderPass分配到不同block.FillBlockRanges(blockEventLimits, blockRanges);……//设置shader光照常量和光照相关keywordSetupLights(context, ref renderingData);//3,根据不同的渲染block,取出这个block所有Pass依次执行其中的渲染过程。ExecuteRenderPass+submitExecuteBlock(RenderPassBlock.BeforeRendering, blockRanges, context, ref renderingData);……// Opaque blocks...ExecuteBlock(RenderPassBlock.MainRenderingOpaque, blockRanges, context, ref renderingData, eyeIndex);// Transparent blocks...ExecuteBlock(RenderPassBlock.MainRenderingTransparent, blockRanges, context, ref renderingData, eyeIndex);// Draw Gizmos...DrawGizmos(context, camera, GizmoSubset.PreImageEffects);// In this block after rendering drawing happens, e.g, post processing, video player capture.ExecuteBlock(RenderPassBlock.AfterRendering, blockRanges, context, ref renderingData, eyeIndex);//4,cleanup所有的pass,释放RT,重置渲染对象,清空pass队列InternalFinishRendering(context, cameraData.resolveFinalTarget);……
}
RenderPassEvent字段大小:
 public enum RenderPassEvent{BeforeRendering = 0,BeforeRenderingShadows = 50, // 0x00000032AfterRenderingShadows = 100, // 0x00000064BeforeRenderingPrepasses = 150, // 0x00000096AfterRenderingPrePasses = 200, // 0x000000C8BeforeRenderingOpaques = 250, // 0x000000FAAfterRenderingOpaques = 300, // 0x0000012CBeforeRenderingSkybox = 350, // 0x0000015EAfterRenderingSkybox = 400, // 0x00000190BeforeRenderingTransparents = 450, // 0x000001C2AfterRenderingTransparents = 500, // 0x000001F4BeforeRenderingPostProcessing = 550, // 0x00000226AfterRenderingPostProcessing = 600, // 0x00000258AfterRendering = 1000, // 0x000003E8}

三,后处理

  • URP后处理是有4部分组成,分别是渲染器(Forward Renderer)— 后处理(Volume) — Pass模块 —Shader:

3.1 RenderFeature后处理

  • RenderFeature是用来拓展Pass的,依附于ForwardRenderer,可以在渲染的某个时机插入一次渲染命令(例如渲染不透明后描边、渲染半透明后滤镜等),因此一般的全屏渲染后处理可以使用RenderFeature处理。
  • 「注意:在URP里原MonoBehaviour里的OnRenderImage函数被取消了,需要使用ScriptableRenderPass 来完成类似功能」

RenderFeature在URPTest_Renderer.asset文件的面板下可以看到,写好类后通过“Add Renderer Feature”新增:

按照下图步骤creat RenderFeature类文件:

  • 创建RenderFeature后处理类需要继承ScriptableRendererFeature类,再加两个类组成简单逻辑:

    1. CustomRenderPass类,继承ScriptableRenderPass类,包含核心渲染逻辑。
    2. XXXSettings类,用于在RenderFeature面板上传参。
  • 大致代码结构如下:

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;public class XXXTest : ScriptableRendererFeature
{[System.Serializable]public class XXXSettings{//指定该RendererFeature在渲染流程的哪个时机插入public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingTransparents;//需要搭载一个材质设定public Material material = null;}public class CustomRenderPass : ScriptableRenderPass{//在渲染执行前被调用,可以在这里配置render target,初始化状态,创建临时的渲染纹理        public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor){}//后处理的逻辑和渲染核心函数,基本相当于内置管线的OnRenderImage函数public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData){}//完成渲染相机后调用,用于释放本次渲染流程创建的分配资源public override void FrameCleanup ( CommandBuffer){}}public XXXSettings settings = new XXXSettings();CustomRenderPass scriptablePass;public override void Create(){}public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData){}
}
  • 其中Create()进行初始化操作,可以把settings里的参数从面板上赋予给CustomRenderPass:
public override void Create()
{scriptablePass = new CustomRenderPass();scriptablePass.material = settings.material;scriptablePass.renderPassEvent = settings.renderPassEvent;scriptablePass.Scale = settings.Scale;
}
  • AddRenderPasses()将CustomRenderPass加入队列,也可以在这里把相机输出给到CustomRenderPass(需要增加Setup函数)。
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{scriptablePass.Setup(renderer.cameraColorTarget);renderer.EnqueuePass(scriptablePass);
}
  • Renderer Pass里核心是Execute函数,基本相当于内置管线的OnRenderImage函数
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{//另一种获取相机tex的方法RenderTargetIdentifier cameraColorTexture = new RenderTargetIdentifier("_CameraColorTexture");material.SetFloat("_Distance", _Distance);material.SetFloat("_Width", _Width);//CommandBuffer类主要用于收集一系列GL指令,然后执行CommandBuffer cmd = CommandBufferPool.Get();//按pass渲染cmd.Blit(cameraColorTexture, tmpTex, material,passint);//最后把结果放回相机cameraColorTexturecmd.Blit(tmpTex, cameraColorTexture);//执行命令缓冲区的该命令context.ExecuteCommandBuffer(cmd);cmd.Clear();//释放命令CommandBufferPool.Release(cmd);
}
  • 再搭配对应的URP效果shader即可

3.2 Volume后处理

3.2.1urp自带后处理

  • URP自带了很多后处理集成在Volume里,使用的时候要在GameObject里创建Volume组件,其中Global Volume代表后处理效果应用所有摄像机;Box Volume是在一个盒子区域内才应用;Sphere Volume是在一个球形区域才应用;Convex Mesh Volume是使用自定义的网格区域。
  • Volume组件上有几个参数如下表:
名称 作用
Mode Global:无边界的影响每一个摄像机; Local:指定边界,只影响边界内部的摄像机
Weight Volume在场景中的影响值
Priority 当场景中有多个Volume时,URP通过此值决定使用哪一个Volume,优先使用priority更高的
Profile Profile文件存储URP处理Volume的数据
  • 需要创建一个Volume Profile来设置后处理效果,并且需要在相机里勾选Post Processing开关才能看到效果
  • URP自带的后处理效果有:辉光(Bloom)、通道混合(Channel Mixer)、色差(Chromatic Aberration)、色彩调整(Color Adjustments)、曲线(Color Curves)、景深(Depth Of Field)、胶片颗粒(Film Grain)、镜头变形(Lens Distortion)、暗部gamma亮部(Lift Gamma Gain)、运动模糊(Motion Blur)、帕尼尼投影(Panini Projection)、阴影中间调高光(Shadows Midtones Hightlights)、色调分离(Split Toning)、色调(Tonemapping)、暗角(Vignette)、白平衡(White Balance)

3.2.2拓展Volume后处理

  • 在Volume里拓展后处理,除了上边用到的RenderFeature Class和RenderPass Class外,还需要VolumeComponent Class。一共2个脚本1个shader文件。

  • VolumeComponent Class:在com.unity.render-pipelines.universal@7.7.1/Runtime/Overrides里可以找到所有为Volume配置文件添加的效果的属性脚本,参考里边的写法创建拓展后处理的效果参数。

using System;namespace UnityEngine.Rendering.Universal
{[Serializable, VolumeComponentMenu("My Post-processing/Test")]public sealed class Test : VolumeComponent, IPostProcessComponent{//鼠标放到参数上时显示的描述信息[Tooltip("Strength of the bloom filter.")]//只有用官方封装的类型定义的变量才能在面板中显示public MinFloatParameter intensity = new MinFloatParameter(0f, 0f);public ClampedFloatParameter scatter = new ClampedFloatParameter(0.7f, 0f, 1f);public ColorParameter tint = new ColorParameter(Color.white, false, false, true);public BoolParameter highQualityFiltering = new BoolParameter(false);public TextureParameter dirtTexture = new TextureParameter(null);public bool IsActive() => intensity.value > 0f;public bool IsTileCompatible() => false;}
}
  • 示例代码:
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;public class XXXTest : ScriptableRendererFeature
{[System.Serializable]public class XXXSettings{public RenderPassEvent renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;    public Shader shader;      // 设置后处理Shader}public XXXSettings settings = new XXXSettings();CustomRenderPass scriptablePass;public override void Create(){this.name = "TestPass";        // 外部显示名字scriptablePass = new CustomRenderPass(RenderPassEvent.BeforeRenderingPostProcessing, settings.shader);      // 初始化Pass}public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData){scriptablePass.Setup(renderer.cameraColorTarget);                 // 初始化Pass里的属性renderer.EnqueuePass(scriptablePass);}
}
public class CustomRenderPass : ScriptableRenderPass
{static readonly string k_RenderTag = "Test Effects";          // 设置渲染 Tagsstatic readonly int MainTexId = Shader.PropertyToID("_MainTex");   // 设置主贴图static readonly int TempTargetId = Shader.PropertyToID("_TempTargetColorTint");    // 设置储存图像信息Test test;// 传递到volumeMaterial material;     // 后处理使用材质RenderTargetIdentifier cameraColorTexture;   // 设置当前渲染目标public ColorTintPass(RenderPassEvent evt, Shader testshader){renderPassEvent = evt;         // 设置渲染事件的位置var shader = testshader;  // 输入Shader信息// 判断如果不存在Shaderif (shader = null)         // Shader如果为空提示{Debug.LogError("没有指定Shader");return;}//如果存在新建材质material = CoreUtils.CreateEngineMaterial(testshader);}public void Setup(in RenderTargetIdentifier currentTarget){this.cameraColorTexture = currentTarget;}//后处理的逻辑和渲染核心函数,基本相当于内置管线的OnRenderImage函数public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData){// 判断材质是否为空if (material == null){Debug.LogError("材质初始化失败");return;}// 判断是否开启后处理if (!renderingData.cameraData.postProcessEnabled){return;}// 渲染设置var stack = VolumeManager.instance.stack;          // 传入volumetest = stack.GetComponent<Test>();       // 拿到我们的volumeif (test == null){Debug.LogError(" Volume组件获取失败 ");return;}var cmd = CommandBufferPool.Get(k_RenderTag);   // 设置渲染标签Render(cmd, ref renderingData);                 // 设置渲染函数context.ExecuteCommandBuffer(cmd);              // 执行函数CommandBufferPool.Release(cmd);                 // 释放}void Render(CommandBuffer cmd, ref RenderingData renderingData){ref var cameraData = ref renderingData.cameraData;      // 获取摄像机属性var camera = cameraData.camera;                         // 传入摄像机var source = cameraColorTexture;                             // 获取渲染图片int destination = TempTargetId;                         // 渲染结果图片colorTintMaterial.SetColor("_Color", test.tint.value);   // 获取value 组件的颜色cmd.SetGlobalTexture(MainTexId, source);                // 获取当前摄像机渲染的图片cmd.GetTemporaryRT(destination, cameraData.camera.scaledPixelWidth, cameraData.camera.scaledPixelHeight, 0, FilterMode.Trilinear, RenderTextureFormat.Default);cmd.Blit(source, destination);                          // 设置后处理cmd.Blit(destination, source, material, 0);    // 传入颜色处理}
}

参考资料

1,URP主要源码解析
2,URP学习之三
3,URP/LWRP学习入门
4,URP屏幕后处理
5,URP | 后处理-自定义后处理

unityURP管线学习+后处理相关推荐

  1. Urp下自定义特效管线和后处理特效实现

    一.如何获得颜色缓冲 网上搜索Unity的后处理或者获得屏幕缓冲,大部分会提到用grabpass到一张指定纹理上或者写一个后处理脚本挂在摄像机上.但是这种方式在Urp管线下已经不生效了.urp取消了默 ...

  2. Unity URP管线设置 后处理的使用

    Unity推出通用渲染管线和高清渲染管线有很长一段时间了,但是感觉使用度上不是很高,很多人不愿意尝试新的渲染管线. 我在最开始使用Unity做可视化大屏的时候,也是选择的默认渲染管线,主要是Asset ...

  3. vulkan管线学习7

    这个图: 虽然渲染管线还是这么个样子,但是... 这个OpenGL的API:glEnable(GL_DEPTH_TEST) 好使吧 Vulkan里面写很多代码才能控制这个东西,以及这个graphic ...

  4. vulkan管线学习12

    上一个部分已经把东西画出来了,开始做顶点信息处理和UBO处理的学习了 这里先顶点 这里教程用的例子 前面2个是position后面三个是rgb 一个inputbinding描述,具体如下 好像可以bi ...

  5. 基于Qt的OpenGL可编程管线学习(9)- X射线

    X射线也就是轮廓线,效果如下图所示 原理:物体表面的法线与人眼睛缩成的角度为90度时,刚好能看到物体的轮廓 Fragment shader代码如下: uniform sampler2D U_MainT ...

  6. 基于Qt的OpenGL可编程管线学习(14)- 正片叠底、逆正片叠底

    1.正片叠底 shader // 正片叠底 uniform sampler2D U_MainTexture; uniform sampler2D U_SubTexture;varying vec2 M ...

  7. vulkan管线学习5

    swap chain 这里描述swapchain是一个基础设施,功能用来同步即将被呈现在屏幕上的图片们. 然后会有显卡不支持prestentation, 例如是服务器或者奇怪的原因,所以要检查是否支持 ...

  8. vulkan管线学习8

    Renderpass 介绍说这个是用来指定绘制的时候,有多少颜色缓冲,深度缓冲,多少次采样,还有他们各自的内容是啥样. 然后这个是挂在VkFramebuffer的 然后由于这个教程这里只需要color ...

  9. vulkan管线学习10

    然后即将开始绘制了 这个绘制大概是这样的,创建一个commandbuffer,然后在初始就把你要做的事情记录下来,在while循环的时候submit就行了 就相当于一开始你要清楚你要做啥,才好制作这个 ...

最新文章

  1. 2018-3-20论文(一种新的群体智能算法--狼群算法)笔记一(引言中提到的的一些智能算法,以及自己的感想)
  2. 美军认知技术发展态势
  3. 《Storm企业级应用:实战、运维和调优》——1.4 Storm的特性
  4. python工具-文件及文件夹移动及处理
  5. python echo和linux交互_Python与shell的3种交互方式介绍
  6. eeprom stm8l 擦除 读写_[STM8L]EEPROM操作读与写
  7. Deepgreen数据库日志清理脚本
  8. python-虚拟环境-centos系统安装
  9. matlab循环遍历数组_MatLab简易教程 #8 循环
  10. python相机拍照显示_从solvePnP获取摄影机姿势
  11. 求解偏微分方程开源有限元软件deal.II学习--Step 7
  12. 计算机软考高级论文,非IT专业,写论文太难了!怎么一次考过软考高项?
  13. 运动轨迹 php,两种JS实现小球抛物线轨迹运动的方法
  14. kappa一致性检验教程_一致性检验(kappa一致性分析)
  15. 12306抢票软件的一些学习
  16. 【小牛分享】人员组织架构图 - 为纪念2013即将结束而分享
  17. 外贸邮箱能群发吗?用哪个外贸邮箱发开发信回复率高?
  18. LTE - 以IMS SIP消息为例深入解析RLC AM PDU收发过程
  19. 2022年武汉大学计算机考研复试分数线
  20. ubuntu终端下快捷键~字体放大缩小

热门文章

  1. 画论77 汤贻汾《画筌析览》
  2. Excel在统计分析中的应用—第八章—假设检验-方差已知下总体均值的双侧检验
  3. php选课系统,GitHub - kidaze/CourseSelectionSystem: 基于PHP的简易网上选课系统,实现管理员、老师、学生三种身份不同需求的php简易网上选课系统。...
  4. 2017淘宝有好货报名要求
  5. [BYR]找什么样的工作?——从找工作中的种种怪象说开去
  6. shell 检测文件是否存在
  7. npm install:Comand failed:E\pythopython.exe ................................
  8. image.paste()函数【将一张图片粘贴到另一张图片上】
  9. Node.js 基础篇(十三):Express快速入门
  10. 如何使用nginx实现用户个性化的独立子域名