[Good for shader debug] UAV RandomWriteTarget

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:

  1. #pragma target 5.0
    • Since it’s using compute buffer
  2. RWStructuredBuffer Field : register(u4);
    • Remember to match the number in C# script
  3. 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:

  1. Wrap the buffer codes with #ifdef UNITY_COMPILER_HLSL … #endif
    • Surface shader is not ordinary shaders…
  2. 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

https://github.com/cinight/MinimalCompute

One thought on “[Good for shader debug] UAV RandomWriteTarget

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s