使用法线贴图进行渲染会导致旋转相关的照明

时间:2018-12-25 01:06:02

标签: opengl glsl lighting

当对象没有从原点旋转时,法线贴图看起来很棒,并且聚光灯和定向光都起作用,但是当我在某个点旋转一个对象时,它只是变暗,然后又变亮,仅在顶面上。

我正在使用多维数据集进行测试。我使用了一个几何着色器来可视化我的计算出的法线(乘以TBN矩阵后),它们似乎位于正确的位置。如果我从等式中取出法线贴图,那么照明就可以了。

在这里计算TBN:

void calculateTBN()
{
    //get the normal matrix
    mat3 model = mat3(transpose(inverse(mat3(transform))));
    vec3 T = normalize(vec3(model * tangent.xyz ));

    vec3 N = normalize(vec3(model * normal      ));

    vec3 B = cross(N, T);

    mat3 TBN = mat3( T , B , N);

    outputVertex.TBN =TBN;
}

然后对法线进行采样和转换:

vec3 calculateNormal()
{
    //Sort the input so that the normal is between 1 and minus 1 instead of 0 and 1
    vec3 input = texture2D(normalMap, inputFragment.textureCoord).xyz;

    input = 2.0 * input - vec3(1.0, 1.0, 1.0);

    vec3 newNormal = normalize(inputFragment.TBN* input);

    return newNormal;
}  

“我的照明”位于世界空间中(据我所知,该术语考虑的是变换矩阵,而不是相机或投影矩阵)

我确实尝试了将TBN作为逆(或转置)传递下来,然后将除法线之外的每个向量乘以它的技术。具有相同的效果。无论如何,我还是宁愿在世界空间工作,因为这显然对减光照明更好?或者,我听说过。

如果您想查看任何照明代码等等,我将其添加进来,但我认为没有必要,因为它可以分开工作。

编辑:: 根据要求,这里是顶点和片段着色器的一部分

    #version 330


uniform mat4 T; // Translation matrix
uniform mat4 S; // Scale matrix
uniform mat4 R; // Rotation matrix
uniform mat4 camera; // camera matrix
uniform vec4 posRelParent; // the position relative to the parent


// Input vertex packet
layout (location = 0) in vec4 position;
layout (location = 2) in vec3 normal;
layout (location = 3) in vec4 tangent;
layout (location = 4) in vec4 bitangent;
layout (location = 8) in vec2 textureCoord;


// Output vertex packet
out packet {

    vec2 textureCoord;
    vec3 normal;
    vec3 vert;
    mat3 TBN;
    vec3 tangent;
    vec3 bitangent;
    vec3 normalTBN;

} outputVertex;

mat4 transform;
mat3 TBN;

void calculateTBN()
{
    //get the model matrix, the transform of the object with scaling and transform  removeds
    mat3 model = mat3(transpose(inverse(transform)));

    vec3 T = normalize(model*tangent.xyz);

    vec3 N = normalize(model*normal);

    //I used to retrieve the bitangents by crossing the normal and tangent but now they are calculated independently
    vec3 B = normalize(model*bitangent.xyz);

    TBN = mat3( T , B , N);

    outputVertex.TBN = TBN;

    //Pass though TBN vectors for colour debugging in the fragment shader
    outputVertex.tangent = T;
    outputVertex.bitangent = B;
    outputVertex.normalTBN = N;


}

void main(void) {
    outputVertex.textureCoord = textureCoord;


    // Setup local variable pos in case we want to modify it (since position is constant)
    vec4 pos = vec4(position.x, position.y, position.z, 1.0) + posRelParent;

    //Work out the transform matrix
    transform = T * R * S;

//Work out the normal for lighting
    mat3 normalMat = transpose(inverse(mat3(transform)));

    outputVertex.normal = normalize(normalMat* normal);

    calculateTBN();

    outputVertex.vert =(transform* pos).xyz;

    //Work out the final pos of the vertex
    gl_Position = camera * transform * pos;
    }

以及片段的光照向量:

