/* * シャドウマッピング */ #include #include "glext.h" #define TEX_WIDTH 512 #define TEX_HEIGHT 512 static const GLfloat lightPos[] = { 0.0, 15.0, 3.0, 1.0 }; /* 位置        */ static const GLfloat lightCol[] = { 0.8, 0.8, 0.8, 1.0 }; /* 直接光強度     */ static const GLfloat lightDif[] = { 0.2, 0.2, 0.2, 1.0 }; /* 影内の拡散反射強度 */ static const GLfloat lightBlk[] = { 0.0, 0.0, 0.0, 1.0 }; /* 影内の鏡面反射強度 */ static const GLfloat lightAmb[] = { 0.0, 0.0, 0.0, 1.0 }; /* 環境光強度     */ /* 箱 */ void box(double x, double y, double z) { /* 頂点データ */ const GLdouble vertex[8][3]={ {-x, -y, -z}, { x, -y, -z}, { x, y, -z}, {-x, y, -z}, {-x, -y, z}, { x, -y, z}, { x, y, z}, {-x, y, z}, }; /* 面データ */ static const GLdouble *face[6][4]={ {vertex[0], vertex[1], vertex[2], vertex[3]}, {vertex[1], vertex[5], vertex[6], vertex[2]}, {vertex[5], vertex[4], vertex[7], vertex[6]}, {vertex[4], vertex[0], vertex[3], vertex[7]}, {vertex[4], vertex[5], vertex[1], vertex[0]}, {vertex[3], vertex[2], vertex[6], vertex[7]}, }; /* 面の法線ベクトル */ static const GLdouble normal[6][3]={ { 0.0, 0.0,-1.0}, { 1.0, 0.0, 0.0}, { 0.0, 0.0, 1.0}, {-1.0, 0.0, 0.0}, { 0.0,-1.0, 0.0}, { 0.0, 1.0, 0.0}, }; /* 箱の色 */ static const GLfloat color[] = {0.2, 0.2, 0.8, 1.0}; int i, j; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color); glBegin(GL_QUADS); for (j = 0; j < 6; j++){ glNormal3dv(normal[j]); for (i = 4; --i >= 0;){ glVertex3dv(face[j][i]); } } glEnd(); } /* シーンを描画 */ void scene() { glPushMatrix(); glRotated(15.0, 0.0, 1.0, 0.0); glRotated(45.0, 1.0, 0.0, 0.0); glRotated(45.0, 0.0, 1.0, 0.0); box(0.5, 0.5 ,0.5); glPopMatrix(); glPushMatrix(); glTranslated(0.0, -1.5, 0.0); box(1.0, 0.5 ,1.0); glPopMatrix(); } /* 初期化 */ void init(void) { /* 背景色の指定 R 赤 G 緑 B 青 A 透明度 の順 */ glClearColor(0.0, 0.0, 0.0, 0.0); /* 光源の設定 */ glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb); glLightfv(GL_LIGHT0, GL_POSITION, lightPos); glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDif); //glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.0); //glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.2); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); /* デプスバッファの有効化 */ glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); } void resize(int w, int h) { /* ビューポートの設定 */ glViewport(0, 0, w, h); /* 射影変換モードに */ glMatrixMode(GL_PROJECTION); /* 変換行列を単位行列に */ glLoadIdentity(); /* 正射影の視野長方形 左、右、下、上、手前、奥 */ glFrustum(-1.33, 1.33, -1.0, 1.0, 1.0, 15.0); /* 射影変換モードに */ glMatrixMode(GL_MODELVIEW); } /* テクスチャ設定 */ void initTexture(void) { /* テクスチャの割り当て */ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, TEX_WIDTH, TEX_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); /* テクスチャを拡大・縮小する方法の指定 */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); /* テクスチャの繰り返し方法の指定 */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); /* 書き込むポリゴンのテクスチャ座標値のRとテクスチャとの比較を行うようにする */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); /* もしRの値がテクスチャの値以下なら真 */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); /* 比較の結果をアルファ値として得る */ glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_ALPHA); /* テクスチャ座標に視点座標系における物体の座標値を用いる */ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); /* 生成したテクスチャ座標をそのまま (S, T, R, Q) に使う */ static const GLdouble genfunc[][4] = { { 1.0, 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0, 1.0 }, }; glTexGendv(GL_S, GL_EYE_PLANE, genfunc[0]); glTexGendv(GL_T, GL_EYE_PLANE, genfunc[1]); glTexGendv(GL_R, GL_EYE_PLANE, genfunc[2]); glTexGendv(GL_Q, GL_EYE_PLANE, genfunc[3]); } /* 画面表示 */ void display(void) { GLint viewport[4]; /* ビューポートの保存用     */ GLdouble modelview[16]; /* モデルビュー変換行列の保存用 */ GLdouble projection[16]; /* 透視変換行列の保存用     */ /* 深さオフセットを補正する */ glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.1, 4.0); /* 第1ステップ */ /* デプスバッファをクリアする */ glClear(GL_DEPTH_BUFFER_BIT); /* 現在のビューポートを保存しておく */ glGetIntegerv(GL_VIEWPORT, viewport); /* ビューポートをテクスチャのサイズに設定する */ glViewport(0, 0, TEX_WIDTH, TEX_HEIGHT); /* 現在の透視変換行列を保存しておく */ glGetDoublev(GL_PROJECTION_MATRIX, projection); /* 透視変換行列を単位行列に設定する */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* 光源位置を視点としシーンが視野に収まるようモデルビュー変換行列を設定する */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 30.0); glTranslated(0.0, 0.0, -10.0); glRotated(90.0, 1.0, 0.0, 0.0); /* 設定したモデルビュー変換行列を保存しておく */ glGetDoublev(GL_MODELVIEW_MATRIX, modelview); /* デプスバッファの内容だけを取得するのでフレームバッファには書き込まない */ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); /* したがって陰影付けも不要なのでライティングをオフにする */ glDisable(GL_LIGHTING); /* デプスバッファには背面のポリゴンの奥行きを記録するようにする */ glCullFace(GL_FRONT); /* シーンを描画する */ scene(); /* デプスバッファの内容をテクスチャメモリに転送する */ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TEX_WIDTH, TEX_HEIGHT); /* 通常の描画の設定に戻す */ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); glMatrixMode(GL_PROJECTION); glLoadMatrixd(projection); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glEnable(GL_LIGHTING); glCullFace(GL_BACK); glDisable( GL_POLYGON_OFFSET_FILL ); /* 第2ステップ */ /* フレームバッファとデプスバッファをクリアする */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* モデルビュー変換行列の設定 */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* 視点の位置を設定する */ glTranslated(0.0, 0.0, -3.0); /* 光源の位置を設定する */ glLightfv(GL_LIGHT0, GL_POSITION, lightPos); /* テクスチャ変換行列を設定する */ glMatrixMode(GL_TEXTURE); glLoadIdentity(); /* テクスチャ座標の [-1,1] の範囲を [0,1] の範囲に収める */ glTranslated(0.5, 0.5, 0.5); glScaled(0.5, 0.5, 0.5); /* テクスチャのモデルビュー変換行列と透視変換行列の積をかける */ glMultMatrixd(modelview); /* 現在のモデルビュー変換の逆変換をかけておく */ glTranslated(0.0, 0.0, 3.0); /* モデルビュー変換行列に戻す */ glMatrixMode(GL_MODELVIEW); /* テクスチャマッピングとテクスチャ座標の自動生成を有効にする */ glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_R); glEnable(GL_TEXTURE_GEN_Q); glEnable(GL_ALPHA_TEST); /* アルファテストのしきい値を日向の部分に設定する */ glAlphaFunc(GL_GEQUAL, 0.5f); /* 光源の明るさを日向の部分での明るさに設定 */ glLightfv(GL_LIGHT0, GL_DIFFUSE, lightCol); glLightfv(GL_LIGHT0, GL_SPECULAR, lightCol); /* シーンを描画する */ scene(); /* 第3ステップ */ /* アルファテストのしきい値を影の部分に設定する */ glAlphaFunc(GL_LESS, 0.5f); /* 光源の明るさを影の部分での明るさに設定 */ glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDif); glLightfv(GL_LIGHT0, GL_SPECULAR, lightBlk); /* シーンを描画する */ scene(); glDisable(GL_ALPHA_TEST); /* テクスチャマッピングとテクスチャ座標の自動生成を無効にする */ glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glDisable(GL_TEXTURE_GEN_R); glDisable(GL_TEXTURE_GEN_Q); glDisable(GL_TEXTURE_2D); glFlush(); } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitWindowPosition(100, 50); glutInitWindowSize(400, 300); glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH); glutCreateWindow(argv[0]); /* 各関数の指定 */ glutDisplayFunc(display); glutReshapeFunc(resize); /* 初期化 */ init(); /* テクスチャ準備 */ initTexture(); /* メインループ */ glutMainLoop(); return 0; }