If thatâs the case, could we get this docs page updated accordingly? Itâs the top result when searching ârendergraph createtextureâ and says to use UniversalRenderer.CreateRenderGraphTextureâit doesnât even mention that renderGraph.CreateTexture exists as an alternative.
The post you linked to gives an example for getting a depth texture & descriptor which worked perfectly, but is there an equivalent for a color texture?
InvalidOperationException: Trying to use a texture (_InternalGradingLut) that was already released or not yet created. Make sure you declare it for reading in your pass or you don't read it before it's been written to at least once.
Which I guess makes sense since cameraColor at this point references _InternalGradingLut, and I havenât told render graph that Iâm using that in my pass.
Is there something similar to resourceData.cameraDepthTexture but for a color texture whose descriptor I could steal for my pass? I just want a descriptor that describes a color texture with the same dimensions as the screen.
Creating a TextureDesc from scratch seems rather daunting since I have no idea what most of its fields do, so for now Iâve done this:
This appears to work, but is it an appropriate way to approach this? It seems a little silly to have to create a RenderTextureDescriptor just to create a TextureDesc from it, and the TextureDesc constructor which takes a RenderTextureDescriptor says it does âa best effort conversionâ which sounds a bit sketchy
Strange, resourceData.cameraColor should work if you are using the intermediate textures and not rendering directly to the backbuffer.
Otherwise, use the backbuffer (see my previous tips and tricks).
The texture resources.
with the backbuffer, but this returns a RenderTargetInfo. Is there a way I can convert that to a TextureDesc? Or how do I turn this into a TextureHandle?
Hey @tomweiland, here is one way to use the backbuffer RenderTargetInfo to obtain a TextureDesc, and then use it to create a TextureHandle and attach it to your pass. Handling the backbuffer is a bit more complicated than internal RenderGraph resources because it comes from the native engine with limited information, making it hard to generate a full TextureDesc that can be reused.
Iâm having trouble adapting this render list feature to one that renders the selected layers for use as a global shader texture rather than blitting to the screen. When looking at the Frame Debugger I can see the meshes rendering properly but when checking the texture with a quad or full screen pass itâs completely empty / white. Is SetGlobalTextureAfterPass the correct way to handle this? The code Iâm working on is here:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.Universal;
public class RenderLayersToTextureFeature : ScriptableRendererFeature
{
public RenderPassEvent injectionPoint = RenderPassEvent.AfterRenderingOpaques;
public LayerMask layerMask;
public bool writeToDepth;
public string shaderID = "_GlobalTextureID";
RenderLayersToTexturePass pass;
public override void Create()
{
pass = new(this)
{
renderPassEvent = injectionPoint
};
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
renderer.EnqueuePass(pass);
}
class RenderLayersToTexturePass : ScriptableRenderPass
{
private readonly RenderLayersToTextureFeature feature;
private readonly List<ShaderTagId> shaderTagIDs = new ();
private readonly int shaderID;
public RenderLayersToTexturePass(RenderLayersToTextureFeature feature)
{
this.feature = feature;
shaderID = Shader.PropertyToID(feature.shaderID);
}
// Sample utility method that showcases how to create a renderer list via the RenderGraph API
private void InitRendererLists(ContextContainer frameData, ref PassData passData, RenderGraph renderGraph)
{
// Access the relevant frame data from the Universal Render Pipeline
UniversalRenderingData universalRenderingData = frameData.Get<UniversalRenderingData>();
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
UniversalLightData lightData = frameData.Get<UniversalLightData>();
var sortFlags = cameraData.defaultOpaqueSortFlags;
RenderQueueRange renderQueueRange = RenderQueueRange.opaque;
FilteringSettings filterSettings = new(renderQueueRange, feature.layerMask);
ShaderTagId[] forwardOnlyShaderTagIds = new ShaderTagId[]
{
new("UniversalForwardOnly"),
new("UniversalForward"),
new("SRPDefaultUnlit"), // Legacy shaders (do not have a gbuffer pass) are considered forward-only for backward compatibility
new("LightweightForward") // Legacy shaders (do not have a gbuffer pass) are considered forward-only for backward compatibility
};
shaderTagIDs.Clear();
foreach (ShaderTagId sid in forwardOnlyShaderTagIds)
shaderTagIDs.Add(sid);
DrawingSettings drawSettings = RenderingUtils.CreateDrawingSettings(shaderTagIDs, universalRenderingData, cameraData, lightData, sortFlags);
var param = new RendererListParams(universalRenderingData.cullResults, drawSettings, filterSettings);
passData.rendererListHandle = renderGraph.CreateRendererList(param);
}
// This class stores the data needed by the pass, passed as parameter to the delegate function that executes the pass
private class PassData
{
public RendererListHandle rendererListHandle;
}
// This static method is used to execute the pass and passed as the RenderFunc delegate to the RenderGraph render pass
static void ExecutePass(PassData data, RasterGraphContext context)
{
context.cmd.ClearRenderTarget(RTClearFlags.Color, Color.black, 1, 0);
context.cmd.DrawRendererList(data.rendererListHandle);
}
// This is where the renderGraph handle can be accessed.
// Each ScriptableRenderPass can use the RenderGraph handle to add multiple render passes to the render graph
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
// Add a raster render pass to the render graph, specifying the name and the data type that will be passed to the ExecutePass function
using (var builder = renderGraph.AddRasterRenderPass<PassData>(feature.name, out var passData))
{
// 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>();
// Fill up the passData with the data needed by the pass
InitRendererLists(frameData, ref passData, renderGraph);
// We declare the RendererList we just created as an input dependency to this pass, via UseRendererList()
builder.UseRendererList(passData.rendererListHandle);
var desc = resourceData.activeColorTexture.GetDescriptor(renderGraph);
var destinationTexture = renderGraph.CreateTexture(desc);
builder.SetRenderAttachment(destinationTexture, 0, AccessFlags.Write);
if (feature.writeToDepth)
builder.SetRenderAttachmentDepth(resourceData.activeDepthTexture, AccessFlags.Write);
builder.SetGlobalTextureAfterPass(destinationTexture, shaderID);
// 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));
builder.SetRenderFunc<PassData>(ExecutePass);
}
}
}
}
Unfortunately Iâm getting very strange results with the code you provided.
In the pass that renders my mask (and creates the texture) the render target is correctly set to _WaterFogMaskTexture_1049x590_B10G11R11_UFloatPack32_Tex2DArray (and the Render Graph Viewer confirms the texture has the correct size, though it displays R16G16B16A16_SFloat as the format), but by the time the pass which consumes/uses this mask texture is executed, it has somehow been reduced to a 16x16 gray texture with none of the information in it which it definitely did contain earlier in the frame:
Any idea what could be causing this? Itâs as if the texture is being reinitialized with different parameters later in the frameâŚ
As janky/scuffed as it feels to create a RenderTextureDescriptor just to convert it to a TextureDesc, the backbuffer approach doesnât feel a whole lot better/more proper
Is there a way to âadd a rendererâ to a rendererList or rerun the rendererList creation after the graph is already created, mid-execution before the draw command executes?
This was something that was incredibly easy with the previous setup, but seems impossible with renderGraph from everything Iâve tried, and also seems like a common use case? Here is my use case:
I have a rendergraph pass setup like this:
MyCustomPrePass: This renders the objects in a special way to a render texture
MyCustomReadPass: This reads the render texture, and modifies rendering layers on renderers before our main pass
MyCustomMainPass: Looks for specific rendering layers and reacts different to them during our main pass.
The issue Iâm running into is a one frame delay in my main pass picking up a renderer layer change, a delay that seems systemic to rendergraph.
Unless Iâm completely misunderstanding something, there is no way to change a rendererList to a newly generated one before finally doing the draw command, add a renderer, or anything of the sort. A passes rendererList is determined at graph compile time, and thatâs that?
Or is there some way to ârefreshâ a rendererList? I believe the issue Iâm encountering is that since the rendererList is at compile time, the object newly placed on a renderer Layer wonât be properly placed in the cull results until the next compile.
Again, this technique worked with the non-rendergraph approach. And I can think of many âgameâ use cases for having a pass that âinformsâ the rendererList of a later pass. But alasâŚhere we are unless I am just completely misunderstanding things, which I would love.
I though Unity 6 was in LTS mode, not in make nothing work mode in every update.
Seems this will require to release a new asset version for Unity 6.2 specifically
Now will be a separate asset for each Unity update as it seems
Also these changes are not clear at all how to be handled, change the render order might affect other things, also change the Y-flipping might affect other modes etc etc and is not clear what to change where and at which stage of our effects.
This can be massive amount of work to handle and fix, if everything is fixable after such huge changes.
Is it not possible to absorb these changes in your side of the rendering pipeline and keep our code intact for example ?
To keep the Render Graph thread focused, weâve created a new discussion for the AfterRendering changes here. I also updated my original post.
The AfterRendering change fixes historic inconsistencies across settings. We will also provide an upgrade guide soon. Feel free to continue the discussion in the new thread - weâre happy to help if needed!
Having to make some decisions about what to support in our render pipeline. I want to use RenderGraph, but its proving inflexible in not allowing a user to have passes that inform the rendererList of a future pass
Anyone have any idea how or where CreateSharedTexture should be done? It must be done outside of the rendergraph execution, but you need to access RenderGraph in order to do it so its feeling like a catch 22 without another base method to override that gives access to rendergraph.
or if anyone wants to point out the(probably numerous) flaws in my attempt to convert something to rendergraph, the old execute works as compatibility mode. Completely unsure of how to create persistent rendertexture data for use over multiple frames. BlazeBin - iftbyrloavkl
If a texture needs to persistent across cameras or frames, you can create and manage an RTHandle yourself, and import it in RenderGraph every frame using RG.ImportTexture(). This samples uses that pattern.
You can find more samples and learning materials here.
Graphics.Blit does get me what I want, but I assume I should really be using the rendergraph context here? Neither of the commented out parts appear to modify the bleed texture at all
looks like I should stick with compatibility mode and legacy passes then if I need to edit rendererlists after a pass but before another? @AljoshaD@oliverschnabel