Problems with lights & shadows in Cg Dot3 Bumpmapping

Hello,

since several days i try to develop an cg fragment and vertex shader for dot3 based bumpmapping. The shaders looks like working, i got my bumpmapped object, but i’ve problems with the light and shadowing …

Because an Image tells more than thousand words, here is the one:
http://img.photobucket.com/albums/v211/Hellhound_01/shadow.jpg

What you see is a simple object, the object looks like a dot3 bumpmapped object, but the shadows are too sharpen at the edges and when i move the light arround the object often the shadows gets translucent.

The other problem is a lighting problem. When i move a light source arround the object, you can see a “switch” of the texture to the side where the light comes from. I’ve tested the shaders again and again and figured out, that only two states of light are computed. When i place the position of the light on the right side of the object i got the correct lighting of the object from the right side.

When i now move the light position near to the object, normaly the reflection must be more intensive but there is no approximation computed. On the other hand, when i move the light more far a way the object must be lighted darker, but nothing happends …

When i move the light position through the object on the other side, the lighting switches hardly at the “zero” point to the other side.

I’ve no idea what could be wrong. The Light position looks like correct computed in the shader. Has anyone an idea what could be wrong?

I’ve added some additional pictures which shows the lighting failure in more detail (The purple sphere represents the position of the light):

The last image shows the failure of lighting in detail. I’ve marked the edge of the “texture switch” with red elipses. The lower part shows the texture by lighting from left, the upper part shows the texture by lighting from right…

I think there could be a problem in my calculations, perhaps someone of you could help me …

Here is my vertex shader:

// input structure
struct appl2vert
{
   float3 Position         : POSITION;
   float3 Normal         : NORMAL;
   float2 TextureCoords            : TEXCOORD0;
   float3 Tangents                 : TEXCOORD1;
};

// output structure
struct vert2frag
{
   float4 Position            : POSITION;
   float2 TextureCoords               :TEXCOORD0;
   float3 TangentSpaceLightPos             :TEXCOORD1;
};


void main(const appl2vert IN, out vert2frag OUT,
        const uniform float4x4 ModelViewProj,
        const uniform float4x4 InvModelViewMatrix,
        const uniform float4   LightPos,
        )
{
   // calculations for rasterizer
   OUT.Position = mul(ModelViewProj, float4(IN.Position, 1) );

   // get Light form world space to eye space
   float4   lightPosOS = mul(InvModelViewMatrix, LightPos);
   float3  surface2light = normalize(lightPosOS.xyz - IN.Position.xyz);

   // calculate the TangentSpaceMatrix (TBN)
   float3 binormal = cross( IN.Normal, IN.Tangents );
   float3x3 tbn_matrix = float3x3( IN.Tangents, binormal, IN.Normal );

    // get light direction L
   OUT.TangentSpaceLightPos = mul(tbn_matrix, surface2light.xyz);
   
   // transfer coords
   OUT.TextureCoords = IN.TextureCoords;
} 

And here my fragment shader:

// input structure
struct vert2frag
{
float2 TextureCoords:TEXCOORD0;
float3 TangentSpaceLightPos:TEXCOORD1;
};

void main(const vert2frag IN, out float3 oColor:COLOR,
const uniform sampler2D NormalMap,
const uniform sampler2D DecalMap )
{
// normalize Light
float3 normTangentSpaceLightPos = normalize(IN.TangentSpaceLightPos);

// Do Dot3 calculation (N.L) (multiplication for more reflection)
float3 nmap= 2*(tex2D(NormalMap,IN.TextureCoords)-0.5).rgb;

//adding decal color (multiplication for better color results)
oColor = dot(nmap.xyz, normTangentSpaceLightPos)*tex2D(DecalMap,IN.TextureCoords);
}

And here is my openGL code fragment:

// Bind the programs
cgGLBindProgram(m_pCgDot3VertexShader);
cgGLBindProgram(m_pCgDot3FragmentShader);

