How to get screen buffer RenderTargetIdentifier?

I’m trying to implement my lighting system with the help of command buffers, but i can’t get the screen buffer in forward rendering mode.

Using BuiltinRenderTextureType.CurrentActive or BuiltinRenderTextureType.CameraTarget as a source when bliting does not help, i just get a white texture. Though if i use CameraTarget when making a “grab” blit, it works. I don’t get it.
How to do it without unnecessary copy via command buffer blit?

I also would like to use screen buffer’s depth texture, but it is not copied when making a “grab” blit, why? i have to render the scene depth separately by setting the camera in depth rendering mode, which i would like to avoid

CachedCamera.depthTextureMode = DepthTextureMode.Depth;

So here is the algorithm which uses command buffers to render some custom lights

private void ConfigureCommandBuffer(CommandBuffer commandBuffer)
        {
            if (commandBuffer == null) return;

            //var simpleLightTexPropID = Shader.PropertyToID("_MainTex");
            //var simpleLightTexRtID = new RenderTargetIdentifier(simpleLightTexPropID);

            var overrideTexPropID = Shader.PropertyToID("_Overlay");
            var overrideRtID = new RenderTargetIdentifier(overrideTexPropID);

            var simpleLightPropID = Shader.PropertyToID("_SimpleLightAndGlobalTransitions");
            var simpleLightRtID = new RenderTargetIdentifier(simpleLightPropID);

            var screenTexPropID = Shader.PropertyToID("_MainTex");
            var screenRtID = new RenderTargetIdentifier(screenTexPropID);

            //render fake light on top of source(screen in this case)
            DrawRenderers(commandBuffer, FakeLights);

            commandBuffer.GetTemporaryRT(overrideTexPropID, -1, -1, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
            commandBuffer.GetTemporaryRT(simpleLightPropID, -1, -1, 24, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
            commandBuffer.GetTemporaryRT(screenTexPropID, -1, -1, 24, FilterMode.Bilinear, RenderTextureFormat.ARGB32);

            commandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, screenRtID);

            //render override lights + transitions
            commandBuffer.SetRenderTarget(overrideRtID, BuiltinRenderTextureType.Depth);
            //clear before rendering to it
            commandBuffer.ClearRenderTarget(false, true, Color.clear);
            //render
            DrawRenderers(commandBuffer, OverrideLights);
            //render fake light as override light(into rgba)
            DrawRenderers(commandBuffer, FakeLights);

            commandBuffer.SetRenderTarget(simpleLightRtID, BuiltinRenderTextureType.Depth);
            //clear color on simple light rt
            commandBuffer.ClearRenderTarget(false, true, Color.clear);
            //render simple light(into rgb) and global transition(into a)
            DrawRenderers(commandBuffer, SimpleLights);

            commandBuffer.SetGlobalColor("_GlobalLightColor", GlobalColor);
            commandBuffer.SetGlobalTexture(overrideTexPropID, overrideRtID);
            commandBuffer.SetGlobalTexture(simpleLightPropID, simpleLightRtID);
            commandBuffer.Blit(screenRtID, BuiltinRenderTextureType.CameraTarget, Material,
                (int)StandardImageEffect.BlendModes.LightAsPostprocess);

            commandBuffer.ReleaseTemporaryRT(overrideTexPropID);
            commandBuffer.ReleaseTemporaryRT(simpleLightPropID);
            commandBuffer.ReleaseTemporaryRT(screenTexPropID);
        }

Here are the problems with it

First:

commandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, screenTexPropID);

I would like to get rid of this line, because why would i need to make a copy of a screen buffer, when it is already there, somewhere, i don’t know how to get it and BuiltinRenderTextureType doesn’t seem to support it either, if you know, please give me a hint.

Also, copying the screen buffer like that works, i get the correct image, but when i try to blit directly from it(second blit), i just get a white texture.
I mean, if i change this line

commandBuffer.Blit(screenTexPropID, BuiltinRenderTextureType.CameraTarget, Material,
                (int)StandardImageEffect.BlendModes.LightAsPostprocess);

to this line

commandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, BuiltinRenderTextureType.CameraTarget, Material,
                (int)StandardImageEffect.BlendModes.LightAsPostprocess);

i get a white texture, not the screen buffer’s image, why is that?

Second:
if i try to use the depth buffer from screenRtID, like that

commandBuffer.SetRenderTarget(overrideRtID, screenRtID);//second argument is the depth buffer

it doesn’t work, the depth texture is black in the frame debugger, as if the depth was not copied when doing blit from screen to temporary render texture, this line show how i try to use the depth from screen buffer’s copy

commandBuffer.SetRenderTarget(overrideRtID, screenRtID);

and i have to render the scene depth separately, and use it like this

commandBuffer.SetRenderTarget(overrideRtID, BuiltinRenderTextureType.Depth);

and it works, yes, but at the cost of additional rendering of depth, just because i cant get the depth from screen buffer directly.

All the problems could be solved if i could get the screen buffer as a RenderTargetIdentifier, so, how to do it?

1 Like

Okey, here is something more obscure

If i copy from BuiltinRenderTextureType.CurrentActive to temporary RT, i get this:


But if i copy from CurrentActive into CurrentActive i get this:

