Касательная и битангенс не ортогональны нормальному - PullRequest
1 голос
/ 28 мая 2020

Я пытаюсь вычислить векторы касательной и битангенса для моего ландшафта. Я следил за этим учебником, чтобы выяснить, как вычислить эти 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

Точечное произведение Tangent и Normal довольно мало для первой итерации, но для некоторых из них она становится намного больше. Правильно ли я понимаю концепцию? Эти 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;
}

Как Как указано в комментариях, каждая из вершин имеет свою нормаль, и они могут отличаться друг от друга. Как бы мне поступить с расчетом касательной и битангенса в этом случае?

...