////////////////////////////// MOVING GRASS // Vertex program to wave some grass about // Assumes UV texture coords of v==0 indicates the top of the grass void grass_vp(float4 position : POSITION, float3 normal : NORMAL, float2 uv : TEXCOORD0, out float4 oPosition : POSITION, out float2 oUv : TEXCOORD0, out float4 oColour : COLOR, uniform float4x4 worldViewProj, //uniform float4 camObjPos, uniform float4 ambient, uniform float4 objSpaceLight, uniform float4 lightColour, uniform float4 offset) { float4 mypos = position; //offset = float4(0.5, 0, 0, 0); float4 factor = float4(1,1,1,1) - uv.yyyy; mypos = mypos + offset * factor; oPosition = mul(worldViewProj, mypos); oUv = uv; // Color // get vertex light direction (support directional and point) float3 light = normalize(objSpaceLight.xyz - (mypos.xyz * objSpaceLight.w)); // grass is just 2D quads, so if light passes underneath we need to invert the normal // abs() will have the same effect float diffuseFactor = abs(dot(normal.xyz, light)); oColour = ambient + diffuseFactor * lightColour; } void grass_fp( float4 position : POSITION, float2 uv : TEXCOORD0, float4 colour : COLOR, out float4 oColour : COLOR, uniform sampler2D diffuseMap ) { float4 texColor = tex2D(diffuseMap, uv.xy); oColour = float4(texColor.rgb * colour.rgb, texColor.a); if(oColour.a < 0.58) discard; } void grassTex_vp( float4 position : POSITION, float4 normal : NORMAL, float2 uv : TEXCOORD0, out float4 oPosition : POSITION, out float2 oUv : TEXCOORD0, //out float4 oNormal : NORMAL, uniform float4x4 worldViewProj, uniform float4 ambient, uniform float4 objSpaceLight, uniform float4 lightColour, uniform float4 offset) { // Position float4 mypos = position; float4 factor = float4(1,1,1,1) - uv.yyyy; mypos = mypos + offset * factor; oPosition = mul(worldViewProj, mypos); // Texture Coord oUv.xy = uv.xy; } /// grass_vp ambient void grassAmbient_vp( float4 position : POSITION, float4 normal : NORMAL, float2 uv : TEXCOORD0, out float4 oPosition : POSITION, out float2 oUv : TEXCOORD0, out float4 oColour : COLOR, //out float4 oNormal : NORMAL, //uniform float4 camObjPos, uniform float4x4 worldViewProj, uniform float4 ambient, uniform float4 offset) { // Position float4 mypos = position; float4 factor = float4(1,1,1,1) - uv.yyyy; mypos = mypos + offset * factor; oPosition = mul(worldViewProj, mypos); // Texture Coord oUv.xy = uv.xy; /* // Normal // Make vec from vertex to camera float4 EyeVec = camObjPos - mypos; // Dot the v to eye and the normal to see if they point // in the same direction or opposite float aligned = dot(normal, EyeVec); // -1..1 // If aligned is negative, we need to flip the normal if (aligned < 0) normal = -normal; //oNormal = normal; */ // Color oColour = ambient; } void grassAmbient_fp( float4 position : POSITION, float2 uv : TEXCOORD0, float4 colour : COLOR, out float4 oColour : COLOR, uniform sampler2D diffuseMap ) { float4 texColor = tex2D(diffuseMap, uv.xy); oColour = float4(colour.rgb, texColor.a); } //////////////////////// GRASS SHADOW CASTER // Shadow caster vertex program. void grasscaster_vp(float4 position : POSITION, float2 uv : TEXCOORD0, out float4 oPosition : POSITION, out float2 oUv : TEXCOORD0, out float2 oDepth : TEXCOORD1, uniform float4x4 worldViewProj, uniform float4 offset, uniform float4 texelOffsets) { float4 mypos = position; float4 factor = float4(1,1,1,1) - uv.yyyy; mypos = mypos + offset * factor; oPosition = mul(worldViewProj, mypos); // fix pixel / texel alignment oPosition.xy += texelOffsets.zw * oPosition.w; oDepth.x = oPosition.z; oDepth.y = oPosition.w; oUv = uv; } void grasscaster_fp( float4 position : POSITION, float2 uv : TEXCOORD0, float2 depth : TEXCOORD1, out float4 result : COLOR, uniform sampler2D diffuseMap ) { float alpha = tex2D(diffuseMap, uv).a; if (alpha > 0.001) { result = float4(1.0f, 1.0f, 1.0f, 0.0f); } else { float finalDepth = depth.x / depth.y; // just smear across all components // therefore this one needs high individual channel precision result = float4(finalDepth.xxx, 1.0f); } } //////////////////////// GRASS SHADOW RECEIVER void grassreceiver_vp( float4 position : POSITION, float4 normal : NORMAL, float2 uv : TEXCOORD0, out float4 oPosition : POSITION, out float4 oShadowUV : TEXCOORD0, out float3 oUv : TEXCOORD1, out float4 oColour : COLOR, //out float4 oNormal : NORMAL, uniform float4x4 world, uniform float4x4 worldViewProj, uniform float4x4 texViewProj, uniform float4 camObjPos, uniform float4 objSpaceLight, uniform float4 lightColour, uniform float4 offset) { float4 mypos = position; float4 factor = float4(1,1,1,1) - uv.yyyy; mypos = mypos + offset * factor; oPosition = mul(worldViewProj, mypos); oUv.xy = uv.xy; // Transform position to world space float4 worldPos = mul(world, mypos); // calculate shadow map coords oShadowUV = mul(texViewProj, worldPos); // Make vec from vertex to camera float4 EyeVec = camObjPos - mypos; // Dot the v to eye and the normal to see if they point // in the same direction or opposite float alignedEye = dot(normal, EyeVec); // -1..1 // If aligned is negative, we need to flip the normal if (alignedEye < 0) normal = -normal; //oNormal = normal; // get vertex light direction (support directional and point) float3 lightVec = normalize(objSpaceLight.xyz - (mypos.xyz * objSpaceLight.w)); // Dot the v to light and the normal to see if they point // in the same direction or opposite float alignedLight = dot(normal.xyz, lightVec); // -1..1 // If aligned is negative, shadowing/lighting is not possible. oUv.z = (alignedLight < 0)? 0 : 1 ; float diffuseFactor = max(alignedLight, 0); //oColour = diffuseFactor * lightColour; oColour = lightColour; } void grassreceiver_fp( float4 position : POSITION , float4 shadowUV : TEXCOORD0 , float3 uv : TEXCOORD1 , float4 vertexLight : COLOR , out float4 oColour : COLOR , uniform sampler2D shadowMap : register(s0) , uniform sampler2D diffuseMap : register(s1) //, uniform float inverseShadowmapSize , uniform float fixedDepthBias , uniform float gradientClamp , uniform float gradientScaleBias ) { if (shadowUV.z > 0) { float4 diffuse = tex2D(diffuseMap, uv.xy); if (diffuse.a > 0.001) { oColour = float4(0.0f, 0.0f, 0.0f, 0.0f); } else { // point on shadowmap (no gradient as cg1.4 compiler is unable to handle that complexity) shadowUV = shadowUV / shadowUV.w; float4 shadowDepths = tex2D(shadowMap, shadowUV.xy); float gradientFactor = gradientClamp * gradientScaleBias; float depthAdjust = gradientFactor + fixedDepthBias * shadowDepths.x; float centerdepth = shadowDepths.x + depthAdjust; oColour = (centerdepth > shadowUV.z) ? float4(vertexLight.rgb, diffuse.a) : float4(0, 0, 0, diffuse.a); } } else { oColour = float4(0.0f, 0.0f, 0.0f, 0.0f); } }