付録 A: 接線および従法線ベクトル

以下では、ポリゴン メッシュ ジオメトリに対して接線および従法線ベクトルが Maya ではどのように計算されるかを簡単に説明します。

三角ポリゴンごとの接線計算

入力: 三角ポリゴンの各頂点に対して、次の値を渡します: v(頂点の位置、float(浮動小数点数)3 桁)、n(法線の位置、float 3 桁)、t(テクスチャの座標値、float 2 桁): v[3][3], n[3][3] t[3][2];

出力: 各頂点に対して、接線ベクトル(float3 桁)を計算して返します: tangentArray[3][3];

 float $edge1[3];
 float $edge2[3];
 float $crossP[3];
 float $tangentArray[3][3];
 //==============================================
 // x, s, t
 // S & T vectors get used several times in this vector,
 // but are only computed once.
 //==============================================
 $edge1[0] = $v[1][0] - $v[0][0];
 $edge1[1] = $t[1][0] - $t[0][0]; // s-vector - don't need to compute this multiple times
 $edge1[2] = $t[1][1] - $t[0][1]; // t-vector
 $edge2[0] = $v[2][0] - $v[0][0];
 $edge2[1] = $t[2][0] - $t[0][0]; // another s-vector
 $edge2[2] = $t[2][1] - $t[0][1]; // another t-vector
 $crossP = crossProduct( $edge1, $edge2 ) ;
 normalize( $crossP );
 bool $degnerateUVTangentPlane = equivalent( $crossP[0], 0.0f );
 if (degnerateUVTangentPlane)
 $crossP[0] = 1.0f;
 float $tanX = -$crossP[1]/$crossP[0];
 $tangentArray[0][0] = $tanX;
 $tangentArray[1][0] = $tanX;
 $tangentArray[2][0] = $tanX;
 //--------------------------------------------------------
 // y, s, t
 //--------------------------------------------------------
 $edge1[0] = $v[1][1] - $v[0][1];
 $edge2[0] = $v[2][1] - $v[0][1];
 $edge2[1] = $t[2][0] - $t[0][0];
 $edge2[2] = $t[2][1] - $t[0][1];
 $crossP = crossProduct( $edge1, $edge2 );
 normalize( $crossP );
 degnerateUVTangentPlane = equivalent( $crossP[0], 0.0f );
 if (degnerateUVTangentPlane)
 $crossP[0] = 1.0f;
 float $tanY = -$crossP[1]/$crossP[0];
 $tangentArray[0][1] = $tanY;
 $tangentArray[1][1] = $tanY;
 $tangentArray[2][1] = $tanY;
 //------------------------------------------------------
 // z, s, t
 //------------------------------------------------------
 $edge1[0] = $v[1][2] - $v[0][2];
 $edge2[0] = $v[2][2] - $v[0][2];
 $edge2[1] = $t[2][0] - $t[0][0];
 $edge2[2] = $t[2][1] - $t[0][1];
 $crossP = crossProduct( $edge1 , $edge2 );
 normalize( $crossP );
 degnerateUVTangentPlane = equivalent( $crossP[0], 0.0f );
 if (degnerateUVTangentPlane)
 $crossP[0] = 1.0f;
 float $tanZ = -$crossP[1]/$crossP[0];
 $tangentArray[0][2] = $tanZ;
 $tangentArray[1][2] = $tanZ;
 $tangentArray[2][2] = $tanZ;
 // Orthnonormalize to normal
 for( int $i = 0; $i < 3; $i++)
 {
 $tangentArray[i] -= $n[i] * $tangentArray[i].dot( n[i]);
 }
 // Normalize tangents
 normalize( $tangentArray[0] );
 normalize( $tangentArray[1] );
 normalize( $tangentArray[2] );
 
 return $tangentArray;

サーフェス接線および従法線計算

接線計算は、使用されている特定のテクスチャ座標セット(uvset)のテクスチャ座標(uv)に基づいています。使用される法線は、スムージングおよびユーザ法線を考慮するジオメトリ法線です。

フェース上の各三角ポリゴンに対して、その三角ポリゴンの各頂点の接線が計算されます。三角形がマッピングされていて(つまり、UV が存在していて)、かつその UV が縮退ではない場合は、三角ポリゴンごとの接線計算に記載された計算が実行されます。

縮退 uv とは、三角ポリゴンの任意のエッジに沿う uv 空間に長さ 0 のベクトルが存在するということです。三角形がマッピングされていない、または縮退ではない場合、ジオメトリ エッジが接線の計算に使用されます。三角ポリゴンの各頂点(i)に対して、以下の計算が実行されます。

tangent[i] = vertex[i+1 % 3] - vertex[i];
tangent[i] = tangent[i] - normal[i] * dotProduct( tangent[i], normal[i]);
normalize( tangent[i] );

マッピングされたフェースでは、頂点の関連する normalId が同一な場合のみ、その頂点の各 uvId に対する共有接線のリストを維持します。

uvId は uv セットデータ配列へのオフセットであり、normalId は法線データ配列へのオフセットです。接線データ配列は、uvId データ配列の大きさと同じになります。各リストは、最終的な共有接線ベクトルの計算用に正規化されます。

従法線は、フェース上の特定の頂点における、接線ベクトルと法線ベクトルの正規化されたベクトル積として計算されます。従法線は、オンデマンドで計算されキャッシュされます。