Shadows on terrain with SplattingShader

Falagard

28-05-2006 06:18:17

Greetings,

Has anyone gotten texture shadows to work on the PLM2 terrain with SplattingShader?

I've tried with and without vertex compression enabled, and variations of turning on and off vertex normals, vertex program morph, vertex lit, etc. and so far haven't been successful.

BTW, there's a bug in ShadowReceiver.cg that was fixed in DecompressShadowReceiver.cg back in march not in ShadowReceiver. Generates a CG error unless you change it to:

Coord1 = mul(texViewProjMatrix, iTexcoord);

Tuan, have you tried shadows with the SplattingShader? I had shadows working with regular fixed function Splatting2Edit but that didn't require a shadow receiver VP obviously.

Falagard

28-05-2006 07:37:03

Okay, did some playing with it.

First, I turned of vertex compression in the terrain config and commented out the shadow_receiver_vertex_program_ref in the SplattingMaterialShader knowing that the normal fixed function shadows would work, however as I expected the shadows have z-fighting issues on my geForce 6800 because of precision issues - the terrain is rendered through vertex shader pipeline and the shadows through fixed function so it gives z-fighting problems. Plus this solution won't hold once vertex morphing is working, and with compressed terrain.

Then I did some searching on main forums and found a couple posts with custom splatting receiver vertex programs and the two I found had vps that looked something like this:


void main_vp(
float4 pos : POSITION,
float4 tex : TEXCOORD0,
out float4 oPos : POSITION,
out float2 Coord1 : TEXCOORD0,
out float2 Coord2 : TEXCOORD1,
out float4 color: COLOR,
uniform float4x4 worldViewProjMatrix,
uniform float4x4 texViewProjMatrix,
uniform float4x4 worldMatrix
)
{
oPos = mul(worldViewProjMatrix, pos);
// multiply position by world matrix, then by projective view/proj
float4 newpos = mul(worldMatrix, pos);
Coord1 = mul(texViewProjMatrix, newpos);
Coord2 = Coord1 ;

color = float4(1,1,1,1);
}


whereas the vertexshadowreceiver/vp used by plm2 looks something like this (non compressed version for simplicity)


void main_vp(
float4 pos : POSITION,
float4 iTexcoord : TEXCOORD0,

uniform float4 compressionSettings,
uniform float4x4 worldViewProj,
//uniform float4x4 worldMatrix,
uniform float4x4 texViewProjMatrix,

out float4 oPos : POSITION,
out float4 Coord1 : TEXCOORD0,
out float4 Coord2 : TEXCOORD1
)
{
oPos = mul(worldViewProj, iTexcoord);

//Coord1 = mul(worldMatrix, oPos);
Coord1 = mul(texViewProjMatrix, iTexcoord);
Coord2 = Coord1 ;
}


They look completely different, what's the deal? :-)
The oPos is being set by the incoming texture coordinate?
And you're setting the output coord1 ... to the incoming texture coordinate * texviewprojmatrix?

Anyhow, I'm not an expert but those two code samples seem to be doing completely different things?

Anyhow, I tried modifying it to be the same as the first CG program above and that didn't seem to work either ;-)

Oh and I'm using modulative texture shadows.

tuan kuranes

30-05-2006 09:49:43

I tried to automatically support shader+shadows with Crashy's help, but never found the time to test it... It's supposed to work (DecompressShadowReceiver.cg, ShadowReceiver.cg in paginglandscape2/materials/scripts)


oPos = mul(worldViewProj, iTexcoord);
that looks like an error (the copy&paste ones...)

to the incoming texture coordinate * texviewprojmatrix?
yep, that was coming from http://www.ogre3d.org/docs/manual/manual_19.html#SEC105

But a re-read of all that doc part against our proposed shaders by a native english speaker that may be mandatory...

Falagard

02-06-2006 20:06:53

I've fixed the shaders and materials so shadows now work when using SplattingShader both compressed and non compressed.

