切线和位线与法线不正交。

问题描述 投票:1回答:1

我想计算地形的切线和位切向量。我按照 这个 教程中,我想知道如何计算这2个向量,根据我的理解,切线等切线和法线向量应该都是相互正交的,对吗?我正在检查,但似乎我做错了什么,因为它们不是正交的。谁能给我解释一下我到底做错了什么?这是我的代码。

for (int i = 0; i < indices.size(); i += 3) {
    glm::vec3 v0 = vertices.at(indices.at(i)).position;
    glm::vec3 v1 = vertices.at(indices.at(i + 1)).position;
    glm::vec3 v2 = vertices.at(indices.at(i + 2)).position;

    std::cout << "v0 " << glm::to_string(v0) << std::endl;
    std::cout << "v1 " << glm::to_string(v1) << std::endl;
    std::cout << "v2 " << glm::to_string(v2) << std::endl;

    glm::vec2 uv0 = vertices.at(indices.at(i)).texcoord;
    glm::vec2 uv1 = vertices.at(indices.at(i + 1)).texcoord;
    glm::vec2 uv2 = vertices.at(indices.at(i + 2)).texcoord;

    std::cout << "uv0 " << glm::to_string(uv0) << std::endl;
    std::cout << "uv1 " << glm::to_string(uv1) << std::endl;
    std::cout << "uv2 " << glm::to_string(uv2) << std::endl;

    glm::vec3 deltaPos1 = v1 - v0;
    glm::vec3 deltaPos2 = v2 - v0;

    std::cout << "e1 " << glm::to_string(deltaPos1) << std::endl;
    std::cout << "e2 " << glm::to_string(deltaPos2) << std::endl;

    glm::vec2 deltaUV1 = uv1 - uv0;
    glm::vec2 deltaUV2 = uv2 - uv0;

    std::cout << "deltaUV1 " << glm::to_string(deltaUV1) << std::endl;
    std::cout << "deltaUV2 " << glm::to_string(deltaUV2) << std::endl;

    GLfloat r = (GLfloat) (1.f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x));

    std::cout << "r is: " << r << std::endl;

    glm::vec3 tangent = glm::normalize((deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r);
    glm::vec3 bitangent = glm::normalize((deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r);

    std::cout << "normal 1 " << glm::to_string(vertices.at(indices.at(0)).normal) << std::endl;
    std::cout << "normal 2 " << glm::to_string(vertices.at(indices.at(1)).normal) << std::endl;
    std::cout << "normal 3 " << glm::to_string(vertices.at(indices.at(2)).normal) << std::endl;

    std::cout << "tangent " << glm::to_string(tangent) << std::endl;
    std::cout << "bitangent " << glm::to_string(bitangent) << std::endl;

    glm::vec3 normal1 = vertices.at(indices.at(i)).normal;
    glm::vec3 normal2 = vertices.at(indices.at(i + 1)).normal;
    glm::vec3 normal3 = vertices.at(indices.at(i + 2)).normal;
    for (int j = 0; j < 3; j++) {
        glm::vec3 norm;
        if (j == 0) {
            norm = normal1;
        } else if (j == 1) {
            norm = normal2;
        } else {
            norm = normal3;
        }
        GLfloat tangentDot = glm::dot(norm, tangent);
        GLfloat bitangentDot = glm::dot(norm, bitangent);

        if (tangentDot != 0 || bitangentDot != 0) {
            std::cerr << "ERROR::Terrain::Tangent or bitangent were not orthogonal" << std::endl;
            std::cerr << tangentDot << " " << bitangentDot << std::endl;
        }
    }

    vertices.at(indices.at(i)).tangents = tangent;
    vertices.at(indices.at(i)).bitangents = bitangent;
    vertices.at(indices.at(i + 1)).tangents = tangent;
    vertices.at(indices.at(i + 1)).bitangents = bitangent;
    vertices.at(indices.at(i + 2)).tangents = tangent;
    vertices.at(indices.at(i + 2)).bitangents = bitangent;
}

这里是我第一次迭代的调试输出,作为一个例子。

v0 vec3(0.000000, 0.078430, 0.000000)
v1 vec3(0.000000, 0.078430, 3.137255)
v2 vec3(3.137255, 0.078430, 0.000000)
uv0 vec2(0.000000, 0.000000)
uv1 vec2(0.000000, 0.003922)
uv2 vec2(0.003922, 0.000000)
e1 vec3(0.000000, 0.000000, 3.137255)
e2 vec3(3.137255, 0.000000, 0.000000)
deltaUV1 vec2(0.000000, 0.003922)
deltaUV2 vec2(0.003922, 0.000000)
r is: -65025
normal 1 vec3(-0.039155, 0.998466, -0.039155)
normal 2 vec3(-0.039185, 0.999232, 0.000000)
normal 3 vec3(0.000000, 0.999232, -0.039185)
tangent vec3(1.000000, -0.000000, -0.000000)
bitangent vec3(-0.000000, -0.000000, 1.000000)

ERROR::Terrain::Tangent or bitangent were not orthogonal
-0.0391549 -0.0391549
ERROR::Terrain::Tangent or bitangent were not orthogonal
-0.039185 0
ERROR::Terrain::Tangent or bitangent were not orthogonal
0 -0.039185

第一次迭代时,切线和法线的点积非常小,但有些点积会变大。我对这个概念的理解正确吗?这3个向量必须是正交的吗?我检查了用ASSIMP导入的网格中的向量的相同点积,它们都是正交的。

-- 编辑:这是我计算法线的方法。

glm::vec3 Terrain::calculateNormal(int x, int z, unsigned char *textureData, int imageWidth, int imageHeight, int imageChannels) {
// TODO: Not optimal since we are calculating the same vertice height multiple times
// TODO: We also do the same calls above, maybe it will be smarter to just create a lookup table?

float heightL = getHeight(x - 1, z, textureData,imageWidth, imageHeight, imageChannels);
float heightR = getHeight(x + 1, z, textureData,imageWidth, imageHeight, imageChannels);
float heightD = getHeight(x, z - 1, textureData,imageWidth, imageHeight, imageChannels);
float heightU = getHeight(x, z + 1, textureData,imageWidth, imageHeight, imageChannels);

glm::vec3 normal = glm::vec3{heightL - heightR, 2.f, heightD - heightU};
normal = glm::normalize(normal);

return normal;
}

正如评论中所指出的,每个顶点都有自己的法线,而且它们可能彼此不同。在这种情况下,我将如何处理切线和位切线的计算?

c++ opengl game-engine glm-math bump-mapping
1个回答
© www.soinside.com 2019 - 2024. All rights reserved.