Normal mapping issues

Started by
4 comments, last by hplus0603 18 years, 7 months ago
After looking through the DirectX SDK and various other resources, I wrote a program that just renders a normal mapped object, but it is not working properly and I cannot seem to find the solution. The object seems to be lit indefinitely in a horizontal line between the X and Z axis. Here is a screenshot to show you what I am talking about. (just for reference, that square is made up of 32 triangles) http://www.equalmeans.net/~chriss/NormalMapping.jpg Also, it seems to treat the lights position in the X axis the same as it does in the Z axis, meaning I can move the light left to right and it does the exact same thing as if it is moved front to back, so possibly a problem with the light vector somewhere? I am fairly certain that all the values are set properly, so I really cannot figure out where it is going wrong. I'll leave a link to my demo in case anyone wants to look through it, if not, any other help would be great. Thanks for the help, Chris http://www.equalmeans.net/~chriss/PS.zip The demo was written onto a pre-existing program from: http://moon-labs.com/ And the shader is an unaltered copy straight from: http://www.pieterg.com/Tutorials/bump_normal.php
Advertisement
Hi there bengaltgrs,
How are you doing?

The Problem
Lighting in normal mapping is all screwy :P

The Solution
When working with normal maps you must make sure that your mesh contains the following information to be sent to the shader.
Position, Normal, Texture, Tangent, BiNormal
I have had a look at your source and I couldn't find anywhere where your actually calculate the Tangent and BiNormal information. This means that the lighting calculations might go al messy since you create a BiTangent transformation matrix and transform your light to tangent space using this matrix.

Something like the following should work.
D3DVERTEXELEMENT9 elements[] ={	{ 0, sizeof( float ) * 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },	{ 0, sizeof( float ) * 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },	{ 0, sizeof( float ) * 6, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },	{ 0, sizeof( float ) * 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0 },	{ 0, sizeof( float ) * 15, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0 },	D3DDECL_END()};LPD3DXMESH temp;if ( FAILED( pMesh->CloneMesh( D3DXMESH_MANAGED, elements, pDevice, &temp ) ) ){	pMesh = NULL;	return;}pMesh->Release();pMesh = temp;void* pData;pMesh->LockVertexBuffer(D3DLOCK_DISCARD, &pData);pMesh->UnlockVertexBuffer();D3DXComputeTangentFrame(pMesh, 0);


What goes on here is quite simple. You create a new vertex format for your mesh since you want the mesh to have available space for the information you are about to calculate and store in it. You then just clone the mesh with the new vertex format and calculate the Tangent/BiNormal information using D3DXComputeTangentFrame().

Other than that. I cannot really see anything else wrong.

I hope this helps buddy.
Take care.
First, thank you very much for looking through my code and helping me out, I really appreciate it. The extra code you supplied worked very with one exception... the object was being lit properly, but the texture was shading in the wrong direction. For example, if I moved the light to the right, the texture would shade as if the light was moved toward the camera, even though the object was actually being lit properly. Basically the X and Z positions getting to the pixel shader were switched. Here is a screen of it:

http://www.equalmeans.net/~chriss/Normals.jpg

Anyways, I switched a piece of code in your shader from:

float3x3 TBNMatrix = float3x3(IN.tangent, IN.binormal , IN.normal);
to
float3x3 TBNMatrix = float3x3(IN.binormal, IN.tangent , IN.normal);

and it is working perfectly now. I do have one last question though, how would I go about adding some ambient light to this so the back of the object isn't black, and switch the color of the light?

Thank you again very much for your help,
Chris

[Edited by - bengaltgrs on September 10, 2005 4:43:10 AM]
Hi Bengaltgrs,
How are you doing?

The Problem
Adding ambient light

The Solution
It's very simple, simpler than you think
In the pixel shader. Just add this line to the bottom of your pixel shader.
OUT.color.rgb += 0.1f;
This will add a 0.1f ambient color to each of the red/green/blue components :)

Take care bud. Have fun.
I see, it seems that adding the "OUT.color.rgb += 0.1f;" to the pixel shader just lightens everything, so the black areas just turn grey, and the texture does not show through at all. So instead I added this:

//find attenuation * color
float AttCol = IN.att * color;

//add the diffuse and ambient lighting
OUT.color = (AttCol * diffuse) + (AttCol * 0.2f);

This way, even the darkest parts of the mesh will always show some texture. The only thing I do not know how to do is change the color of the light. Say I wanted the object to have an orange fire-like tint to it, how would I go about doing that?

Thanks again,
Chris
The lighting equations are well defined in the DirectX documentation as well as in the OpenGL documentation. The terms you're looking for is typically something like:

sceneColors = { sceneAmbient };lightColors = { lightAmbient, lightDiffuse, lightSpecular };materialColors = { materialAmbient, materialDiffuse, materialSpecular, materialEmissive, specularPower };textureColor = { read from texture };attenuation = { calculate based on light-object distance };diffuseContribution = { clamp( N dot L, 0, 1 ) };specularContribution = { clamp( reflect( E, N ) dot L, 0, 1 ) };outputColor =   (materialEmissive +    sceneAmbient +    (materialAmbient*lightAmbient +     materialDiffuse*lightDiffuse*diffuseContribution    )*attenuation  )*textureColor +  lightSpecular*materialSpecular*(specularContribution ** specularPower)*attenuation;


E is the unit vector from object to eye; L is the unit vector from object to light; N is the normal (which you typically get from the normal map and translate into object or world space).

Last, you don't necessarily need to send all of normal, binormal and tangent to the shader; you can send two of them, and re-construct the third using a cross product. May save some bandwidth, depending on your specific geometry.


Edit: forgot to add scene ambient.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement