Jump to content
  • Advertisement
Sign in to follow this  
bgoldbeck

Bumpmap Phong Shader doesn't look correct

This topic is 2444 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

bump.jpg
Hello,
As you see, I am attempting to bump map a cube. However, my specular color seems to span multiple sides of the cube at once. I am not sure where in my code I am going wrong, although I have a feeling it's something to do with my tangent and bitangent calculations.

I will post pieces of my code and I get my tangent function from this website. Tangent Space Calculation

Vertex Shader


#version 400

uniform mat4 viewMatrix, projectionMatrix, modelMatrix;
uniform vec3 fvLightPosition;
uniform vec3 fvEyePosition;

in vec4 in_Vertex;
in vec3 in_Normal;
in vec2 in_Texcoord;
in vec4 in_Tangent;
in vec3 in_Bitangent;

out vec2 vf_Texcoord;
out vec3 vf_LightDirection;
out vec3 vf_ViewDirection;

void main()
{
gl_Position = (projectionMatrix * viewMatrix * modelMatrix) * in_Vertex;

vec4 fvObjectPosition = modelMatrix * in_Vertex;

vec3 nLightDirection = fvLightPosition - fvObjectPosition.xyz;
vec3 nViewDirection = fvEyePosition - fvObjectPosition.xyz;

mat3 nMatrix = inverse(mat3(modelMatrix));
nMatrix = transpose(nMatrix);

vec3 nNormal = nMatrix * in_Normal;
vec3 nTangent = nMatrix * in_Tangent.xyz;
vec3 nBitan = nMatrix * in_Bitangent;

vf_ViewDirection.x = dot(nTangent, nViewDirection);
vf_ViewDirection.y = dot(nBitan, nViewDirection);
vf_ViewDirection.z = dot(nNormal, nViewDirection);

vf_LightDirection.x = dot(nTangent, nLightDirection.xyz);
vf_LightDirection.y = dot(nBitan, nLightDirection.xyz);
vf_LightDirection.z = dot(nNormal, nLightDirection.xyz);
vf_Texcoord = in_Texcoord;
}


Fragment Shader


#version 400

uniform sampler2D textureMap;
uniform sampler2D bumpMap;
uniform vec4 fvAmbient;
uniform vec4 fvSpecular;
uniform vec4 fvDiffuse;
uniform float fSpecularPower;

in vec2 vf_Texcoord;
in vec3 vf_ViewDirection;
in vec3 vf_LightDirection;

out vec4 out_Color;

void main( void )
{
vec3 fvLightDirection = normalize( vf_LightDirection );
vec3 fvNormal = normalize( ( texture2D( bumpMap, vf_Texcoord ).xyz * 2.0 ) - 1.0 );
float fNDotL = dot( fvNormal, fvLightDirection );

vec3 fvReflection = normalize( ( ( 2.0 * fvNormal ) * fNDotL ) - fvLightDirection );
vec3 fvViewDirection = normalize( vf_ViewDirection );
float fRDotV = max( 0.0, dot( fvReflection, fvViewDirection ) );

vec4 fvBaseColor = texture2D( textureMap, vf_Texcoord );

vec4 fvTotalAmbient = fvAmbient * fvBaseColor;
vec4 fvTotalDiffuse = fvDiffuse * fNDotL * fvBaseColor;
vec4 fvTotalSpecular = fvSpecular * ( pow( fRDotV, fSpecularPower ) );

out_Color = ( fvTotalAmbient + fvTotalDiffuse + fvTotalSpecular );
}


Calculating the tangents / bitangents


void GLSDLEngine::CalculateTangentArray(long vertexCount, const Point3D *vertex, const Vector3D *normal,
const Point2D *texcoord, long triangleCount, const Triangle *triangle, Vector4D *tangent)
{
Vector3D *tan1 = new Vector3D[vertexCount * 2];
Vector3D *tan2 = tan1 + vertexCount;
ZeroMemory(tan1, vertexCount * sizeof(Vector3D) * 2);

for (long a = 0; a < triangleCount; a++)
{
long i1 = triangle->index[0];
long i2 = triangle->index[1];
long i3 = triangle->index[2];

const Point3D& v1 = vertex[i1];
const Point3D& v2 = vertex[i2];
const Point3D& v3 = vertex[i3];

const Point2D& w1 = texcoord[i1];
const Point2D& w2 = texcoord[i2];
const Point2D& w3 = texcoord[i3];

float x1 = v2.x - v1.x;
float x2 = v3.x - v1.x;
float y1 = v2.y - v1.y;
float y2 = v3.y - v1.y;
float z1 = v2.z - v1.z;
float z2 = v3.z - v1.z;

float s1 = w2.x - w1.x;
float s2 = w3.x - w1.x;
float t1 = w2.y - w1.y;
float t2 = w3.y - w1.y;

float r = 1.0F / (s1 * t2 - s2 * t1);
Vector3D sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
(t2 * z1 - t1 * z2) * r);
Vector3D tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
(s1 * z2 - s2 * z1) * r);

