ゲームプログラミング技術集 
ひっと

ポリゴンの表裏の判定方法

外積と内積を使ったポリゴン表裏の判定方法について。説明とプログラミング例。

ポリゴン表裏の判定

まず、ポリゴンのどちらを表側と定義するかについて...

右手座標系の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;
}


戻る     次へ