Terrain Grass Lighting

Hello everyone,

I noticed that terrain grass isn’t affected by dynamic lights at all. See for yourself: Create a new scene, add a directional light (set light color to black), then add a terrain and some grass. The grass is full-bright inbetween the dark terrain. This also applies for trees that are displayed as billboards.

I’m trying to fix this problem but I’m quite new to shader programming. I already learned that you can replace the built-in shader and I found out that each grass billboard’s color is calculated in TerrainWaveGrass (file TerrainEngine.cginc). The function takes the color values from the dry/healthy settings and passes is back to the shader (eg. “Hidden/TerrainEngine/Details/BillboardWavingDoublePass”). The shader however doesn’t take lighting into account. I feel like this is no big deal but I have no clue where to start or what to do exactly. Any help is appreciated!

Yhoko

Hi Yhoko,

from what I have see - the grass is more effected by a shadow map on the terrain then lights in general. (Example - if the shadow map is red - the grass will be tinted red) Tho I think I remember seeing a “How to” to make the grass be affected by light.

Perhaps burn out your lights to a light map, then have them effect the grass?

Cheers
~t

Thanks for your reply, ~t

Unfortunately I need to dynamically move/change the light so baking lightmaps is not an option (but it would be great if both could be combined, basic lightmaps and additional scene lights). It’d be a great help if you could dig up that example.

hi,

you will have to hack the built in terrain shader.
have a look at
http://forum.unity3d.com/viewtopic.php?t=45290
there you will find the source for a hacked terrain engine vertexlit 1sided shader. this might be a good starting point.

lars

Thanks, but I’m not getting along at all. I tried something like

UsePass “Diffuse/PPL”

but all I get is the following warning:

Shader wants normals, but the mesh doesn’t have them

My terrain is set to use Pixel Lighting so the normals should be there, right? I really need support on this, it’s too complex for me. I’d even be happy with simple ambient lighting for the grass. Please help!

I don’t think the grass mesh has normals. You’ll have to just do lighting by attenuation rather than surface modelling.

try this shader:

you have to place grass as detail meshes then choose “vertexlit”
the shader needs 2 sided geometry.

but maybe the results won’t convince you…

Shader "Hidden/TerrainEngine/Details/Vertexlit" { 
   Properties { 
   // we get no color?
   _Color ("Main Color", Color) = (1,1,1,1) 
   _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {} 
   _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5 
} 

Category { 
   Tags {"RenderType"="TransparentCutout"} 
   LOD 200 
   Alphatest Greater [_Cutoff] 
   AlphaToMask True 
   ColorMask RGB 
   Blend AppSrcAdd AppDstAdd
    
    
    
   // ------------------------------------------------------------------ 
   // ARB fragment program 
    
   SubShader { 
      Pass {
			Name "BASE"
			Tags {"LightMode" = "PixelOrNone"}
			Color [_PPLAmbient]
			SetTexture [_MainTex] {constantColor [_Color] Combine texture * primary DOUBLE, texture * primary}
		}
       
      // Vertex lights
		Pass { 
			Name "BASE"
			Tags {"LightMode" = "Vertex"}
			Lighting On
			Material {
				Diffuse [_Color]
				Emission [_PPLAmbient]
			} 
			SetTexture [_MainTex] {combine texture * primary DOUBLE, texture * primary}
		}
		
		
		/// 2nd pass
      Pass { 
        
         // Only render pixels less or equal to the value
         AlphaTest LEqual [_Cutoff]
                  
         // Set up alpha blending
         Blend SrcAlpha OneMinusSrcAlpha
         // Dont write to the depth buffer
         ZWrite Off
         SetTexture [_MainTex] { constantColor [_Color] Combine texture * constant, texture * constant}
      }
    /// end 2nd pass
    
      
    
    
    
   }    
    
    } 

Fallback "Transparent/Cutout/VertexLit", 2 

}

@Daniel Brauer: Thanks, I’m now applying the ambient lighting and it looks okay. Here’s my modified WavingGrass.cginc:

#include "UnityCG.cginc"
#include "TerrainEngine.cginc"


struct v2f {
	float4 pos : POSITION;
	float4 color : COLOR;
	float fog : FOGC;
	float4 uv : TEXCOORD0;
};