what is going on?

The command buffer code(this method is called in update loop):

private void ConfigureCommandBuffer(CommandBuffer commandBuffer)
        {
            if (commandBuffer == null) return;
            commandBuffer.Clear();

            var screenTexPropId = Shader.PropertyToID("_MainTex2");
            var screenRtId = new RenderTargetIdentifier(Shader.PropertyToID("_MainTex2"));

            commandBuffer.GetTemporaryRT(screenTexPropId, -1, -1, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);

            commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, screenRtId);
            commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, BuiltinRenderTextureType.CurrentActive);

            commandBuffer.ReleaseTemporaryRT(screenTexPropId);
        }

I’ve found out that SetGlobalTexture method from command buffer does not work, i just get a black texture in the shader, even though i can see how stuff is drawn to it in frame debugger.
If i define that texture in shader Properties, it is of that color that is specified by defaul, i mean this

Properties
    {
        [PerRendererData]_Overlay("Overlay (RGBA)", 2D) = "gray" {}
    }

i get a gray texture if _Overlay is defined in the properties, but if it is not defined, i get a black texture, even tho i set it as global texture

var overrideTexPropId = Shader.PropertyToID("_Overlay");
var overrideRtId = new RenderTargetIdentifier(Shader.PropertyToID("_Overlay"));
commandBuffer.GetTemporaryRT(overrideTexPropId, -1, -1, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
commandBuffer.SetRenderTarget(overrideRtId, BuiltinRenderTextureType.Depth);
foreach (var light in lights)
{
    commandBuffer.DrawRenderer(light.CachedRenderer, light.CachedRenderer.sharedMaterial);
}
commandBuffer.SetGlobalTexture(overrideTexPropId, overrideRtId);
commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, BuiltinRenderTextureType.CurrentActive, Material,(int)StandardImageEffect.BlendModes.LightAsPostprocess);

It’s hard to do stuff with new features, especially when there is little info :cry:
bump

Lets start with this, then I’ll read the rest of your wall of text :smile:
You can not bind the same render texture as a target AND a resource. (Not completely true, as if your only reading it seems possible to read depth and have depth+stencil bound for stencil checks. But I have not tried this with anything but a depth+stencil buffer used as a depth+stencil buffer!)

When you were getting the grey color you had [PerRendererData] attribute on the property, so it would ignore the global state.

As far as I know depth buffers are never copied when doing blits, as generally you have no reason to have a COPY of a depth buffer. (Different issue if you want to read from it while writing to a different one however, but in those cases you usually don’t treat the one you read from as a depth buffer anymore).

BuiltinRenderTextureType.CameraTarget

One suggestion to learning this stuff is not thinking about it as command buffers, but normal post process effects.
As it acts the same way! Sure we sometimes choose to use the identifiers instead, but generally it really is the same. With the same restrictions.
If you were to upload more complete code and shaders it would be useful. As I have a hard time following exactly what your trying to achieve here.

1 Like

That is the price of sufficient explanation to a problem, if it would not be a wall of text, it would not be clear enough. I tried to format the post so it would be less of a wall, but it is still a wall, im sorry i just had to provide enough data. Thanks for replying! :slight_smile:

I just tried, you can, and it works. I just passed my light map texture as a source and destination, the shader just multiplied the color by 0.5 when blitting, and it works.

I tried it, it does not work. Just inferring from the name, it is not really related to the screen buffer, it is related to camera target render texture, which is null in my case, because camera renders directly into screen buffer. The closest thing that i have found to access the screen buffer data is via Display.main, but it has colorbuffer and depthbuffer, not a render texture, so i still can not get the id of a screen buffer texture.

I knew it would come to this, i will do it maybe later, because it is quite a large system with stuff all over the place. I will need to strip the code and the assets to highlight the core problem.

It would be nice if i could set the render target by providing RenderBuffer data, that way i could use the Display.main.colorBuffer etc, but the API forces me to use RenderTargetIndentifier, which is kinda limiting(well not by much, i just had to bump into this specific problem from specific angle to not be able to use what is provided)

1 Like

Well, actually i can explain it very briefly. I am trying to optimize the algorithm, i can’t use the screen buffer’s colorBuffer and depthBuffer, because i don’t have its RenderTargetIdentifier, this way i am forced to do 2 more things that can be optimized away, which is

  1. Set camera in depth rendering mode so i can get the depth data (which is 1 addition rendering of the scene depth)
  2. Make additional blit from screen buffer to a temporary render texture, so i could access the color buffer from the screen.

I myself like both reading and writing WoT’s, so no worries there! And it’s actually awesome for once getting a FULL description from the start!

Well, the thing is that the swap buffer (screen buffer) is not something you can read from. So that’s why the BuiltinRenderTextureType.CameraTarget is what you should view as your output target.

Oh and if the project is using meta files, then grabbing it shouldn’t be to bad sending it (ofc without the library folder).
My internet here is pretty awesome!

Oh and if you have skype feel free to pm me and we can talk there after work hours (I’m gmt +1)

I got it working, see: Has anyone ever gotten a stencil buffer to copy with CommandBuffer.Blit? - Unity Engine - Unity Discussions

1 Like