Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

CommandBuffer and non-temporary RenderTexture

Discussion in 'General Graphics' started by MXAdd, Apr 29, 2015.

  1. MXAdd

    MXAdd

    Joined:
    Apr 23, 2015
    Posts:
    74
    Hi

    Is there any possibility to use non-temporary RenderTexture with CommandBuffer (as target for .Blit)

    for now code like this:
    Code (CSharp):
    1.  
    2. // create somewhere at start
    3. LinearZDownRT = new RenderTexture( TargetSX / 2, TargetSY / 2, 0, RenderTextureFormat.RGHalf, RenderTextureReadWrite.Linear );
    4.  
    5. // some time later
    6. RenderBeforeLights.Clear();
    7. RenderBeforeLights.Blit( BuiltinRenderTextureType.CurrentActive, LinearZDownRT, master.ZDownMaterial, 0 );
    8. RenderCamera.AddCommandBuffer(CameraEvent.BeforeLighting, RenderBeforeLights);
    9.  
    I would expect that from the moment of call to RenderCamera.AddCommandBuffer the LinearZDownRT will be filled every frame with content generated by master.ZDownMaterial shader.
    But the effect is that the RenderBeforeLights is not executed at all ;( [judging by frame debugger] ... why ?
    (if I change to temporary RT generated by CommandBuffer then all works fine)
     
  2. slice3d

    slice3d

    Joined:
    May 7, 2011
    Posts:
    207
    @Aras Why it is not allowed to use permanent RenderTexture instance as a target for CommandBuffer rendering?
    I'm trying to keep CommandBuffer rendering result for a later use (after another camera rendering finished with the same effect in the most difficult case).

    Here's another example with hacky workaround I made (project attached). Load and launch 'Test' scene, and you will see this:
    CB_Fail.png

    Uncomment #define ENABLE_WORKAROUND on top of the ImageEffect.cs script, and you'll see proper result for my example (but unfortunately this workaround doesn't cover all the cases I need):
    CB_Works.png

    CommandBuffersRenderTextureInstance.unitypackage

    Code (CSharp):
    1. #define ENABLE_WORKAROUND
    2.  
    3. using UnityEngine;
    4. using UnityEngine.Rendering;
    5. using System.Collections;
    6.  
    7. [RequireComponent(typeof(Camera))]
    8. public class ImageEffect : MonoBehaviour
    9. {
    10.     private const CameraEvent queue = CameraEvent.BeforeImageEffectsOpaque;
    11.     private const int downsampleFactor = 4;
    12.  
    13.     private int cachedWidth = -1;
    14.     private int cachedHeight = -1;
    15.     private int cachedAA = -1;
    16.     private CommandBuffer renderBuffer;
    17.     private Camera cam;
    18.  
    19.     private RenderTexture renderTexture;
    20.  
    21.     private readonly string renderTexturePropertyName = "_Test";
    22.     private int renderTexturePropertyID;
    23.     private RenderTargetIdentifier renderTextureID;
    24.  
    25.     private Material blitMaterial;
    26.  
    27.     private bool isDirty = false;
    28.  
    29.     //
    30.     void Awake()
    31.     {
    32.         cam = GetComponent<Camera>();
    33.  
    34.         renderTexturePropertyID = Shader.PropertyToID(renderTexturePropertyName);
    35.  
    36.         #if ENABLE_WORKAROUND
    37.         renderTextureID = new RenderTargetIdentifier(renderTexturePropertyID);
    38.         #endif
    39.  
    40.         Shader shader = Shader.Find("Custom/Blit");
    41.         blitMaterial = new Material(shader);
    42.  
    43.         UpdateTexture();
    44.     }
    45.  
    46.     //
    47.     void OnEnable()
    48.     {
    49.         renderBuffer = new CommandBuffer();
    50.         renderBuffer.name = "TestBuffer";
    51.         cam.AddCommandBuffer(queue, renderBuffer);
    52.     }
    53.  
    54.     //
    55.     void LateUpdate()
    56.     {
    57.         UpdateTexture();
    58.     }
    59.  
    60.     //
    61.     void OnPreRender()
    62.     {
    63.         if (isDirty)
    64.         {
    65.             UpdateBuffer();
    66.             isDirty = false;
    67.         }
    68.     }
    69.  
    70.     //
    71.     private int GetAA()
    72.     {
    73.         int aa = QualitySettings.antiAliasing;
    74.         if (aa == 0) { aa = 1; }
    75.      
    76.         // Reset aa value to 1 in case camera is in DeferredLighting or DeferredShading Rendering Path
    77.         if (cam.actualRenderingPath == RenderingPath.DeferredLighting || cam.actualRenderingPath == RenderingPath.DeferredShading) { aa = 1; }
    78.      
    79.         return aa;
    80.     }
    81.  
    82.     //
    83.     private void UpdateTexture()
    84.     {
    85.         int aa = GetAA();
    86.      
    87.         if (cam.pixelWidth == cachedWidth && cam.pixelHeight == cachedHeight && aa == cachedAA) { return; }
    88.      
    89.         cachedWidth = cam.pixelWidth;
    90.         cachedHeight = cam.pixelHeight;
    91.         cachedAA = aa;
    92.      
    93.         if (renderTexture != null && renderTexture.IsCreated())
    94.         {
    95.             renderTexture.Release();
    96.         }
    97.      
    98.         renderTexture = new RenderTexture(cachedWidth, cachedHeight, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
    99.         renderTexture.antiAliasing = cachedAA;
    100.         renderTexture.filterMode = FilterMode.Bilinear;
    101.         renderTexture.useMipMap = false;
    102.         renderTexture.wrapMode = TextureWrapMode.Clamp;
    103.         if (!renderTexture.Create())
    104.         {
    105.             Debug.LogError("UpdateTexture() : Failed to create highlightingBuffer!");
    106.         }
    107.         Shader.SetGlobalTexture(renderTexturePropertyID, renderTexture);
    108.  
    109.         #if !ENABLE_WORKAROUND
    110.         renderTextureID = new RenderTargetIdentifier(renderTexture);
    111.         #endif
    112.  
    113.         isDirty = true;
    114.  
    115.         Debug.Log("RenderTexture updated");
    116.     }
    117.  
    118.     //
    119.     private void UpdateBuffer()
    120.     {
    121.         renderBuffer.Clear();
    122.  
    123.         #if ENABLE_WORKAROUND
    124.         int aa = GetAA();
    125.         renderBuffer.GetTemporaryRT(renderTexturePropertyID, -1, -1, 24, FilterMode.Bilinear, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default, aa);
    126.         #endif
    127.  
    128.         renderBuffer.SetRenderTarget(renderTextureID);
    129.         renderBuffer.ClearRenderTarget(true, true, Color.cyan);
    130.  
    131.         int width = cam.pixelWidth / downsampleFactor;
    132.         int height = cam.pixelHeight / downsampleFactor;
    133.  
    134.         int texProperty = Shader.PropertyToID("_Temp");
    135.         RenderTargetIdentifier texID = new RenderTargetIdentifier(texProperty);
    136.  
    137.         renderBuffer.GetTemporaryRT(texProperty, width, height, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
    138.  
    139.         // Downsample rendered texture
    140.         renderBuffer.Blit(renderTextureID, texID);
    141.  
    142.         // Upsample rendered texture
    143.         renderBuffer.Blit(texID, renderTextureID);
    144.  
    145.         // Cleanup
    146.         renderBuffer.ReleaseTemporaryRT(texProperty);
    147.  
    148.         Debug.Log("CommandBuffer updated");
    149.     }
    150.  
    151.     //
    152.     private void OnRenderImage(RenderTexture src, RenderTexture dst)
    153.     {
    154.         Graphics.Blit(src, dst, blitMaterial);
    155.     }
    156. }
    157.  
     

    Attached Files:

  3. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    http://docs.unity3d.com/ScriptReference/Rendering.RenderTargetIdentifier-ctor.html
    Look at the constructor, perhaps you can create an identifier from your non-temporary render texture? (It does claim to handle it implicitly, so it "should" be enough to pass in your RT as a parameter?)

    Another thing I have noticed these last couple of days, LateUpdate is a BAD place to modify something you use while rendering! Much better to use OnPostRender. (It can otherwise cause some "fun" flickering issues!)

    Not to mention, why do you create a new RT every frame?
     
  4. slice3d

    slice3d

    Joined:
    May 7, 2011
    Posts:
    207
    @Zicandar Thanks for your reply, but:
    1. I'm initializing RenderTargetIdentifier with RenderTexture instance on line 110 if ENABLE_WORKAROUND is not defined.
    2. I'm using LateUpdate to resize (create new) RenderTexture because OnPreRender is called multiple times during Game window resizing.
    3. Why do you think that I'm creating RT every frame? "RenderTexture updated" is logged to the console only on start and then only after game window resizing.
     
  5. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    Well, I think I figured out what is happening!
    And this might be funny:
    Code (CSharp):
    1.        
    2. RenderTargetIdentifier testIdent = new RenderTargetIdentifier(renderTextureTest);
    3. RenderTargetIdentifier testIdent2 = new RenderTargetIdentifier("_MainTex");
    Now these should be different right?
    Well they ARE different, or at least their InstanceID's are. However the "_MainTex" uses m_nameID = 0.
    And well, anything NOT using name ID's are also getting that set to 0.

    This results in you NOT using your render texture, but whatever is set to _MainTex as the log is complaining about.
    (In this case it NOT being set, and you clearning the actual screen!...)

    Capture.PNG Obviously this is a bug in unity. As the RenderTargetIdentifier have the ability to use non-temporary render targets...

    I Strongly suggest you file a bug report with as simplified example as possible.
    (Just set render target and clear in the command buffer, it's enough to make it go bad...)
     
  6. slice3d

    slice3d

    Joined:
    May 7, 2011
    Posts:
    207
  7. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    Seconding this, however how it at all managed to be released like that is sad!
     
  8. slice3d

    slice3d

    Joined:
    May 7, 2011
    Posts:
    207
    Another related issue has appeared in Unity 5.4 beta - CommandBuffer.Blit no longer works to blit from non-temporary RenderTexture. @Aras Could you please take a look? I've filed a new bug report (case 776523)
     
  9. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    slice3d likes this.
  10. Deleted User

    Deleted User

    Guest

    Sorry to bump an old thread but this thread comes up on Google, and this is one of the threads I came to in my 40-hour journey to try to get something similar to this working for me. I did get this working, and without the need to define "Enable_Workaround". I posted two example scenes here in case anyone else is struggling with this: http://forum.unity3d.com/threads/ha...-with-commandbuffer-blit.432503/#post-2797158
     
    Frencich likes this.
  11. leozzyzheng2

    leozzyzheng2

    Joined:
    Jul 2, 2021
    Posts:
    60
    For anyone has the same problem today, just use the correct constructor of RenderTargetIdentifier, use the constructor takes Texture as input instead of the one take name as input.

    RenderTexture renderTexture = ....;
    renderTexture.Create();
    RenderTargetIdentifier rtid = new RenderTargetIdentifier(renderTexture); <-- use texture, don't use id or name
     
    Frencich likes this.