tan1[i1] += sdir;
tan1[i2] += sdir;
tan1[i3] += sdir;

tan2[i1] += tdir;
tan2[i2] += tdir;
tan2[i3] += tdir;

triangle++;
}

for (long a = 0; a < vertexCount; a++)
{
const Vector3D& n = normal[a];
const Vector3D& t = tan1[a];

// Gram-Schmidt orthogonalize
tangent[a] = (t - n * Dot(n, t)).Normalize();

// Calculate handedness
tangent[a].w = (Dot(Cross(n, t), tan2[a]) < 0.0F) ? -1.0F : 1.0F;
}

delete[] tan1;
}



Building the Cube.


//Top //x /y /z
vertices[0].Set(1.0f, 1.0f, -1.0f); // Top Right Of The Quad (Top)
vertices[1].Set(-1.0f, 1.0f, -1.0f); // Top Left Of The Quad (Top)
vertices[2].Set(-1.0f, 1.0f, 1.0f); // Bottom Left Of The Quad (Top)
vertices[3].Set(1.0f, 1.0f, 1.0f); // Bottom Right Of The Quad (Top)
//Bottom
vertices[4].Set(1.0f, -1.0f, 1.0f);
vertices[5].Set(-1.0f, -1.0f, 1.0f);
vertices[6].Set(-1.0f, -1.0f, -1.0f);
vertices[7].Set(1.0f, -1.0f, -1.0f);
//Front.
vertices[8].Set(1.0f, 1.0f, 1.0f);
vertices[9].Set(-1.0f, 1.0f, 1.0f);
vertices[10].Set(-1.0f, -1.0f, 1.0f);
vertices[11].Set(1.0f, -1.0f, 1.0f);

//Back
vertices[12].Set(1.0f, -1.0f, -1.0f);
vertices[13].Set(-1.0f, -1.0f, -1.0f);
vertices[14].Set(-1.0f, 1.0f, -1.0f);
vertices[15].Set(1.0f, 1.0f, -1.0f);
//Left
vertices[16].Set(-1.0f, 1.0f, 1.0f);
vertices[17].Set(-1.0f, 1.0f, -1.0f);
vertices[18].Set(-1.0f, -1.0f, -1.0f);
vertices[19].Set(-1.0f, -1.0f, 1.0f);
//Right
vertices[20].Set(1.0f, 1.0f, -1.0f);
vertices[21].Set(1.0f, 1.0f, 1.0f);
vertices[22].Set(1.0f, -1.0f, 1.0f);
vertices[23].Set(1.0f, -1.0f, -1.0f);

//Top
normals[0].Set(0.0f, 1.0f, 0.0f); normals[1].Set(0.0f, 1.0f, 0.0f);
normals[2].Set(0.0f, 1.0f, 0.0f); normals[3].Set(0.0f, 1.0f, 0.0f);

//Bottom
normals[4].Set(0.0f,-1.0f, 0.0f); normals[5].Set(0.0f,-1.0f, 0.0f);
normals[6].Set(0.0f,-1.0f, 0.0f); normals[7].Set(0.0f,-1.0f, 0.0f);

//Front
normals[8].Set(0.0f, 0.0f, 1.0f); normals[9].Set(0.0f, 0.0f, 1.0f);
normals[10].Set(0.0f, 0.0f, 1.0f); normals[11].Set(0.0f, 0.0f, 1.0f);

//Back
normals[12].Set(0.0f, 0.0f, -1.0f); normals[13].Set(0.0f, 0.0f, -1.0f);
normals[14].Set(0.0f, 0.0f, -1.0f); normals[15].Set(0.0f, 0.0f, -1.0f);