Here are the changes. They involved fixing the cg programs with correct shadow receiving code, and modifying the materials so they they used param_named_auto instead of param_indexed_auto and passed the world_matrix to the shader. The fragment programs aren't used so weren't modified beyond some formatting changes.

DecompressShadowReceiver.cg

void main_vp(
float4 iPos : POSITION,
float4 iTexCoord0 : TEXCOORD0,
float1 iLodPos : BLENDWEIGHT,

uniform float4 compressionSettings,
uniform float4x4 worldViewProj,
uniform float4x4 worldMatrix,
uniform float4x4 texViewProjMatrix,

out float4 oPos : POSITION,
out float4 oTexCoord0 : TEXCOORD0,
out float4 oTexCoord1 : TEXCOORD1,
out float4 oColor : COLOR
)
{
float height = ((iPos.x + 32768) + (iLodPos.x - iPos.x) * compressionSettings[3]) * compressionSettings[1];
oPos = float4(iTexCoord0.x * compressionSettings[0], height, iTexCoord0.y * compressionSettings[2], 1.0);
float4 uv = mul(worldMatrix, oPos);
oPos = mul(worldViewProj, oPos); //at this time, oPos is the uncompressed input position
oTexCoord0 = mul(texViewProjMatrix, uv);
oTexCoord1 = oTexCoord0;
oColor = float4(1.0f, 1.0f, 1.0f, 1.0f);
}

void main_fp(
float4 uvproj : TEXCOORD0,
float2 uv : TEXCOORD1,

out float4 colour : COLOR,

uniform float4 lightDiffuse,
uniform sampler2D shadowMap,
uniform sampler2D colorMap,
uniform sampler2D detailMap)
{
// get shadow value
float3 shadow = tex2Dproj(shadowMap, uvproj).xyz;

// Calculate dot product
colour = tex2Dproj(shadowMap, uvproj) * tex2D(detailMap, uv) * tex2D(colorMap, uv);
}


ShadowReceiver.cg

void main_vp(
float4 iPos : POSITION,
out float4 oPos : POSITION,
out float4 oTexCoord0 : TEXCOORD0,
out float4 oTexCoord1 : TEXCOORD1,
out float4 oColor : COLOR,
uniform float4x4 worldViewProj,
uniform float4x4 worldMatrix,
uniform float4x4 texViewProjMatrix
)
{
oPos = mul(worldViewProj, iPos);
float4 uv = mul( worldMatrix, iPos);
oTexCoord0 = mul(texViewProjMatrix, uv);
oTexCoord1 = oTexCoord0;
oColor = float4(1.0f, 1.0f, 1.0f, 1.0f);
}

void main_fp(
float4 uvproj : TEXCOORD0,
float2 uv : TEXCOORD1,

out float4 colour : COLOR,

uniform float4 lightDiffuse,
uniform sampler2D shadowMap,
uniform sampler2D colorMap,
uniform sampler2D detailMap)
{
// get shadow value
float3 shadow = tex2Dproj(shadowMap, uvproj).xyz;

// Calculate dot product
colour = tex2Dproj(shadowMap, uvproj) * tex2D(detailMap, uv) * tex2D(colorMap, uv);
}


SplattingShader.material

material SplattingMaterialShaderDecompress
{
technique
{
pass
{
vertex_program_ref DecompressSplatShadercg/VP
{
param_named_auto worldViewProj worldviewproj_matrix
//param_named_auto lightDirection light_direction_object_space 0
//param_named_auto ambientLight ambient_light_colour

// x scale
// y scale
// z scale
// Morph Factor
param_named compressionSettings float4 90000.0 1.37331 90000.0 0.0
/// 90000 / 65535

// Fog settings are;
// start
// end
// scale (e.g. 0.0 to switch off)
//param_named fogSettings float4 500.0 1000.0 1.0 0.0
// Fog colour
//param_named fogColour float4 0.93, 0.86, 0.76 1.0
}

shadow_receiver_vertex_program_ref DecompressVertexShadowReceiver/VP
{
param_named_auto worldViewProj worldviewproj_matrix
param_named_auto worldMatrix world_matrix
param_named_auto texViewProjMatrix texture_viewproj_matrix

// Config settings are;
// x scale
// y (height) start
// z scale
//
param_named compressionSettings float4 90000.0 1.37331 90000.0 50000.0
}

fragment_program_ref DecompressSplatShadercg/FP
{
//param_named_auto lightDirection light_direction_object_space 0
//param_named_auto ambientLight ambient_light_colour
}

texture_unit
{
// coverage texture : rgba handling alpha for each splat
texture none
}

texture_unit
{
texture splatting_sand.png
}

texture_unit
{
texture splatting_grass.png
}

texture_unit
{
texture splatting_rock.png
}

texture_unit
{
texture splatting_snow.png
}
}
}
}

