View more

View more

View more

### Image of the Day Submit

IOTD | Top Screenshots

### The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.

# Light doesn't work without bump map

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.

26 replies to this topic

### #1Medo3337  Members

Posted 27 July 2013 - 05:25 AM

I created a point light on the terrain and it works perfectly, however when I remove the bump map, it doesn't work anymore.

When I do the following I don't see the light on the terrain:

float3 n = normalize(IN.Normal);

When I do the following I see the light:

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

I checked to see if the mesh has normal and found that it has normal.

### #2DwarvesH  Members

Posted 27 July 2013 - 07:51 AM

Are you multiplying the normal with the world inverse transposed inside the vertex shader?

OUT.normal = mul(IN.normal, (float3x3)worldInverseTransposeMatrix);


### #3gfxgangsta  Members

Posted 27 July 2013 - 07:54 AM

3 suggestions:

1. Even though you know the mesh has normals, check that the normals are passed all the way from your Direct3D code (C/C++?) to the shader where you're doing the lighting (HLSL). Does your vertex declaration include a normal? If you're doing per pixel lighting, perhaps the normal is available in the vertex shader, but it's not being passed to the pixel shader?

2. You can use PIX to debug graphics issues (just google "pix debug tutorial")

3. Post the full shader code here

### #4Medo3337  Members

Posted 27 July 2013 - 10:09 AM

float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 worldInverseTransposeMatrix;

float3 cameraPos;
float materialPower;
float4 materialDiffuse;
float4 materialAmbient;
float4 materialSpecular;

float3 lightPosition;
float4 lightDiffuse;
float4 lightSpecular;
float lightRange;

float4 globalAmbient;

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

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

struct VERTEX
{
float3 Pos : POSITION;
float3 Normal : NORMAL;
float2 UV : TEXCOORD0;
};

struct VS_OUTPUT
{
float4 Pos : POSITION;
float2 UV : TEXCOORD0;
float3 Normal : TEXCOORD1;
float4 worldPos : TEXCOORD2;
};

VS_OUTPUT VS( VERTEX IN )
{
VS_OUTPUT OUT;
OUT = (VS_OUTPUT)0;
float4x4 WVP = mul(World, mul(View, Projection));
OUT.Pos = mul(float4(IN.Pos, 1.0f), WVP);
OUT.Normal = mul(IN.Normal, (float3x3)worldInverseTransposeMatrix);
OUT.UV = IN.UV;
OUT.worldPos = mul(float4(IN.Pos, 1.0f), World);
return OUT;
}

float4 PS( VS_OUTPUT IN ) : COLOR
{
float3 viewDir = cameraPos - IN.worldPos;
float3 lightDir = (lightPosition - IN.worldPos) / lightRange;
float atten = saturate(1.0f - dot(lightDir, lightDir));

float3 n =  normalize(IN.Normal);
// *** LIGHT ONLY WORKS WHEN I REPLACE THE ABOVE LINE WITH THIS LINE --> normalize(tex2D(normalMap, IN.UV).rgb * 2.0f - 1.0f); ***
float3 l = normalize(lightDir);
float3 v = normalize(viewDir);
float3 h = normalize(l + v);

float nDotL = saturate(dot(n, l));
float nDotH = saturate(dot(n, h));
float power = (nDotL == 0.0f) ? 0.0f : pow(nDotH, materialPower);

float4 diffuse = materialDiffuse * lightDiffuse;
float4 specular = materialSpecular * lightSpecular;
float4 lightColor = (materialAmbient + globalAmbient) +
(diffuse * nDotL * atten) +
(specular * power * atten);
return tex2D(colorMap, IN.UV) * lightColor;
}

technique TerrainTech
{
pass p0
{
}
}

Yes, the vertex declaration include Normal.

### #5Migi0027 (肉コーダ)  Members

Posted 27 July 2013 - 11:43 AM

I agree with gfxgansta, even though you have the normals in the vertex declarations, it may be possible that they are not correctly passed from the cpu to the gpu.

Try visualising the normals, like: PS: return float4(IN.Normal, 1.0f);

Edited by Migi0027, 27 July 2013 - 11:44 AM.

FastCall22: "I want to make the distinction that my laptop is a whore-box that connects to different network"

Blog about... stuff (GDNet, WordPress): www.gamedev.net/blog/1882-the-cuboid-zone/cuboidzone.wordpress.com/

### #6Medo3337  Members

Posted 27 July 2013 - 06:13 PM

I'm sure this problem is related to the light shader itself.

The light DOES work on some meshes, while it doesn't work on the terrain, also I THINK it's not working correctly on other meshes, the mesh sometimes is lighting from one side even the mesh is over the light (it should light from other sides as well) then when I move it it get some light from sides.

