Search Unity

CommandBuffer.Blit() - Unexpected behaviour

Discussion in 'General Graphics' started by Freaking-Pingo, Dec 6, 2018.

  1. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    Hi Uniteers

    I wish to do some post-processing effects in Unity 2018.2.14f1. I can't get
    CommandBuffer.Blit()
    to work because I am seeing unexpected behaviours.
    1. When using
      CommandBuffer.Blit(src, dest)
      , the result is upside-down.
      Code (CSharp):
      1. int texID = Shader.PropertyToID("_SomeProperty");
      2. cameraBuffer.GetTemporaryRT(texID, camera.pixelWidth, camera.pixelHeight);
      3. cameraBuffer.Blit(BuiltinRenderTextureType.CameraTarget, texID);
      4. cameraBuffer.Blit(texID, BuiltinRenderTextureType.CameraTarget);

    2. When using
      CommandBuffer.Blit(src, dest, new Material(Shader.Find("Hidden/BlitCopy")));
      the
      "_MainTex"
      property is not populated
    Code (CSharp):
    1.  int texID = Shader.PropertyToID("_SomeProperty");
    2. cameraBuffer.GetTemporaryRT(texID, camera.pixelWidth, camera.pixelHeight);
    3. cameraBuffer.Blit(BuiltinRenderTextureType.CameraTarget, texID , new Material(Shader.Find("Hidden/BlitCopy")));
    4. cameraBuffer.Blit(texID, BuiltinRenderTextureType.CameraTarget);

    Solution attempts:
    • For the upside-down error I tried setting
      camera.forceIntoRenderTexture = true;
      and applying HDR button on the Camera
    • For the missing
      "_MainTex"
      property I have tried adding a global texture property
      "_MainTex"
      :

    Code (CSharp):
    1.  int texID = Shader.PropertyToID("_SomeProperty");
    2. cameraBuffer.GetTemporaryRT(texID, camera.pixelWidth, camera.pixelHeight);
    3. cameraBuffer.SetGlobalTexture("_MainTex", BuiltinRenderTextureType.CameraTarget);
    4. cameraBuffer.Blit(BuiltinRenderTextureType.CameraTarget, texID , new Material(Shader.Find("Hidden/BlitCopy")));
    5. cameraBuffer.Blit(texID, BuiltinRenderTextureType.CameraTarget);

    I have found two threads with similar issues:
    @AaronBrownLM: https://forum.unity.com/threads/com...er-blit-with-internal_blitcopy-shader.432699/
    @Simod: https://forum.unity.com/threads/how-to-use-hidden-blitcopy-shader.447041/

    Anyone with a solution or idea of why this is happening?
     
    Last edited: Dec 6, 2018
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Because Direct3D is weird and flips render targets upside down when MSAA is enabled.

    My understanding of what's happening is Unity has internal code that tries to keep track of if the render buffer is flipped or not so it knows to invert it before showing it on screen. However when you use Blit() it assumes you've flipped it and doesn't invert it anymore. The default blit (which uses "Hidden/BlitCopy" already) doesn't have any of that code and just directly copies the contents.

    This information is conveniently hidden, er, I mean documented here:
    https://docs.unity3d.com/Manual/SL-PlatformDifferences.html
     
    AcidArrow likes this.
  3. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    I did not know of this ressource, thank you for showing it.

    I tried disabling MSAA from the camera, but that did not resolve the upside-down issue.

    I guess I could resolve the up-side down issue by applying a shader as the third parameter in commandBuffer.Blit() but for some reason the "_MainTex" parameter is not getting populated. I tried the fix mentioned by others but when observing it through the frame debugger the "_MainTex" is still not populated. The fix is the following code:

    Code (CSharp):
    1. int texID = Shader.PropertyToID("_SomeProperty");
    2. cameraBuffer.GetTemporaryRT(texID, camera.pixelWidth, camera.pixelHeight);
    3. cameraBuffer.SetGlobalTexture("_MainTex", BuiltinRenderTextureType.CameraTarget);
    4. cameraBuffer.Blit(BuiltinRenderTextureType.CameraTarget, texID , new Material(Shader.Find("Hidden/BlitCopy")));
    5. cameraBuffer.Blit(texID, BuiltinRenderTextureType.CameraTarget);
    Any idea of why this is happening? The bug and fix is mentioned in these threads.

    https://forum.unity.com/threads/com...internal_blitcopy-shader.432699/#post-2891602

    https://forum.unity.com/threads/com...-material-source-texture-is-incorrect.454404/

    I tried with the following code:
     
    Last edited: Dec 9, 2018
  4. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    Alright, so I believe to have resolved the issue. I ended up doing the following:

    Code (CSharp):
    1. int texID = Shader.PropertyToID("_MainTex");
    2. cameraBuffer.GetTemporaryRT(texID, camera.pixelWidth, camera.pixelHeight);
    3. cameraBuffer.Blit(BuiltinRenderTextureType.CameraTarget, texID);
    4. cameraBuffer.Blit(texID, BuiltinRenderTextureType.CameraTarget, new Material(Shader.Find("Hidden/BlitCopyUpsideDown")));
    I can't explain fully why this work, but I guess it has to do with the fact that the property I have populated is named "_MainTex" and therefore it is populated in the shader field "_MainTex". My assumption was that this should not be necessary, but I guess I am in the wrong.
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    I don't have an explanation for why _MainTex isn't getting populated in the general case. However if the src and dst of a blit are the same texture, only the destination will be populated since you cannot read from the texture that is the current target.
     
  6. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    Getting the same, and it's simply a bug ... identical code in 2019 works correctly, but in 2018.4 LTS it appears that Graphics.Blit is just broken: it won't set _MainTex.

    (mumble mumble apparently considered "not important enough" for them to include the fix in LTS, nor even to update the docs once they knew it was broken mumble)