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

How to use texture array as render target depths?

Discussion in 'General Graphics' started by crazii, Aug 11, 2016.

  1. crazii

    crazii

    Joined:
    Jun 27, 2016
    Posts:
    31
    Hi there,

    I'm using texture array as render targets, well it's a bit unclear on the doc:
    http://docs.unity3d.com/Manual/SL-TextureArrays.html

    What I'm trying to do:
    1.create color & depth textures, set dimension. Dunno how to set the array length, I'm guessing volumeDepth.
    Code (CSharp):
    1.     void Start () {
    2.         _texture = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.ARGB32);
    3.         _texture.filterMode = FilterMode.Point;
    4.         _texture.useMipMap = false;
    5.         _texture.generateMips = false;
    6.         _texture.dimension = UnityEngine.Rendering.TextureDimension.Tex2DArray;
    7.         _texture.volumeDepth = 4;
    8.  
    9.         _depth = new RenderTexture(Screen.width, Screen.height, 16, RenderTextureFormat.Depth);
    10.         _depth.filterMode = FilterMode.Point;
    11.         _depth.useMipMap = false;
    12.         _depth.generateMips = false;
    13.         _depth.dimension = UnityEngine.Rendering.TextureDimension.Tex2DArray;
    14.         _depth.volumeDepth = 4;
    15.  
    16.         Shader.SetGlobalTexture("_TestTextureArray", _texture);
    17.         Shader.SetGlobalTexture("_TestTextureArrayDepth", _depth);
    18.  
    19.         if (_cam == null)
    20.             _cam = (new GameObject("TextureaArray_TestCam", typeof(Camera))).GetComponent<Camera>();
    21.  
    22.         _cam.enabled = false;
    23.         _cam.orthographic = true;
    24.         _cam.renderingPath = RenderingPath.Forward;
    25.         _cam.depth = Camera.main.depth - 1;
    26.         _cam.clearFlags = CameraClearFlags.SolidColor;
    27.         _cam.backgroundColor = Color.black;
    28.  
    29.         if (ms_DummyTexture == null)
    30.             ms_DummyTexture = new RenderTexture(16, 16, 0, RenderTextureFormat.R8);
    31.     }
    [/code]
    2.Use a command buffer to set texture array as render target.
    Code (CSharp):
    1.  
    2.     void Update () {
    3.  
    4.         Color[] c = new Color[4] { Color.blue, Color.green, Color.grey, Color.red };
    5.         float[] depth = new float[4] { 0, 0.25f, 0.5f, 0.75f };
    6.  
    7.         for(int i = 0; i < 4; ++i)
    8.         {
    9.             CommandBuffer cb = new CommandBuffer();
    10.             cb.SetRenderTarget(_texture, _depth, 0, CubemapFace.Unknown, i); //i as depthSlice: element index in array
    11.             cb.ClearRenderTarget(true, true, c[i], depth[i]);
    12.  
    13.             _cam.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, cb);
    14.             _cam.cullingMask = 0;    //not actually drawing anything. just use the CommandBuffer to draw.
    15.             _cam.targetTexture = ms_DummyTexture;
    16.             _cam.Render();
    17.             _cam.RemoveAllCommandBuffers();
    18.         }
    19.     }
    20.  
    To simplify, I just use the clear color/depth to verify the result.

    The result:
    color texture array is fine, it turns out the right different color if you changes the array "index" in shader.
    But depth texture array is interesting: which ever index I chose, it always samples the last element:

    Code (CSharp):
    1. Shader "CraziiWorks/TextureArrayTest"
    2. {
    3.     SubShader
    4.     {
    5.         Tags
    6.         {
    7.             "RenderType" = "Opaque"
    8.             "Queue" = "Geometry+1"
    9.         }
    10.  
    11.         Pass{
    12.             Tags{ "LightMode" = "ForwardBase" }
    13.             CGPROGRAM
    14.             #pragma target 3.5
    15.             #pragma vertex vert
    16.             #pragma fragment frag
    17.  
    18.             struct appdata_t {
    19.                 float4 vertex : POSITION;
    20.             };
    21.  
    22.             struct v2f {
    23.                 float4 vertex : SV_POSITION;
    24.                 half4 uv : TEXCOORD0;
    25.             };
    26.  
    27.             UNITY_DECLARE_TEX2DARRAY(_TestTextureArrayDepth);
    28.             UNITY_DECLARE_TEX2DARRAY(_TestTextureArray);
    29.  
    30.             v2f vert(appdata_t v)
    31.             {
    32.                 v2f o = (v2f)0;
    33.                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    34.                 o.uv = o.vertex;
    35. #if UNITY_UV_STARTS_AT_TOP
    36.                 o.uv.y *= -1;
    37. #endif
    38.                 return o;
    39.             }
    40.  
    41.             half4 frag(v2f i) : SV_Target
    42.             {
    43.                 i.uv.xy /= i.uv.w;
    44.                 i.uv.xy = (i.uv.xy + 1) * 0.5;
    45.                 static const int index = 0; //statically change index here
    46.  
    47.                 //return UNITY_SAMPLE_TEX2DARRAY(_TestTextureArray, float3(i.uv.xy, index)); //this is OK
    48.                 return UNITY_SAMPLE_TEX2DARRAY(_TestTextureArrayDepth, float3(i.uv.xy,index));    //always the same(last) one?
    49.             }
    50.             ENDCG
    51.         }//Pass
    52.  
    53.     }//SubShader
    54.     FallBack Off
    55. }
    56.  
    i.e. for above code, the sampling result fro depth array element (index=0), is 0.75f bright red. (cleared depth value for last element).
    But It should be 0(black) - the cleared depth value for the first element. and index = 0,1,2, have the same result.

    I seems to me as if Unity doesn't bind the right element of depth buffer array, or it just have one unique element.


    Am I doing wrong? If it is the expected behavior, Is There any hardware limitation on this?
    Thanks a lot if anyone shines some light.


    Suggestions To UNITY TEAM:
    This new feature is good, but when used as Render Target, it brings some confusion and inconvenience:

    1.The documentation is unclear: To set the array length, volumeDepth is right, but it's still a kinda guessing.
    2.No Camera functions to set exact element (yeah it's less used but it's still needed), So I have to do the trick with CommandBuffer.
    Graphics.SetRenderTarget() may be another option, but it's low level and I need to do custom draws.
     
  2. GuardHei

    GuardHei

    Joined:
    Feb 10, 2018
    Posts:
    85
    I think the problem still remains in 2019.2 ...
     
  3. AsFlower

    AsFlower

    Joined:
    Aug 1, 2017
    Posts:
    10
    I don't think it is possible to set mulitple depth buffer for a draw call on a DirectX 11 platform. What CommandBuffer.SetRenderTarget() do is just to set the render texture array(_texture) as mulitple render targets and ONE depth texture(_depth) as the depth buffer.
    What are you trying to achieve anyway?
     
  4. GuardHei

    GuardHei

    Joined:
    Feb 10, 2018
    Posts:
    85
    I'm trying to render cascaded shadowmaps using texarray, but it is not a problem to me now because Unity uses the color buffer to render the shadowmap. Depth doesn't matter anyway.