【问题标题】:Bump Mapping in OpenGL and GLSLOpenGL 和 GLSL 中的凹凸贴图
【发布时间】:2013-11-29 01:31:40
【问题描述】:

我正在尝试使用 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

如果这些都是正确的,那么问题很可能出在着色器中。我的着色器如下(大部分取自一本书):

垂直:

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

【问题讨论】:

    标签: opengl graphics glsl bump-mapping


    【解决方案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)。

    我的建议是尝试手动设置 x 和 z 面沿 y 轴的切线,看看是否会有所不同。如果它有帮助,那么您就知道问题出在您的切线计算上。

    如果没有帮助,您可以通过将片段着色器中的值作为屏幕颜色输出来进行故障排除。尝试显示 viewDirection、lightDirection、normalDelta、reflectDir 以及您能想到的任何其他内容,以查看导致黑度的变量。

    奖励:将 glClear 颜色切换为黑色以外的颜色?让它看起来不像是一张漂浮在太空中的脸。

    【讨论】:

    • 感谢您的提示。其实,再看一遍之后,我错误地看到了实际出现的面孔。原来出现的是左脸和右脸。另外,我按照您的建议仔细检查了切线值,我相信它们是正确的。对于每个三角形,我手动检查了正常 X 切线向量的 wolfram alpha,并且在每种情况下,它都给出了一个适当的双切线向量,它构成了一个完整的坐标系。所以,我猜测(并希望)我可以将问题缩小到着色器中。
    • 检查我的编辑 3. 虽然发布我的整个代码(其中可能包含我提到的错误)是不切实际的,但您的建议帮助我调试和仔细检查与切向量相关的所有内容。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-25
    相关资源
    最近更新 更多