法线贴图 OpenGL GetAttribLocation returns -1 对于两个输入

Normal Mapping OpenGL GetAttribLocation returns -1 for two inputs

我尝试将法线映射实现到我的顶点(稍后也在我的片段着色器中)。 我为所需的切线和副切线(aNormalTangentaNormalBiTangent)添加了属性,最多 10 盏灯(uLightPos[10])作为统一和 int 全局统一 disable/enable法线贴图的使用。

编译着色器程序时,没有出现错误。但是,如果我尝试找出相应的句柄 [with GL.GetAttribLocation(currentProgram, "aNormalTangent")],我总是会得到属性 aNormalTagentaNormalBiTangent 的 -1。 所有其他属性位置和所有其他制服都有效。

我的代码哪里出错了?我尝试注释掉部分内容,但我没有找到错误的来源...

这是我的顶点着色器代码:

#version 330

in      vec3 aPosition;
in      vec3 aColor;
in      vec2 aTexture;
in      vec3 aNormal;
in      vec3 aNormalTangent;
in      vec3 aNormalBiTangent;

out     vec4 vPosition;
out     vec4 vColor;
out     vec2 vTexture;
out     vec3 vNormal;

// for shadows:
out     vec2 vTexCoordinate;
out     vec4 vShadowCoord;

// for normal mapping:
out     vec3 vLightPosTanSpace[10];

uniform mat4 uMVP;
uniform mat4 uM;
uniform mat4 uMV;
uniform mat4 uNormalMatrix;
uniform mat4 uShadowMVP;
uniform int uUseNormalMap;
uniform vec4 uLightPos[10];

void main()
{
    vShadowCoord = vec4(uShadowMVP * vec4(aPosition, 1.0));
    vPosition = uM * vec4(aPosition, 1.0);
    vColor = vec4(aColor, 1.0); 
    vTexture = aTexture; 
    vNormal = normalize(vec3(uNormalMatrix * vec4(aNormal, 0.0)));

    // Normal mapping calculations:
    if(uUseNormalMap > 0)
    {
        mat3 mv3x3 = mat3(uMV[0].xyz, uMV[1].xyz, uMV[2].xyz);
        vec3 vertexNormal_cameraspace = mv3x3 * normalize(aNormal);
        vec3 vertexTangent_cameraspace = mv3x3 * normalize(aNormalTangent);
        vec3 vertexBitangent_cameraspace = mv3x3 * normalize(aNormalBiTangent);
        mat3 TBN = transpose(mat3(vertexTangent_cameraspace, vertexBitangent_cameraspace, vertexNormal_cameraspace));
        vLightPosTanSpace[0] = TBN * vec3(uLightPos[0]);
        // --- 9 other array slots filled with vec3(0,0,0) for testing ---      
    }
    else
    {
        vLightPosTanSpace = vec3[10](
            vec3(0,0,0),
            vec3(0,0,0),
            vec3(0,0,0),
            vec3(0,0,0),
            vec3(0,0,0),
            vec3(0,0,0),
            vec3(0,0,0),
            vec3(0,0,0),
            vec3(0,0,0),
            vec3(0,0,0)
        );
    }

    gl_Position = uMVP * vec4(aPosition, 1.0); 
}

好的,现在 - 尽管我得到了反对票(无论出于何种原因),我还是想与大家分享我的最终解决方案:

我决定将法线(从法线贴图获得)转换为世界 space。因为我的所有其他计算都发生在世界 space 中,所以我认为这是最简单的解决方案(目前)。我知道将一切都转换为切线 space 可以在顶点着色器中进行,因此成本更低,但现在我的目标不是尽可能获得最佳性能。我只是想让它工作。随后将进行清理和优化。

所以,顶点着色器:

#version 330

in      vec3 aPosition;
in      vec3 aColor;
in      vec2 aTexture;
in      vec3 aNormal;
in      vec3 aNormalTangent;
in      vec3 aNormalBiTangent;

out     vec4 vPosition;
out     vec4 vColor;
out     vec2 vTexture;
out     vec3 vNormal;

// for shadows:
out     vec2 vTexCoordinate;
out     vec4 vShadowCoord;

// for normal mapping:
out     mat3 TBN;

uniform mat4 uMVP;
uniform mat4 uM;
uniform mat4 uMV;
uniform mat4 uNormalMatrix; // inverse transpose of model matrix
uniform mat4 uShadowMVP;
uniform int uUseNormalMap;


void main()
{
    vShadowCoord = vec4(uShadowMVP * vec4(aPosition, 1.0));
    vPosition = uM * vec4(aPosition, 1.0); 
    vColor = vec4(aColor, 1.0); 
    vTexture = aTexture; 
    vNormal = normalize(vec3(uNormalMatrix * vec4(aNormal, 0.0)));

    vec3 tangent = normalize(vec3(uM * vec4(aNormalTangent, 0.0)));
    vec3 biTangent = normalize(vec3(uM * vec4(aNormalBiTangent, 0.0)));
    vec3 normal = normalize(vec3(uM * vec4(aNormal, 0.0)));
    TBN = mat3(tangent.xyz, biTangent.xyz, normal.xyz);

    gl_Position = uMVP * vec4(aPosition, 1.0); 
}

...和片段着色器:

vec3 normal = vec3(0, 0, 0); 
if(uUseNormalMap > 0)
{
    // receive normal from normal map texture:
    normal = normalize(texture(uTextureNormalMap, vTexture).xyz * 2.0 - 1.0);
    // convert normal to world space by multiplying it with TBN matrix:
    normal = normalize(TBN * normal);
}
else
{
    // if no normal map is available, use the normal from the
    // vertex shader instead:
    normal = vNormal;
}

vec4 colorComponentTotal = vec4(0,0,0,1);
for(int i = 0; i < 10; i++)
{
    if(uLightPos[i].w > -1) // is it a real light or just an empty dummy value?
    {   
        vec3 lightPos = vec3(uLightPos[i]);
        vec4 lightColor = uLightColor[i];
        vec3 lightTargetPos = vec3(uLightTargetPos[i]);
        vec3 lightVector = lightPos - vec3(vPosition);

        float distance = length(lightVector);
        lightVector = normalize(lightVector);
        float dotProductNormalLight = max(dot(normal, lightVector), 0.0);

        if(uLightPos[i].w > 0) // is it a directional light?
        {   
            // calculate diffuse component depending on the light's distance,
            // with fixed intensity (8.0)
            diffuseComponent = calculateDiffuseComponent(dotProductNormalLight, distance, 8.0);
            // calculate light cone for directional light:
            diffuseComponent = calculateFallOff(diffuseComponent, lightVector, normalize(lightTargetPos));
        }
        else
        {
            diffuseComponent = calculateDiffuseComponentPoint(dotProductNormalLight, distance, 2.0);
        }
        colorComponentTotal = mix(colorComponentTotal, lightColor, min(lightColor.w, diffuseComponent));
        diffuseComponentTotal += diffuseComponent;
    }
    else
    {
        break;
    }
}

outputColor = (diffuseComponentTotal * mix(colorComponentTotal, vColor, 0.1) + ambient * vec4(1,1,1,1)) * texture(uTexture, vTexture);

我希望这个解决方案可以帮助其他人。干杯!