vec3 applyLight(Light thisLight, vec3 baseColor, vec3 surfacePos, vec3 surfaceToCamera)
{
    float attenuation = 1.0f;
    vec3 lightPos = (thisLight.finalLightMatrix*thisLight.position).xyz;
    vec3 surfaceToLight;

    vec3 coneDir = normalize(thisLight.coneDirection);

    if (thisLight.position.w == 0.0f)
    {
        //Directional Light (all rays same angle, use position as direction)
        surfaceToLight = normalize( (thisLight.position).xyz);
        attenuation = 1.0f;
    }
    else
    {
        //Point light
        surfaceToLight = normalize(lightPos - surfacePos);


        float distanceToLight = length(lightPos - surfacePos);
        attenuation = 1.0 / (1.0f + thisLight.attenuation * pow(distanceToLight, 2));

        //Work out the Cone restrictions
        float lightToSurfaceAngle = degrees(acos(dot(-surfaceToLight, normalize(coneDir))));

        if (lightToSurfaceAngle > thisLight.coneAngle)
        {
            attenuation = 0.0;
        }
    }

}

这也是片段着色器的主要内容:

void main(void) {
    //get the base colour from the texture
    vec4 tempFragColor = texture2D(textureImage, inputFragment.textureCoord).rgba;

    //Support for objects with and without a normal map
    if (useNormalMap == 1)
    {  
        calcedNormal = calculateNormal();
    }
    else
    {
        calcedNormal = inputFragment.normal;

    }


    vec3 surfaceToCamera = normalize((cameraPos_World) - (inputFragment.vert));

    vec3 tempColour = vec3(0.0, 0.0, 0.0);

    for (int count = 0; count < numLights; count++)
    {
        tempColour += applyLight(allLights[count], tempFragColor.xyz, inputFragment.vert, surfaceToCamera);
    }


    vec3 gamma = vec3(1.0 / 2.2);

    fragmentColour = vec4(pow(tempColour,gamma), tempFragColor.a);
    //fragmentColour = vec4(calcedNormal, 1);
}

编辑2:

用于通过TBN矩阵可视化“采样的”法线的几何着色器,如下所示:

np.cumsum

void GenerateLineAtVertex(int index)
{
    vec3 testSampledNormal = vec3(0, 0, 1);

    vec3 bitangent = cross(gs_in[index].normal, gs_in[index].tangent);

    mat3 TBN = mat3(gs_in[index].tangent, bitangent, gs_in[index].normal);

    testSampledNormal = TBN * testSampledNormal;


    gl_Position = gl_in[index].gl_Position;

    EmitVertex();

    gl_Position =
         gl_in[index].gl_Position 
        +  vec4(testSampledNormal, 0.0) * MAGNITUDE;


    EmitVertex();


    EndPrimitive();
}

这是顶点着色器

void main(void) {

// Setup local variable pos in case we want to modify it (since position is constant)
vec4 pos = vec4(position.x, position.y, position.z, 1.0);

mat4 transform = T* R * S;

// Apply transformation to pos and store result in gl_Position
gl_Position = projection* camera* transform * pos;


mat3 normalMatrix = mat3(transpose(inverse(camera * transform)));
vs_out.tangent = normalize(vec3(projection * vec4(normalMatrix * tangent.xyz, 0.0)));
vs_out.normal =  normalize(vec3(projection * vec4(normalMatrix * normal     , 0.0)));
}

这是可视化的TBN向量。点上的微小角度是由于我如何应用投影矩阵而引起的,而不是实际矢量中的错误。红线只是显示我在纹理上绘制的箭头的位置,从那个角度看,它们还不是很清楚。

1 个答案:

答案 0 :(得分:0)

问题已解决! 实际上,与上面的代码无关,尽管感谢所有提供帮助的人。

我正在使用自己的纹理加载器导入纹理,该加载器默认使用非伽玛校正的32位SRGB颜色。我将其切换为24位,仅使用RGB颜色,并且可以立即使用。典型的开发人员问题。...

Before and After