Search Unity

How to get screen buffer RenderTargetIdentifier?

Discussion in 'General Graphics' started by iSinner, Apr 21, 2015.

  1. iSinner

    iSinner

    Joined:
    Dec 5, 2013
    Posts:
    201
    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
    Code (CSharp):
    1. CachedCamera.depthTextureMode = DepthTextureMode.Depth;
    So here is the algorithm which uses command buffers to render some custom lights
    Code (CSharp):
    1. private void ConfigureCommandBuffer(CommandBuffer commandBuffer)
    2.         {
    3.             if (commandBuffer == null) return;
    4.  
    5.             //var simpleLightTexPropID = Shader.PropertyToID("_MainTex");
    6.             //var simpleLightTexRtID = new RenderTargetIdentifier(simpleLightTexPropID);
    7.  
    8.             var overrideTexPropID = Shader.PropertyToID("_Overlay");
    9.             var overrideRtID = new RenderTargetIdentifier(overrideTexPropID);
    10.  
    11.             var simpleLightPropID = Shader.PropertyToID("_SimpleLightAndGlobalTransitions");
    12.             var simpleLightRtID = new RenderTargetIdentifier(simpleLightPropID);
    13.  
    14.             var screenTexPropID = Shader.PropertyToID("_MainTex");
    15.             var screenRtID = new RenderTargetIdentifier(screenTexPropID);
    16.  
    17.             //render fake light on top of source(screen in this case)
    18.             DrawRenderers(commandBuffer, FakeLights);
    19.  
    20.             commandBuffer.GetTemporaryRT(overrideTexPropID, -1, -1, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
    21.             commandBuffer.GetTemporaryRT(simpleLightPropID, -1, -1, 24, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
    22.             commandBuffer.GetTemporaryRT(screenTexPropID, -1, -1, 24, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
    23.  
    24.             commandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, screenRtID);
    25.  
    26.             //render override lights + transitions
    27.             commandBuffer.SetRenderTarget(overrideRtID, BuiltinRenderTextureType.Depth);
    28.             //clear before rendering to it
    29.             commandBuffer.ClearRenderTarget(false, true, Color.clear);
    30.             //render
    31.             DrawRenderers(commandBuffer, OverrideLights);
    32.             //render fake light as override light(into rgba)
    33.             DrawRenderers(commandBuffer, FakeLights);
    34.  
    35.             commandBuffer.SetRenderTarget(simpleLightRtID, BuiltinRenderTextureType.Depth);
    36.             //clear color on simple light rt
    37.             commandBuffer.ClearRenderTarget(false, true, Color.clear);
    38.             //render simple light(into rgb) and global transition(into a)
    39.             DrawRenderers(commandBuffer, SimpleLights);
    40.  
    41.             commandBuffer.SetGlobalColor("_GlobalLightColor", GlobalColor);
    42.             commandBuffer.SetGlobalTexture(overrideTexPropID, overrideRtID);
    43.             commandBuffer.SetGlobalTexture(simpleLightPropID, simpleLightRtID);
    44.             commandBuffer.Blit(screenRtID, BuiltinRenderTextureType.CameraTarget, Material,
    45.                 (int)StandardImageEffect.BlendModes.LightAsPostprocess);
    46.  
    47.             commandBuffer.ReleaseTemporaryRT(overrideTexPropID);
    48.             commandBuffer.ReleaseTemporaryRT(simpleLightPropID);
    49.             commandBuffer.ReleaseTemporaryRT(screenTexPropID);
    50.         }
    Here are the problems with it

    First:
    Code (CSharp):
    1. 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
    Code (CSharp):
    1. commandBuffer.Blit(screenTexPropID, BuiltinRenderTextureType.CameraTarget, Material,
    2.                 (int)StandardImageEffect.BlendModes.LightAsPostprocess);
    to this line
    Code (CSharp):
    1. commandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, BuiltinRenderTextureType.CameraTarget, Material,
    2.                 (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
    Code (CSharp):
    1. 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
    Code (CSharp):
    1. commandBuffer.SetRenderTarget(overrideRtID, screenRtID);
    and i have to render the scene depth separately, and use it like this
    Code (CSharp):
    1. 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?
     
    Last edited: Apr 22, 2015
    Elringus likes this.
  2. iSinner

    iSinner

    Joined:
    Dec 5, 2013
    Posts:
    201
    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):
    Code (CSharp):
    1. private void ConfigureCommandBuffer(CommandBuffer commandBuffer)
    2.         {
    3.             if (commandBuffer == null) return;
    4.             commandBuffer.Clear();
    5.  
    6.             var screenTexPropId = Shader.PropertyToID("_MainTex2");
    7.             var screenRtId = new RenderTargetIdentifier(Shader.PropertyToID("_MainTex2"));
    8.  
    9.             commandBuffer.GetTemporaryRT(screenTexPropId, -1, -1, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
    10.  
    11.             commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, screenRtId);
    12.             commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, BuiltinRenderTextureType.CurrentActive);
    13.  
    14.             commandBuffer.ReleaseTemporaryRT(screenTexPropId);
    15.         }
     
  3. iSinner

    iSinner

    Joined:
    Dec 5, 2013
    Posts:
    201
    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
    Code (CSharp):
    1.  
    2. Properties
    3.     {
    4.         [PerRendererData]_Overlay("Overlay (RGBA)", 2D) = "gray" {}
    5.     }
    6.  
    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
    Code (CSharp):
    1. var overrideTexPropId = Shader.PropertyToID("_Overlay");
    2. var overrideRtId = new RenderTargetIdentifier(Shader.PropertyToID("_Overlay"));
    3. commandBuffer.GetTemporaryRT(overrideTexPropId, -1, -1, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);
    4. commandBuffer.SetRenderTarget(overrideRtId, BuiltinRenderTextureType.Depth);
    5. foreach (var light in lights)
    6. {
    7.     commandBuffer.DrawRenderer(light.CachedRenderer, light.CachedRenderer.sharedMaterial);
    8. }
    9. commandBuffer.SetGlobalTexture(overrideTexPropId, overrideRtId);
    10. commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, BuiltinRenderTextureType.CurrentActive, Material,(int)StandardImageEffect.BlendModes.LightAsPostprocess);
     
    Last edited: Apr 22, 2015
  4. iSinner

    iSinner

    Joined:
    Dec 5, 2013
    Posts:
    201
    It's hard to do stuff with new features, especially when there is little info :'(
    *bump*
     
  5. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    Lets start with this, then I'll read the rest of your wall of text :D
    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.
     
    iSinner likes this.
  6. iSinner

    iSinner

    Joined:
    Dec 5, 2013
    Posts:
    201
    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! :)
    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)
     
    Baggers_ likes this.
  7. iSinner

    iSinner

    Joined:
    Dec 5, 2013
    Posts:
    201
    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.
     
  8. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    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)
     
  9. Deleted User

    Deleted User

    Guest