Send data to c# script from shader: vert/frag and surface shaders!
C# Script
It keeps a compute buffer which stores the float array, and it’s buffer size is declared to store three float values (4 byte each). The compute buffer will then bind to number 4 UAV buffer.
On each frame when you hit play, it grabs the value of the compute buffer and show them on console.
using UnityEngine;
using System.Collections;
public class UAVTest : MonoBehaviour
{
public Material mat;
private ComputeBuffer fieldbuf;
private float[] fdata = new float[3];
void OnEnable()
{
Setup();
}
void OnDisable()
{
if (fieldbuf != null)
{
fieldbuf.Release();
fieldbuf.Dispose();
fieldbuf = null;
}
}
void Setup()
{
if (fieldbuf == null)
{
fieldbuf = new ComputeBuffer(3, sizeof(float), ComputeBufferType.Default);
}
}
void OnRenderObject()
{
Graphics.ClearRandomWriteTargets();
Setup();
mat.SetPass(0);
mat.SetBuffer("Field", fieldbuf);
Graphics.SetRandomWriteTarget(4, fieldbuf);
fieldbuf.GetData(fdata);
for (int i = 0; i < fdata.Length; i++)
{
print(mat.name+" : " + i + ": " + fdata[i]);
}
}
}
Vert and Fragment shader
It also keeps a structured float array and it’s using the number 4 UAV buffer. You can assign values to the float array in pixel shader. Things that you need to add into your shader code:
- #pragma target 5.0
- Since it’s using compute buffer
- RWStructuredBuffer Field : register(u4);
- Remember to match the number in C# script
- Field[0] = 12.3;, Field[1] = 4.56;, Field[2] = 0.789f;
- Since you declared there are 3 float values in C# script so you are free to use them at anywhere in fragment shader
Shader "UAVTest/VertFrag"
{
Properties
{
_MainTex("_MainTex (RGBA)", 2D) = "white" {}
}
SubShader
{
Tags{ "RenderType" = "Opaque" }
LOD 200
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 5.0
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
RWStructuredBuffer Field : register(u4);
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
float4 col = tex2D(_MainTex, i.uv);
Field[0] = 12.3;
Field[1] = 4.56;
Field[2] = 0.789f;
return col;
}
ENDCG
}
}
}
Surface shader
It’s actually same as vert+frag shader. But more things need to be done:
- Wrap the buffer codes with #ifdef UNITY_COMPILER_HLSL … #endif
- Surface shader is not ordinary shaders…
- Others are just same as vert and frag!
Shader "UAVTest/VertSurf"
{
Properties
{
_Amount("Extrusion Amount", Range(-1,1)) = 0.5
_MainTex("Albedo (RGB)", 2D) = "white" {}
_Glossiness("Smoothness", Range(0,1)) = 0.5
_Metallic("Metallic", Range(0,1)) = 0.0
}
SubShader
{
Tags{ "RenderType" = "Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Standard fullforwardshadows addshadow vertex:vert
#pragma multi_compile_instancing
#pragma target 5.0
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
#ifdef UNITY_COMPILER_HLSL
RWStructuredBuffer Field : register(u4);
#endif
//D3D 64KB * 500 Objects OPENGL 16KB * 125 Objects
UNITY_INSTANCING_CBUFFER_START(Props)
UNITY_DEFINE_INSTANCED_PROP(float, _Amount)
UNITY_INSTANCING_CBUFFER_END
void vert(inout appdata_full v, out Input o)
{
UNITY_INITIALIZE_OUTPUT(Input,o);
UNITY_SETUP_INSTANCE_ID(v);
v.vertex.xyz += v.normal * UNITY_ACCESS_INSTANCED_PROP(_Amount);
}
void surf(Input IN, inout SurfaceOutputStandard o)
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
#ifdef UNITY_COMPILER_HLSL
Field[0] = 0.123f;
Field[1] = 0.0456f;
Field[2] = 0.00789f;
#endif
}
ENDCG
}
}
Result
On the scene, create a sphere, create a material using either shader, assign the script, and hit play.
You will see 3 float values which comes from shader on console. 🙂
Project Link: https://drive.google.com/file/d/0BwLgUykgFtANVTdSaDF6R2FvaWs/view?usp=sharing
OR
One thought on “[Good for shader debug] UAV RandomWriteTarget”