0

大家好,我正在尝试在 Directx 中实现法线映射,并且我非常接近创建它,但是我在某些对象上得到了这些奇怪的黑色。这是没有法线贴图的样子:

在此处输入图像描述

当我应用法线贴图效果时,它看起来是这样的:

在此处输入图像描述

在此处输入图像描述

我在例如墙壁和立方体的某些部分上得到黑色的地方很奇怪。

我的像素着色器文件如下所示:

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

}

我的顶点着色器看起来像这样:

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;
}

我从 CPU 端计算每个顶点的 Binormal 和 Tangent 的方法是使用这种方法(取自 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;
}
4

0 回答 0