Shading a GeoMipTerrain

Hey all,

I am newcomer to Panda 3D but a long time Python and game programmer. My experiences with panda so far have been great :slight_smile:

I do however have a question. I am using a GeoMipTerrain and I am using a pixel shader to do some texture splatting, I then tried to add vertex lighting for an ambient and directional light however I am having no luck. Everything runs however I am not seeing the terrain lit like I would expect from the directional light i.e. it is all the same lighting intensity.

If I turn my shader off and use the built in lighting then everything looks like I would expect (just without texture splatting of course). It appears to me that I am getting incorrect normals from the terrain, I was just wondering whether this can be ruled out as a problem or not?

On a side note I was wondering whether people mainly use lightmaps or realtime lighting for terrains?

Cheers

Aaron

The problem is simple: if you have a shader applied, you will need to calculate the shading/lighting in the shader itself.

I use lightmaps myself, but if you need day/night cycles, you’ll probably need realtime lighting.

Thanks for the reply :slight_smile:

Yeah I understand that once I write a custom shader that I need to handle lighting calculations myself. That is what I thought I was doing in the shader below as well as doing my texture splatting with 3 textures and the alpha maps packed into the rgb channels of 1 texture.

//Cg
//Cg profile arbvp1 arbfp1

void vshader(in float4 vtx_position : POSITION,
            in float3 vtx_normal : NORMAL,
            in float2 vtx_texcoord0 : TEXCOORD0,
            in uniform float4x4 mat_modelproj,
            in uniform float4x4 trans_model_to_world,
            in uniform float4 k_lightvec,
            in uniform float4 k_lightcolor,
            in uniform float4 k_ambientlight,
            out float l_brightness,
            out float2 l_texcoord0 : TEXCOORD0,
            out float4 l_position : POSITION)
{   
    l_position = mul(mat_modelproj, vtx_position);
    l_texcoord0 = vtx_texcoord0;
  
    // lighting
    float3 N = normalize(vtx_normal);
    float3 L = normalize(k_lightvec.xyz);
    l_brightness = (max(dot(-N, L), 0.0f)* k_lightcolor) + k_ambientlight;
}

void fshader( in float4 l_position : POSITION,
              in float2 l_texcoord0 : TEXCOORD0,
              in float  l_brightness,
              in uniform sampler2D tex_0 : TEXUNIT0,
              in uniform sampler2D tex_1 : TEXUNIT1,
              in uniform sampler2D tex_2 : TEXUNIT2,
              in uniform sampler2D tex_3 : TEXUNIT3,
              out float4 o_color : COLOR )
{
    float4 texelColor0 = tex2D(tex_0, l_texcoord0 * 35.0);
    float4 texelColor1 = tex2D(tex_1, l_texcoord0 * 35.0);
    float4 texelColor2 = tex2D(tex_2, l_texcoord0 * 35.0);
    float4 blendColor = tex2D(tex_3, l_texcoord0);
    o_color = (texelColor0 * blendColor.x) + (texelColor1 * blendColor.y) + (texelColor2 * blendColor.z);
    o_color = texelColor0 * l_brightness;
    o_color.a = 1.0;
}

Provided I supply the correct shader inputs, do you see any reason why this shader is not working for a GeoMipTerrain?

Hmm, looks right at first glance. You could try isolating the problem by first checking if the normal is correct (by setting the normal vector as o_color), if that is correct, check k_lightvec, then the dot product by outputting them as color. Then you’ll be able to isolate the problem.

great suggestion.

I output the normal vector as a color and it is constant blue for a terrain with a big hill in the middle.
Are the normals supposed to get scaled when you do a terrain_node.setSz()?
If not how could I go about getting correct normals?

I have already tried

terrain_node.setAttrib(RescaleNormalAttrib.make(RescaleNormalAttrib.MRescale))

but that did not seem to help at all

The test shader

//Cg
//Cg profile arbvp1 arbfp1

void vshader(in float4 vtx_position : POSITION,
            in float3 vtx_normal : NORMAL,
            in float2 vtx_texcoord0 : TEXCOORD0,
            in uniform float4x4 mat_modelproj,
            out float3 l_color0: COLOR0,
            out float2 l_texcoord0 : TEXCOORD0,
            out float4 l_position : POSITION)
{   
    l_position = mul(mat_modelproj, vtx_position);
    l_texcoord0 = vtx_texcoord0;
  
    float3 N = normalize(vtx_normal);

    l_color0 = N;
}

void fshader( in float4 l_position : POSITION,
              in float2 l_texcoord0 : TEXCOORD0,
              in float3 l_color0: COLOR0,
              out float4 o_color : COLOR)
{
    o_color.xyz = l_color0;
    o_color.a = 1.0;
}

Cheers

Are you using Panda3D 1.6.1? I remember there used to be a bug in the normal calculation in GeoMipTerrain, which I believe was fixed in 1.5.4.

Otherwise can you make a tiny python file for me to test?

I am using 1.6.1 and yeah I have read up about the previous problems with terrain normals and I just can’t make sense of what is going on.

I have made a sample app that is extremely simple and sent it to your email address. :slight_smile:

Good luck!

All right, here’s the problem. vtx_normal just copies the raw vertex normal from the model - so this is not scaled along with the terrain.
You can fix this by transforming the normals yourself in the shader.

Sweet. Thanks for taking the time to help me out.

It feels a lot better knowing for certain what is going on :smiley: