I am writing a ScriptableRenderPass using RenderGraph, in order to implement planar reflections, in URP.
Before using RenderGraph, I used
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
to get the ScriptableRenderContext, modify the camera position and viewM and calculate cullingResults.
How can I also implement this in the RecordRenderGraph function?
This is my current code
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameContext)
{
using var builder = renderGraph.AddRasterRenderPass<PassData>("Planar Ref", out var passData);
var renderingData = frameContext.Get<UniversalRenderingData>();
var cameraData = frameContext.Get<UniversalCameraData>();
var lightData = frameContext.Get<UniversalLightData>();
var sortFlags = cameraData.defaultOpaqueSortFlags;
var renderQueueRange = RenderQueueRange.opaque;
var filterSettings = new FilteringSettings(renderQueueRange, ~0);
var shadersToOverride = new ShaderTagId("UniversalForward");
var drawSettings = RenderingUtils.CreateDrawingSettings(shadersToOverride, renderingData, cameraData, lightData, sortFlags);
var textureProperties = cameraData.cameraTargetDescriptor;
textureProperties.depthBufferBits = 0;
var texture =
UniversalRenderer.CreateRenderGraphTexture(renderGraph, textureProperties, "Mask Texture", false);
var camera = cameraData.camera;
var camTransform = camera.transform;
var rotation = camTransform.rotation;
var mirrorPos = mirrorPlanar.mirrorPos(camTransform.position);
var viewM = mirrorPlanar.GetViewMat(camTransform.position, rotation);
var plane = mirrorPlanar.plane;
var cullMat = Matrix4x4.Frustum(-1, 1, -1, 1, 0.0000001f, 10000000f);
camera.cullingMatrix = cullMat * viewM;
camera.TryGetCullingParameters(out var cullingParameters);
ScriptableRenderContext context = ____________________;
var cullingResults = context.Cull(ref cullingParameters);
var rendererListParameters = new RendererListParams(cullingResults, drawSettings, filterSettings);
passData.rendererList = renderGraph.CreateRendererList(rendererListParameters);
The ScriptableRenderContext is indeed hidden in the new API but starting with Unity 6.1 you can have access to the culling using the CullContextData object. Check out the Packages\com.unity.render-pipelines.universal\Samples~\URPRenderGraphSamples\Culling\CullingRenderPassRendererFeature.cs
code sample on how to use this. Here’s a snippet from it to get the idea:
using (var builder = renderGraph.AddRasterRenderPass<PassData>(passName, out var passData, profilingSampler))
{
// 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.
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
var cameraData = frameData.Get<UniversalCameraData>();
// CullContextData contains the culling APIs.
var cullContextData = frameData.Get<CullContextData>();
// Retrieve the culling parameters for the camera used.
cameraData.camera.TryGetCullingParameters(false, out var cullingParameters);
// Perform culling using the CullContextData API.
var cullingResults = cullContextData.Cull(ref cullingParameters);
// Fill up the passData with the data needed by the pass
InitRendererLists(cullingResults, frameData, ref passData, renderGraph);
// 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 and UseTextureFragmentDepth, which are the equivalent of using the old cmd.SetRenderTarget(color,depth).
builder.SetRenderAttachment(resourceData.activeColorTexture, 0);
builder.SetRenderAttachmentDepth(resourceData.activeDepthTexture, AccessFlags.Write);
// 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));
}
The render pass culling API 6.1 is great, but using it gives me an error when I call cullContextData.Cull(ref cullingParameters)
Unable to add Renderer to the Scene after Culling.
Possible cause: A Camera callback, such as OnPreRender, called Graphics.DrawMesh.
Solution: If this is the cause, move the callback to earlier in the frame, to in OnPreCull, for example.
The most obvious reason that comes to mind for triggering this error is the use of any Graphics.Draw<...> or Graphics.Render<...> call inside the render loop (or relevant user callback called in the render loop, as the error states). Other causes are possibly linked to terrain and detail on terrains, but that seems less probable. Is your project using any of these and at what point in the PlayerLoop?
That’s interesting. So yes, I just saw that there is already a bug report about this error involving Terrain as well, so most probably the same issue. Is this a big blocker for you (seems like it)?
Not an immediate concern. For now, I will use the existing camera culling for my planar reflection. There is popping in the reflection if the object/s are not on screen, so it would be nice if this is eventually fixed.
I was hoping the recent culling fix with HDRP and terrain would fix my “Unable to add Renderer to the Scene after Culling” issue with culling, but it does not. Maybe that is specific to HDRP? I am using URP and the problem appears to be related to how Unity is drawing trees. I have made a simple repro project and reported as a bug- IN-107078
I have to admit that the documentation is absolutely unclear as to what this cullingMatrix actually does . It turns out it is used only with Umbra occlusion culling. Depending on what you would like to achieve, you should probably set up the culling planes accordingly, via the SetCullingPlane method of ScriptableCullingParameters.
I got it working by changing the culling matrix on the camera before calling the TryGetCullingParameters. That way I can keep changing the culling matrix on the camera and get different culling matrices for each of my ScriptableCullingParameters. But it was definitely a headache to figure that out.