//Left
normals[16].Set(-1.0f, 0.0f, 0.0f); normals[17].Set(-1.0f, 0.0f, 0.0f);
normals[18].Set(-1.0f, 0.0f, 0.0f); normals[19].Set(-1.0f, 0.0f, 0.0f);

//Right
normals[20].Set(1.0f, 0.0f, 0.0f); normals[21].Set(1.0f, 0.0f, 0.0f);
normals[22].Set(1.0f, 0.0f, 0.0f); normals[23].Set(1.0f, 0.0f, 0.0f);


//Texcoords.
for(int i = 0; i < 23; i+=4)
{
texcoords[i ].Set(0.0f, 0.0f); texcoords[i + 1].Set(0.0f, 1.0f);
texcoords[i + 2].Set(1.0f, 1.0f); texcoords[i + 3].Set(1.0f, 0.0f);
}

triangles[0 ].index[0] = 0; triangles[0 ].index[1] = 1; triangles[0 ].index[2] = 2;
triangles[1 ].index[0] = 2; triangles[1 ].index[1] = 3; triangles[1 ].index[2] = 0;
triangles[2 ].index[0] = 4; triangles[2 ].index[1] = 5; triangles[2 ].index[2] = 6;
triangles[3 ].index[0] = 6; triangles[3 ].index[1] = 7; triangles[3 ].index[2] = 4;
triangles[4 ].index[0] = 8; triangles[4 ].index[1] = 9; triangles[4 ].index[2] = 10;
triangles[5 ].index[0] = 10; triangles[5 ].index[1] = 11; triangles[5 ].index[2] = 8;
triangles[6 ].index[0] = 12; triangles[6 ].index[1] = 13; triangles[6 ].index[2] = 14;
triangles[7 ].index[0] = 14; triangles[7 ].index[1] = 15; triangles[7 ].index[2] = 12;
triangles[8 ].index[0] = 16; triangles[8 ].index[1] = 17; triangles[8 ].index[2] = 18;
triangles[9 ].index[0] = 18; triangles[9 ].index[1] = 19; triangles[9 ].index[2] = 16;
triangles[10].index[0] = 20; triangles[10].index[1] = 21; triangles[10].index[2] = 22;
triangles[11].index[0] = 22; triangles[11].index[1] = 23; triangles[11].index[2] = 20;


CalculateTangentArray(24, vertices, normals, texcoords, 12, triangles, tangents);

for(int i = 0; i < 24; i++)
{
printf("Tangent: %2d : X: %+0.2f Y: %+0.2f Z: %+0.2f W: %+0.2f \n", i,tangents.x, tangents.y, tangents.z, tangents.w);
}

//Converting tangents 4d array into a 3d array to use in cross product with normal.
Vector3D tempTans[24];
for(int i = 0; i < 24; i++)
{
tempTans.x = tangents.x;
tempTans.y = tangents.y;
tempTans.z = tangents.z;

}

for(int i = 0; i < 24; i++)
{
//Normals Cross Temp Tangents * mutiply by tangent.w
bitangents = (normals % tempTans) * tangents.w;
printf("BiTangent: %2d : X: %+0.2f Y: %+0.2f Z: %+0.2f \n", i, bitangents.x, bitangents.y, bitangents.z);
}



These are the ouputs of my tangent/bitangent calculations