// Update matrix
cgGLSetStateMatrixParameter(m_cgpMdlViewProjMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
cgGLSetStateMatrixParameter(m_cgpInvModelViewMatrix, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE);

// Update Light Pos
cgGLSetParameter4fv(m_cgpLightPos, m_pLightSource->m_pvLightPosition);

// Enable the profiles
cgGLEnableProfile(m_pCgVertexProfile);
cgGLEnableProfile(m_pCgFragmentProfile);

// Set Decal Texture (Param1 TEXCOORDS0 as TextureCoords)
texIter = pDmgLvTexturesToMap->find(CTextureSetElement::TYPE_DECAL);

//Aktivate array for VBOs
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glBindBufferARB( GL_ARRAY_BUFFER_ARB, getGPUTextureOffsetID());
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );
glEnable(GL_TEXTURE_2D);

//Aktivate and bind decaltexture
glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, getTextureOffsetID());

// bind texture to fragment-shader
cgGLSetTextureParameter(m_cgpBaseTexture, getTextureOffsetID());
cgGLEnableTextureParameter(m_cgpBaseTexture);

// bind tangents to vertex-shader (Param2 TEXTURECOORDS1)
for (int i=0; i<m_pMeshesToRender->getVertexCount(); i++) {
glMultiTexCoord3fARB(GL_TEXTURE1_ARB, m_pMeshesToRender->m_pvTangents[i].m_fX, m_pMeshesToRender->m_pvTangents[i].m_fY, m_pMeshesToRender->m_pvTangents[i].m_fZ);
}


// bind normal texture to fragment-shader
cgGLSetTextureParameter(m_cgpNormalMapTexture, getNormalTextureOffsetID());
cgGLEnableTextureParameter(m_cgpNormalMapTexture);

I’ve figured out, that my sytem hardly crashes when i use the following sniplet in the OpenGl code instad of the loop with glMultiTexCoord.

m_pIRenderer->glClientActiveTextureARB(GL_TEXTURE1_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Tangents
glTexCoordPointer(3, GL_FLOAT, 0, m_pMeshesToRender->m_pvTangents);

Thanks for any help,
Christian

Hi,
you should clamp the result of the dot product between the light vector and the per pixel normal vector to be in the range of 0…1. Otherwise, if the light is on the negative half space of the polygon, you get a negative light value, which will be interpreted as lightened. Try to do a max(0, L.N) instruction or so (haven’t had time to play around with CG yet) to clamp the result into the correct range.

Hope this helps,
Jens

After a second look, i ask myself, why do you have the light position in eye space? It’s much easier to deliver it in world space. That way you can get rid of this line:

// get Light form eye space to object space
float4   lightPosOS = mul(InvModelViewMatrix, LightPos);

Also, i can’t find “Dot3Texture” to be declared in “appl2vert”.

Another thing i found in you fragment shader:

// Do Dot3 calculation (N.L) (multiplication for more reflection)
float3 nmap= 2*(tex2D(NormalMap,IN.TextureCoords)-0.5).rgb;

This comment is not correct. You take the color from the normal map, which is in the range between 0 and 1 and convert it with (color-0.5)*2 into the range -1…1. It has nothing to do with reflections :slight_smile:
For the last bug you describe, try to reset the texture unit 1 after rendering. Otherwise it might screw up some other render path.

Jens

Hi Jens,

thanks for your replies. First, i follow your hint with the clamp and changed the last line in the fragement shader to:

oColor = saturate(dot(nmap.xyz, normTangentSpaceLightPos))+tex2D(DecalMap,IN.TextureCoords);

But this change has no effect, the problem is still the same…

Now to your hints in the second reply. Both are copy, paste and translation failures of me, sorry.

The comment must be from modelspace to eye-space and the Dot3Texture Parameter must be named Tangents. I have corrected the first post.

I’ve tested my shader again and again, it seems to me that the light calculations are static. I’ve figured out, if i move the light to the backside of the object the light is computed as front lighting, the backside is always shadowed…