Frage

Um die normale Zuordnung in GLSL -Shadern zu verwenden, müssen Sie die normalen, tangente und bitangenten Vektoren jedes Scheitelpunkts kennen. Rendermonkey macht dies einfach, indem es seine eigenen vordefinierten Variablen bereitstellt (rm_tangent und rm_binormal) dafür. Ich versuche, diese Funktionalität meiner eigenen 3D -Engine hinzuzufügen. Anscheinend ist es möglich, die Tangente und die Bi -Tangente jedes Scheitelpunkts in einem Dreieck unter Verwendung der XYZ -Koordinaten der einzelnen Scheitelpunkte, der UV -Texturkoordinaten und dem normalen Vektor zu berechnen. Nach einiger Suche habe ich diese Funktion entwickelt, um die Tangente und das Bitangent für jeden Scheitelpunkt in meiner Dreiecksstruktur zu berechnen.

void CalculateTangentSpace(void) {
    float x1 = m_vertices[1]->m_pos->Get(0) - m_vertices[0]->m_pos->Get(0);
    float x2 = m_vertices[2]->m_pos->Get(0) - m_vertices[0]->m_pos->Get(0);
    float y1 = m_vertices[1]->m_pos->Get(1) - m_vertices[0]->m_pos->Get(1);
    float y2 = m_vertices[2]->m_pos->Get(1) - m_vertices[0]->m_pos->Get(1);
    float z1 = m_vertices[1]->m_pos->Get(2) - m_vertices[0]->m_pos->Get(2);
    float z2 = m_vertices[2]->m_pos->Get(2) - m_vertices[0]->m_pos->Get(2);

    float u1 = m_vertices[1]->m_texCoords->Get(0) - m_vertices[0]->m_texCoords->Get(0);
    float u2 = m_vertices[2]->m_texCoords->Get(0) - m_vertices[0]->m_texCoords->Get(0);
    float v1 = m_vertices[1]->m_texCoords->Get(1) - m_vertices[0]->m_texCoords->Get(1);
    float v2 = m_vertices[2]->m_texCoords->Get(1) - m_vertices[0]->m_texCoords->Get(1);

    float r = 1.0f/(u1 * v2 - u2 * v1);

    Vec3<float> udir((v2 * x1 - v1 * x2) * r, (v2 * y1 - v1 * y2) * r, (v2 * z1 - v1 * z2) * r);
    Vec3<float> vdir((u1 * x2 - u2 * x1) * r, (u1 * y2 - u2 * y1) * r, (u1 * z2 - u2 * z1) * r);

    Vec3<float> tangent[3];
    Vec3<float> tempNormal;

    tempNormal = *m_vertices[0]->m_normal;
    tangent[0]=(udir-tempNormal*(Vec3Dot(tempNormal, udir)));
    m_vertices[0]->m_tangent=&(tangent[0].Normalize());
    m_vertices[0]->m_bitangent=Vec3Cross(m_vertices[0]->m_normal, m_vertices[0]->m_tangent);

    tempNormal = *m_vertices[1]->m_normal;
    tangent[1]=(udir-tempNormal*(Vec3Dot(tempNormal, udir)));
    m_vertices[1]->m_tangent=&(tangent[1].Normalize());
    m_vertices[1]->m_bitangent=Vec3Cross(m_vertices[1]->m_normal, m_vertices[1]->m_tangent);

    tempNormal = *m_vertices[2]->m_normal;
    tangent[2]=(udir-tempNormal*(Vec3Dot(tempNormal, udir)));
    m_vertices[2]->m_tangent=&(tangent[2].Normalize());
    m_vertices[2]->m_bitangent=Vec3Cross(m_vertices[2]->m_normal, m_vertices[2]->m_tangent);
}

Wenn ich diese Funktion benutze und die kalkulierten Werte an meinen Shader sende, sehen die Modelle fast wie in Rendermonkey aus, flackern jedoch auf sehr seltsame Weise. Ich habe das Problem auf die Tangente und das Bitangent zurückgeführt, das ich OpenGL sende. Dies lässt mich vermuten, dass mein Code etwas falsch macht. Kann jemand Probleme sehen oder Vorschläge für andere Methoden haben?

Ich sollte auch darauf hinweisen, dass der obige Code sehr hackig ist und ich sehr wenig Verständnis für die Mathematik hinter dem, was vor sich geht.

War es hilfreich?

Lösung

Fand die Lösung. Viel einfacher (aber immer noch ein kleiner hackiger) Code:

void CalculateTangentSpace(void) {
    float x1 = m_vertices[1]->m_pos->Get(0) - m_vertices[0]->m_pos->Get(0);
    float y1 = m_vertices[1]->m_pos->Get(1) - m_vertices[0]->m_pos->Get(1);
    float z1 = m_vertices[1]->m_pos->Get(2) - m_vertices[0]->m_pos->Get(2);

    float u1 = m_vertices[1]->m_texCoords->Get(0) - m_vertices[0]->m_texCoords->Get(0);

    Vec3<float> tangent(x1/u1, y1/u1, z1/u1);
    tangent = tangent.Normalize();

    m_vertices[0]->m_tangent = new Vec3<float>(tangent);
    m_vertices[1]->m_tangent = new Vec3<float>(tangent);
    m_vertices[2]->m_tangent = new Vec3<float>(tangent);

    m_vertices[0]->m_bitangent=new Vec3<float>(Vec3Cross(m_vertices[0]->m_normal, m_vertices[0]->m_tangent)->Normalize());
    m_vertices[1]->m_bitangent=new Vec3<float>(Vec3Cross(m_vertices[1]->m_normal, m_vertices[1]->m_tangent)->Normalize());
    m_vertices[2]->m_bitangent=new Vec3<float>(Vec3Cross(m_vertices[2]->m_normal, m_vertices[2]->m_tangent)->Normalize());
}

Andere Tipps

Sie erhalten keine Teilung in Ihrer "R" -Bechne für bestimmte Werte von U1, U2, V1 und V2, was zu einem unbekannten Verhalten für 'R' führt. Sie sollten sich dagegen schützen. Finden Sie heraus, was 'R' sein sollte, wenn der Nenner Null ist, und das kann Ihr Problem beheben. Ich habe auch wenig Verständnis für die Mathematik dahinter.

Vorgeschlagene Implementierung, die r = 0 festlegt, wenn der Nenner Null ist:

#include <cmath>
...
static float PRECISION = 0.000001f;
...
float denominator = (u1 * v2 - u2 * v1);
float r = 0.f; 
if(fabs(denominator) > PRECISION) {    
    r = 1.0f/denominator;
}
...
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top