material SplattingMaterialShader
{
technique
{
pass
{
vertex_program_ref SplatShadercg/VP
{
param_named_auto worldViewProj worldviewproj_matrix
//param_named_auto lightDirection light_direction_object_space 0
//param_named_auto ambientLight ambient_light_colour

// Fog settings are;
// start
// end
// scale (e.g. 0.0 to switch off)
//param_named fogSettings float4 500.0 1000.0 1.0 0.0

// Fog colour
//param_named fogColour float4 0.93, 0.86, 0.76 1.0
}

shadow_receiver_vertex_program_ref VertexShadowReceiver/VP
{
param_named_auto worldViewProj worldviewproj_matrix
param_named_auto worldMatrix world_matrix
param_named_auto texViewProjMatrix texture_viewproj_matrix
}

fragment_program_ref SplatShadercg/FP
{
//param_named_auto lightDirection light_direction_object_space 0
//param_named_auto ambientLight ambient_light_colour
}

texture_unit
{
// coverage texture : rgba handling alpha for each splat
texture none
}

texture_unit
{
texture splatting_sand.png
}

texture_unit
{
texture splatting_grass.png
}

texture_unit
{
texture splatting_rock.png
}

texture_unit
{
texture splatting_snow.png
}
}
}
}

Crashy

02-06-2006 20:17:26

Falagard, you can confirm it works with all shadow technique? :)

tuan kuranes

02-06-2006 20:20:11

Thanks a lot, I'll add that asap to cvs.

Falagard

02-06-2006 20:26:19


Falagard, you can confirm it works with all shadow technique? Smile


It seems to work with stencil and texture modulative modes, haven't tried additive yet. Maybe you can confirm.

Crashy

02-06-2006 20:35:00

I'll try to confirm soon

tuan kuranes

02-06-2006 21:03:38

Added in cvs and to instantbase, image and splatting5 texturemode. (all using shaders too)

Aren't we supposed to specify a "shadow_receiver_fragment_program_ref" somewhere ?

Falagard

02-06-2006 21:11:12

Ya, actually I think it's needed for additive texture mode.

From documentation:

When using additive texture shadows, the shadow pass render is actually the lighting render, so if you perform any fragmene program lighting you also need to pull in a custom fragment program. You use the shadow_receiver_fragment_program_ref for this:


shadow_receiver_fragment_program_ref myShadowReceiverFragmentProgram
{
param_named_auto lightDiffuse light_diffuse_colour 0
}

You should pass the projected shadow coordinates from the custom vertex program. As for textures, texture unit 0 will always be the shadow texture. Any other textures which you bind in your pass will be carried across too, but will be moved up by 1 unit to make room for the shadow texture. Therefore your shadow receiver fragment program is likely to be the same as the bare lighting pass of your normal material, except that you insert an extra texture sampler at index 0, which you will use to adjust the result by (modulating diffuse and specular components).


I think this is ONLY for additive texture shadows so we'd need to have a different shader for this particular mode.

I tested additive texture shadows just now, and they worked but were ultra dark, probably because of the lack of that fragment program.

Actually, one of the problems is that the terrain isn't actually being lit yet. We need to create a "Lit" version of the splatting shader, or something else - I may take this to a different post since I have some questions about instant base texture shadowed vs lighting the terrain with normals and lights.

Stencil additive shadows didn't seem to work, the entire terrain was dark. Not sure why that is.