2009-08-29 7 views
2

GLSL 쉐이더에서 일반 매핑을 사용하려면 각 꼭지점의 법선, 접선 및 비트 대열 벡터를 알아야합니다. RenderMonkey는 이것을 위해 미리 정의 된 변수 (rm_tangentrm_binormal)를 제공하여 쉽게 만듭니다. 내 자신의 3D 엔진에이 기능을 추가하려고합니다. 분명히 각 꼭지점의 xyz 좌표, uv 텍스처 좌표 및 법선 벡터를 사용하여 삼각형의 각 꼭지점의 탄젠트 및 양 탄젠트를 계산할 수 있습니다. 몇 가지 검색을 한 후에이 함수를 사용하여 삼각형 구조의 각 정점에 대한 탄젠트 및 비트 탄젠트를 계산했습니다. 그들이 렌더에서처럼 3D 접선 공간 계산

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

나는이 기능을 사용하여 내 쉐이더로 계산 된 값을 보내

는 모델은 거의 볼하지만 그들은 아주 이상한 방법으로 깜박. 나는이 문제를 탄젠트와 비트로 추적했다. 나는 OpenGL을 보내고있다. 이것은 내 코드가 뭔가 잘못되었다고 의심하게 만든다. 누구든지 문제를 보거나 다른 방법을 시도해 볼 수 있습니까?

나는 위의 코드가 매우 해킹 된 것을 지적해야하며 나는 일어나고있는 일에 뒤늦은 수학에 대해 거의 이해하지 못했다.

답변

4

용액 알았다. 훨씬 간단한 (그래도 조금 해킹 된) 코드 :

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()); 
} 
+2

죄송하지만, 그건 잘못되었습니다. 당신은 단순히 가장자리 v01을 1/u1로 스케일링하는 것입니다. u1이 0 일뿐만 아니라 분명히 올바르지 않습니다. 정답은 http://stackoverflow.com/questions/5255806/how-to-calculate-tangent-and-binormal을 참조하십시오. – Gottfried

0

u1, u2, v1 및 v2의 특정 값에 대해 'r'계산에서 제로 나눗셈을 얻으므로 'r'에 대해 알 수없는 동작이 발생합니다. 너는 이것을 막아야한다. 분모가 0이고 문제가 해결되면 'r'이 무엇인지 파악하십시오. 나도이 배후의 수학에 대해 거의 이해하지 못했다. 분모가 0 인 경우, R = 0으로 설정

제안 구현 :

#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; 
} 
... 
+0

답장을 보내 주셔서 감사합니다. 불행히도 귀하의 제안은 도움이되지 않습니다. –