I am following a tutorial about making a gaussian blur post-process.
However the tutorial is for 2021 LTS, and I am on version 6. Now, in URP 17, render graph API has been implemented, so the tutorial no longer works
I could enable compatibility mode, but nothing else needs it, and I would like to learn the current way of doing things, but I had difficulty in doing so…
I am having issues with converting the tutorial to the modern version (VolumeComponent and the shader itself seem to be fine)
Here is my current attempt at a ScriptableRendererFeature and a ScriptableRenderPass:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.Universal;
public sealed class BlurRendererFeature : ScriptableRendererFeature
{
private Material material;
private BlurRenderPass blurRenderPass;
public override void Create()
{
if (material == null)
{
material = new Material(Shader.Find("Post-processing/Blur"));
}
if(material)
{
blurRenderPass = new BlurRenderPass();
}
name = "Blur";
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if(material == null || blurRenderPass == null)
{
return;
}
if(renderingData.cameraData.cameraType == CameraType.Preview || renderingData.cameraData.cameraType == CameraType.Reflection)
{
return;
}
BlurVolumeComponent volume = VolumeManager.instance.stack?.GetComponent<BlurVolumeComponent>();
if(volume == null || !volume.IsActive())
{
return;
}
blurRenderPass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
blurRenderPass.ConfigureInput(ScriptableRenderPassInput.None);
renderer.EnqueuePass(blurRenderPass);
}
private class BlurRenderPass : ScriptableRenderPass
{
class PassData
{
internal TextureHandle copySourceTexture;
}
static void ExecutePass(PassData data, RasterGraphContext context)
{
Blitter.BlitTexture(context.cmd, data.copySourceTexture, new Vector4(1, 1, 0, 0), 0, false);
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
string passName = "Blur";
// Add a raster render pass to the render graph. The PassData type parameter determines
// the type of the passData output variable.
using (var builder = renderGraph.AddRasterRenderPass<PassData>(passName, out var passData))
{
// UniversalResourceData contains all the texture references used by URP,
// including the active color and depth textures of the camera.
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
// Populate passData with the data needed by the rendering function
// of the render pass.
// Use the camera's active color texture
// as the source texture for the copy operation.
passData.copySourceTexture = resourceData.activeColorTexture;
// Create a destination texture for the copy operation based on the settings,
// such as dimensions, of the textures that the camera uses.
// Set msaaSamples to 1 to get a non-multisampled destination texture.
// Set depthBufferBits to 0 to ensure that the CreateRenderGraphTexture method
// creates a color texture and not a depth texture.
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
RenderTextureDescriptor desc = cameraData.cameraTargetDescriptor;
desc.msaaSamples = 1;
desc.depthBufferBits = 0;
// For demonstrative purposes, this sample creates a temporary destination texture.
// UniversalRenderer.CreateRenderGraphTexture is a helper method
// that calls the RenderGraph.CreateTexture method.
// Using a RenderTextureDescriptor instance instead of a TextureDesc instance
// simplifies your code.
TextureHandle destination = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "Blur", false);
// Declare that this render pass uses the source texture as a read-only input.
builder.UseTexture(passData.copySourceTexture);
// Declare that this render pass uses the temporary destination texture
// as its color render target.
// This is similar to cmd.SetRenderTarget prior to the RenderGraph API.
builder.SetRenderAttachment(destination, 0);
// RenderGraph automatically determines that it can remove this render pass
// because its results, which are stored in the temporary destination texture,
// are not used by other passes.
// For demonstrative purposes, this sample turns off this behavior to make sure
// that render graph executes the render pass.
builder.AllowPassCulling(false);
// Set the ExecutePass method as the rendering function that render graph calls
// for the render pass.
// This sample uses a lambda expression to avoid memory allocations.
builder.SetRenderFunc((PassData data, RasterGraphContext context)
=> ExecutePass(data, context));
}
}
}
}
Most of it is copied from documentation here
So how can I change this to work like in the video?
I am sorry if it feels like I’m to lazy to do it myself, but I spent over 4 hours already trying to do something with no progress
Here are the rest of the code that seem to be functioning:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[VolumeComponentMenu("Post-processing/Blur")]
[VolumeRequiresRendererFeatures(typeof(BlurRendererFeature))]
[SupportedOnRenderPipeline(typeof(UniversalRenderPipelineAsset))]
public sealed class BlurVolumeComponent : VolumeComponent, IPostProcessComponent
{
public BlurVolumeComponent()
{
displayName = "Blur";
}
[Tooltip("Standart deviation (spread) of the blur. Grid size is approx. 3x larger.")]
public ClampedFloatParameter intesity = new ClampedFloatParameter(0f, 0f, 15f);
public bool IsActive()
{
return (intesity.value > 0f) && active;
}
}
and the shader
Shader "Post-processing/Blur"
{
Properties
{
_MainTex("InputTex", 2D) = "white" {}
_Spread("Standard Deviation (Spread)", Float) = 0
_GridSize("Grid Size", Integer) = 1
}
SubShader
{
Tags
{
"RenderType" = "Opaque"
"RenderPipeline" = "UniversalPipeline"
}
Blend One Zero
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#define E 2.71828f
sampler2D _MainTex;
CBUFFER_START(UnityPerMaterial)
float4 _MainTex_TexelSize;
uint _GridSize;
float _Spread;
CBUFFER_END
float gaussian(int x)
{
float sigmaSqu = _Spread * _Spread;
return (1 / sqrt(TWO_PI * sigmaSqu)) * pow(E, -(x*x) / (2 * sigmaSqu));
}
struct appdata
{
float4 positionOS : Position;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 positionCS : SV_Position;
float2 uv : TEXCOORD0;
};
v2f vert(appdata v)
{
v2f o;
o.positionCS = TransformObjectToHClip(v.positionOS.xyz);
o.uv = v.uv;
return o;
}
ENDHLSL
Pass
{
Name "Horizontal"
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag_horizontal
float4 frag_horizontal(v2f i) : SV_Target
{
float3 col = float3(0.0f, 0.0f, 0.0f);
float gridSum = 0.0f;
int upper = ((_GridSize - 1) * 0.5f);
int lower = -upper;
for(int x = lower; x <= upper; ++x)
{
float gauss = gaussian(x);
gridSum += gauss;
float2 uv = i.uv + float2(_MainTex_TexelSize.x * x, 0.0f);
col += gauss * tex2D(_MainTex, uv).xyz;
}
col /= gridSum;
return float4(col, 1.0f);
}
ENDHLSL
}
Pass
{
Name "Vertical"
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag_vertical
float4 frag_vertical(v2f i) : SV_Target
{
float3 col = float3(0.0f, 0.0f, 0.0f);
float gridSum = 0.0f;
int upper = ((_GridSize - 1) * 0.5f);
int lower = -upper;
for(int y = lower; y <= upper; ++y)
{
float gauss = gaussian(y);
gridSum += gauss;
float2 uv = i.uv + float2(0.0f, _MainTex_TexelSize.y * y);
col += gauss * tex2D(_MainTex, uv).xyz;
}
col /= gridSum;
return float4(col, 1.0f);
}
ENDHLSL
}
}
}
Currently I also receive these errors: