Constructing a Cube Primitive using Shader

Ive been trying to construct a Cube Primitive using Shaders, but havent really got anything to appear on the screen. Im using Unity Pro 4.3.1f1 at Windows 7 and using a GTX 260 as graphic card. The “Use Direct 3D 11” option at Player Settings is enable.

The reason I need to construct a Cube Primitive using Shader is that I need to render a Point Cloud (10k+ points), where every point has got to be rendered using cubes.

This is my try so far:

Shader "Custom/CubeColor" 
{	
	Properties 
	{
		_MainTex ("TileTexture", 2D) = "white" {}
		_PointSize("PointSize", Float) = 10 
		_MyColor ("Some Color", Color) = (0,1,0,1) 
	}
	
	SubShader 
	{
		LOD 200
		
		Pass 
		{
			CGPROGRAM

			#pragma only_renderers d3d11
			#pragma target 4.0
			
			#include "UnityCG.cginc"

			#pragma vertex   myVertexShader
			#pragma geometry myGeometryShader
			#pragma fragment myFragmentShader
	
			struct vIn // Into the vertex shader
			{
				float4 vertex : POSITION;
                float4 color  : COLOR0;
            };
            
            struct gIn // OUT vertex shader, IN geometry shader
			{
				float4 pos : SV_POSITION;
				float4 col : COLOR0;				
	            float size : PSIZE;
            };
            
 			struct v2f // OUT geometry shader, IN fragment shader 
			{
				float4 pos 		  : SV_POSITION;
                float2 uv_MainTex : TEXCOORD0;
				float4 col : COLOR0;	
            };
            
            float4 	  _MainTex_ST;
            sampler2D _MainTex; 
            float     _PointSize;
            fixed4 _MyColor; 
			
			// ----------------------------------------------------
			gIn myVertexShader(vIn v)
			{
			    gIn o; // Out here, into geometry shader
				UNITY_INITIALIZE_OUTPUT(gIn,o);

				// Passing on color to next shader (using .r/.g there as tile coordinate)
				o.col = _MyColor;//v.color;
				
				o.size = _PointSize;
				
				// Passing on center vertex (tile to be built by geometry shader from it later)
				o.pos = v.vertex;
 
                return o;
			}	
			
			[maxvertexcount(10)]    // 8 vertex
			// ----------------------------------------------------
			// Using "point" type as input, not "triangle"
			void myGeometryShader(point gIn vert[1], inout TriangleStream<v2f> triStream)
			{
				const float f = _PointSize/2; //half size
				
				 The 8 vertex positions of a CUBE tile
			    const float4 vc[8] = { float4( -f, -f, -f, 0.0f ),
			    					   float4( -f, -f, +f, 0.0f ),
			    					   float4( -f, +f, -f, 0.0f ),
			    					   float4( -f, +f, +f, 0.0f ),
			    					   float4( +f, -f, -f, 0.0f ),
			    					   float4( +f, -f, +f, 0.0f ),
			    					   float4( +f, +f, -f, 0.0f ),
			    					   float4( +f, +f, +f, 0.0f ) };	
			  								
				const int TRI_STRIP_CUBE[9]  = { 0, 2, 1, 3, 5, 7, 4, 6, 0 };
			
				v2f v[12]; //for CUBE
				
				// Assign new vertices positions (12 new tile vertices, forming CUBE)
				for (int i=0;i<12;i++) { v_.pos = vert[0].pos + vc*;	}*_

* // Position in view space*
for (int i=0;i<6;i++) { v.pos = mul(UNITY_MATRIX_MVP, v*.pos); }*

* // Build the CUBE tile by submitting triangle strip vertices*
for (int i=0;i<9;i++) triStream.Append(v[TRI_STRIP_CUBE*]);
_ triStream.RestartStrip();
}*_

* // ----------------------------------------------------*
* half4 myFragmentShader(v2f IN) : COLOR*
* {*
* // Not considering normals/light here. Just texture*
* half4 c = tex2D (MainTex, IN.uv_MainTex);*
* return c;
}*_

* ENDCG*
* }*
* }*
* FallBack “Diffuse”*
}

