I have resolved this issue, so I’ll post my findings for the future forum historians.
The way the Base/Overlay system seems to work is that BaseCameras and OverlayCameras share the same RenderTexture, they simply render to it in a specific order, this is what caused my blurring on my main texture.
To workaround this I do the following steps:
-
Set my Overlay Camera to a Base Camera.
-
Change the Enivornment Background Type to be SolidColor and the Background to be Black with no Alpha.
-
Send the output to a RenderTexture.
-
Create a AdditiveBlending material with my RenderTarget
Code Here:
Shader "Add" {
Properties{
_Combine("_Combine", 2D) = "black" {}
_MainTex("_MainTex", 2D) = "black" {}
}
SubShader{
Tags { "Queue" = "Transparent" }
Pass {
Blend One One
SetTexture[_Combine]
SetTexture[_MainTex] { combine previous, texture }
}
}
}
- Add a OverlayPass RenderFeature to my BaseCamera’s RenderPipeline.
Code here:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class OverlayPass : ScriptableRendererFeature
{
[System.Serializable]
public class OverlaySettings
{
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
public Material overlayMaterial;
}
public OverlaySettings settings = new OverlaySettings();
class CustomRenderPass : ScriptableRenderPass
{
public Material overlayMaterial;
private string profilerTag;
private RenderTargetIdentifier source { get; set; }
public void Setup(RenderTargetIdentifier source)
{
this.source = source;
}
public CustomRenderPass(string profilerTag)
{
this.profilerTag = profilerTag;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get(profilerTag);
cmd.Blit(source, source, overlayMaterial);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
CommandBufferPool.Release(cmd);
}
}
CustomRenderPass scriptablePass;
public override void Create()
{
scriptablePass = new CustomRenderPass("OverlayPass");
scriptablePass.overlayMaterial = settings.overlayMaterial;
scriptablePass.renderPassEvent = settings.renderPassEvent;
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
var src = renderer.cameraColorTarget;
scriptablePass.Setup(src);
renderer.EnqueuePass(scriptablePass);
}
}
(Based off KawaseBlur’s code here: urp_kawase_blur/Assets/Scripts/KawaseBlur.cs at master · sebastianhein/urp_kawase_blur · GitHub)
Which then achieves this lovely effect:
Limitations:
Because I’m rendering to a RenderTexture, I don’t seem to be able to change resolution at runtime, I’ve tried it with a script it doesn’t seem to work.
This is quite a heavy limitation, in theory you’d have to have set resolutions and swap out rander textures as your resolution changes at runtime to make this effect continue to work instead of getting stretched out and distorted.
This occurs because the blending shader renders the pixel information of both textures based off UV co-ordinates, meaning the overlay image is warped to match the aspect ratio of the main image.
There are two workarounds I see for this:
-
Alter the shader to scale the RenderTexture’s X or Y to scale properly with the main cameras Render.
Limitations: Any difference in aspect Ratio between the two cameras will cause outlines to be culled.
-
Instead of Rendering to a RenderTexture, simply make the Overlay camera a Base Camera with a lower rendering index, pass the camera to the OverlayPass RenderFeature and finally apply it’s activeRenderTexture to the additive material.
Limitations: In theory none, but it feels rather hacky.
There’s also a secret 3rd workaround which seems very obvious, “why not simply make the second base camera have a higher Priority than your first base camera? Surely that’ll simply make it render on top and avoid this issue?”, in theory yes, in practice it seems only the BaseCamera with the highest Priority gets rendered to the screen, whether this is a bug or intentional I’m not sure, only time will tell.
Good luck to ya!
Harry.
Update: Solution 2 is not possible because it relies on references to objects within the scene heirarchy, which you cannot pass into a static render pass, it seems solution 1 is the only way to do this from a practical standpoint, a shame.
All the best,
Harry.