まず、ポリゴンのどちらを表側と定義するかについて...
・
右手座標系のOPenGLでは視点から見て
反時計回りだと表
・
左手座標系のDirectXでは視点から見て
時計回りだと表
とされています。なぜ逆なのかというと、外積(AB×BC)のベクトルがポリゴンの表側を示すからです。
つまり外積で表裏を判定できます。
外積(AB×BC)がポリゴンの表側ベクトル
三角形ABCのベクトルABとBCを外積することで直交するベクトルが作れます。
表裏の定義を逆にしたことで、座標系にかかわらず直交ベクトルはポリゴンの表側を向きます。
この直交ベクトルと、視点の方向ベクトルで内積を求めれば表裏が判定できます。
外積によるベクトルの向き( 右手座標系では3角形の反時計周り側を向く)
ポリゴンの回り順を逆にすると外積ベクトルは反対を向く。裏表も入れ替わります。
カメラや太陽光となるベクトルvに対して、ポリゴンが表裏どちらを向いているかを求めます。
#include <math.h>
//ベクトルの定義と各種計算
struct Vector3D{
double x;
double y;
double z;
};
//頂点の定義(ベクトルと同じ)
#define Vertex3D Vector3D
//ベクトル外積( vl × vr )
Vector3D cross_product( const Vector3D& vl, const Vector3D& vr )
{
Vector3D ret;
ret.x = vl.y * vr.z - vl.z * vr.y;
ret.y = vl.z * vr.x - vl.x * vr.z;
ret.z = vl.x * vr.y - vl.y * vr.x;
return ret;
}
//ベクトル内積
double dot_product( const Vector3D& vl, const Vector3D vr) {
return vl.x * vr.x + vl.y * vr.y + vl.z * vr.z;
}
// ベクトルvに対してポリゴンが表裏どちらを向くかを求める
// 戻り値 0:表 1:裏 -1:エラー
int polygon_side_chk( Vertex3D A, Vertex3D B, Vertex3D C, Vertex3D v ) {
//ABCが三角形かどうか。ベクトルvが0でないかの判定は省略します
//AB BCベクトル
Vector3D AB;
Vector3D BC;
AB.x = B.x - A.x;
AB.y = B.y - A.y;
AB.z = B.z - A.z;
BC.x = C.x - A.x;
BC.y = C.y - A.y;
BC.z = C.z - A.z;
//AB BCの外積
Vector3D c = cross_product( AB ,BC );
//ベクトルvと内積。順、逆方向かどうか調べる
double d = dot_product( v, c );
if ( d < 0.0 ) {
return 0; //ポリゴンはベクトルvから見て表側
}else
if ( d > 0.0 ) {
return 1; //ポリゴンはベクトルvから見て裏側
}
// d==0 ポリゴンは真横を向いている。表裏不明
return -1;
}