WIP Grass Shader, Vague Error Message...

Working on translating the grass shader from: Instant Animated Grass | TU Wien – Research Unit of Computer Graphics into Unity4 and coming across some errors that are very vague:

Shader "Hidden/TerrainEngine/Splatmap/Lightmap-FirstPass"
{
	Properties
	{
		_Control ("Control (RGBA)", 2D) = "red" {}
		_Splat3 ("Layer 3 (A)", 2D) = "white" {}
		_Splat2 ("Layer 2 (B)", 2D) = "white" {}
		_Splat1 ("Layer 1 (G)", 2D) = "white" {}
		_Splat0 ("Layer 0 (R)", 2D) = "white" {}
		
		// used in fallback on old cards
		_MainTex ("BaseMap (RGB)", 2D) = "white" {}
		_Color ("Main Color", Color) = (1,1,1,1)
		_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
	}

	SubShader
	{
		Tags
		{
			"SplatCount" = "4"
			"Queue" = "Geometry-100"
			"RenderType" = "Opaque"
		}
			
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#pragma target 3.0
		#pragma exclude_renderers d3d11_9x d3d11
		#include "UnityCG.cginc"
		
		struct v2f
		{
			float4 position : POSITION;
			float4 color : COLOR;			// vertex  color, per vertex lightmap?
			float2 texcoord : TEXCOORD0;
			float2 texcoord1 : TEXCOORD1;
			float3 eyeDirTan : TEXCOORD2;
			//float4 positionViewProj : TEXCOORD3;
		};

		float4 _EyePosition;
		float _WindTime; // runs from 0 to 10 per second
		sampler2D _GrassTex;
		sampler2D _GrassTex1;
		sampler2D _GrassBlades;
		sampler2D _WindNoise;
		sampler2D _ColorMap;
		float4 _GrassTex_ST;
		float4 _GrassTex1_ST;
		
		v2f vert (inout appdata_full v)
		{			
			// Supply the shader with tangents for the terrain
			//float3 normal = v.normal;
			//float3 binormal = cross(float3(1, 0, 1), normal);
			//float3 tangent = normalize(cross(normal, binormal));
			//
			// set tangent
			//v.tangent.xyz = tangent.xyz;
			//if (dot(cross(normal, tangent), binormal) < 0)
			//{
			//	v.tangent.w = -1.0f;
			//}
			//else
			//{
			//	v.tangent.w = 1.0f;
			//}
			//float3x3 TangentBinormalNormalMatrix  = float3x3(tangent, binormal, normal);
			float3x3 TangentBinormalNormalMatrix  = float3x3(float3(0,0,0), float3(0,0,0), float3(0,0,0));

			v2f output;
			
			output.position = mul(UNITY_MATRIX_MVP, v.vertex);	
			//output.positionViewProj = output.position;
			
			output.texcoord = TRANSFORM_TEX(v.texcoord, _GrassTex);
            output.texcoord1 = TRANSFORM_TEX(v.texcoord1, _GrassTex1);
			output.texcoord1 = float2((output.texcoord1.x + _WindTime * 0.2) / 2,
									  (output.texcoord1.y + _WindTime * 0.2) / 2);	// coordinate offset by time from wind texture
								
			output.color = v.color;
			
			float4 eyeDir = -(_EyePosition - output.position);
			output.eyeDirTan = normalize(mul(TangentBinormalNormalMatrix, eyeDir.xyz));	
			
			return output;
		}

		// Set everything which is constant in the fragment shader, the values used are for the moderate height data set.
		#define MAX_RAYDEPTH 5 // Number of iterations.
		#define PLANE_NUM 16.0 // Number of grass slice grid planes per unit in tangent space.
		#define PLANE_NUM_INV (1.0 / PLANE_NUM)
		#define PLANE_NUM_INV_DIV2 (PLANE_NUM_INV / 2)
		#define GRASS_SLICE_NUM 8 // Number of grass slices in texture grassblades.
		#define GRASS_SLICE_NUM_INV (1.0 / GRASS_SLICE_NUM)
		#define GRASS_SLICE_NUM_INV_DIV2 (GRASS_SLICE_NUM_INV / 2)
		#define GRASSDEPTH GRASS_SLICE_NUM_INV // Depth set to inverse of number of grass slices so no stretching occurs.
		#define TC1_TO_TC2_RATIO 8 // Ratio of texture coordinate set 1 to texture coordinate set 2, used for the animation lookup.
		#define PREMULT (GRASS_SLICE_NUM_INV*PLANE_NUM) // Saves a multiply in the shader.

		void frag(v2f input)
		{
			//Initialize increments/decrements and per fragment constants
		 	float2 orthoLookup; // Will contain texture lookup coordinates for grassblades texture.
			float4 color = float4(0.0, 0.0, 0.0, 0.0);
		 	float2 plane_offset = float2(0.0, 0.0);					
		 	float3 rayEntry = float3(input.texcoord.xy, 0.0);
			float zOffset = 0.0;
			bool zFlag = 1;
		
		 	//The signs of eyeDirTan determines if we increment or decrement along the tangent space axis
			//plane_correct, planemod and pre_dir_correct are used to avoid unneccessary if-conditions. 
		 	float2 dirSign = float2(sign(input.eyeDirTan.x), sign(input.eyeDirTan.y));	
		 	float2 plane_correct = float2((dirSign.x + 1) * GRASS_SLICE_NUM_INV_DIV2,
		 	                              (dirSign.y + 1) * GRASS_SLICE_NUM_INV_DIV2);
		 	float2 planemod = float2(floor(rayEntry.x * PLANE_NUM) / PLANE_NUM,
		 	                         floor(rayEntry.y * PLANE_NUM) / PLANE_NUM);
			float2 pre_dir_correct = float2((dirSign.x + 1) * PLANE_NUM_INV_DIV2,
			                                (dirSign.y + 1) * PLANE_NUM_INV_DIV2);
		
			int hitcount;
		 	for (hitcount = 0; hitcount < MAX_RAYDEPTH % (MAX_RAYDEPTH + 1); hitcount++) // %([MAX_RAYDEPTH] + 1) speeds up compilation.
																						 // It may prove to be faster to early exit this loop
																						 // depending on the hardware used.
		 	{
				//Calculate positions of the intersections with the next grid planes on the u, v tangent space axis independently.
		 		float2 dir_correct = float2(dirSign.x * plane_offset.x + pre_dir_correct.x,
		 		                            dirSign.y * plane_offset.y + pre_dir_correct.y);			
				float2 distance = float2((planemod.x + dir_correct.x - rayEntry.x) / (input.eyeDirTan.x),
				                         (planemod.y + dir_correct.y - rayEntry.y) / (input.eyeDirTan.y));
		 					
		 		float3 rayHitpointX = rayEntry + input.eyeDirTan * distance.x;   
		  		float3 rayHitpointY = rayEntry + input.eyeDirTan * distance.y;
				
				//Check if we hit the ground. If so, calculate the intersection and look up the ground texture and blend colors.
		  		if ((rayHitpointX.z <= -GRASSDEPTH)  (rayHitpointY.z <= -GRASSDEPTH)) 	
		  		{
		  			float distanceZ = (-GRASSDEPTH) / input.eyeDirTan.z; // rayEntry.z is 0.0 anyway 
		
		  			float3 rayHitpointZ = rayEntry + input.eyeDirTan * distanceZ;
					float2 orthoLookupZ = float2(rayHitpointZ.x, rayHitpointZ.y);
								
		  			color += (1.0 - color.w) * tex2D(_ColorMap, orthoLookupZ);
		  			if (zFlag == 1)
		  			{
		  				zOffset = distanceZ; // write the distance from rayEntry to intersection
		  			}
		  			zFlag = 0; //Early exit here if faster.		
		  		}  
		  		else
		 		{		
		 			//check if we hit a u or v plane, calculate lookup accordingly with wind shear displacement.
					if(distance.x <= distance.y)
		 			{
		 				float4 windX = (tex2D(_WindNoise, input.texcoord1 + rayHitpointX.xy / TC1_TO_TC2_RATIO) - 0.5) / 2;
						
						float lookupX = -(rayHitpointX.z + (planemod.x + dirSign.x * plane_offset.x) * PREMULT) - plane_correct.x;
						orthoLookup = float2(rayHitpointX.y + windX.x * (GRASSDEPTH + rayHitpointX.z), lookupX); 
						
						plane_offset.x += PLANE_NUM_INV; // increment/decrement to next grid plane on u axis
						if (zFlag==1)
						{
							zOffset = distance.x;
						}
					}
					else
					{
						float4 windY = (tex2D(_WindNoise, input.texcoord1 + rayHitpointY.xy / TC1_TO_TC2_RATIO) -0.5) / 2;
		 			
						float lookupY = -(rayHitpointY.z + (planemod.y + dirSign.y * plane_offset.y) * PREMULT) - plane_correct.y;
						orthoLookup = float2(rayHitpointY.x + windY.y * (GRASSDEPTH + rayHitpointY.z), lookupY);
		 			
						plane_offset.y += PLANE_NUM_INV;  // increment/decrement to next grid plane on v axis
						if (zFlag==1)
						{
							zOffset = distance.y;
						}
		  			}
		  			 
		 	 		color += (1.0 - color.w) * tex2D(_GrassBlades, orthoLookup);
		 	
		 	 		if (color.w >= 0.49)
		 	 		{
		 	 			zFlag = 0;
		 	 		}	//Early exit here if faster.
		  		}
			}
		
		    color += (1.0 - color.w) * tex2D(_ColorMap, orthoLookup); //Fill remaining transparency in case there is some left. Can be replaced by a texture lookup
							   										   //into a fully opaque grass slice using orthoLookup.
		
		
		    color.xyz *= (input.color.xyz); //Modulate with per vertex lightmap,as an alternative, modulate with N*L for dynamic lighting.
		
		    //zOffset is along eye direction, transform and add to vertex position to get correct z-value.
		    //input.positionViewProj += mul(UNITY_MATRIX_MVP, input.eyeDirTan.xzy * zOffset); 
		
		    //Divide by homogenous part.
		    //input.depth = positionView.z/positionView.w;
		}
		
		ENDCG
	}
		
	// Fallback to Diffuse
	Fallback "Diffuse"
}

You’ll notice that there were some variables defined: “normal”, “binormal”, “tangent”. I worried that these might be naming conflicts so I first commented them out (as in the above code) and replaced their dependencies. This unfortunately had no affect. I have also renamed them and deleted them completely and still get the same error messages.

What am I doing wrong? :slight_smile:

Vague error messages are what shaderlab is all about! Sorry I got nothin.

I dont know if its same or not, but here is something to start with:
http://forum.unity3d.com/threads/120531-Free-Grass-shader

Well your very first error message is pointing on your pragma vertex vert line. I had some problems with shaders partially dependent on vertex light in unity 4. The easiest, though kind of butchery, solution was to remove “vertex vert” from pragma. I’m still learning ways of shaders, not good enough to translate existing shaders into shaderlab, but simple trial and error (and certain amount of wasted time) so far works for me.

Turns out the problem was using inout for appdata_full. I think the “out” status was insisting that I was setting the vertex properties somehow. Removing that seemed to solve the problem.