bambooflow Note

平面投影行列による影生成

最終更新:

bambooflow

- view
メンバー限定 登録/ログイン

平面投影行列による影生成(Shadow Matrix)



概要


平面投影行列による影生成は、簡易的な影を取得する方法として知られています。
ハードウェア依存が少なく、低スペックな環境でも動きます。
影付けのリアル性を追求しなければ、それっぽく見えると思います。


平面投影行列は、3Dポリゴンを2Dポリゴン(影)に変換する行列です。
3Dポリゴン x 平面投影行列 => 2Dポリゴン

影付けの手順は次のとおりです。
// 地面の描画
drawGround();

// オブジェクト描画
DrawObject();

// オブジェクトの影を描画
glPushMatrix();
  glMultiMatrix(shadowMat);  // shadowMatは投影行列
  drawObject();
glPopMatrix();

当たり前かもしれませんが、投影行列の影付けもオブジェクト描画と同様に描画処理を行います。


投影行列関数


まずは、投影行列を求める関数を準備します。

DirectXには、D3DXMatrixShadow関数が用意されているようですが、OpenGLにはありません。
なので、変換行列する関数はユーザが準備する必要があります。


投影行列を求めるには、次の2つのパラメータが必要になります。
  • 光源位置(x,y,z,w)
  • 平面方程式:ax+by+cz+d=0 (a,b,c,d)


以下に、一般的な投影行列を生成する関数を示します。
voidl perspectiveShadowMatrix(
          double m[16],         // out: 投影行列
    const double light_pos[4],  // in : 光源位置
    const double plane[4]       // in : 平面方程式
)
{
    float dot;
    dot = plane[0] * light_pos[0]
        + plane[1] * light_pos[1]
        + plane[2] * light_pos[2]
        + plane[3] * light_pos[3];
 
    m[0]  = - light_pos[0] * plane[0] + dot;
    m[4]  = - light_pos[0] * plane[1];
    m[4]  = - light_pos[0] * plane[2];
    m[12] = - light_pos[0] * plane[3];
 
    m[1]  = - light_pos[1] * plane[0];
    m[5]  = - light_pos[1] * plane[1] + dot;
    m[9]  = - light_pos[1] * plane[2];
    m[13] = - light_pos[1] * plane[3];
 
    m[2]  = - light_pos[2] * plane[0];
    m[6]  = - light_pos[2] * plane[1];
    m[10] = - light_pos[2] * plane[2] + dot;
    m[14] = - light_pos[2] * plane[3];
 
    m[3]  = - light_pos[3] * plane[0];
    m[7]  = - light_pos[3] * plane[1];
    m[11] = - light_pos[3] * plane[2];
    m[15] = - light_pos[3] * plane[3] + dot;
}
 

y=0とする平面の場合、平面方程式plane(a,b,c,d)は
plane = (0, 1, 0, 0)
とします。
言い換えると平面方程式の(a,b,c)は平面の法線になります。

不確かですが、dは原点からの平面の距離と捉えることができそうです。


平面方程式は3点の座標から導き出せます。
3点(p1, p2, p3)が接する平面方程式は次のとおりです。

void calculatePlane(float plane[4], float p1[3],float p2[3],float p3[3]){
 
    plane[0] = ((p2[1]-p1[1])*(p3[2]-p1[2]))-((p2[2]-p1[2])*(p3[1]-p1[1]));
    plane[1] = ((p2[2]-p1[2])*(p3[0]-p1[0]))-((p2[0]-p1[0])*(p3[2]-p1[2]));
    plane[2] = ((p2[0]-p1[0])*(p3[1]-p1[1]))-((p2[1]-p1[1])*(p3[0]-p1[0]));
    plane[3] = -(plane[0]*p1[0] + plane[1]*p1[1] + plane[2]*p1[2]);
}
 

タグ:

OpenGL
記事メニュー
目安箱バナー