我正在尝试使用OpenGL和GLSL在多维数据集上实现凹凸贴图。然而,当我旋转我的立方体时,只出现左侧正方形和右侧正方形(即,在负x和正x方向),立方体的其他四个面(顶部,底部,正面,背面) )是黑色的。这是一个例子:
我的网格类由indexList和vertexList组成(Vertex类包含x,y,z等)。我正在使用this简单的cube.ply模型,它包含s,t纹理坐标。借用this example,我按如下方式计算切向量:
void Mesh::computeTangents() {
for (size_t i = 0; i < m_indexList.size(); i += 3) {
Vertex v1 = m_vertexList[m_indexList[i]];
Vertex v2 = m_vertexList[m_indexList[i+1]];
Vertex v3 = m_vertexList[m_indexList[i+2]];
glm::vec3 pos1 = glm::vec3(v1.getX(), v1.getY(), v1.getZ());
glm::vec3 pos2 = glm::vec3(v2.getX(), v2.getY(), v2.getZ());
glm::vec3 pos3 = glm::vec3(v3.getX(), v3.getY(), v3.getZ());
glm::vec2 tex1 = glm::vec2(v1.getS(), v1.getT());
glm::vec2 tex2 = glm::vec2(v2.getS(), v2.getT());
glm::vec2 tex3 = glm::vec2(v3.getS(), v3.getT());
glm::vec3 edge1 = glm::normalize(pos2 - pos1);
glm::vec3 edge2 = glm::normalize(pos3 - pos1);
glm::vec2 texEdge1 = glm::normalize(tex2 - tex1);
glm::vec2 texEdge2 = glm::normalize(tex3 - tex1);
float det = (texEdge1.x * texEdge2.y) - (texEdge1.y * texEdge2.x);
glm::vec3 tangent;
if(fabsf(det) < 1e-6f) {
tangent.x = 1.0;
tangent.y = 0.0;
tangent.z = 0.0;
}
else {
det = 1.0 / det;
tangent.x = (texEdge2.y * edge1.x - texEdge1.y * edge2.x) * det;
tangent.y = (texEdge2.y * edge1.y - texEdge1.y * edge2.y) * det;
tangent.z = (texEdge2.y * edge1.z - texEdge1.y * edge2.z) * det;
glm::normalize(tangent);
}
m_vertexList[m_indexList[i]].setTanX(tangent.x);
m_vertexList[m_indexList[i]].setTanY(tangent.y);
m_vertexList[m_indexList[i]].setTanZ(tangent.z);
m_vertexList[m_indexList[i+1]].setTanX(tangent.x);
m_vertexList[m_indexList[i+1]].setTanY(tangent.y);
m_vertexList[m_indexList[i+1]].setTanZ(tangent.z);
m_vertexList[m_indexList[i+2]].setTanX(tangent.x);
m_vertexList[m_indexList[i+2]].setTanY(tangent.y);
m_vertexList[m_indexList[i+2]].setTanZ(tangent.z);
}
}
如果我输出每个三角形的切线向量的值,我得到这些值:
1,0,0
1,0,0
0,0,-1
0,0,-1
0,0,1
0,0,1
-1,0,0
-1,0,0,
1,0,0
1,0,0
1,0,0
1,0,0,
如果这些是正确的,则问题可能出在着色器中。我的着色器如下(主要取自一本书):
vert:
attribute vec4 vertexPosition;
attribute vec3 vertexNormal;
attribute vec2 vertexTexture;
attribute vec3 vertexTangent;
varying vec2 texCoord;
varying vec3 viewDirection;
varying vec3 lightDirection;
uniform vec3 diffuseColor;
uniform float shininess;
uniform vec4 lightPosition;
uniform mat4 modelViewMatrix;
uniform mat4 normalMatrix;
uniform mat4 MVP; // modelview projection
void main() {
vec4 eyePosition = modelViewMatrix * vertexPosition;
vec3 N = normalize(vec3(normalMatrix * vec4(vertexNormal, 1.0)));
vec3 T = normalize(vec3(normalMatrix * vec4(vertexTangent, 1.0)));
vec3 B = normalize(cross(N, T));
vec3 v;
v.x = dot(lightPosition.xyz, T);
v.y = dot(lightPosition.xyz, B);
v.z = dot(lightPosition.xyz, N);
lightDirection = normalize(v);
v.x = dot(eyePosition.xyz, T);
v.y = dot(eyePosition.xyz, B);
v.z = dot(eyePosition.xyz, N);
viewDirection = normalize(v);
texCoord = vertexTexture;
gl_Position = MVP * vertexPosition;
}
分片:
varying vec2 texCoord;
varying vec3 viewDirection;
varying vec3 lightDirection;
uniform vec3 diffuseColor;
uniform float shininess;
void main() {
float bumpDensity = 16.0;
float bumpSize = 0.15;
vec2 c = bumpDensity * texCoord;
vec2 p = fract(c) - vec2(0.5);
float d, f;
d = dot(p, p);
f = 1.0 / sqrt(d + 1.0);
if (d >= bumpSize) {
p = vec2(0.0);
f = 1.0;
}
vec3 normalDelta = vec3(p.x, p.y, 1.0) * f;
vec3 litColor = diffuseColor * max(dot(normalDelta, lightDirection), 0.0);
vec3 reflectDir = reflect(lightDirection, normalDelta);
float spec = max(dot(viewDirection, reflectDir), 0.0);
spec *= shininess;
litColor = min(litColor + spec, vec3(1.0));
gl_FragColor = vec4(litColor, 1.0);
}
编辑:更改背景以更清晰地看到黑色面孔。另外,我错误地注意到之前实际出现过哪些面孔。
编辑2:我发现片段着色器中max(dot(normalDelta,lightDirection),0.0)的值为这些面返回0。但是,我仍然不知道为什么。
编辑3:嗯,问题原来是我在Vertex类中传递了切线向量的错误索引。也就是说,我在这一行中有10而不是9:
glVertexAttribPointer(v3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof( float ) * 9));
答案 0 :(得分:1)
好吧,问题是xz平面上任何法线的面都没有正确渲染,即 正确渲染的面是沿y轴法线的面(顶面和底面)。
您的切线列表:
1, 0, 0
1, 0, 0
0, 0, -1
0, 0, -1
0, 0, 1
0, 0, 1
-1, 0, 0
-1, 0, 0
1, 0, 0
1, 0, 0
1, 0, 0
1, 0, 0
都是沿x轴或z轴。所以我猜测可能正在发生的是你的法线和切线指向相同(或相反)的方向,在这种情况下你的顶点着色器中的这一行:
vec3 B = normalize(cross(N, T));
将导致vec3(0.0,0.0,0.0),无法归一化。
我的建议是尝试沿y轴手动给出x和z面切线,看看是否有所不同。如果它有帮助,那么你知道问题在于你对切线的计算。
如果没有帮助,您可以通过从片段着色器输出值作为屏幕颜色进行故障排除。尝试显示viewDirection,lightDirection,normalDelta,reflectDir以及您可以想到的任何其他信息,以查看导致黑度的变量。
奖励:将glClear颜色切换为黑色以外的颜色?所以它看起来不像是漂浮在太空中的脸。