Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Using CopyTexture from RenderTexture to Texture2D not working !?!?!?

Discussion in 'Shaders' started by Vagabond_, Oct 31, 2017.

  1. Vagabond_

    Vagabond_

    Joined:
    Aug 26, 2014
    Posts:
    1,145
    Hi, i am using an nVidia GTX 750 Ti with full DX11/12 support and unity 5.6 to 2017.3 beta6 to try using Graphics.CopyTexture to copy information from a render texture to a normal Texture2D which should be possible as the platform and the GPU seems to be capable of this.

    Copying from a Texture2D to a render texture is working great just the opposite is not.

    How one suppose to copy a RenderTexture information to a regular Texture2D using Gprahics.CopyTexture... ?

    All the textures are created without mip maps.

    Same with Texture2DArrays. Copying the Texture2DArray to the render texture array is working fine for me but i am not able to do the opposite.

    There are no any errors - it is just the normal textures are purely white instead of having the appropriate color copied from the render texture!

    Notes:
    * the render texture has color information because when i save it it is as it should.
    * both render texture and the Texture2D are the same ARGB32 type and the same resolution.
     
    Last edited: Oct 31, 2017
  2. Vagabond_

    Vagabond_

    Joined:
    Aug 26, 2014
    Posts:
    1,145
    I just noticed that the actual CopyTexture is working. The issue though is that the texture to which the information is copied can not be just saved to an asset. I guess the texture exists in the GPU memory, but it is visible in the inspector with all the colors. Once i attempt to save it, the new saved texture is white.

    Same question still - how should one have to properly save a Texture2D when Graphics.CopyTexture was used to copy info to it. I guess it should be done on the CPU side before save it to an asset !?
     
  3. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
  4. Vagabond_

    Vagabond_

    Joined:
    Aug 26, 2014
    Posts:
    1,145
  5. Marco-Sperling

    Marco-Sperling

    Joined:
    Mar 5, 2012
    Posts:
    620
    So what was your solution?
     
  6. kripto289

    kripto289

    Joined:
    Feb 21, 2013
    Posts:
    466
    What about using "Graphics.Blit(RenderTexture, Texture2D);"?
     
  7. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
  8. Tomer-Barkan

    Tomer-Barkan

    Joined:
    Jul 31, 2012
    Posts:
    150
    @Vagabond_ could you please share your solution? I'm having the same issue, texture is saved grey but appears correct in the explorer.
     
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,236
    If you need to save an image out of a render texture, you must use ReadPixels() to copy the contents of a RenderTexture to a Texture2D. This is because the contents of a render texture only exists on the GPU, and CopyTexture() is purely a GPU side operation* if a render texture is used as either the source or destination.

    * If you use CopyTexture() on two non rendertexture texture assets that are both marked as readable, it will also perform a separate CPU side copy in addition to the GPU side copy.
     
    Last edited: Feb 20, 2019
  10. Tomer-Barkan

    Tomer-Barkan

    Joined:
    Jul 31, 2012
    Posts:
    150
    I see. It's weird because the copy does work, and the inspector does show the Texture2D with what was on the render texture. So it creates a strange scenario where the Texture2D that exists on the GPU is different than the one that exists in the RAM.
     
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,236
    What renders on screen is what's on the GPU, so the inspector is showing you the contents of the texture as they exist on the GPU as that's all the GPU knows about. Most of the time these are in sync, so it's not a problem; the texture on the GPU only has data because the GPU that was on disk / in RAM is what was sent to the GPU in the first place. CopyTexture() subverts this expectation as the data in the texture can be copied from essentially any arbitrary data on the GPU, including from render textures which as mentioned above the CPU has zero knowledge of.

    That's what ReadPixels() exists for though, to ask the GPU for the data so it can be transferred back to the domain of the CPU.


    Basically CopyTexture is great for doing stuff that only needs to happen on the GPU as it leaves all of the work to the GPU and thus is super fast. That's what it exists for. For most modern cases the CPU doesn't ever need to know the contents of a texture. Indeed with the usual work flow the contents of a texture asset don't even stay in CPU side RAM after it's been sent to the GPU as it's no longer needed. Texture assets are read from the disk, sent to the GPU, and then flushed from CPU RAM.
     
    a52, jjbish, Roman200333 and 4 others like this.
  12. mbhdra

    mbhdra

    Joined:
    Jul 23, 2019
    Posts:
    1
    @Vagabond_ how did you manage to get it worked? I have the same issue and I need your solution. Could you please share?
     
  13. Chrisi12er

    Chrisi12er

    Joined:
    Sep 7, 2014
    Posts:
    9
    There is also the option to use the AsyncGPUReadback class. This can avoid any blocking caused by the GPU Resource Readback when leveraging the AsyncCallback and is also more flexible in terms of supported formats. I, for example, needed to copy data from an RG32 RenderTexture which is not supported by ReadPixels. You still need to call SetPixelData which probably isn't for free but it should be less blocking overall when using the AsyncCallback to set the Texture2D Data. Haven't done any performance comparisons though.

    Edit: Removed unnecessary Graphics.CopyTexture calls (thanks for pointing that out @GeorgeAdamon)

    Code (CSharp):
    1.  
    2. using UnityEngine.Rendering;
    3.  
    4. //Required Textures (need to have similar formats obviously)
    5. RenderTexture renderTexture = new RenderTexture(64, 64, 0);
    6. Texture2D texture2D = new Texture2D(64, 64);
    7.  
    8. //Synchronously
    9.  var asyncAction = AsyncGPUReadback.Request(renderTexture, 0);
    10. asyncAction.WaitForCompletion();
    11. texture2D.SetPixelData(asyncAction.GetData<byte>(), 0);
    12. texture2D.Apply();
    13.  
    14. //Asynchronously
    15. AsyncGPUReadback.Request(renderTexture, 0, (AsyncGPUReadbackRequest asyncAction) =>
    16. {
    17.     texture2D.SetPixelData(asyncAction.GetData<byte>(), 0);
    18.     texture2D.Apply();
    19. });
    20.  
     
    Last edited: Jan 14, 2023
  14. GeorgeAdamon

    GeorgeAdamon

    Joined:
    May 31, 2017
    Posts:
    47
    The above code (at least the asynchronous part, which I tested) works even without the Graphics.CopyTexture() call.
     
  15. zhutianlun810

    zhutianlun810

    Joined:
    Sep 17, 2017
    Posts:
    162
    I am still curious on it. If I create a Texture2D like Texture2d test = new Texture2D(), and use CopyTexture to copy a renderTexture to it, what will actually happen? I think creating a texture2D is a pure CPU operation, so the texture2d must be in CPU RAM. But the CopyTexture is doing stuff on GPU side?
     
  16. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,236
    My guess is as soon as you call CopyTexture() Unity will create the Texture2D resource on the GPU and copy the contents of the RenderTexture to it.
     
  17. Intraterrestrial_

    Intraterrestrial_

    Joined:
    Jun 27, 2021
    Posts:
    20
    Did anyone find a fix to use copytexture like extracting only pixel data or
    something?
     
  18. NitinAltran

    NitinAltran

    Joined:
    Mar 9, 2021
    Posts:
    8
    Was any one able to solve this issue for Android as the AsyncReadback request is not supported on android?
     
  19. iiiVSLAM

    iiiVSLAM

    Joined:
    Mar 5, 2020
    Posts:
    3
    The graphic api only enables Vulkan and it should work