I believe the shader light is not correct, can someone check the shader and let me know if it's a VALID light shader?

@Migi0027: Tried that, it doesn't work.

Edited by Medo3337, 27 July 2013 - 08:04 PM.

### #7Pink Horror  Members

Posted 27 July 2013 - 08:18 PM

I created a point light on the terrain and it works perfectly, however when I remove the bump map, it doesn't work anymore.

When I do the following I don't see the light on the terrain:

float3 n = normalize(IN.Normal);

When I do the following I see the light:

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

I checked to see if the mesh has normal and found that it has normal.

The first line depends on IN.Normal. The second line only depends on IN.UV. I'm no lighting expert, but I'm fairly sure that the normals from your texture are supposed to be transformed in some way.

How does your bump map work perfectly? You are calculating a normal for each vertex and then throwing them away. That cannot be intentional.

Edited by Pink Horror, 27 July 2013 - 08:19 PM.

### #8Medo3337  Members

Posted 27 July 2013 - 09:10 PM

@Pink Horror: Check out my shader above, when I apply bump map it DOES look very well.

When I remove the bump map I don't see the light, I tried to move the terrain upwards, now I get to see the light, I also get to see the light when I set large amount of "point light radius".

I guess the light get positioned incorrectly when I don't use bump map.

In Vertex Shader, I'm transforming the normal as the following:

OUT.Normal = mul(IN.Normal, (float3x3)worldInverseTransposeMatrix);

Edited by Medo3337, 28 July 2013 - 12:06 AM.

### #9Migi0027 (肉コーダ)  Members

Posted 28 July 2013 - 01:52 AM

What do you mean by, it does not work? Is it black?

Try normalizing them and then visualize them, if there is literally no color change around the terrain, with the normal visualisation, that means that the normals are not passed to the shader.

FastCall22: "I want to make the distinction that my laptop is a whore-box that connects to different network"

Blog about... stuff (GDNet, WordPress): www.gamedev.net/blog/1882-the-cuboid-zone/cuboidzone.wordpress.com/

### #10Medo3337  Members

Posted 28 July 2013 - 02:03 AM

@Migi0027: The light EXISTS, but it's not on the valid position (on the terrain), I can only see it when I move the terrain up or increase the light radius.

Though, the light is affecting other objects over the terrain.

EDIT: After testing, I notice that the light ONLY affect the terrain when its position is colliding with the terrain, however you know that point light position doesn't necessarily have to collide with the mesh, it could affect the mesh from some distance (according to the light radius/range).

I also tested to make sure that the normals are passed and found that the program pass it to the shader, however, still the same issue.

Edited by Medo3337, 28 July 2013 - 02:45 AM.

### #11Pink Horror  Members

Posted 28 July 2013 - 12:34 PM

@Pink Horror: Check out my shader above, when I apply bump map it DOES look very well.

When I remove the bump map I don't see the light, I tried to move the terrain upwards, now I get to see the light, I also get to see the light when I set large amount of "point light radius".

I guess the light get positioned incorrectly when I don't use bump map.

In Vertex Shader, I'm transforming the normal as the following:

OUT.Normal = mul(IN.Normal, (float3x3)worldInverseTransposeMatrix);

Why are you computing this normal?

### #12Medo3337  Members

Posted 28 July 2013 - 12:57 PM

@Pink Horror: I think I should transform it in the vertex shader? Correct me if I'm wrong.

### #13belfegor  Members

Posted 28 July 2013 - 01:57 PM

Of course you need to transform the normal because it depends on object orientation.

Can you create minimal project, zip it and share a link here so it will be easier to help you.

Edited by belfegor, 28 July 2013 - 01:58 PM.

### #14Medo3337  Members

Posted 28 July 2013 - 07:53 PM

@belfegor: I created a new project, in this project I have a plane and a box

When I set:

Light position to (XYZ: 0.0f, 0.0f, 0.0f)

Plane position to (XYZ: 0.0f, 0.0f, 0.0f)

Light range: 5000.0f

I don't see the light

BUT, when I move the light up, I start to see the light:

Light position to (XYZ: 0.0f, 10.0f, 0.0f)

Plane position to (XYZ: 0.0f, 0.0f, 0.0f)

Light range: 5000.0f

EDIT:

Another problem I noticed now, when I apply bump map, the light get positioned incorrectly.

I do that by replacing float3 n = normalize(IN.Normal); to normalize(tex2D(normalMap, IN.UV).rgb * 2.0f - 1.0f); and passing a bump map texture to the shader.

Edited by Medo3337, 28 July 2013 - 11:37 PM.

### #15belfegor  Members

Posted 29 July 2013 - 01:48 AM

