法线贴图 OpenGL GetAttribLocation returns -1 对于两个输入
Normal Mapping OpenGL GetAttribLocation returns -1 for two inputs
我尝试将法线映射实现到我的顶点(稍后也在我的片段着色器中)。
我为所需的切线和副切线(aNormalTangent
、aNormalBiTangent
)添加了属性,最多 10 盏灯(uLightPos[10]
)作为统一和 int
全局统一 disable/enable法线贴图的使用。
编译着色器程序时,没有出现错误。但是,如果我尝试找出相应的句柄 [with GL.GetAttribLocation(currentProgram, "aNormalTangent")
],我总是会得到属性 aNormalTagent
和 aNormalBiTangent
的 -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);
我希望这个解决方案可以帮助其他人。干杯!
我尝试将法线映射实现到我的顶点(稍后也在我的片段着色器中)。
我为所需的切线和副切线(aNormalTangent
、aNormalBiTangent
)添加了属性,最多 10 盏灯(uLightPos[10]
)作为统一和 int
全局统一 disable/enable法线贴图的使用。
编译着色器程序时,没有出现错误。但是,如果我尝试找出相应的句柄 [with GL.GetAttribLocation(currentProgram, "aNormalTangent")
],我总是会得到属性 aNormalTagent
和 aNormalBiTangent
的 -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);
我希望这个解决方案可以帮助其他人。干杯!