-
-
Save ScottJDaley/db06257d35dce5de29f20dbe5b322be1 to your computer and use it in GitHub Desktop.
using System; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.Rendering; | |
using UnityEngine.Rendering.Universal; | |
public class RenderObjectsToTextureFeature : ScriptableRendererFeature | |
{ | |
public RenderObjectsToTexturePass.Settings Settings = new(); | |
private RenderObjectsToTexturePass _renderPass; | |
public override void Create() | |
{ | |
_renderPass = new RenderObjectsToTexturePass(name, Settings); | |
} | |
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) | |
{ | |
_renderPass.Setup(renderingData.cameraData.cameraTargetDescriptor); | |
renderer.EnqueuePass(_renderPass); | |
} | |
} | |
public class RenderObjectsToTexturePass : ScriptableRenderPass | |
{ | |
private const int DepthBufferBits = 32; | |
private readonly Settings _settings; | |
private RenderTextureDescriptor _descriptor; | |
private FilteringSettings _filteringSettings; | |
private RenderTargetHandle _tempTextureHandle; | |
private RenderTargetHandle _textureHandle; | |
[Serializable] | |
public class Settings | |
{ | |
[Flags] | |
public enum LightModeTags | |
{ | |
None = 0, | |
SRPDefaultUnlit = 1 << 0, | |
UniversalForward = 1 << 1, | |
UniversalForwardOnly = 1 << 2, | |
LightweightForward = 1 << 3, | |
DepthNormals = 1 << 4, | |
DepthOnly = 1 << 5, | |
Standard = SRPDefaultUnlit | UniversalForward | UniversalForwardOnly | LightweightForward, | |
} | |
public Material Material; | |
public int MaterialPassIndex = -1; // -1 means render all passes | |
public Material BlitMaterial; | |
public int BlitMaterialPassIndex = -1; // -1 means render all passes | |
public RenderPassEvent RenderPassEvent = RenderPassEvent.AfterRenderingOpaques; | |
public ScriptableRenderPassInput RenderPassInput = ScriptableRenderPassInput.None; | |
[Range(0, 5000)] | |
public int RenderQueueLowerBound; | |
[Range(0, 5000)] | |
public int RenderQueueUpperBound = 2499; | |
public RenderTextureFormat ColorFormat = RenderTextureFormat.ARGB32; | |
public SortingCriteria SortingCriteria = SortingCriteria.CommonOpaque; | |
public LayerMask LayerMask = -1; | |
public string TextureName = "_MyTexture"; | |
public LightModeTags LightMode = LightModeTags.Standard; | |
public GlobalKeyword[] GlobalShaderKeywords; | |
[Serializable] | |
public struct GlobalKeyword | |
{ | |
public enum Mode | |
{ | |
None, | |
Enable, | |
Disable, | |
} | |
public string Name; | |
public bool Disabled; | |
public Mode BeforeRenderMode; | |
public Mode AfterRenderMode; | |
} | |
public RenderQueueRange RenderQueueRange => new(RenderQueueLowerBound, RenderQueueUpperBound); | |
public List<ShaderTagId> LightModeShaderTags | |
{ | |
get | |
{ | |
var tags = new List<ShaderTagId>(); | |
if (LightMode.HasFlag(LightModeTags.SRPDefaultUnlit)) | |
{ | |
tags.Add(new ShaderTagId("SRPDefaultUnlit")); | |
} | |
if (LightMode.HasFlag(LightModeTags.UniversalForward)) | |
{ | |
tags.Add(new ShaderTagId("UniversalForward")); | |
} | |
if (LightMode.HasFlag(LightModeTags.UniversalForwardOnly)) | |
{ | |
tags.Add(new ShaderTagId("UniversalForwardOnly")); | |
} | |
if (LightMode.HasFlag(LightModeTags.LightweightForward)) | |
{ | |
tags.Add(new ShaderTagId("LightweightForward")); | |
} | |
if (LightMode.HasFlag(LightModeTags.DepthNormals)) | |
{ | |
tags.Add(new ShaderTagId("DepthNormals")); | |
} | |
if (LightMode.HasFlag(LightModeTags.DepthOnly)) | |
{ | |
tags.Add(new ShaderTagId("DepthOnly")); | |
} | |
return tags; | |
} | |
} | |
} | |
public RenderObjectsToTexturePass(string profilingName, Settings settings) | |
{ | |
_settings = settings; | |
renderPassEvent = settings.RenderPassEvent; | |
profilingSampler = new ProfilingSampler(profilingName); | |
_filteringSettings = new FilteringSettings(settings.RenderQueueRange, settings.LayerMask.value); | |
_textureHandle.Init(settings.TextureName); | |
_tempTextureHandle.Init("_TempBlitMaterialTexture"); | |
} | |
public void Setup(RenderTextureDescriptor baseDescriptor) | |
{ | |
baseDescriptor.colorFormat = _settings.ColorFormat; | |
baseDescriptor.depthBufferBits = DepthBufferBits; | |
// Depth-Only pass don't use MSAA | |
baseDescriptor.msaaSamples = 1; | |
_descriptor = baseDescriptor; | |
ConfigureInput(_settings.RenderPassInput); | |
} | |
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) | |
{ | |
cmd.GetTemporaryRT(_textureHandle.id, _descriptor, FilterMode.Point); | |
ConfigureTarget(_textureHandle.Identifier()); | |
ConfigureClear(ClearFlag.All, Color.clear); | |
cmd.GetTemporaryRT(_tempTextureHandle.id, _descriptor, FilterMode.Point); | |
} | |
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) | |
{ | |
DrawingSettings drawingSettings = CreateDrawingSettings( | |
_settings.LightModeShaderTags, | |
ref renderingData, | |
_settings.SortingCriteria | |
); | |
drawingSettings.overrideMaterial = _settings.Material; | |
drawingSettings.overrideMaterialPassIndex = _settings.MaterialPassIndex; | |
CommandBuffer cmd = CommandBufferPool.Get(); | |
using (new ProfilingScope(cmd, profilingSampler)) | |
{ | |
UpdateKeywordsBeforeRender(cmd); | |
context.ExecuteCommandBuffer(cmd); | |
cmd.Clear(); | |
context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref _filteringSettings); | |
if (_settings.BlitMaterial != null) | |
{ | |
Blit( | |
cmd, | |
_textureHandle.Identifier(), | |
_tempTextureHandle.Identifier(), | |
_settings.BlitMaterial, | |
_settings.BlitMaterialPassIndex | |
); | |
Blit(cmd, _tempTextureHandle.Identifier(), _textureHandle.Identifier()); | |
} | |
cmd.SetGlobalTexture(_settings.TextureName, _textureHandle.Identifier()); | |
UpdateKeywordsAfterRender(cmd); | |
} | |
context.ExecuteCommandBuffer(cmd); | |
CommandBufferPool.Release(cmd); | |
} | |
public override void OnCameraCleanup(CommandBuffer cmd) | |
{ | |
if (cmd == null) | |
{ | |
throw new ArgumentNullException("cmd"); | |
} | |
cmd.ReleaseTemporaryRT(_tempTextureHandle.id); | |
} | |
private void UpdateKeywordsBeforeRender(CommandBuffer cmd) | |
{ | |
if (_settings.GlobalShaderKeywords == null) | |
{ | |
return; | |
} | |
foreach (Settings.GlobalKeyword keyword in _settings.GlobalShaderKeywords) | |
{ | |
if (keyword.Disabled) | |
{ | |
continue; | |
} | |
switch (keyword.BeforeRenderMode) | |
{ | |
case Settings.GlobalKeyword.Mode.None: | |
break; | |
case Settings.GlobalKeyword.Mode.Enable: | |
cmd.EnableShaderKeyword(keyword.Name); | |
break; | |
case Settings.GlobalKeyword.Mode.Disable: | |
cmd.DisableShaderKeyword(keyword.Name); | |
break; | |
default: | |
throw new ArgumentOutOfRangeException(); | |
} | |
} | |
} | |
private void UpdateKeywordsAfterRender(CommandBuffer cmd) | |
{ | |
if (_settings.GlobalShaderKeywords == null) | |
{ | |
return; | |
} | |
foreach (Settings.GlobalKeyword keyword in _settings.GlobalShaderKeywords) | |
{ | |
if (keyword.Disabled) | |
{ | |
continue; | |
} | |
switch (keyword.AfterRenderMode) | |
{ | |
case Settings.GlobalKeyword.Mode.None: | |
break; | |
case Settings.GlobalKeyword.Mode.Enable: | |
cmd.EnableShaderKeyword(keyword.Name); | |
break; | |
case Settings.GlobalKeyword.Mode.Disable: | |
cmd.DisableShaderKeyword(keyword.Name); | |
break; | |
default: | |
throw new ArgumentOutOfRangeException(); | |
} | |
} | |
} | |
} |
Just wanted to leave a comment saying that this was RIDICULOUSLY helpful. Huge thanks for sharing 🙏
Glad you found it helpful!
I can't seem to figure out how to draw world space canvas'. DrawUIOverlay and DrawGizmos both work hmm
Hi,
In URP 16+, RenderTargetHandle
and ScriptableRenderContext.DrawRenderers(...)
are deprecated.
Here is the same script fixed for URP 16+
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class RenderObjectsToTextureFeature : ScriptableRendererFeature
{
public RenderObjectsToTexturePass.Settings Settings = new();
private RenderObjectsToTexturePass _renderPass;
public override void Create()
{
_renderPass = new RenderObjectsToTexturePass(name, Settings);
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
renderer.EnqueuePass(_renderPass);
}
public override void SetupRenderPasses(ScriptableRenderer renderer, in RenderingData renderingData)
{
_renderPass.Setup(renderingData.cameraData.cameraTargetDescriptor);
}
protected override void Dispose(bool disposing)
{
_renderPass?.Dispose();
}
}
public class RenderObjectsToTexturePass : ScriptableRenderPass
{
private const int DepthBufferBits = 32;
private readonly Settings _settings;
private RenderTextureDescriptor _descriptor;
private FilteringSettings _filteringSettings;
private RTHandle _tempTextureHandle;
private RTHandle _textureHandle;
private RTHandle _textureHandleDepth;
[Serializable]
public class Settings
{
[Flags]
public enum LightModeTags
{
None = 0,
SRPDefaultUnlit = 1 << 0,
UniversalForward = 1 << 1,
UniversalForwardOnly = 1 << 2,
LightweightForward = 1 << 3,
DepthNormals = 1 << 4,
DepthOnly = 1 << 5,
Standard = SRPDefaultUnlit | UniversalForward | UniversalForwardOnly | LightweightForward,
}
public Material Material;
public int MaterialPassIndex = -1; // -1 means render all passes
public Material BlitMaterial;
public int BlitMaterialPassIndex = -1; // -1 means render all passes
public RenderPassEvent RenderPassEvent = RenderPassEvent.AfterRenderingOpaques;
public ScriptableRenderPassInput RenderPassInput = ScriptableRenderPassInput.None;
[Range(0, 5000)]
public int RenderQueueLowerBound;
[Range(0, 5000)]
public int RenderQueueUpperBound = 2499;
public RenderTextureFormat ColorFormat = RenderTextureFormat.ARGB32;
public SortingCriteria SortingCriteria = SortingCriteria.CommonOpaque;
public LayerMask LayerMask = -1;
public string TextureName = "_MyTexture";
public LightModeTags LightMode = LightModeTags.Standard;
public GlobalKeyword[] GlobalShaderKeywords;
[Serializable]
public struct GlobalKeyword
{
public enum Mode
{
None,
Enable,
Disable,
}
public string Name;
public bool Disabled;
public Mode BeforeRenderMode;
public Mode AfterRenderMode;
}
public RenderQueueRange RenderQueueRange => new(RenderQueueLowerBound, RenderQueueUpperBound);
public List<ShaderTagId> LightModeShaderTags
{
get
{
var tags = new List<ShaderTagId>();
if (LightMode.HasFlag(LightModeTags.SRPDefaultUnlit))
{
tags.Add(new ShaderTagId("SRPDefaultUnlit"));
}
if (LightMode.HasFlag(LightModeTags.UniversalForward))
{
tags.Add(new ShaderTagId("UniversalForward"));
}
if (LightMode.HasFlag(LightModeTags.UniversalForwardOnly))
{
tags.Add(new ShaderTagId("UniversalForwardOnly"));
}
if (LightMode.HasFlag(LightModeTags.LightweightForward))
{
tags.Add(new ShaderTagId("LightweightForward"));
}
if (LightMode.HasFlag(LightModeTags.DepthNormals))
{
tags.Add(new ShaderTagId("DepthNormals"));
}
if (LightMode.HasFlag(LightModeTags.DepthOnly))
{
tags.Add(new ShaderTagId("DepthOnly"));
}
return tags;
}
}
}
public RenderObjectsToTexturePass(string profilingName, Settings settings)
{
_settings = settings;
renderPassEvent = settings.RenderPassEvent;
profilingSampler = new ProfilingSampler(profilingName);
_filteringSettings = new FilteringSettings(settings.RenderQueueRange, settings.LayerMask.value);
}
public void Setup(RenderTextureDescriptor baseDescriptor)
{
baseDescriptor.colorFormat = _settings.ColorFormat;
baseDescriptor.depthBufferBits = DepthBufferBits;
// Depth-Only pass don't use MSAA
baseDescriptor.msaaSamples = 1;
_descriptor = baseDescriptor;
ConfigureInput(_settings.RenderPassInput);
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
RenderingUtils.ReAllocateIfNeeded(ref _textureHandleDepth, _descriptor, name: _settings.TextureName + "Depth");
RenderTextureDescriptor descColor = _descriptor;
descColor.depthBufferBits = 0; // No depth for the color texture
RenderingUtils.ReAllocateIfNeeded(ref _textureHandle, descColor, name: _settings.TextureName);
ConfigureTarget(_textureHandle, _textureHandleDepth);
ConfigureClear(ClearFlag.All, Color.clear);
RenderingUtils.ReAllocateIfNeeded(ref _tempTextureHandle, descColor, name: "_TempBlitMaterialTexture");
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
DrawingSettings drawingSettings = CreateDrawingSettings(
_settings.LightModeShaderTags,
ref renderingData,
_settings.SortingCriteria
);
drawingSettings.overrideMaterial = _settings.Material;
drawingSettings.overrideMaterialPassIndex = _settings.MaterialPassIndex;
CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, profilingSampler))
{
UpdateKeywordsBeforeRender(cmd);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
RendererListParams rendererListParams = new RendererListParams(renderingData.cullResults, drawingSettings, _filteringSettings);
RendererList list = context.CreateRendererList(ref rendererListParams);
cmd.DrawRendererList(list);
if (_settings.BlitMaterial != null)
{
Blit(
cmd,
_textureHandle,
_tempTextureHandle,
_settings.BlitMaterial,
_settings.BlitMaterialPassIndex
);
Blit(cmd, _tempTextureHandle, _textureHandle);
}
cmd.SetGlobalTexture(_settings.TextureName, _textureHandle);
UpdateKeywordsAfterRender(cmd);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public override void OnCameraCleanup(CommandBuffer cmd)
{
if (cmd == null)
{
throw new ArgumentNullException("cmd");
}
}
public void Dispose()
{
_tempTextureHandle?.Release();
_textureHandleDepth?.Release();
_textureHandle?.Release();
}
private void UpdateKeywordsBeforeRender(CommandBuffer cmd)
{
if (_settings.GlobalShaderKeywords == null)
{
return;
}
foreach (Settings.GlobalKeyword keyword in _settings.GlobalShaderKeywords)
{
if (keyword.Disabled)
{
continue;
}
switch (keyword.BeforeRenderMode)
{
case Settings.GlobalKeyword.Mode.None:
break;
case Settings.GlobalKeyword.Mode.Enable:
cmd.EnableShaderKeyword(keyword.Name);
break;
case Settings.GlobalKeyword.Mode.Disable:
cmd.DisableShaderKeyword(keyword.Name);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
private void UpdateKeywordsAfterRender(CommandBuffer cmd)
{
if (_settings.GlobalShaderKeywords == null)
{
return;
}
foreach (Settings.GlobalKeyword keyword in _settings.GlobalShaderKeywords)
{
if (keyword.Disabled)
{
continue;
}
switch (keyword.AfterRenderMode)
{
case Settings.GlobalKeyword.Mode.None:
break;
case Settings.GlobalKeyword.Mode.Enable:
cmd.EnableShaderKeyword(keyword.Name);
break;
case Settings.GlobalKeyword.Mode.Disable:
cmd.DisableShaderKeyword(keyword.Name);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}
This is a huge lifesaver!
Has there been an updated script, for Unity 6 Render graph?
I haven't tested this with the latest versions of unity, but I did update it to use render graph at some point for a project of mine. Here is the code for the render pass:
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.Universal;
public class RenderTexturePass : ScriptableRenderPass
{
private Settings _settings;
private RenderTextureDescriptor _descriptor;
private RenderStateBlock _renderStateBlock;
[Serializable]
public class Settings
{
[Flags]
public enum LightModeTags
{
None = 0,
// ReSharper disable once InconsistentNaming
SRPDefaultUnlit = 1 << 0,
UniversalForward = 1 << 1,
UniversalForwardOnly = 1 << 2,
LightweightForward = 1 << 3,
DepthNormals = 1 << 4,
DepthOnly = 1 << 5,
DepthNormalsOnly = 1 << 6,
Standard = SRPDefaultUnlit | UniversalForward | UniversalForwardOnly | LightweightForward,
}
public Material Material;
public int MaterialPassIndex = -1; // -1 means render all passes
// TODO: Add support for doing a blit after rendering the objects to a texture
// public Material BlitMaterial;
// public int BlitMaterialPassIndex = -1; // -1 means render all passes
public RenderPassEvent RenderPassEvent = RenderPassEvent.AfterRenderingOpaques;
public ScriptableRenderPassInput RenderPassInput = ScriptableRenderPassInput.None;
[Range(0, 5000)]
public int RenderQueueLowerBound;
[Range(0, 5000)]
public int RenderQueueUpperBound = 2499;
public RenderTextureFormat ColorFormat = RenderTextureFormat.ARGB32;
public SortingCriteria SortingCriteria = SortingCriteria.CommonOpaque;
public LayerMask LayerMask = ~0;
public LightLayerEnum RenderLayerMask = LightLayerEnum.Everything;
public string TextureName = "_MyTexture";
public LightModeTags LightMode = LightModeTags.Standard;
public GlobalKeyword[] GlobalShaderKeywords;
public List<string> ShaderTags;
public bool Depth;
public bool WriteDepth;
public CompareFunction DepthCompare = CompareFunction.LessEqual;
[Serializable]
public struct GlobalKeyword
{
public enum Mode
{
None,
Enable,
Disable,
}
public string Name;
public bool Disabled;
public Mode BeforeRenderMode;
public Mode AfterRenderMode;
}
public RenderQueueRange RenderQueueRange => new(RenderQueueLowerBound, RenderQueueUpperBound);
public List<ShaderTagId> LightModeShaderTags
{
get
{
var tags = new List<ShaderTagId>();
if (LightMode.HasFlag(LightModeTags.SRPDefaultUnlit))
{
tags.Add(new ShaderTagId("SRPDefaultUnlit"));
}
if (LightMode.HasFlag(LightModeTags.UniversalForward))
{
tags.Add(new ShaderTagId("UniversalForward"));
}
if (LightMode.HasFlag(LightModeTags.UniversalForwardOnly))
{
tags.Add(new ShaderTagId("UniversalForwardOnly"));
}
if (LightMode.HasFlag(LightModeTags.LightweightForward))
{
tags.Add(new ShaderTagId("LightweightForward"));
}
if (LightMode.HasFlag(LightModeTags.DepthNormals))
{
tags.Add(new ShaderTagId("DepthNormals"));
}
if (LightMode.HasFlag(LightModeTags.DepthNormalsOnly))
{
tags.Add(new ShaderTagId("DepthNormalsOnly"));
}
if (LightMode.HasFlag(LightModeTags.DepthOnly))
{
tags.Add(new ShaderTagId("DepthOnly"));
}
if (ShaderTags != null)
{
foreach (string tag in ShaderTags)
{
tags.Add(new ShaderTagId(tag));
}
}
return tags;
}
}
}
private class PassData
{
public RendererListHandle RendererListHandle;
public Settings.GlobalKeyword[] GlobalKeywords;
}
public void Setup(string profilingName, Settings settings)
{
_settings = settings;
renderPassEvent = _settings.RenderPassEvent;
profilingSampler = new ProfilingSampler(profilingName);
_renderStateBlock = new RenderStateBlock(RenderStateMask.Nothing);
// Debug.Log($"RenderTexturePass: depth? {_settings.Depth}");
if (_settings.Depth)
{
_renderStateBlock.mask |= RenderStateMask.Depth;
bool writeEnabled = _settings.WriteDepth;
CompareFunction function = _settings.DepthCompare;
_renderStateBlock.depthState = new DepthState(writeEnabled, function);
}
ConfigureInput(settings.RenderPassInput);
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
using IRasterRenderGraphBuilder builder = renderGraph.AddRasterRenderPass(
_settings.TextureName,
out PassData passData,
profilingSampler
);
// Initialize the pass data
InitPassData(renderGraph, frameData, ref passData);
// Create the destination texture
TextureHandle destination = CreateDestinationTexture(renderGraph, frameData);
// Make sure the renderer list is valid
if (!passData.RendererListHandle.IsValid())
{
return;
}
// We declare the RendererList we just created as an input dependency to this pass, via UseRendererList()
builder.UseRendererList(passData.RendererListHandle);
// Setup as a render target via UseTextureFragment, which is the equivalent of using the old cmd.SetRenderTarget
builder.SetRenderAttachment(destination, 0);
// builder.SetRenderAttachmentDepth(
// resourceData.activeDepthTexture,
// _settings.WriteDepth ? AccessFlags.ReadWrite : AccessFlags.Read
// );
builder.SetGlobalTextureAfterPass(destination, Shader.PropertyToID(_settings.TextureName));
// Shader keyword changes are considered as global state modifications
builder.AllowGlobalStateModification(true);
builder.AllowPassCulling(false);
// Assign the ExecutePass function to the render pass delegate, which will be called by the render graph when executing the pass
builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecutePass(data, context));
}
// This static method is used to execute the pass and passed as the RenderFunc delegate to the RenderGraph render pass
private static void ExecutePass(PassData data, RasterGraphContext context)
{
UpdateKeywordsBeforeRender(data, context.cmd);
context.cmd.ClearRenderTarget(RTClearFlags.ColorDepth, Color.black, 0, 0);
context.cmd.DrawRendererList(data.RendererListHandle);
UpdateKeywordsAfterRender(data, context.cmd);
}
private static void UpdateKeywordsBeforeRender(PassData data, RasterCommandBuffer cmd)
{
if (data.GlobalKeywords == null)
{
return;
}
foreach (Settings.GlobalKeyword keyword in data.GlobalKeywords)
{
if (keyword.Disabled)
{
continue;
}
switch (keyword.BeforeRenderMode)
{
case Settings.GlobalKeyword.Mode.None:
break;
case Settings.GlobalKeyword.Mode.Enable:
cmd.EnableShaderKeyword(keyword.Name);
break;
case Settings.GlobalKeyword.Mode.Disable:
cmd.DisableShaderKeyword(keyword.Name);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
private static void UpdateKeywordsAfterRender(PassData data, RasterCommandBuffer cmd)
{
if (data.GlobalKeywords == null)
{
return;
}
foreach (Settings.GlobalKeyword keyword in data.GlobalKeywords)
{
if (keyword.Disabled)
{
continue;
}
switch (keyword.AfterRenderMode)
{
case Settings.GlobalKeyword.Mode.None:
break;
case Settings.GlobalKeyword.Mode.Enable:
cmd.EnableShaderKeyword(keyword.Name);
break;
case Settings.GlobalKeyword.Mode.Disable:
cmd.DisableShaderKeyword(keyword.Name);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
private void InitPassData(RenderGraph renderGraph, ContextContainer frameData, ref PassData passData)
{
// Fill up the passData with the data needed by the passes
// UniversalResourceData contains all the texture handles used by the renderer, including the active color and depth textures
// The active color and depth textures are the main color and depth buffers that the camera renders into
var universalRenderingData = frameData.Get<UniversalRenderingData>();
// The destination texture is created here,
// the texture is created with the same dimensions as the active color texture, but with no depth buffer, being a copy of the color texture
// we also disable MSAA as we don't need multisampled textures for this sample
var cameraData = frameData.Get<UniversalCameraData>();
var lightData = frameData.Get<UniversalLightData>();
DrawingSettings drawingSettings = RenderingUtils.CreateDrawingSettings(
_settings.LightModeShaderTags,
universalRenderingData,
cameraData,
lightData,
_settings.SortingCriteria
);
drawingSettings.overrideMaterial = _settings.Material;
drawingSettings.overrideMaterialPassIndex = _settings.MaterialPassIndex;
var filteringSettings = new FilteringSettings(
_settings.RenderQueueRange,
_settings.LayerMask,
(uint)_settings.RenderLayerMask
);
RendererListHandle renderListHandle = RenderingHelpers.CreateRendererListWithRenderStateBlock(
renderGraph,
ref universalRenderingData.cullResults,
drawingSettings,
filteringSettings,
_renderStateBlock
);
passData.RendererListHandle = renderListHandle;
passData.GlobalKeywords = _settings.GlobalShaderKeywords;
}
private TextureHandle CreateDestinationTexture(RenderGraph renderGraph, ContextContainer frameData)
{
var cameraData = frameData.Get<UniversalCameraData>();
RenderTextureDescriptor desc = cameraData.cameraTargetDescriptor;
desc.colorFormat = _settings.ColorFormat;
desc.depthBufferBits = 0;
desc.msaaSamples = 1;
TextureHandle destination = UniversalRenderer.CreateRenderGraphTexture(
renderGraph,
desc,
_settings.TextureName,
false
);
return destination;
}
}
Note: you'll need to use this render pass in a RendererFeature like in the original code though. I can try to share a more complete script at some point when I have time.
Thank you! 🙌
Looks like RenderTexturePass missing RenderingHelpers.
Looks like RenderTexturePass missing RenderingHelpers.
Oops, I guess that's what happens when you try copy and paste a bunch of code on your phone. Here is the RenderingHelpers class. It is worth noting that this is just a copy of an internal unity function inside of RenderingUtils.
using Unity.Collections;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
public static class RenderingHelpers
{
private static readonly ShaderTagId[] _shaderTagValues = new ShaderTagId[1];
private static readonly RenderStateBlock[] _renderStateBlocks = new RenderStateBlock[1];
// --- Copied from internal method RenderingUtils.CreateRendererListWithRenderStateBlock() ---
// Create a RendererList using a RenderStateBlock override is quite common so we have this optimized utility function for it
public static RendererListHandle CreateRendererListWithRenderStateBlock(
RenderGraph renderGraph,
ref CullingResults cullResults,
DrawingSettings drawingSettings,
FilteringSettings filteringSettings,
RenderStateBlock renderStateBlock)
{
_shaderTagValues[0] = ShaderTagId.none;
_renderStateBlocks[0] = renderStateBlock;
var tagValues = new NativeArray<ShaderTagId>(_shaderTagValues, Allocator.Temp);
var stateBlocks = new NativeArray<RenderStateBlock>(_renderStateBlocks, Allocator.Temp);
var param = new RendererListParams(cullResults, drawingSettings, filteringSettings)
{
tagValues = tagValues, stateBlocks = stateBlocks, isPassTagName = false,
};
return renderGraph.CreateRendererList(param);
}
}
Just wanted to leave a comment saying that this was RIDICULOUSLY helpful. Huge thanks for sharing 🙏