v2f vert (appdata_grass v) {
	v2f o;

	float waveAmount = v.color.a * _WaveAndDistance.z;	
	TerrainWaveGrass (v.vertex, waveAmount, v.color.rgb, o.color);

	o.pos = mul (glstate.matrix.mvp, v.vertex);
	o.fog = o.pos.z;
	o.uv = v.texcoord;

	// Saturate because Radeon HD drivers on OS X 10.4.10 don't saturate vertex colors properly
	float3 offset = v.vertex.xyz - _CameraPosition.xyz;	
	o.color.a = saturate( _WaveAndDistance.w - dot(offset, offset) );

	// Apply ambient lighting
	o.color *= glstate.lightmodel.ambient * 2;
	
	return o;
}


v2f BillboardVert (appdata_grass v) {
	v2f o;
	TerrainBillboardGrass (v.vertex, v.texcoord1.xy);
	float waveAmount = v.texcoord1.y;
	TerrainWaveGrass (v.vertex, waveAmount, v.color.rgb, o.color);
		
	float4 pos = mul (glstate.matrix.mvp, v.vertex);	
	o.pos = mul (glstate.matrix.mvp, v.vertex);
	o.fog = o.pos.z;
	o.uv = v.texcoord;

	// Apply ambient lighting
	o.color *= glstate.lightmodel.ambient * 2;
	
	return o;
}

@larsbertram: I tried this one but it looks really ugly. The soft grass was much better, I’m sorry.

And here’s a short demo showing the code in action:

http://www.yhoko.com/temp/unity/DarkGrass.html

  • No shadows yet as the grass wouldn’t receive them.

  • You’ll eventually see the moon in the second night :slight_smile:

Yhoko

Yhoko, that looks great. I was trying to get it to work on my end but with no luck. I replaced the built in WavingGrass.cginc with your edited verson, and I restarted unity, but the grass color isn’t affected by the ambient color. can you give a more detailed explanation on your method? :cry:

The file <WavingGrass.cginc> is being included by the shader files <WavingGrass.shader> and <WavingGrassBillboard.shader>. You have to add (copy) all of these files to your project, then restart Unity. If it doesn’t work after this, right-click on the shader files and chose “Reimport” - this also needs to be done after any changes to the .cginc file.

Btw. You should not modify the built-in shader files at all.

:smile: :smile: :smile:
THANK YOU!

I’ve been trying to get grass to change with the overall lighting of a scene ever since first picking up Unity. I had finally given up, thinking it was out of reach.

I tweaked some of your settings based on my light setup… I’m blending it with the diffuse color of the main lightsource as well as he ambient color of the scene:

	o.color=(glstate.light[0].diffuse)+(glstate.lightmodel.ambient);

Works wonderfully!

Now if we could only get it to accept shadow colors :slight_smile:

Thanks again Thoko… you just made my month!

My name is Yhoko, thank you.

I’m sorry but I can’t agree to your modifications at all. First: You leave out the original o.color completely, thus effecively removing the “color waves” from dry to healthy. Second: Your code does not take the light’s attenuation into account. Try adding a point light near your grass and modify the range value - looks horrible.

I suggest the following code for ambient, point and spot lights: (replaces all previous modifications)

	// Ambient lighting
	float4 lighting = glstate.lightmodel.ambient * 2;
	
	// Point and spot lights
	float4 lightpos = glstate.light[0].position;
	if( lightpos.w == 1 )
	{
		float4 att = glstate.light[0].attenuation;
		float3 dist = length( mul( lightpos, glstate.matrix.invtrans.modelview[0] ).xyz - v.vertex );
		
		lighting = max( lighting, glstate.light[0].diffuse * max( 0, 1 / ( att.x + att.y * dist + att.z * dist * dist ) ) );
	}
	
	// Apply lighting
	o.color *= lighting;

Directional lights are left out because of the missing normals.

To show the effect in action I added some fireflies to the grass demo: http://www.yhoko.com/temp/unity/DarkGrass.html

Yhoko

oops sorry about that Yhoko, was a slip of the keyboard :sweat_smile:

I see what you mean about the o.color affecting the grass colors. I had previously set them to both be white so I didn’t see it not taking affect.

Your updated code works great, and the firefly example is beautiful. thanks again for your help!

I am a shader noob but want the same effect, can someone please show that full shader’s code, I am not sure where to add the code to the current one to enable this. :sweat_smile:

Just install Unity 3, it’s implemented now.