Hi guys' I'm trying to implement Normal Mapping in Directx and I'm very close to creating it but I'm getting these weird black colors on some objects. This is how it looks like without the Normal Mapping:
And when I apply the Normal Mapping effect this is how it looks:
Where I get the black color on e.g the wall and some part of the cube which is odd.
My Pixel Shader file looks like this:
cbuffer PositionBuffer : register(b1)
{
float3 cameraPos;
float pad;
float3 lightPos;
float pad1;
};
cbuffer PhongBuffer : register(b2) {
float4 ambient;
float4 diffus;
float4 blank;
float shininess;
float3 padd;
};
Texture2D texDiffuse : register(t0);
Texture2D texNormal : register(t1);
SamplerState texSampler : register(s0);
struct PSIn
{
float4 Pos : SV_Position;
float3 Normal : NORMAL;
float2 TexCoord : TEX;
float4 PosWorld : VIEWPOSITION;
float4 Tangent : TANGENT; //Added this
float4 Binormal : BINORMAL; //Added this
};
//-----------------------------------------------------------------------------------------
// Pixel Shader
//-----------------------------------------------------------------------------------------
float4 PS_main(PSIn input) : SV_Target
{
float3 N;
float3 L;
float3 R;
float3 V;
float3 I;
float3 textureColor;
float4 bumpMap;
float3 bumpNormal;
// Sample the texture pixel at this location.
textureColor = texDiffuse.Sample(texSampler, input.TexCoord).xyz;
// Sample the pixel in the bump map.
bumpMap = texNormal.Sample(texSampler, input.TexCoord);
// Expand the range of the normal value from (0, +1) to (-1, +1).
bumpMap = (bumpMap * 2.0f) - 1.0f;
// Calculate the normal from the data in the bump map.
bumpNormal = (bumpMap.x * input.Tangent) + (bumpMap.y * input.Binormal) + (bumpMap.z * input.Normal);
// Normalize the resulting bump normal.
//bumpNormal = Normalize(bumpNormal;
L = lightPos - input.PosWorld;
//N = input.Normal;
N = bumpNormal;
V = cameraPos - input.PosWorld;
R = reflect(-L, N);
L = normalize(L);
N = normalize(N);
V = normalize(V);
R = normalize(R);
I = ambient.xyz + (textureColor * max(dot(L,N), 0) + blank.xyz * max(pow(dot(R,V), shininess), 0)); //Phong Shader Formula
if(texNormal.Sample(texSampler, input.TexCoord).z <= 0) { //Prevent the objects that don't have bump map from being given the Normal Mapping effect
return texDiffuse.Sample(texSampler, input.TexCoord);
}
if(dot(L, N) < 0) {
return texDiffuse.Sample(texSampler, input.TexCoord);
}
return float4(I, 1);
}
And my Vertex Shader looks like this:
cbuffer MatrixBuffer : register(b0)
{
matrix ModelToWorldMatrix;
matrix WorldToViewMatrix;
matrix ProjectionMatrix;
};
struct VSIn
{
float3 Pos : POSITION;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
float3 Binormal : BINORMAL;
float2 TexCoord : TEX;
};
struct PSIn
{
float4 Pos : SV_Position;
float3 Normal : NORMAL;
float2 TexCoord : TEX;
float4 PosWorld : VIEWPOSITION;
float3 Tangent : TANGENT; //Added this
float3 Binormal : BINORMAL; //Added this
};
//-----------------------------------------------------------------------------------------
// Vertex Shader
//-----------------------------------------------------------------------------------------
PSIn VS_main(VSIn input)
{
PSIn output = (PSIn)0;
// Model->View transformation
matrix MV = mul(WorldToViewMatrix, ModelToWorldMatrix);
// Model->View->Projection (clip space) transformation
// SV_Position expects the output position to be in clip space
matrix MVP = mul(ProjectionMatrix, MV);
// Perform transformations and send to output
output.Pos = mul(MVP, float4(input.Pos, 1));
output.Normal = normalize( mul(ModelToWorldMatrix, float4(input.Normal,0)).xyz ); //Convert the Normal for the vertex to World Space
output.TexCoord = input.TexCoord;
output.PosWorld = mul(ModelToWorldMatrix, float4(input.Pos, 1)); //Convert to World Space
output.Tangent = normalize( mul(ModelToWorldMatrix, float4(input.Tangent,0)).xyz ); //Convert the Tangent for the vertex to World Space
output.Binormal = normalize( mul(ModelToWorldMatrix, float4(input.Binormal,0)).xyz ); //Convert the Binormal for the vertex to World Space
return output;
}
The way I calculate the Binormal and Tangent for each vertex from the CPU side is using this method (taken from Rasterek Tutorial http://www.rastertek.com/dx11tut20.html):
void OBJModel_t::CalculateModelVectors(std::vector<vertex_t> & vertices) {
int faceCount, i, index;
vertex_t vertex1, vertex2, vertex3;
vec3f tangent, binormal, normal;
int m_vertexCount = vertices.size();
// Calculate the number of faces in the model.
faceCount = m_vertexCount / 3;
// Initialize the index to the model data.
index = 0;
// Go through all the faces and calculate the the tangent, binormal, and normal vectors.
for (i = 0; i<faceCount; i++)
{
// Get the three vertices for this face from the model.
vertex1.Pos.x = vertices[index].Pos.x;
vertex1.Pos.y = vertices[index].Pos.y;
vertex1.Pos.z = vertices[index].Pos.z;
vertex1.TexCoord.x = vertices[index].TexCoord.x;
vertex1.TexCoord.y = vertices[index].TexCoord.y;
vertex1.Normal.x = vertices[index].Normal.x;
vertex1.Normal.y = vertices[index].Normal.y;
vertex1.Normal.z = vertices[index].Normal.z;
index++;
vertex2.Pos.x = vertices[index].Pos.x;
vertex2.Pos.y = vertices[index].Pos.y;
vertex2.Pos.z = vertices[index].Pos.z;
vertex2.TexCoord.x = vertices[index].TexCoord.x;
vertex2.TexCoord.y = vertices[index].TexCoord.y;
vertex2.Normal.x = vertices[index].Normal.x;
vertex2.Normal.y = vertices[index].Normal.y;
vertex2.Normal.z = vertices[index].Normal.z;
index++;
vertex3.Pos.x = vertices[index].Pos.x;
vertex3.Pos.y = vertices[index].Pos.y;
vertex3.Pos.z = vertices[index].Pos.z;
vertex3.TexCoord.x = vertices[index].TexCoord.x;
vertex3.TexCoord.y = vertices[index].TexCoord.y;
vertex3.Normal.x = vertices[index].Normal.x;
vertex3.Normal.y = vertices[index].Normal.y;
vertex3.Normal.z = vertices[index].Normal.z;
index++;
// Calculate the tangent and binormal of that face.
CalculateTangentBinormal(vertex1, vertex2, vertex3, tangent, binormal);
// Calculate the new normal using the tangent and binormal.
CalculateNormal(tangent, binormal, normal);
// Store the normal, tangent, and binormal for this face back in the model structure.
vertices[index - 1].Normal.x = normal.x;
vertices[index - 1].Normal.y = normal.y;
vertices[index - 1].Normal.z = normal.z;
vertices[index - 1].Tangent.x = tangent.x;
vertices[index - 1].Tangent.y = tangent.y;
vertices[index - 1].Tangent.z = tangent.z;
vertices[index - 1].Binormal.x = binormal.x;
vertices[index - 1].Binormal.y = binormal.y;
vertices[index - 1].Binormal.z = binormal.z;
vertices[index - 2].Normal.x = normal.x;
vertices[index - 2].Normal.y = normal.y;
vertices[index - 2].Normal.z = normal.z;
vertices[index - 2].Tangent.x = tangent.x;
vertices[index - 2].Tangent.y = tangent.y;
vertices[index - 2].Tangent.z = tangent.z;
vertices[index - 2].Binormal.x = binormal.x;
vertices[index - 2].Binormal.y = binormal.y;
vertices[index - 2].Binormal.z = binormal.z;
vertices[index - 3].Normal.x = normal.x;
vertices[index - 3].Normal.y = normal.y;
vertices[index - 3].Normal.z = normal.z;
vertices[index - 3].Tangent.x = tangent.x;
vertices[index - 3].Tangent.y = tangent.y;
vertices[index - 3].Tangent.z = tangent.z;
vertices[index - 3].Binormal.x = binormal.x;
vertices[index - 3].Binormal.y = binormal.y;
vertices[index - 3].Binormal.z = binormal.z;
}
return;
}
void OBJModel_t::CalculateTangentBinormal(vertex_t vertex1, vertex_t vertex2, vertex_t vertex3, vec3f& tangent, vec3f& binormal) {
float vector1[3], vector2[3];
float tuVector[2], tvVector[2];
float den;
float length;
// Calculate the two vectors for this face.
vector1[0] = vertex2.Pos.x - vertex1.Pos.x;
vector1[1] = vertex2.Pos.y - vertex1.Pos.y;
vector1[2] = vertex2.Pos.z - vertex1.Pos.z;
vector2[0] = vertex3.Pos.x - vertex1.Pos.x;
vector2[1] = vertex3.Pos.y - vertex1.Pos.y;
vector2[2] = vertex3.Pos.z - vertex1.Pos.z;
// Calculate the tu and tv texture space vectors.
tuVector[0] = vertex2.TexCoord.x - vertex1.TexCoord.x;
tvVector[0] = vertex2.TexCoord.y - vertex1.TexCoord.y;
tuVector[1] = vertex3.TexCoord.x - vertex1.TexCoord.x;
tvVector[1] = vertex3.TexCoord.y - vertex1.TexCoord.y;
// Calculate the denominator of the tangent/binormal equation.
den = 1.0f / (tuVector[0] * tvVector[1] - tuVector[1] * tvVector[0]);
// Calculate the cross products and multiply by the coefficient to get the tangent and binormal.
tangent.x = (tvVector[1] * vector1[0] - tvVector[0] * vector2[0]) * den;
tangent.y = (tvVector[1] * vector1[1] - tvVector[0] * vector2[1]) * den;
tangent.z = (tvVector[1] * vector1[2] - tvVector[0] * vector2[2]) * den;
binormal.x = (tuVector[0] * vector2[0] - tuVector[1] * vector1[0]) * den;
binormal.y = (tuVector[0] * vector2[1] - tuVector[1] * vector1[1]) * den;
binormal.z = (tuVector[0] * vector2[2] - tuVector[1] * vector1[2]) * den;
// Calculate the length of this normal.
length = sqrt((tangent.x * tangent.x) + (tangent.y * tangent.y) + (tangent.z * tangent.z));
// Normalize the normal and then store it
tangent.x = tangent.x / length;
tangent.y = tangent.y / length;
tangent.z = tangent.z / length;
// Calculate the length of this normal.
length = sqrt((binormal.x * binormal.x) + (binormal.y * binormal.y) + (binormal.z * binormal.z));
// Normalize the normal and then store it
binormal.x = binormal.x / length;
binormal.y = binormal.y / length;
binormal.z = binormal.z / length;
return;
}
void OBJModel_t::CalculateNormal(vec3f tangent, vec3f binormal, vec3f& normal)
{
float length;
// Calculate the cross product of the tangent and binormal which will give the normal vector.
normal.x = (tangent.y * binormal.z) - (tangent.z * binormal.y);
normal.y = (tangent.z * binormal.x) - (tangent.x * binormal.z);
normal.z = (tangent.x * binormal.y) - (tangent.y * binormal.x);
// Calculate the length of the normal.
length = sqrt((normal.x * normal.x) + (normal.y * normal.y) + (normal.z * normal.z));
// Normalize the normal.
normal.x = normal.x / length;
normal.y = normal.y / length;
normal.z = normal.z / length;
return;
}