0

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:

enter image description here

And when I apply the Normal Mapping effect this is how it looks:

enter image description here

enter image description here

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;
}
Awni
  • 41
  • 1
  • 5
  • A stab in the dark, but might be that the normal needs to be recalculated on the form normal * 2 - 1. Since for X you go from 0 to 1 and you need it to go from -1 to 1 – Bozemoto Mar 30 '18 at 09:12
  • @Bozemoto Hmm don't I do that in the pixel shader? :) – Awni Mar 30 '18 at 10:22
  • @Anwi you do. Perhaps just outputting the normal as the colour would be good? Would let you see what the shader calculates the normal to. Also, if statements are something to avoid in shaders (any branching really). – Bozemoto Mar 30 '18 at 10:32
  • @Bozemoto I'll try that. :) I believe the issue is coming from were I calculate the Bionormal and the Tangent, i.e. the CalculateModelVectors() function since the denominator is giving off an inf value when I output it and not a number and that might be causing the issue. – Awni Mar 31 '18 at 06:32

0 Answers0