And the test Mesh is created with the following method:
void CreateMesh( int startRange, int endRange, Mesh currMesh ) {
* Vector3[] points = new Vector3[maxPointsPerMesh];*
* int[] indexes = new int[maxPointsPerMesh];*
* Color[] colors = new Color[maxPointsPerMesh];*
* for(int i=0;i<points.Length;++i) {*
_ points = new Vector3(Random.Range(startRange,endRange), Random.Range (startRange,endRange), Random.Range (startRange,endRange));
indexes = i;
colors = new Color(Random.Range(0.0f,1.0f),Random.Range (0.0f,1.0f),Random.Range(0.0f,1.0f),1.0f);
* }*_

* currMesh.vertices = points;*
* currMesh.colors = colors;*
* currMesh.SetIndices(indexes, MeshTopology.Points,0);*

* }*
My Game Object has a MeshFilter and a MeshRenderer.
What am I doing wrong?
Thank you all!

Well, haven’t used a geometry shader yet, mainly because i don’t have a dx11 card :smiley: (i’m still on winxp 32bit with dx9.0c).

However your cube creation looks a bit strange:

  • First of all a cube needs 24 vertices, not 12. You have 6 sides with 4 vertices each.
  • Next thing is your “vc” array has a size of 8 but you use your for variable “i” which goes up to index 11 so you’re out of bounds here.
  • Why do you only multiply the first 6 elements in your “v” array with the MVP?
  • Why do you only have 9 indices? shouldn’t that be 36 indices? (6*2*3)
  • Finally it seems you map a texture in your fragment shader but you don’t set any uvs when you create the new vertices.

Well, as i said i haven’t written a geometry shaders yet, but i guess it should be something like that:

[maxvertexcount(24)] // 24 vertices
void myGeometryShader(point gIn vert[1], inout TriangleStream<v2f> triStream)
{
    const float f = _PointSize/2; //half size
    const float4 vc[8] = { float4( -f, -f, -f, 0.0f ),  //0
                           float4( -f, -f, +f, 0.0f ),  //1
                           float4( -f, +f, -f, 0.0f ),  //2
                           float4( -f, +f, +f, 0.0f ),  //3
                           float4( +f, -f, -f, 0.0f ),  //4
                           float4( +f, -f, +f, 0.0f ),  //5
                           float4( +f, +f, -f, 0.0f ),  //6
                           float4( +f, +f, +f, 0.0f ) };//7
    const int VERT_ORDER[24] = {0,1,3,2, // left
                                0,2,6,4, // front  
                                4,6,7,5, // right
                                7,3,1,5, // back
                                2,3,7,6, // top
                                0,4,5,1  // bottom
                               };
    v2f v[24]; //for CUBE
     
    // Assign new vertices positions (24 new tile vertices, forming CUBE)
    for (int i=0;i<24;i++) { v<em>.pos = vert[0].pos + vc[VERT_ORDER*]; }*</em>

// Position in view space
for (int i=0;i<24;i++) { v.pos = mul(UNITY_MATRIX_MVP, v*.pos); }*

// Build the CUBE tile by submitting triangle strip vertices
for (int i=0;i<6;i++)
{
triStream.Append(v[i*4 + 0]);
triStream.Append(v[i*4 + 1]);
triStream.Append(v[i*4 + 3]);
triStream.Append(v[i*4 + 2]);
triStream.RestartStrip();
}
}
I can’t test it, so if you have some time, feel free to go ahead :wink: Oh, i didn’t calculated uvs yet, so the cube will have the same color. Since your vertex-struct doesn’t have a normal, i’m not sure if the lighting will work as it should.

I finally made it, and it also worked on my previous hardware. Thank you @Bunny85 for your marvelous help!
Here is the code that got it working:

