Hi!
I would like to use the SV_RENDERTARGETARRAYINDEX in a geometry shader to use a volume (3D) RenderTexture as a RenderTarget.
The following example fails in Unity 4 (does not write to the texture, as confirmed by debugging with PIX). It creates a volume texture, sets it as a RT, then uses DrawProcedural and a geometry shader. It compiles and runs fine, without obvious errors.
Component:
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour {
public Shader shader;
RenderTexture tex;
private Material material;
public int size = 16;
void CreateResources()
{
if (material == null)
{
material = new Material(shader);
material.hideFlags = HideFlags.HideAndDontSave;
}
if (tex == null)
{
tex = new RenderTexture (size, size, 0, RenderTextureFormat.ARGB32);
//tex = new RenderTexture (size, size, 0, RenderTextureFormat.ARGBFloat);
tex.volumeDepth = size;
tex.isVolume = true;
tex.Create();
//tex = new RenderTexture(size, size, 32, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
}
}
void Start ()
{
CreateResources();
material.SetFloat("Size", (float)size);
}
// Update is called once per frame
void Update ()
{
if (!shader)
return;
CreateResources();
material.SetPass(0);
Graphics.SetRenderTarget(tex);
Graphics.DrawProcedural(MeshTopology.Points, size);
}
}
Shader:
Shader "Custom/Volume Tex (GS)" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader
{
Pass
{
Tags { "RenderType"="Opaque" }
ZWrite Off
Blend One One
ZTest Always
Cull Off
CGPROGRAM
#pragma target 5.0
#pragma vertex VS_Main
#pragma fragment FS_Main
#pragma geometry GS_Main
#include "UnityCG.cginc"
struct GS_INPUT
{
float4 pos : SV_POSITION;
};
struct FS_INPUT
{
float4 pos : SV_POSITION;
uint layer : SV_RENDERTARGETARRAYINDEX;
};
float Size;
GS_INPUT VS_Main(uint id: SV_VertexID)
{
GS_INPUT output = (GS_INPUT)0;
output.pos.x = (float)id;
return output;
}
[maxvertexcount(6)]
void GS_Main(point GS_INPUT p[1], inout TriangleStream<FS_INPUT> triStream)
{
FS_INPUT output;
uint layer = p[0].pos.x;
output.layer = layer;
output.pos = float4(-1.0f, 1.0f, 0.0f, 1.0f);
triStream.Append(output);
output.pos = float4(1.0f, 1.0f, 0.0f, 1.0f);
triStream.Append(output);
output.pos = float4(1.0f, -1.0f, 0.0f, 1.0f);
triStream.Append(output);
output.pos = float4(1.0f, -1.0f, 0.0f, 1.0f);
triStream.Append(output);
output.pos = float4(-1.0f, -1.0f, 0.0f, 1.0f);
triStream.Append(output);
output.pos = float4(-1.0f, 1.0f, 0.0f, 1.0f);
triStream.Append(output);
}
float4 FS_Main(FS_INPUT input) : SV_Target
{
return float4(0.0f, 1.0f, 0.0f, 1.0f);
}
ENDCG
}
}
Fallback Off
}
I rewrote the code in a small DX11 c++ app and it works fine. I can’t tell with PIX what flags the 3D Texture is created with, so that might be a difference. Also I noticed CreateRenderTargetView fails if the format parameter is a “TYPELESS” type, as with which PIX reports the type of the Unity “tex” volume texture. So maybe that’s the difference? Or could it be some silly thing I am forgetting? Changing to a 2D texture allows this code to work fine (the commented line).
Mr Aras, if you see this, consider this either a cry for help, bug report, or feature request. It is really nice to be able to use normal shaders for 3D rendertargets, instead of compute shaders, because of the speed of hardware blending, compared to atomic ops. Those will be my fallback – if I have time I’ll compare the performance with an optimized implementation in a DX11 c++ app.
Thanks!