- Home /
Using Texture2DArray as RenderTarget and passing data to fragment shader
I'd like to render multiple views into an array of 2D textures, then pass this array into a fragment shader for processing.
Imagine a stack of differing 2D viewpoints of the 3D scene, where on the 0th texture we render the left-most view and the last element is the right-most view of the scene.
I would like to pass this array to a fragment shader for processing.
Currently I'm just using one render texture and tiling the views, which works but has limitations in dimension sizes.
I came across a post that said 5.4 has hardware 2D texture array support, but there is no documentation on using the class Texture2DArray. I've tried but I'm not sure how to access each 2D texture element from the array to write to it, or read from it in the shader.
Is there any way to bind all slices of a texture array as $$anonymous$$RTs? I have 2 sets of lighting effects coefficients I need to subsample in screen space. It would be great if I could make 2 textures arrays with 4 slices each, render into them using $$anonymous$$RT, and not have to bind a bajillion textures in the shaders that read from them.
The docs make it sound like binding slice -1 is supposed to do that, but it's kind of vague and only binds slice 0. Rendering into texture arrays in 5.6.0 also appears to be completely broken in the GLCore renderer. :-\
Answer by crazii · Aug 10, 2016 at 06:50 PM
For render textures, you don't use Texture2DArray,
Still, use RenderTexture. Set RenderTexture.dimension to be TextureDimension.Tex2DArray, and the desired volumeDepth(array length), after creating the RenderTexture object.
Then, you can use Graphics.SetRenderTarget with the depthSlice indicating which element of the array you want to render to.
How to read it is much more simpler, just use a float3 with z as the array index.
FYI: https://docs.unity3d.com/540/Documentation/Manual/SL-TextureArrays.html
Hi crazii, do you have an example of that? Have you tried (and achieved) to do that? I tried but it always writes to the slice 0, no matter what index do I pass as depthSlice. I checked everything with RenderDoc and all is ok, I can't understand what's happening. Do I have to write any extra code in the shader that uses the slice as render target? Thanks in advance.
Yes, I managed to do it on tex2d array of color buffer. but for depth texture, unity always write to the same slice.
using UnityEngine; using System.Collections; using UnityEngine.Rendering;
public class TextureArrayTest : $$anonymous$$onoBehaviour {
public RenderTexture _texture;
private RenderTexture _depth;
private Camera _cam;
static private RenderTexture ms_DummyTexture;
// Use this for initialization
void Start () {
_texture = new RenderTexture(Screen.width, Screen.height, 16, RenderTextureFormat.ARGB32);
_texture.filter$$anonymous$$ode = Filter$$anonymous$$ode.Point;
_texture.use$$anonymous$$ip$$anonymous$$ap = false;
_texture.generate$$anonymous$$ips = false;
_texture.dimension = UnityEngine.Rendering.TextureDimension.Tex2DArray;
_texture.volumeDepth = 4;
_depth = new RenderTexture(Screen.width, Screen.height, 16, RenderTextureFormat.Depth);
_depth.filter$$anonymous$$ode = Filter$$anonymous$$ode.Point;
_depth.use$$anonymous$$ip$$anonymous$$ap = false;
_depth.generate$$anonymous$$ips = false;
_depth.dimension = UnityEngine.Rendering.TextureDimension.Tex2DArray;
_depth.volumeDepth = 4;
Shader.SetGlobalTexture("_TestTextureArray", _texture);
Shader.SetGlobalTexture("_TestTextureArrayDepth", _depth);
if (_cam == null)
_cam = (new GameObject("TextureaArray_TestCam", typeof(Camera))).GetComponent<Camera>();
_cam.enabled = false;
_cam.orthographic = true;
_cam.renderingPath = RenderingPath.Forward;
_cam.depth = Camera.main.depth - 1;
_cam.clearFlags = CameraClearFlags.SolidColor;
_cam.backgroundColor = Color.black;
if (ms_DummyTexture == null)
ms_DummyTexture = new RenderTexture(16, 16, 0, RenderTextureFormat.R8);
}
// Update is called once per frame
void Update () {
Color[] c = new Color[4] { Color.blue, Color.green, Color.grey, Color.red };
float[] depth = new float[4] { 0, 0.25f, 0.5f, 0.75f };
//for (int i = 0; i < 4; ++i)
//{
// CommandBuffer cb = new CommandBuffer();
// cb.SetRenderTarget(_texture, _depth, 0, CubemapFace.$$anonymous$$, i); //i as depthSlice: element index in array
// cb.ClearRenderTarget(true, true, c[i], depth[i]);
// _cam.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, cb);
// _cam.culling$$anonymous$$ask = 0; //not actually drawing anything. just use the CommandBuffer.
// _cam.targetTexture = ms_DummyTexture;
// _cam.Render();
// _cam.RemoveAllCommandBuffers();
//}
for (int i = 0; i < 4; ++i)
{
_cam.targetTexture = _texture;
Graphics.SetRenderTarget(_texture, 0, CubemapFace.$$anonymous$$, i);
//Graphics.SetRenderTarget(_texture.colorBuffer, _depth.depthBuffer, 0, CubemapFace.$$anonymous$$, i);
//Graphics.SetRenderTarget(_depth, 0, CubemapFace.$$anonymous$$, i);
GL.Clear(true, true, c[i], depth[i]);
}
}
}
Shader "Test/Tex2DArrayVisualization" { SubShader { Tags { "RenderType" = "Opaque" "Queue" = "Geometry+1" }
Pass{
Tags{ "Light$$anonymous$$ode" = "ForwardBase" }
CGPROGRA$$anonymous$$
#pragma target 3.5
#pragma vertex vert
#pragma fragment frag
struct appdata_t {
float4 vertex : POSITION;
};
struct v2f {
float4 vertex : SV_POSITION;
half4 uv : TEXCOORD0;
};
UNITY_DECLARE_TEX2DARRAY(_TestTextureArrayDepth);
UNITY_DECLARE_TEX2DARRAY(_TestTextureArray);
v2f vert(appdata_t v)
{
v2f o = (v2f)0;
o.vertex = mul(UNITY_$$anonymous$$ATRIX_$$anonymous$$VP, v.vertex);
o.uv = o.vertex;
if UNITY_UV_STARTS_AT_TOP
o.uv.y *= -1;
endif
return o;
}
half4 frag(v2f i) : SV_Target
{
i.uv.xy /= i.uv.w;
i.uv.xy = (i.uv.xy + 1) * 0.5;
static const int index = 1;
return UNITY_SA$$anonymous$$PLE_TEX2DARRAY(_TestTextureArray, float3(i.uv.xy, index)); //this is O$$anonymous$$
//return UNITY_SA$$anonymous$$PLE_TEX2DARRAY(_TestTextureArrayDepth, float3(i.uv.xy,index)); //always the same(last) one?
}
ENDCG
}//Pass
}//SubShader
FallBack Off
}
Thank you very much. I don't see any difference regarding the code I wrote in my project but will try to copy/paste yours in an empty project and see what happens.
Your answer
Follow this Question
Related Questions
Copy non-rectangle part of one texture to another 2 Answers
Texture2D GetPixel returns the same value everywhere 2 Answers
How do I initialize a float texture by script? 1 Answer
GetPixels of RenderTexture 3 Answers
Get RenderTexture 1 Answer