Version: HDRP 17.0.3, Unity 6000.0.29f1
I prefer modifying the HDRP source code rather than using CustomPass because the CustomPass examples I’ve seen so far are mostly focused on post-processing, whereas I aim to work on GI-related tasks.
My goal is to add a render pass in the HDRP source code to capture an RSMBuffer from the light’s perspective. However, for testing purposes, I output red, yellow, and blue directly in the fragment shader to check if the shader works. Frustratingly, the multi-target rendering does not produce the expected output.
The RenderGraph Viewer shows that I have this pass, but it doesn’t display any resources.
Additionally, the Frame Debugger doesn’t show the expected textures.
I referred to the implementation of RenderForwardOpaque. Below are the steps I followed for my implementation. Thank you all for your help!
(1) In the HDRenderPipeline.RenderGraph.cs
file, right after RenderShadows
process, I called the RenderRSMGIBuffer
function,
which is defined as follows:
void RenderRSMGIBuffer(RenderGraph renderGraph,
HDCamera hdCamera,
TextureHandle colorBuffer,
in LightingBuffers lightingBuffers,
in BuildGPULightListOutput lightLists,
RSMGIBuffers rendergraph_rsmgiBuffers,
TextureHandle vtFeedbackBuffer,
ShadowResult shadowResult,
CullingResults cullResults)
{
bool debugDisplay = m_CurrentDebugDisplaySettings.IsDebugDisplayEnabled();
using (var builder = renderGraph.AddRenderPass<RSMGIPassData>(debugDisplay ? "RSM Forward (+ Emissive) Opaque Debug" : "RSM Forward (+ Emissive) Opaque ",
out var passData,
debugDisplay ? ProfilingSampler.Get(HDProfileId.RSMDebug) : ProfilingSampler.Get(HDProfileId.RSM)))
{
var rendererList = renderGraph.CreateRendererList(RSMBufferRendererList(cullResults, hdCamera));
builder.UseRendererList(rendererList);
int index = 0;
passData.rsmGIPassData_rsmgiBuffers.rsmPositionBuffer = builder.UseColorBuffer(rendergraph_rsmgiBuffers.rsmPositionBuffer, index++);
passData.rsmGIPassData_rsmgiBuffers.rsmNormalBuffer = builder.UseColorBuffer(rendergraph_rsmgiBuffers.rsmNormalBuffer, index++);
passData.rsmGIPassData_rsmgiBuffers.rsmFluxBuffer= builder.UseColorBuffer(rendergraph_rsmgiBuffers.rsmFluxBuffer, index++);
passData.noUseDepthBuffer = builder.UseDepthBuffer(CreateDepthBuffer(renderGraph, true, MSAASamples.None), DepthAccess.Write);
builder.AllowRendererListCulling(false);
builder.SetRenderFunc(
(RSMGIPassData data, RenderGraphContext context) =>
{
BindGlobalRSMPassBuffers(data, context.cmd);
CoreUtils.DrawRendererList(context.renderContext, context.cmd, rendererList);
DecalSystem.instance.RenderForwardEmissive(context.cmd);
});
}
}
In the Lit.shader
, I provided the Pass RSMPass
:
Pass
{
Name "MyRSMPass"
Tags{ "LightMode" = "RSMPass" }
Cull[_CullMode]
ZClip [_ZClip]
ZWrite On
ZTest LEqual
ColorMask 0
HLSLPROGRAM
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
//enable GPU instancing support
#pragma multi_compile_instancing
#pragma instancing_options renderinglayer
#pragma multi_compile _ DOTS_INSTANCING_ON
// enable dithering LOD crossfade
#pragma multi_compile _ LOD_FADE_CROSSFADE
#pragma shader_feature_local _ALPHATEST_ON
#define SHADERPASS SHADERPASS_RSM
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/ShaderPass/LitDepthPass.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitData.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassRSMBuffer.hlsl"
#pragma vertex Vert
#pragma fragment Frag
ENDHLSL
}
My ShaderPassRSMBuffer.hlsl
content is as follows:
#if (SHADERPASS != SHADERPASS_RSM)
#error SHADERPASS_is_not_correctly_define
#endif
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VertMesh.hlsl"
PackedVaryingsType Vert(AttributesMesh inputMesh)
{
VaryingsType varyingsType;
varyingsType.vmesh = VertMesh(inputMesh);
return PackVaryingsType(varyingsType);
}
void Frag( PackedVaryingsToPS packedInput,
out float4 outPositionWS : SV_Target0,
out float4 outNormalWS : SV_Target1,
out float4 outColor : SV_Target2)
{
outPositionWS = float4(1.0, 0.0, 0.0, 1.0); //red
outNormalWS = float4(0.0, 1.0, 0.0, 1.0); // green
outColor = float4(0.0, 0.0, 1.0, 1.0); // blue
}
(2) Here are some additional details: the definitions of RSMGIPassData
and RSMGIBuffers
are as follows:
class RSMGIPassData
{
public RSMGIBuffers rsmGIPassData_rsmgiBuffers;
public TextureHandle noUseDepthBuffer;
}
struct RSMGIBuffers
{
public TextureHandle rsmPositionBuffer;
public TextureHandle rsmNormalBuffer;
public TextureHandle rsmFluxBuffer;
}
And initialized as follows:
RSMGIBuffers deferred_rsmgiBuffers = new RSMGIBuffers();
deferred_rsmgiBuffers.rsmPositionBuffer = CreateRSMPositionBuffer(m_RenderGraph, hdCamera, false, "defer_RSMPosition");
deferred_rsmgiBuffers.rsmNormalBuffer = CreateRSMNormalBuffer(m_RenderGraph, hdCamera, hdCamera.msaaSamples,"defer_RSMNormal");
deferred_rsmgiBuffers.rsmFluxBuffer = CreateRSMFluxBuffer(m_RenderGraph, hdCamera, false,"defer_RSMFlux");
TextureHandle CreateRSMPositionBuffer(RenderGraph renderGraph, HDCamera hdCamera, bool msaa, string name)
{
return renderGraph.CreateTexture(
new TextureDesc(Vector2.one, true, true)
{
// format = GetColorBufferFormat(),
format = GraphicsFormat.R32G32B32A32_SFloat,
enableRandomWrite = !msaa,
bindTextureMS = msaa,
msaaSamples = msaa ? hdCamera.msaaSamples : MSAASamples.None,
// clearBuffer = NeedClearColorBuffer(hdCamera),
clearBuffer = true,
clearColor = GetColorBufferClearColor(hdCamera),
name = msaa ? name+"MSAA" : name
});
}
TextureHandle CreateRSMNormalBuffer(RenderGraph renderGraph, HDCamera hdCamera, MSAASamples msaaSamples, string name)
{
bool msaa = msaaSamples != MSAASamples.None;
TextureDesc normalDesc = new TextureDesc(Vector2.one, true, true)
{
// format = GraphicsFormat.R8G8B8A8_UNorm,
format = GraphicsFormat.R32G32B32A32_SFloat,
// clearBuffer = NeedClearGBuffer(hdCamera),
clearBuffer = true,
clearColor = Color.black,
bindTextureMS = msaa,
msaaSamples = msaaSamples,
enableRandomWrite = !msaa,
name = msaa ? name+"MSAA" : name,
fallBackToBlackTexture = true,
};
return renderGraph.CreateTexture(normalDesc);
}
TextureHandle CreateRSMFluxBuffer(RenderGraph renderGraph, HDCamera hdCamera, bool msaa, string name)
{
return renderGraph.CreateTexture(
new TextureDesc(Vector2.one, true, true)
{
// format = GetColorBufferFormat(),
format = GraphicsFormat.R32G32B32A32_SFloat,
enableRandomWrite = !msaa,
bindTextureMS = msaa,
msaaSamples = msaa ? hdCamera.msaaSamples : MSAASamples.None,
// clearBuffer = NeedClearColorBuffer(hdCamera),
clearBuffer = true,
clearColor = GetColorBufferClearColor(hdCamera),
name = msaa ? name+"MSAA" : name
});
}
TextureHandle CreateDiffuseLightingBuffer(RenderGraph renderGraph, MSAASamples msaaSamples)
{
bool msaa = msaaSamples != MSAASamples.None;
return renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
{
format = GraphicsFormat.B10G11R11_UFloatPack32,
enableRandomWrite = !msaa,
bindTextureMS = msaa,
msaaSamples = msaaSamples,
clearBuffer = true,
clearColor = Color.clear,
name = msaa ? "CameraSSSDiffuseLightingMSAA" : "CameraSSSDiffuseLighting"
});
}
(3)The rendererList
I used is defined as follows:
RendererListDesc RSMBufferRendererList(CullingResults cullResults, HDCamera hdCamera)
{
var passName = m_RSMPassNames[0];
return CreateOpaqueRendererListDesc(cullResults, hdCamera.camera, passName, m_CurrentRendererConfigurationBakedLighting);
}
(4)In the HDRenderPipeline.cs
file, I also wrote the corresponding ShaderTagID
list:
ShaderTagId[] m_RSMPassNames = { HDShaderPassNames.s_RSMName};
And in the HDStringConstants.cs
file,
public static readonly string s_RSMPass_Str = "RSMPass";
public static readonly ShaderTagId s_RSMName = new ShaderTagId(s_RSMPass_Str);
(5)In the HDRenderPipeline.LightLoop.cs
file, I bound the global texture ID
static void BindGlobalRSMPassBuffers(in RSMGIPassData passBuffer, CommandBuffer cmd)
{
cmd.SetGlobalTexture(HDShaderIDs.RSMPassPositionVis, passBuffer.rsmGIPassData_rsmgiBuffers.rsmPositionBuffer);
cmd.SetGlobalTexture(HDShaderIDs.RSMPassNormalVis, passBuffer.rsmGIPassData_rsmgiBuffers.rsmNormalBuffer);
cmd.SetGlobalTexture(HDShaderIDs.RSMPassfluxVis, passBuffer.rsmGIPassData_rsmgiBuffers.rsmFluxBuffer);
}
Also in the HDStringConstants.cs
file,
public static readonly int RSMPassPositionVis = Shader.PropertyToID("outPositionWS");
public static readonly int RSMPassNormalVis = Shader.PropertyToID("outNormalWS");
public static readonly int RSMPassfluxVis = Shader.PropertyToID("outColor");