質問
GLSLシェーダで法線マッピングを使用するためには、通常、接線と各頂点のbitangentベクトルを知っている必要があります。 RenderMonkeyは、このためにそれ自身の事前に定義された変数(rm_tangent
とrm_binormal
)を提供することで、これが容易になります。私は自分自身の3Dエンジンにこの機能を追加しようとしています。明らかに、各頂点のXYZ座標、UVテクスチャ座標と法線ベクトルを用いて、三角形の各頂点の接線と両性正接を計算することが可能です。いくつかの検索後、私は私の三角構造の各頂点の接線とbitangentを計算するために、この機能を考案します。
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);
}
私はこの機能を使用して、私のシェーダに計算された値を送信すると、、彼らはRenderMonkeyで行うようにモデルがほとんど見えますが、彼らは非常に奇妙な方法でちらつきます。私はOpenGLを送信しています接線とbitangentに問題をトレースします。これは私のコードが間違って何かをやっていると思われるために私をリード。誰もが何か問題を見たりしようとする他の方法のための任意の提案を持っていることはできますか?
私はまた、上記のコードは非常にハックと私は何が起こっているかの背後にある数学はほとんど理解していることを指摘する必要があります。
解決
解決策を見つけました。はるかに簡単な(しかし、まだ少しハック)コード:
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());
}
他のヒント
あなたは「R」のために、未知の挙動が得られU1、U2、V1、V2との特定の値のためのあなたの「R」の計算でゼロ除算を取得します。あなたはこのを防ぐ必要があります。分母がゼロであり、それはあなたの問題を解決する可能性がある場合はどうあるべきかを「R」を見つけ出します。私もこの背後にある数学の少し理解しています。
分母がゼロの場合、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;
}
...