Tangent: 0 : X: +0.00 Y: +0.00 Z: +1.00 W: -1.00
Tangent: 1 : X: +0.00 Y: +0.00 Z: +1.00 W: -1.00
Tangent: 2 : X: +0.00 Y: +0.00 Z: +1.00 W: -1.00
Tangent: 3 : X: +0.00 Y: +0.00 Z: +1.00 W: -1.00
Tangent: 4 : X: +0.00 Y: +0.00 Z: -1.00 W: -1.00
Tangent: 5 : X: +0.00 Y: +0.00 Z: -1.00 W: -1.00
Tangent: 6 : X: +0.00 Y: +0.00 Z: -1.00 W: -1.00
Tangent: 7 : X: +0.00 Y: +0.00 Z: -1.00 W: -1.00
Tangent: 8 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
Tangent: 9 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
Tangent: 10 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
Tangent: 11 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
Tangent: 12 : X: +0.00 Y: +1.00 Z: +0.00 W: -1.00
Tangent: 13 : X: +0.00 Y: +1.00 Z: +0.00 W: -1.00
Tangent: 14 : X: +0.00 Y: +1.00 Z: +0.00 W: -1.00
Tangent: 15 : X: +0.00 Y: +1.00 Z: +0.00 W: -1.00
Tangent: 16 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
Tangent: 17 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
Tangent: 18 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
Tangent: 19 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
Tangent: 20 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
Tangent: 21 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
Tangent: 22 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
Tangent: 23 : X: +0.00 Y: -1.00 Z: +0.00 W: -1.00
BiTangent: 0 : X: -1.00 Y: -0.00 Z: -0.00
BiTangent: 1 : X: -1.00 Y: -0.00 Z: -0.00
BiTangent: 2 : X: -1.00 Y: -0.00 Z: -0.00
BiTangent: 3 : X: -1.00 Y: -0.00 Z: -0.00
BiTangent: 4 : X: -1.00 Y: -0.00 Z: -0.00
BiTangent: 5 : X: -1.00 Y: -0.00 Z: -0.00
BiTangent: 6 : X: -1.00 Y: -0.00 Z: -0.00
BiTangent: 7 : X: -1.00 Y: -0.00 Z: -0.00
BiTangent: 8 : X: -1.00 Y: -0.00 Z: +0.00
BiTangent: 9 : X: -1.00 Y: -0.00 Z: +0.00
BiTangent: 10 : X: -1.00 Y: -0.00 Z: +0.00
BiTangent: 11 : X: -1.00 Y: -0.00 Z: +0.00
BiTangent: 12 : X: -1.00 Y: +0.00 Z: -0.00
BiTangent: 13 : X: -1.00 Y: +0.00 Z: -0.00
BiTangent: 14 : X: -1.00 Y: +0.00 Z: -0.00
BiTangent: 15 : X: -1.00 Y: +0.00 Z: -0.00
BiTangent: 16 : X: -0.00 Y: -0.00 Z: -1.00
BiTangent: 17 : X: -0.00 Y: -0.00 Z: -1.00
BiTangent: 18 : X: -0.00 Y: -0.00 Z: -1.00
BiTangent: 19 : X: -0.00 Y: -0.00 Z: -1.00
BiTangent: 20 : X: -0.00 Y: -0.00 Z: +1.00
BiTangent: 21 : X: -0.00 Y: -0.00 Z: +1.00
BiTangent: 22 : X: -0.00 Y: -0.00 Z: +1.00
BiTangent: 23 : X: -0.00 Y: -0.00 Z: +1.00


I must thank anyone in advance for any advice they may give me with this problem.biggrin.gif

Share this post


Link to post
Share on other sites
Advertisement
It is very suspicious how you translate the light directions from within the shader (not to mention a serious waste of time).
Send your shader the translated lights once and never modify them. Speaking of wasting time, send your shader the world-view-projection matrix, the normal matrix, and the model-view matrix as well, instead of calculating them for every vertex.

Lights should be translated into view space (not eye space) before being sent to the shader.
Then translate your normal, tangent, and bitangent into view space in the vertex shader.

How the fragment shader works depends on what kind of “bump” map you are using. I see no code for creating a normal from a bump, so I suspect you are actually using normal mapping.
In the fragment shader, read from the normal map as you are now, call it your “normal offset”, and add it to the actual normal in the direction of the tangent and bitangent (every tutorial will show you the dot products for this; I don’t have my code with me now).
This of course means you will also have to send the actual normal to the fragment shader.


L. Spiro

Share this post


Link to post
Share on other sites

It is very suspicious how you translate the light directions from within the shader (not to mention a serious waste of time).
Send your shader the translated lights once and never modify them. Speaking of wasting time, send your shader the world-view-projection matrix, the normal matrix, and the model-view matrix as well, instead of calculating them for every vertex.

Lights should be translated into view space (not eye space) before being sent to the shader.
Then translate your normal, tangent, and bitangent into view space in the vertex shader.

How the fragment shader works depends on what kind of “bump” map you are using. I see no code for creating a normal from a bump, so I suspect you are actually using normal mapping.
In the fragment shader, read from the normal map as you are now, call it your “normal offset”, and add it to the actual normal in the direction of the tangent and bitangent (every tutorial will show you the dot products for this; I don’t have my code with me now).
This of course means you will also have to send the actual normal to the fragment shader.


L. Spiro



Thank you, I should mention I do realize some of the waste of time in my program. However right now i'm more focused on making it work first rolleyes.gif
As for the normal mapping i'm going off of the code used in the RenderMonkey called "Textured Bump."

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!