EDIT: fixed my original problem but still not quite there yet:
I am trying to do bump mapping using a normal map and DOT3 product but it's looking a bit off. It seems like the highlights are more prominent if the light is to the left or top of the texture; even if the light is too far you just see black shape with the white top/left highlights. Any idea why?
The way I do it is by calculating the Vector to Light and storing it in each vertexe's diffuse value. I then use the DOT3 operator between the texture (normal map) and the Diffuse value. It doesn't work. However, if I use TextureFactor instead of diffuse, it works fine.
Also, I know for a fact my VectorToLight values and my normal maps are calculated and stored correctly.
EDIT: If I turn lighting off, the highlights are correct..?
Here's my Vertex definition:
#define CVERTEXBM_FVF (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1)
class cVertexBM
{
public:
float x, y, z; //coordinates of the vertex
float nx, ny, nz; //normal vector of the vertex
DWORD diffuse; //diffuse color
float u, v; //texture coordinates of the vertex
};
Creating my mesh:
//=================================
// Loads level from an X file
//=================================
bool cLevel::LoadFromX(string filename, IDirect3DDevice9 ** D3D9Device)
{
ID3DXBuffer * MaterialBuffer =0; //Material Buffer
ID3DXBuffer * AdjecencyInfo =0; //Adjecency Info
D3DXMATERIAL * MaterialBufferAccess =0; //Pointer to access material buffer
IDirect3DTexture9 * tex = 0; //temporary texture used when loading from file
string TextureFilename; //file name of a texture to load
//clear the mesh if it already exists
if(mesh != 0)
ReleaseAll();
HRESULT result;
//load the mesh
result = D3DXLoadMeshFromX(filename.c_str(),
D3DPOOL_MANAGED | D3DXMESH_32BIT,
(*D3D9Device),
&AdjecencyInfo,
&MaterialBuffer,
0,
(DWORD*)(&MaterialCount),
&mesh );
if( result != D3D_OK)
{
mesh = 0;
return 0;
}
//now, if we have material buffer and the material count is greater than 0
if(MaterialCount != 0 && MaterialBuffer != 0)
{
//first, gain access to the buffer
MaterialBufferAccess = (D3DXMATERIAL*)MaterialBuffer->GetBufferPointer();
//for every single materia...
for(int i = 0; i < MaterialCount; i++)
{
//add material to the list
MaterialBufferAccess.MatD3D.Ambient = MaterialBufferAccess.MatD3D.Diffuse;
materials.push_back(MaterialBufferAccess.MatD3D);
//get the file name of the texture
TextureFilename = MaterialBufferAccess.pTextureFilename;
//if the texture is not undefined
if( !(TextureFilename.empty()) )
{
//load and add the texture
if(D3DXCreateTextureFromFile((*D3D9Device), TextureFilename.c_str(), &tex)!=D3D_OK)
tex=0;
textures.push_back(tex);
//get the filename of the normal
//construct the normal filename and load it
TextureFilename = ConstructNormalFilename(Filename);
if(!TextureFilename.empty())
{
if(D3DXCreateTextureFromFile((*D3D9Device), TextureFilename.c_str(), &tex)!=D3D_OK)
tex=0;
normalmaps.push_back(tex);
}
}
else //otherwise, add an "empty" texture
textures.push_back(0);
}
//we are done; release the material buffer
MaterialBuffer->Release();
}
//convert the mesh to our format
ID3DXMesh * TempMesh = 0;
mesh->CloneMeshFVF(D3DXMESH_MANAGED | D3DXMESH_32BIT, CVERTEXBM_FVF, (*D3D9Device), &TempMesh);
mesh->Release();
mesh = TempMesh;
//optimize
mesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)AdjecencyInfo->GetBufferPointer(), 0,0,0);
//calculate normals
D3DXComputeNormals(mesh, 0);
//release adjecency
AdjecencyInfo->Release();
//calculate collision data
if(RetreiveCollisionData() == 0)
return 0;
return 1;
}
My Light:
//=================================
// Creates omnidirection light
//=================================
void CreateLight()
{
//set all the values of a point light
Light.Type = D3DLIGHT_POINT;
//Light.Type = D3DLIGHT_DIRECTIONAL;
Light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f)*1.0f;
Light.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f)*0.0f;
Light.Specular = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f)*0.0f;
Light.Position = D3D_Vector3(0.0f, 0.0f, -3.0f);
//Light.Direction = D3D_Vector3(1.0f, -0.5f, 1.0f);
Light.Range = 1000.0f;
Light.Attenuation0 = 0;
Light.Attenuation1 = 0.01;
Light.Attenuation2 = 0;
//set the light
D3D9Device->SetLight(0, &Light);
//enable the light
D3D9Device->LightEnable(0, true);
}
My Render States:
//set default render states
D3D9Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); //counter-clockwise culling
D3D9Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); //fill solids
D3D9Device->SetRenderState(D3DRS_NORMALIZENORMALS, true); //renormalize all normals just in case
D3D9Device->SetRenderState(D3DRS_LIGHTING, true); //enable lighting
D3D9Device->SetRenderState(D3DRS_SPECULARENABLE, true); //enable specular lighting
D3D9Device->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
My Rendering:
//set proper FVF
(*D3D9Device)->SetFVF( CVERTEXBM_FVF );
//set correct texture coordinates
(*D3D9Device)->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
(*D3D9Device)->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 0 );
//set first stage operations
(*D3D9Device)->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3 ); // Perform a Dot3 operation...
(*D3D9Device)->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); // between the N (of N.L) which is stored in a normal map texture...
(*D3D9Device)->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); // with the L (of N.L) which is stored in the vertex's diffuse color.
//set second stage operations
(*D3D9Device)->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); // Modulate...
(*D3D9Device)->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); // the texture for this stage with...
(*D3D9Device)->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); // the current argument passed down from stage 0
for(int i = 0; i < MaterialCount; i++)
{
(*D3D9Device)->SetMaterial(&materials);
(*D3D9Device)->SetTexture(0, normalmaps);
(*D3D9Device)->SetTexture(1, 0);
//(*D3D9Device)->SetTexture(1, textures);
mesh->DrawSubset(i);
}
That's the code and it fails miserably... now, it will work fine if I do this instead:
//=================================================
//normal
(*D3D9Device)->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);
//light vector
(*D3D9Device)->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_TFACTOR);
//dot3
(*D3D9Device)->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3);
//set the TFactor to our diffuse of the 12th vertex (just randomly to test it)
D3DXVECTOR3 LightVector;
mesh->LockVertexBuffer(D3DLOCK_DISCARD, (VOID**)&Vertex);
(*D3D9Device)->SetRenderState(D3DRS_TEXTUREFACTOR,Vertex[12].diffuse);
mesh->UnlockVertexBuffer();
//============================================
So, if I let the rendered take the Diffuse value itself, it screws up, but if I set it manually through the Texture Factor and use that instead, it works...
The crappy thing is, I used this method in a program where it works perfectly fine; here it screws up and I have no idea what is the differen :/
Any idea?
[Edited by - Koobazaur on March 16, 2007 2:33:17 PM]