Try the project from attachment.

edit: Forgat to note about camera controls: w-s-a-d movement, left mouse press and move to rotate.

#### Attached Files

Edited by belfegor, 29 July 2013 - 02:10 AM.

### #16Medo3337  Members

Posted 29 July 2013 - 02:23 AM

@belfegor: When I apply bump map, the light change its position to invalid position.

I modified your project to support bump mapping and I can notice the problem:

After running the program hold 'B' to enable bump mapping and see that the light position is not the same.

Edited by Medo3337, 29 July 2013 - 02:23 AM.

### #17belfegor  Members

Posted 29 July 2013 - 02:59 AM

You can't just stitch normal map texture and be done, you need tangent and binormal vectors in mesh VB to have bump mapping! Try this now.

### #18Medo3337  Members

Posted 29 July 2013 - 04:05 AM

@belfegor: I'm using Panda Exporter in 3Ds Max, it's not exporting the mesh with tangent and binormal...

### #19DwarvesH  Members

Posted 29 July 2013 - 04:10 AM

Well you can always compute them, with something similar to this:

/// <summary>
/// Given the 3 vertices (position and texture coordinate) and the
/// face normal of a triangle calculate and return the triangle's
/// tangent vector. This method is designed to work with XNA's default
/// right handed coordinate system and clockwise triangle winding order.
/// Undefined behavior will result if any other coordinate system
/// and/or winding order is used. The handedness of the local tangent
/// space coordinate system is stored in the tangent's w component.
/// </summary>
/// <param name="pos1">Triangle vertex 1 position</param>
/// <param name="pos2">Triangle vertex 2 position</param>
/// <param name="pos3">Triangle vertex 3 position</param>
/// <param name="texCoord1">Triangle vertex 1 texture coordinate</param>
/// <param name="texCoord2">Triangle vertex 2 texture coordinate</param>
/// <param name="texCoord3">Triangle vertex 3 texture coordinate</param>
/// <param name="normal">Triangle face normal</param>
/// <param name="tangent">Calculated tangent vector</param>
public static void CalcTangent(ref Vector3 pos1,
ref Vector3 pos2,
ref Vector3 pos3,
ref Vector2 texCoord1,
ref Vector2 texCoord2,
ref Vector2 texCoord3,
ref Vector3 normal,
out Vector4 tangent)
{
// Create 2 vectors in object space.
// edge1 is the vector from vertex positions pos1 to pos3.
// edge2 is the vector from vertex positions pos1 to pos2.
Vector3 edge1 = pos3 - pos1;
Vector3 edge2 = pos2 - pos1;

edge1.Normalize();
edge2.Normalize();

// 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 texCoord3.
// texEdge2 is the vector from texture coordinates texCoord1 to texCoord2.
Vector2 texEdge1 = texCoord3 - texCoord1;
Vector2 texEdge2 = texCoord2 - texCoord1;

texEdge1.Normalize();
texEdge2.Normalize();

// 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)

Vector3 t;
Vector3 b;
float det = (texEdge1.X * texEdge2.Y) - (texEdge1.Y * texEdge2.X);

if ((float)Math.Abs(det) < 1e-6f)    // almost equal to zero
{
t = Vector3.UnitX;
b = Vector3.UnitY;
}
else
{
det = 1.0f / det;

t.X = (texEdge2.Y * edge1.X - texEdge1.Y * edge2.X) * det;
t.Y = (texEdge2.Y * edge1.Y - texEdge1.Y * edge2.Y) * det;
t.Z = (texEdge2.Y * edge1.Z - texEdge1.Y * edge2.Z) * det;

b.X = (-texEdge2.X * edge1.X + texEdge1.X * edge2.X) * det;
b.Y = (-texEdge2.X * edge1.Y + texEdge1.X * edge2.Y) * det;
b.Z = (-texEdge2.X * edge1.Z + texEdge1.X * edge2.Z) * det;

t.Normalize();
b.Normalize();
}

// 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

Vector3 bitangent = Vector3.Cross(normal, t);
float handedness = (Vector3.Dot(bitangent, b) < 0.0f) ? -1.0f : 1.0f;

tangent.X = t.X;
tangent.Y = t.Y;
tangent.Z = t.Z;
tangent.W = handedness;
}


foe each vertex in your mesh, figure out the other two vertices that make up the triangle using the index array, and call this method.

### #20belfegor  Members

Posted 29 July 2013 - 04:48 AM

@belfegor: I'm using Panda Exporter in 3Ds Max, it's not exporting the mesh with tangent and binormal...

You can calculate them as DwarvesH showed or use D3DXComputeTangentFrame as i have written in the demo since you didn't spot it.

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.