Why does my shader only shade objects based on their normals in the X axis?

I am trying to implement a shader with Gouraud style shading in which the shading is dominated by vertex color. However, my shader only seems to want to use normals that are facing in the X axis to shade, regardless of where the light source is, what type, or if there are even light sources! I know that I am probably missing something blatant, but what?

Shader "Gouraud"
{
	Properties
	{
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_Color ("Diffuse Material Color", Color) = (1,1,1,1)
      	_SpecColor ("Specular Material Color", Color) = (1,1,1,1)
      	_Shininess ("Shininess", Float) = 1
	}
	SubShader
	{
		Pass
		{
	        Tags { "LightMode" = "ForwardBase" }
	
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
	
			// User-specified properties
			uniform float4 _Color;
			uniform float4 _SpecColor;
			uniform float  _Shininess;
	
			// color of light source (from "Lighting.cginc")
			uniform float4 _LightColor0;
	
			// Vertex and Fragment Structs
			struct vertexInput {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
	
			struct vertexOutput {
				float4 pos : SV_POSITION;
				float4 col : COLOR;
			};
	
			vertexOutput vert(vertexInput v)
			{
				vertexOutput output;
	
				// Compute directional vectors
				float3 normalDir = normalize(float3(mul(float4(v.normal, 0.0), _World2Object)));
				float3 lightDir  = normalize(_WorldSpaceLightPos0.xyz - v.vertex);
				float3 viewDir   = normalize(_WorldSpaceCameraPos.xyz - v.vertex);
	
				// Compute the ambient term
				float3 ambientTerm = float3(UNITY_LIGHTMODEL_AMBIENT) * float3(_Color);
	
				// Compute the diffuse term
				float  diffuseLight = max(0.0, dot(normalDir, lightDir));
				float3 diffuseTerm  = _Color * diffuseLight;
	
				// Compute the specular term
				float3 halfwayDir   = normalize(lightDir + viewDir);
				float specularLight = pow(max( 0,dot(normalDir, halfwayDir)), 1);
	
				// If we have no diffuse component, then we have no specular component
				if(diffuseLight <= 0.0)
				{
					specularLight = 0;
				}
	
				float3 specularTerm = specularLight * _LightColor0 * _SpecColor;
	
				// Assign final color and position output
				output.col = float4(ambientTerm + diffuseTerm + specularTerm, 1.0);
				output.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				return output;
			}
	
			float4 frag(vertexOutput input) : COLOR
			{
			 	return input.col;
			}
	
			ENDCG
			}
		}
}

1 Answer

1

Well there are a few problems I can spot:

  • A normal is a direction and they are converted using this code:

    half3 normal = normalize(mul((float3x3) UNITY_MATRIX_IT_MV, v.normal));

  • Your code for the light position won’t work with directional lights, usually that would be:

    float3 lightDir = normalize(_WorldSpaceLightPos0.xyz - (v.vertex * _WorldSpaceLightPos0.w));

w will be 0 for directional lights.

  • Specular lights normally need their specular element calculating in the fragment shader - or you are only getting specularity on vertices and interpolating the results.