I’ve given it my best shot this week using information I’ve gleaned from several source including changing the blur altogether but am unable to get the 2021.3 URP v12.1.7 ‘workaround’ for XR and SPI Blit to function.
The effect works works well in the editor, but when in XR mode, it just leaves an approx. 2mx2m gray plane at the origin.
What Am I missing?
RenderFeature:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
internal class FrostedGlass_RenderFeature: ScriptableRendererFeature {
const string BLUR_SHADER_NAME = "Hidden/URP/KawaseBlur";
const string FEATURE_NAME = "FrostedGlass";
#region settings
public bool enableBlur = true;
public Shader _blurShader;
Material _blurMat;
[Range(1, 15)]
public int blurPasses = 1;
[Range(1, 6)]
public int downsample = 1;
#endregion
FrostedGlass_RenderPass _pass = null;
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) {
if(renderingData.cameraData.cameraType == CameraType.Game ||
renderingData.cameraData.cameraType == CameraType.VR) {
_pass.SetTarget(renderer.cameraColorTarget);
renderer.EnqueuePass(_pass);
}
}
public override void Create() {
// If the blur shader isn't manually assigned, try to find it.
if(!_blurShader) {
_blurShader = Shader.Find(BLUR_SHADER_NAME);
if(!_blurShader) {
throw new MissingReferenceException("Unable to locate required shader '" + BLUR_SHADER_NAME + "'");
}
}
// if no material was created with the blur shader yet, create one.
if(!_blurMat) {
_blurMat = new Material(_blurShader);
_blurMat.hideFlags = HideFlags.HideAndDontSave;
}
_pass = new FrostedGlass_RenderPass(FEATURE_NAME, _blurMat, blurPasses, downsample, enableBlur);
}
protected override void Dispose(bool disposing) {
CoreUtils.Destroy(_blurMat);
}
}
RenderPass:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
internal class FrostedGlass_RenderPass: ScriptableRenderPass {
const string BLUR_MAINTEX_KEY = "_MainTex";
const string BLUR_OFFSET_KEY = "_offset";
string _featureName;
Material _blurMat;
int _passes;
int _downsample;
bool _enableBlur;
RenderTargetIdentifier _blurTargetId;
int _tmpId_0;
int _tmpId_1;
RenderTargetIdentifier _tempRT_0;
RenderTargetIdentifier _tempRT_1;
Camera _camera;
CommandBuffer _cmd;
RenderTextureDescriptor _cameraDescriptor;
public FrostedGlass_RenderPass(string featureName, Material material, int passes, int downsample, bool enableBlur) {
_featureName = featureName;
_blurMat = material;
_passes = passes;
_downsample = downsample;
_enableBlur = enableBlur;
renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
UnityEngine.XR.XRSettings.gameViewRenderMode = UnityEngine.XR.GameViewRenderMode.BothEyes;
}
public void SetTarget(RenderTargetIdentifier blurTargetId) {
_blurTargetId = new RenderTargetIdentifier(blurTargetId, 0, CubemapFace.Unknown, -1);
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) {
if(UnityEngine.XR.XRSettings.eyeTextureDesc.vrUsage == VRTextureUsage.TwoEyes) {
_cameraDescriptor = UnityEngine.XR.XRSettings.eyeTextureDesc;
} else {
_cameraDescriptor = renderingData.cameraData.cameraTargetDescriptor;
_cameraDescriptor.depthBufferBits = 0;
}
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) {
_tmpId_0 = Shader.PropertyToID("_tmpId_0");
_tmpId_1 = Shader.PropertyToID("_tmpId_1");
int width;
int height;
if(UnityEngine.XR.XRSettings.eyeTextureDesc.vrUsage == VRTextureUsage.TwoEyes) {
width = Mathf.FloorToInt(UnityEngine.XR.XRSettings.eyeTextureDesc.width / _downsample);
height = Mathf.FloorToInt(UnityEngine.XR.XRSettings.eyeTextureDesc.width / _downsample);
} else {
width = Mathf.FloorToInt(cameraTextureDescriptor.width / _downsample);
height = Mathf.FloorToInt(cameraTextureDescriptor.height / _downsample);
}
cmd.GetTemporaryRT(_tmpId_0, width, height, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
cmd.GetTemporaryRT(_tmpId_1, width, height, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
_tempRT_0 = new RenderTargetIdentifier(_tmpId_0, 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices);
_tempRT_1 = new RenderTargetIdentifier(_tmpId_1, 0, CubemapFace.Unknown, RenderTargetIdentifier.AllDepthSlices);
ConfigureTarget(_tempRT_0);
ConfigureTarget(_tempRT_1);
}
//Instead of a blit for SPI, we manually draw to a plane
void Render(CommandBuffer cmd, RenderTargetIdentifier target) {
cmd.SetRenderTarget(target);
cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, _blurMat);
}
void RenderAndSetMainTex(CommandBuffer cmd, RenderTargetIdentifier baseMap, RenderTargetIdentifier target) {
cmd.SetGlobalTexture(BLUR_MAINTEX_KEY, baseMap);
Render(cmd, target);
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) {
_camera = renderingData.cameraData.camera;
if((_camera.cameraType != CameraType.Game && _camera.cameraType != CameraType.VR) ||
_blurMat == null) { return; }
_cmd = CommandBufferPool.Get(_featureName);
_cmd.Clear();
//First pass
_blurMat.SetFloat(BLUR_OFFSET_KEY, 1.5f);
if(renderingData.cameraData.xrRendering) {
Render(_cmd, _blurTargetId);
} else {
_cmd.Blit(_blurTargetId, _tmpId_0, _blurMat);
}
//Intermediate passes
RenderTargetIdentifier tmpRti;
if(renderingData.cameraData.xrRendering) {
_tempRT_0 = _blurTargetId;
}
for(int i = 1; i < _passes - 1; i++) {
_blurMat.SetFloat(BLUR_OFFSET_KEY, 0.5f + i);
if(renderingData.cameraData.xrRendering) {
RenderAndSetMainTex(_cmd, _tempRT_0, _tempRT_1);
} else {
_cmd.Blit(_tempRT_0, _tempRT_1, _blurMat);
}
//'Pingpong'
tmpRti = _tempRT_0;
_tempRT_0 = _tempRT_1;
_tempRT_1 = tmpRti;
}
//Last pass
_blurMat.SetFloat(BLUR_OFFSET_KEY, 0.5f + _passes - 1f);
if(_enableBlur) {
if(renderingData.cameraData.xrRendering) {
RenderAndSetMainTex(_cmd, _tempRT_0, _blurTargetId);
} else {
_cmd.Blit(_tempRT_0, _blurTargetId, _blurMat);
}
} else {
_cmd.Blit(_tempRT_0, _tempRT_1, _blurMat);
//_cmd.SetGlobalTexture(BLUR_TEXTURE_KEY, _tempRT_1);
}
context.ExecuteCommandBuffer(_cmd);
_cmd.Clear();
CommandBufferPool.Release(_cmd);
}
}
Shader:
Shader "Hidden/URP/KawaseBlur"{
Properties{
_MainTex("Texture", 2D) = "white" {}
}
SubShader{
Tags { "RenderType" = "Transparent" "RenderPipeline" = "UniversalPipeline"}
LOD 100
Cull Off
ZWrite Off
ZTest Always
Pass{
Name "KawaseBlur"
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "HLSLSupport.cginc"
struct Attributes {
float4 vert : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
//This is a replacement for the CG 'UnityObjectToClipPos()' which is not in HLSL
float4 ObjectToClipPos(float4 pos) {
pos.w = 1;
return mul(UNITY_MATRIX_VP, mul(UNITY_MATRIX_M, pos));
}
Varyings vert(Attributes i) {
Varyings o;
UNITY_SETUP_INSTANCE_ID(i);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.pos = ObjectToClipPos(i.vert);
o.uv = i.uv;
return o;
}
TEXTURE2D_X(_MainTex);
SAMPLER(sampler_MainTex);
//TEXTURE2D_X(_CameraOpaqueTexture);
//SAMPLER(sampler__CameraOpaqueTexture);
float4 _MainTex_TexelSize;
float _offset; //Value set by RenderPass.Execute
half4 frag (Varyings i) : SV_Target{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
//Left=green, right=blue over texture
//half4 eyeColor = lerp(half4(0.2, 0.4, 0.2, 0.3), half4(0.2, 0.2, 0.4, 0.3), unity_StereoEyeIndex);
half4 col;
col = SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv);
col.rgb += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + float2(_offset, _offset) * _MainTex_TexelSize.xy).rgb;
col.rgb += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + float2(_offset, -_offset) * _MainTex_TexelSize.xy).rgb;
col.rgb += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + float2(-_offset, _offset) * _MainTex_TexelSize.xy).rgb;
col.rgb += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + float2(-_offset, -_offset) * _MainTex_TexelSize.xy).rgb;
col.rgb /= 5.0f;
//col += eyeColor;
//col /= 2;
return col;
}
ENDHLSL
}
}
}
I’m extremely hesitant to ‘upgrade’ unity again/further to address failures in the current system(s) hoping that 2022/2023 with RTHandles, or the new, new Blitter will solve this issue as each time I upgrade from one LTS to another, something that used to just work breaks. As it is I’ve already had to re-do the entire input system, the frosted glass effect, and still have a collection of surface shaders that need to be re-written as they didn’t convert from the Built-In renderer to URP.