Shader "Custom/CubeShader" 
{    	
	Properties 
	{
		_MainTex ("TileTexture", 2D) = "white" {}
		_PointSize("Point Size", Float) = 1.0
	}
	
	SubShader 
	{
		LOD 200
		
		Pass 
		{
			CGPROGRAM

			#pragma only_renderers d3d11
			#pragma target 4.0
			
			#include "UnityCG.cginc"

			#pragma vertex   myVertexShader
			#pragma geometry myGeometryShader
			#pragma fragment myFragmentShader
			
			#define TAM 36
						
			struct vIn // Into the vertex shader
			{
				float4 vertex : POSITION;
                float4 color  : COLOR0;
            };
            
            struct gIn // OUT vertex shader, IN geometry shader
			{
				float4 pos : SV_POSITION;
				float4 col : COLOR0;
            };
            
 			struct v2f // OUT geometry shader, IN fragment shader 
			{
				float4 pos 		  : SV_POSITION;
                float2 uv_MainTex : TEXCOORD0;
				float4 col : COLOR0;
            };
            
            float4 	  _MainTex_ST;
            sampler2D _MainTex; 
            float     _PointSize;			
			// ----------------------------------------------------
			gIn myVertexShader(vIn v)
			{
			    gIn o; // Out here, into geometry shader
				// Passing on color to next shader (using .r/.g there as tile coordinate)
				o.col = v.color;				
				// Passing on center vertex (tile to be built by geometry shader from it later)
				o.pos = v.vertex;
 
                return o;
			}
			
			// ----------------------------------------------------
			
			[maxvertexcount(TAM)] 
			// ----------------------------------------------------
			// Using "point" type as input, not "triangle"
			void myGeometryShader(point gIn vert[1], inout TriangleStream<v2f> triStream)
			{							
				float f = _PointSize/20.0f; //half size
				
				const float4 vc[TAM] = { float4( -f,  f,  f, 0.0f), float4(  f,  f,  f, 0.0f), float4(  f,  f, -f, 0.0f),	//Top							     
									     float4(  f,  f, -f, 0.0f), float4( -f,  f, -f, 0.0f), float4( -f,  f,  f, 0.0f),	//Top
									     
									     float4(  f,  f, -f, 0.0f), float4(  f,  f,  f, 0.0f), float4(  f, -f,  f, 0.0f), 	//Right
									     float4(  f, -f,  f, 0.0f), float4(  f, -f, -f, 0.0f), float4(  f,  f, -f, 0.0f), 	//Right
									     
									     float4( -f,  f, -f, 0.0f), float4(  f,  f, -f, 0.0f), float4(  f, -f, -f, 0.0f), 	//Front
									     float4(  f, -f, -f, 0.0f), float4( -f, -f, -f, 0.0f), float4( -f,  f, -f, 0.0f), 	//Front
									     
									     float4( -f, -f, -f, 0.0f), float4(  f, -f, -f, 0.0f), float4(  f, -f,  f, 0.0f),	//Bottom									     
									     float4(  f, -f,  f, 0.0f), float4( -f, -f,  f, 0.0f), float4( -f, -f, -f, 0.0f), 	//Bottom
									     
									     float4( -f,  f,  f, 0.0f), float4( -f,  f, -f, 0.0f), float4( -f, -f, -f, 0.0f),	//Left
									     float4( -f, -f, -f, 0.0f), float4( -f, -f,  f, 0.0f), float4( -f,  f,  f, 0.0f),	//Left
									     
									     float4( -f,  f,  f, 0.0f), float4( -f, -f,  f, 0.0f), float4(  f, -f,  f, 0.0f),	//Back
									     float4(  f, -f,  f, 0.0f), float4(  f,  f,  f, 0.0f), float4( -f,  f,  f, 0.0f) 	//Back
									     };
									     
				
				const float2 UV1[TAM] = { float2( 0.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), 		//Esta em uma ordem
										  float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), 		//aleatoria qualquer.
										  
										  float2( 0.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), 
										  float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ),
										  
										  float2( 0.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), 
										  float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ),
										  
										  float2( 0.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), 
										  float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ),
										  
										  float2( 0.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), 
										  float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ),
										  
										  float2( 0.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), 
										  float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f ), float2( 1.0f,	0.0f )								  		  
								  		  };	
															
				const int TRI_STRIP[TAM]  = {  0, 1, 2,  3, 4, 5,
										       6, 7, 8,  9,10,11,
										      12,13,14, 15,16,17,
										      18,19,20, 21,22,23,
										      24,25,26, 27,28,29,
										      30,31,32, 33,34,35  
										      }; 
															
				v2f v[TAM];
				int i;
				
				// Assign new vertices positions 
				for (i=0;i<TAM;i++) { v<em>.pos = vert[0].pos + vc_; v*.col = vert[0].col;	}*_</em>

* // Assign UV values*
for (i=0;i<TAM;i++) v.uv_MainTex = TRANSFORM_TEX(UV1*,_MainTex);*

* // Position in view space*
for (i=0;i<TAM;i++) { v.pos = mul(UNITY_MATRIX_MVP, v*.pos); }*

* // Build the cube tile by submitting triangle strip vertices*
* for (i=0;i<TAM/3;i++)*
* {*
triStream.Append(v[TRI_STRIP[i*3+0]]);
triStream.Append(v[TRI_STRIP[i*3+1]]);
triStream.Append(v[TRI_STRIP[i*3+2]]);

* triStream.RestartStrip();*
* }*
* }*

* // ----------------------------------------------------*
* float4 myFragmentShader(v2f IN) : COLOR*
* {*
* //return float4(1.0,0.0,0.0,1.0);*
* return IN.col;*
* }*

* ENDCG*
* }*
* }*
}