• Create Account

## Normal Mapping with multiple lights (help please)

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

17 replies to this topic

### #1Hawkblood  Members

950
Like
0Likes
Like

Posted 20 January 2014 - 10:51 AM

I am having problems implementing any fx for normal mapping with multiple lights (except one with multiple passes). This is going to sound like I want someone to "do my homework", but I'm to the point of desperation.....

The problem with the multi-pass approach is that I end up rendering the scene multiple times. I found a few fx's that do this in a single pass, but they don't work (I can't understand how to make them work properly). I had asked for help on one of them a few weeks ago with no luck.....

Now I'm begging for some help. I would like a link or even the actual file with FULL explanation of how to implement it (make it SUPER SIMPLE to understand). HLSL has a lot of terms I have yet to wrap my head around, so the simpler to implement the better.

Here is what I would like:

-- normal mapping

-- ambient light

-- multiple point lights

-- multiple spot lights (could be cubic lights)

-- at least one directional light

### #2richardurich  Members

1187
Like
1Likes
Like

Posted 20 January 2014 - 12:33 PM

If you've tried and failed to get this working, why aren't you posting your shader code? That's the biggest reason I feel like you're asking people to do your homework for you.

If you're getting weird results, you might have forgotten to saturate the addition of the lights. Or you might be multiplying by color/texture before saturating. If you don't understand how you'd add multiple light sources together, here's a tutorial: http://www.rastertek.com/dx10tut30.html If somehow that doesn't make sense, it would really help if you elaborate a bit.

### #3Hawkblood  Members

950
Like
0Likes
Like

Posted 20 January 2014 - 01:04 PM

I'm using DX9....

I have already gone down this road with posting my code in an earlier thread. It got me nowhere because either the people reading didn't understand my code or didn't care to help. I'm going to post it again:


D3DXMATRIX VP=ActorController.Actors[0].rotMatrix*GE->MyCamera.m_projMatrix;
D3DXMATRIX compVM=ActorController.Actors[0].rotMatrix*ShipController.Ship[0].RotationMatrix;
//	D3DXMatrixInverse(&compVM,0,&compVM);
static D3DXHANDLE hTechnique;
static UINT totalPasses;

hTechnique = FXManager.Effect[NormalMappingFX].FX->GetTechniqueByName("NormalMappingPointLighting");

if (FAILED(FXManager.Effect[NormalMappingFX].FX->SetTechnique(hTechnique)))
return;

// Set the camera position.
D3DXVECTOR3 pos=ActorController.Actors[0].ActorLoc.Normalize();
pos*=(float)ActorController.Actors[0].ActorLoc.Length;
FXManager.Effect[NormalMappingFX].FX->SetValue("cameraPos", &pos, sizeof(pos));

// Set the scene global ambient term.
float g_sceneAmbient[4] = {0.1f, 0.1f, 0.1f, 1.0f};

FXManager.Effect[NormalMappingFX].FX->SetValue("globalAmbient", &g_sceneAmbient, sizeof(g_sceneAmbient));

// Set the number of active lights.
int g_numLights=1;
FXManager.Effect[NormalMappingFX].FX->SetValue("numLights", &g_numLights, sizeof(g_numLights));

D3DXHANDLE hLight;
D3DXHANDLE hLightPos;
D3DXHANDLE hLightAmbient;
D3DXHANDLE hLightDiffuse;
D3DXHANDLE hLightSpecular;
hLight = FXManager.Effect[NormalMappingFX].FX->GetParameterElement("lights", 0);

hLightPos = FXManager.Effect[NormalMappingFX].FX->GetParameterByName(hLight, "pos");
hLightAmbient = FXManager.Effect[NormalMappingFX].FX->GetParameterByName(hLight, "ambient");
hLightDiffuse = FXManager.Effect[NormalMappingFX].FX->GetParameterByName(hLight, "diffuse");
hLightSpecular = FXManager.Effect[NormalMappingFX].FX->GetParameterByName(hLight, "specular");
//float Lpos[3]={1,2,2};
D3DXVECTOR3 Lpos(0,0,0);
//		Lpos-=pos;
float amb[4]={0,0,0,0};
float diff[4]={1,0,1,0};
float spec[4]={0,0,0,0};
FXManager.Effect[NormalMappingFX].FX->SetValue(hLightPos, Lpos, sizeof(Lpos));
FXManager.Effect[NormalMappingFX].FX->SetValue(hLightAmbient, amb, sizeof(amb));
FXManager.Effect[NormalMappingFX].FX->SetValue(hLightDiffuse, diff, sizeof(diff));
FXManager.Effect[NormalMappingFX].FX->SetValue(hLightSpecular, spec, sizeof(spec));

Material g_dullMaterial={
0.2f, 0.2f, 0.2f, 1.0f,
0.8f, 0.8f, 0.8f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f,
100.0f
};

FXManager.Effect[NormalMappingFX].FX->SetValue("material.ambient", g_dullMaterial.ambient, sizeof(g_dullMaterial.ambient));
FXManager.Effect[NormalMappingFX].FX->SetValue("material.diffuse", g_dullMaterial.diffuse, sizeof(g_dullMaterial.diffuse));
FXManager.Effect[NormalMappingFX].FX->SetValue("material.emissive", g_dullMaterial.emissive, sizeof(g_dullMaterial.emissive));
FXManager.Effect[NormalMappingFX].FX->SetValue("material.specular", g_dullMaterial.specular, sizeof(g_dullMaterial.specular));
FXManager.Effect[NormalMappingFX].FX->SetFloat("material.shininess", g_dullMaterial.shininess);

FXManager.Effect[NormalMappingFX].FX->SetTexture("colorMapTexture", TextureList[ShipTexture[1].C].Texture);
FXManager.Effect[NormalMappingFX].FX->SetTexture("normalMapTexture", TextureList[ShipTexture[0].N].Texture);

//do a render sort
numInSort=0;
for (UINT s=0;s<Section.size();s++){
D3DXVECTOR3 v(Section[s].pos.x,Section[s].pos.y,Section[s].pos.z);
v-=pos;
float d=D3DXVec3Length(&v);
SL[numInSort].Sect=s;
SL[numInSort].dist=d;
SO[numInSort]=0;
numInSort++;
}
SO[0]=0;
for (int i=1;i<numInSort;i++){
int q=0;
for (q=0;q<i;q++) if (SL[i].dist>SL[SO[q]].dist) break;
if (q<=i) for (int q2=i;q2>q;q2--) SO[q2]=SO[q2-1];//shift everything else down the list
SO[q]=i;
}
bool ZR=false;
if (ActorController.Actors[0].InMesh==-1) ZR=true;
for (int sl=0;sl<numInSort;sl++){
int s=SL[SO[sl]].Sect;
D3DXVECTOR3 v(Section[s].pos.x,Section[s].pos.y,Section[s].pos.z);
v-=pos;
FXManager.Effect[NormalMappingFX].FX->SetValue(hLightPos, Lpos, sizeof(Lpos));
for (UINT i=0;i<Section[s].Objects.size();i++) {
tmp=Section[s].Objects[i].matrix;
tmp(3,0)+=v.x;
tmp(3,1)+=v.y;
tmp(3,2)+=v.z;

FXManager.Effect[NormalMappingFX].FX->SetMatrix("worldMatrix", &tmp);

D3DXMATRIX wit=tmp;
wit(3,0)=0;
wit(3,1)=0;
wit(3,2)=0;
wit(3,3)=1;;
D3DXMatrixInverse(&wit,0,&wit);
D3DXMatrixTranspose(&wit,&wit);
FXManager.Effect[NormalMappingFX].FX->SetMatrix("worldInverseTransposeMatrix", &wit);

tmp*=VP;
FXManager.Effect[NormalMappingFX].FX->SetMatrix("worldViewProjectionMatrix", &tmp);

if (SUCCEEDED(FXManager.Effect[NormalMappingFX].FX->Begin(&totalPasses, 0)))
{
for (UINT pass = 0; pass < totalPasses; ++pass)
{
if (SUCCEEDED(FXManager.Effect[NormalMappingFX].FX->BeginPass(pass)))
{
MeshObject[mesh].ppMesh->DrawSubset(Section[s].Objects[i].ObjIndex);
FXManager.Effect[NormalMappingFX].FX->EndPass();
}
}

FXManager.Effect[NormalMappingFX].FX->End();
}

}
}



Here is the .fx:

//-----------------------------------------------------------------------------
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
//
// Tangent space normal mapping with multiple point lights in a single pass
// using shader model 3.0. This effect file limits the number of point lights
// to 8.
//
//-----------------------------------------------------------------------------

#define MAX_POINT_LIGHTS 8

struct PointLight
{
float3 pos;
float4 ambient;
float4 diffuse;
float4 specular;
};

struct Material
{
float4 ambient;
float4 diffuse;
float4 emissive;
float4 specular;
float shininess;
};

//-----------------------------------------------------------------------------
// Globals.
//-----------------------------------------------------------------------------

float4x4 worldMatrix;
float4x4 worldInverseTransposeMatrix;
float4x4 worldViewProjectionMatrix;

float3 cameraPos;
float4 globalAmbient;
int numLights;

PointLight lights[MAX_POINT_LIGHTS];
Material material;

//-----------------------------------------------------------------------------
// Textures.
//-----------------------------------------------------------------------------

texture colorMapTexture;
texture normalMapTexture;

sampler2D colorMap = sampler_state
{
Texture = <colorMapTexture>;
MagFilter = Linear;
MinFilter = Anisotropic;
MipFilter = Linear;
MaxAnisotropy = 16;
};

sampler2D normalMap = sampler_state
{
Texture = <normalMapTexture>;
MagFilter = Linear;
MinFilter = Anisotropic;
MipFilter = Linear;
MaxAnisotropy = 16;
};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

struct VS_INPUT
{
float3 position : POSITION;
float2 texCoord : TEXCOORD0;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};

struct VS_OUTPUT
{
float4 position : POSITION;
float3 worldPos : TEXCOORD0;
float2 texCoord : TEXCOORD1;
float3 normal : TEXCOORD2;
float3 tangent : TEXCOORD3;
float3 bitangent : TEXCOORD4;
};

VS_OUTPUT VS_PointLighting(VS_INPUT IN)
{
VS_OUTPUT OUT;

OUT.position = mul(float4(IN.position, 1.0f), worldViewProjectionMatrix);
OUT.worldPos = mul(float4(IN.position, 1.0f), worldMatrix).xyz;
OUT.texCoord = IN.texCoord;

OUT.normal = mul(IN.normal, (float3x3)worldInverseTransposeMatrix);
OUT.tangent = mul(IN.tangent.xyz, (float3x3)worldInverseTransposeMatrix);
OUT.bitangent = cross(OUT.normal, OUT.tangent) * IN.tangent.w;

return OUT;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

float4 PS_PointLighting(VS_OUTPUT IN) : COLOR
{
float3 t = normalize(IN.tangent);
float3 b = normalize(IN.bitangent);
float3 n = normalize(IN.normal);

float3x3 tbnMatrix = float3x3(t.x, b.x, n.x,
t.y, b.y, n.y,
t.z, b.z, n.z);

float3 v = normalize(mul(cameraPos - IN.worldPos, tbnMatrix));
float3 l = float3(0.0f, 0.0f, 0.0f);
float3 h = float3(0.0f, 0.0f, 0.0f);

float atten = 0.0f;
float nDotL = 0.0f;
float nDotH = 0.0f;
float power = 0.0f;

float4 color = float4(0.0f, 0.0f, 0.0f, 0.0f);

n = normalize(tex2D(normalMap, IN.texCoord).rgb * 2.0f - 1.0f);

for (int i = 0; i < numLights; ++i)
{
l = mul((lights[i].pos - IN.worldPos) / lights[i].radius, tbnMatrix);
atten = saturate(1.0f - dot(l, l));

l = normalize(l);
h = normalize(l + v);

nDotL = saturate(dot(n, l));
nDotH = saturate(dot(n, h));
power = (nDotL == 0.0f) ? 0.0f : pow(nDotH, material.shininess);

color += (material.ambient * (globalAmbient + (atten * lights[i].ambient))) +
(material.diffuse * lights[i].diffuse * nDotL * atten) +
(material.specular * lights[i].specular * power * atten);
}

return color * tex2D(colorMap, IN.texCoord);
}

//-----------------------------------------------------------------------------
// Techniques.
//-----------------------------------------------------------------------------

technique NormalMappingPointLighting
{
pass
{
}
}



Here is a video illustrating the outcome:

There is supposed to be 1 point light (at the player's head). The surfaces are not rendering properly....

This is how it SHOULD look:

Edited by Hawkblood, 20 January 2014 - 01:38 PM.

### #4phil_t  Members

7648
Like
0Likes
Like

Posted 20 January 2014 - 02:08 PM

Debug a pixel in PIX, step through the pixel shader to see where you're going wrong.

Look at your two videos, it looks like you're missing the green channel for some reason (everything is magenta: red and blue).

### #5Hawkblood  Members

950
Like
0Likes
Like

Posted 20 January 2014 - 03:18 PM

The first video is pink because I wanted to have a contrast.

float diff[4]={1,0,1,0};

This line is the diffuse for the light-- I left out the green component. This is not the problem I was trying to illustrate.

I am convinced it is tied to the Tangent,Bitangent, and Normal calculations in the effect. It seems to be required as an input from the mesh. There is a conversion used in the author's code, but it was used to generate these from a customized vertex buffer. Here is the function:

void CalcTangentVector(float pos1[3], float pos2[3],
float pos3[3], const float texCoord1[2],
const float texCoord2[2], const float texCoord3[2],
float normal[3], D3DXVECTOR4 &tangent){			//********************	MAY HAVE TO USE THIS TO GET THE LIGHTS TO SHOW UP RIGHT
//		*********** WILL HAVE TO CLONEFVF EACH MESH AND CALCULATE THE TANGENTS ***************

// Given the 3 vertices (position and texture coordinates) of a triangle
// calculate and return the triangle's tangent vector. The handedness of
// the local coordinate system is stored in tangent.w. The bitangent is
// then: float3 bitangent = cross(normal, tangent.xyz) * tangent.w.

// Create 2 vectors in object space.
//
// edge1 is the vector from vertex positions pos1 to pos2.
// edge2 is the vector from vertex positions pos1 to pos3.
D3DXVECTOR3 edge1(pos2[0] - pos1[0], pos2[1] - pos1[1], pos2[2] - pos1[2]);
D3DXVECTOR3 edge2(pos3[0] - pos1[0], pos3[1] - pos1[1], pos3[2] - pos1[2]);

D3DXVec3Normalize(&edge1, &edge1);
D3DXVec3Normalize(&edge2, &edge2);

// Create 2 vectors in tangent (texture) space that point in the same
// direction as edge1 and edge2 (in object space).
//
// texEdge1 is the vector from texture coordinates texCoord1 to texCoord2.
// texEdge2 is the vector from texture coordinates texCoord1 to texCoord3.
D3DXVECTOR2 texEdge1(texCoord2[0] - texCoord1[0], texCoord2[1] - texCoord1[1]);
D3DXVECTOR2 texEdge2(texCoord3[0] - texCoord1[0], texCoord3[1] - texCoord1[1]);

D3DXVec2Normalize(&texEdge1, &texEdge1);
D3DXVec2Normalize(&texEdge2, &texEdge2);

// These 2 sets of vectors form the following system of equations:
//
//  edge1 = (texEdge1.x * tangent) + (texEdge1.y * bitangent)
//  edge2 = (texEdge2.x * tangent) + (texEdge2.y * bitangent)
//
// Using matrix notation this system looks like:
//
//  [ edge1 ]     [ texEdge1.x  texEdge1.y ]  [ tangent   ]
//  [       ]  =  [                        ]  [           ]
//  [ edge2 ]     [ texEdge2.x  texEdge2.y ]  [ bitangent ]
//
// The solution is:
//
//  [ tangent   ]        1     [ texEdge2.y  -texEdge1.y ]  [ edge1 ]
//  [           ]  =  -------  [                         ]  [       ]
//  [ bitangent ]      det A   [-texEdge2.x   texEdge1.x ]  [ edge2 ]
//
//  where:
//        [ texEdge1.x  texEdge1.y ]
//    A = [                        ]
//        [ texEdge2.x  texEdge2.y ]
//
//    det A = (texEdge1.x * texEdge2.y) - (texEdge1.y * texEdge2.x)
//
// From this solution the tangent space basis vectors are:
//
//    tangent = (1 / det A) * ( texEdge2.y * edge1 - texEdge1.y * edge2)
//  bitangent = (1 / det A) * (-texEdge2.x * edge1 + texEdge1.x * edge2)
//     normal = cross(tangent, bitangent)

D3DXVECTOR3 bitangent;
float det = (texEdge1.x * texEdge2.y) - (texEdge1.y * texEdge2.x);

if (fabsf(det) < 1e-6f)    // almost equal to zero
{
tangent.x = 1.0f;
tangent.y = 0.0f;
tangent.z = 0.0f;

bitangent.x = 0.0f;
bitangent.y = 1.0f;
bitangent.z = 0.0f;
}
else
{
det = 1.0f / det;

tangent.x = (texEdge2.y * edge1.x - texEdge1.y * edge2.x) * det;
tangent.y = (texEdge2.y * edge1.y - texEdge1.y * edge2.y) * det;
tangent.z = (texEdge2.y * edge1.z - texEdge1.y * edge2.z) * det;
tangent.w = 0.0f;

bitangent.x = (-texEdge2.x * edge1.x + texEdge1.x * edge2.x) * det;
bitangent.y = (-texEdge2.x * edge1.y + texEdge1.x * edge2.y) * det;
bitangent.z = (-texEdge2.x * edge1.z + texEdge1.x * edge2.z) * det;

D3DXVec4Normalize(&tangent, &tangent);
D3DXVec3Normalize(&bitangent, &bitangent);
}

// Calculate the handedness of the local tangent space.
// The bitangent vector is the cross product between the triangle face
// normal vector and the calculated tangent vector. The resulting bitangent
// vector should be the same as the bitangent vector calculated from the
// set of linear equations above. If they point in different directions
// then we need to invert the cross product calculated bitangent vector. We
// store this scalar multiplier in the tangent vector's 'w' component so
// that the correct bitangent vector can be generated in the normal mapping

D3DXVECTOR3 n(normal[0], normal[1], normal[2]);
D3DXVECTOR3 t(tangent.x, tangent.y, tangent.z);
D3DXVECTOR3 b;

D3DXVec3Cross(&b, &n, &t);
tangent.w = (D3DXVec3Dot(&b, &bitangent) < 0.0f) ? -1.0f : 1.0f;

}



For each face of the mesh, the 3 vertex information is extracted and sent as parameters to this function. The result is the tangent.

Because the author used his own custom vertex buffer, I had to create a function to extract the information from the mesh so it could be sent to the function:

void ConvertMeshForLighting(int M,GAMEENGINE *GE){
LPD3DXMESH tmpMesh;
HRESULT hr=MeshObject[M].ppMesh->CloneMeshFVF(D3DPOOL_DEFAULT,NM_CUSTOM_VERTEX,GE->d3ddev,&tmpMesh);
if (hr==D3D_OK){
MeshObject[M].ppMesh->Release();
MeshObject[M].ppMesh=tmpMesh;
LPVOID IB;
if (hr!=D3D_OK) tp2=2345;
short *ib=(short*)IB;
short numFaces=(short)MeshObject[M].ppMesh->GetNumFaces();

LPVOID VB;
hr=MeshObject[M].ppMesh->LockVertexBuffer(D3DLOCK_NO_DIRTY_UPDATE,&VB);
if (hr!=D3D_OK) tp2=345;
NMVertex *vb=(NMVertex*)VB;

for (short f=0;f<numFaces*3;f+=3){
CalcTangentVector(vb[ib[f]].pos,vb[ib[f+1]].pos,vb[ib[f+2]].pos,vb[ib[f]].texCoord,vb[ib[f+1]].texCoord,vb[ib[f+2]].texCoord
,vb[ib[f]].normal,vb[ib[f]].tangent);
vb[ib[f+1]].tangent=vb[ib[f+2]].tangent=vb[ib[f]].tangent;
}

MeshObject[M].ppMesh->UnlockVertexBuffer();
MeshObject[M].ppMesh->UnlockIndexBuffer();
}
else{
if (hr==D3DERR_INVALIDCALL) tp2=12345;
if (hr==E_OUTOFMEMORY) tp2=54321;
}

}



This function first converts the FVF to:

#define NM_CUSTOM_VERTEX (D3DFVF_XYZ|D3DFVF_TEX1|D3DFVF_NORMAL|D3DFVF_TEX2)
struct NMVertex
{
float pos[3];
float texCoord[2];
float normal[3];
D3DXVECTOR4 tangent;
};



It then destroys the original mesh and sets the pointer to the new mesh. Then it locks the IB and VB for the mesh and takes the vertex info from each index and sends it to the function............ I think you get the idea.

This function seems to do nothing for me as the results look exactly the same regardless of whether I use it or not.

### #6phil_t  Members

7648
Like
0Likes
Like

Posted 20 January 2014 - 03:52 PM

Well the tangent and binormal are essential for normal-mapping, so if those aren't correct that would be a problem.

So... do the values for tangent look right? Step through the debugger and find out.

Also... I've never used the FVF's, so I could be wrong about this. But are you sure your custom vertex format matches what is expected in the shader? Your shader expects TANGENT (float4 tangent : TANGENT;), but you have no such thing.

This post suggests that you can't use FVFs if you require TANGENT or BINORMAL in your shader.

### #7Hawkblood  Members

950
Like
0Likes
Like

Posted 21 January 2014 - 08:25 AM

The D3DFVF_TEX2 is a 4 float value so that would handle D3DXVECTOR4. The inability to use FVFs with TANGENT or BINORMAL parameters sounds like a lack of forethought on the part of developers (people responsible for DX and video card interaction). How would I get around that? I am using meshes I construct in 3DSMax and export into .x files…

### #8phil_t  Members

7648
Like
0Likes
Like

Posted 21 January 2014 - 01:01 PM

How would I get around that? I am using meshes I construct in 3DSMax and export into .x files…

http://msdn.microsoft.com/en-us/library/windows/desktop/bb206335(v=vs.85).aspx

### #9Hawkblood  Members

950
Like
0Likes
Like

Posted 21 January 2014 - 01:25 PM

So ID3DXBaseMesh::DrawSubset is obsolete?

### #10Hawkblood  Members

950
Like
0Likes
Like

Posted 21 January 2014 - 02:13 PM

What about indexed primitives? Is that used? What method would be the fastest/most efficient method?

### #11Hawkblood  Members

950
Like
0Likes
Like

Posted 22 January 2014 - 06:56 PM

Ok. I got it to work (sort-of)... I'm currently having problems with attributes (vertex and index buffer) when there are multiple subsets. I'm using PandaSoft's directx xporter and when I include the "materials" option I can get the correct number of subsets, but it doesn't render correctly. If I don't use the "materials" option, it renders fine, but it renders all of it in a single subset. This is bad because I want to use animation where the different subsets move independently.

I have ideas about how to work around this problem:

-- read the .x file as a text file and extract the info manually

-- separate the subsets into their own .x file and assemble them on load

-- *** figure out what I'm doing wrong and fix it (this is preferred)

### #12Hawkblood  Members

950
Like
0Likes
Like

Posted 24 January 2014 - 06:30 PM

Ok. I created a test room and it seems to work fine when the light is centered in the room. When I move the light near the edge, I don't get the correct specular highlights.

I'm using a "tangent space normal mapping with multiple lights in a single pass" .fx from http://www.dhpoware.com/demos/index.html

I had to manually read the .x file of the room and convert it to an indexed primitive that uses:

D3DVERTEXELEMENT9 g_roomVertexElements[] =
{
{0,  0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
{0, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT,  0},
D3DDECL_END()
};



The struct I used to hold the object info is:

struct MESHINDEXINFO{
MESHINDEXINFO(){vStart=vCount=iStart=iCount=0;}
UINT vStart,vCount,iStart,iCount;

//amimation stuff here
vector <D3DXMATRIX> KeyframeMatrix;
};
struct EFFECTMESH{
EFFECTMESH(){VB=NULL;}
IDirect3DVertexBuffer9 *VB;
LPDIRECT3DINDEXBUFFER9 IB;
vector <MESHINDEXINFO> indexInfo;
int NumSubsets;
void Release(void);
};
void EFFECTMESH::Release(){
if (VB!=NULL){
VB->Release();
IB->Release();
VB=NULL;
}
indexInfo.clear();
}



As I was saying, every aspect of it seems to work just fine except the specular (as illustrated in the video).....

Any ideas on what I'm doing wrong?

### #13Hawkblood  Members

950
Like
0Likes
Like

Posted 25 January 2014 - 09:24 AM

Thanks for the help guys......

I figured it out on my own. For the calculations to work, it needs to thing the camera is at the origin. Now I have another problem:

As you can see, there is a sharp edge at the radius of the light when shinning on the wall. This only occurs on the +x & -x walls. It doesn't do this on any other surface. I tried skewing the vertices to see if that helps, but no joy. Well, rotating the entire box DOES change one thing: The verts that angle more away from the light seem to attenuate properly, but the ones that have been moved toward the light don't.

Let's see who can figure this out faster.....

### #14cozzie  Members

4623
Like
0Likes
Like

Posted 26 January 2014 - 04:31 PM

Just a remark, I think you could rephrase your case and questions a bit to get more and quicker help.

Unfortunately I'm not very experienced yet with normal mapping. But I do know you can try KwXport for exporting X files from 3ds max, with the option to include the binormals and tangents directly. If you do this you can probaly save one step after you've loaded the model/ X file.

The last issue might have something to do with a calculation where your camera position is used but not correctly updated, meaning it would only work at x = 0.

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

### #15Hawkblood  Members

950
Like
0Likes
Like

Posted 27 January 2014 - 07:36 AM

I'll look into KwXport.

BTW, does this also export skinned and animated meshes?

I figured out my problem. I was calculating the tangent before I read the normals from the file.

### #16LancerSolurus  Members

630
Like
0Likes
Like

Posted 27 January 2014 - 08:26 AM

Stick with PandaSoft's exporter, it is updated for every new Max version, KWExport hasn't been updated since Max 7-8...

******************************************************************************************

### #17Hawkblood  Members

950
Like
0Likes
Like

Posted 27 January 2014 - 08:46 AM

Thanks for the info LancerSolurus. Do you have a suggestion for an exporter? Or perhapse a better solution to my (almost) brute force read method?

### #18cozzie  Members

4623
Like
1Likes
Like

Posted 27 January 2014 - 01:17 PM

I'm using kwxport with max 2011 with no problems, including tangents, animation etc.
Good to hear that you fixed it

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.