GLSLでシャドウマッピング
をテンプレートにして作成
[
トップ
|
新規
|
一覧
|
検索
|
最終更新
|
ヘルプ
]
開始行:
GLSLを使いシャドウマッピングで影をつける.
----
#contents
----
**シャドウマッピング(Shadow mapping)について [#c4b5a7a8]
物体の影をつける代表的なものとしてシャドウボリューム法と...
シャドウボリューム法は光源から各頂点へのベクトルを伸ばし,
交差によってできる三角形領域の演算処理で影領域を求める方...
影をつけるのには一般的にステンシルバッファが用いられる.
この方法ではモデルの頂点数が増えた場合に計算量がとても多...
また,透過テクスチャなどの影響は考慮できない.
一方,シャドウマッピング法は光源からシーンをレンダリング...
視点からレンダリングしたときにそのデプス値を比較すること...
各デプス値について下図に示す.シャドウマップ内のデプス値...
影領域ではdc > dlとなる.下図では物体自身のシェーディング...
シェーディングに影響しないようにしたい場合はdlを求める際...
#ref(shadowmap.jpg,,100%)
シャドウマップを生成する際にテクスチャを考慮すれば,透過...
ここではGLSLを使ってシャドウマッピングで影付きのレンダリ...
**FBO生成 [#i8b09ae7]
光源からのレンダリング結果を格納するためにFBOを用いる.
FBOについては[[OpenGL - FBO]]を参照.
FBO確保のコードは以下.
#code(C){{
GLuint m_iFBODepth; //!< 光源から見たときのデプスを格納...
GLuint m_iTexDepth; //!< m_iFBODepthにattachするテクスチャ
double m_fDepthSize[2]; //!< デプスを格納するテクスチャの...
/*!
* シャドウマップ用FBOの初期化
* @param[in] w,h シャドウマップの解像度
*/
void InitShadow(int w, int h)
{
m_fDepthSize[0] = w;
m_fDepthSize[1] = h;
// デプス値テクスチャ
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &m_iTexDepth);
glBindTexture(GL_TEXTURE_2D, m_iTexDepth);
// テクスチャパラメータの設定
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL...
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL...
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLA...
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLA...
GLfloat border_color[4] = {1, 1, 1, 1};
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR,...
// テクスチャ領域の確保(GL_DEPTH_COMPONENTを用いる)
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, m_fDe...
GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// FBO作成
glGenFramebuffersEXT(1, &m_iFBODepth);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_iFBODepth);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
// デプスマップテクスチャをFBOに接続
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHME...
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
}}
まず,GLSLから参照するためのテクスチャ(GL_TEXTURE_2D)を作...
フォーマットがGL_DEPTH_COMPONENTになっていること以外は通...
34行目からFBOを作成して,テクスチャと関連づけている.
引数のw,hでシャドウマップの解像度を設定する.解像度が高い...
**シャドウマップの生成 [#ef07c150]
光源を視点に設定し,シャドウマップを生成する.
まず,光源の広がり方などを設定するために以下の視錘台構造...
#code(C){{
struct rxFrustum
{
double Near;
double Far;
double FOV; // deg
double W, H;
Vec3 Origin;
Vec3 LookAt;
Vec3 Up;
};
}}
FOV(視野角),Near,Farやアスペクト比を求めるためのW,Hの他に,
視点位置,注視点,上方向ベクトルを格納する.
rxFrustumの情報を使って視点,視錘台を設定する関数は以下.
#code(C){{
/*!
* プロジェクション行列,視点位置の設定
* @param[in] f 視錘台
*/
void SetFrustum(const rxFrustum &f)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(f.FOV, (double)f.W/(double)f.H, f.Near, f...
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(f.Origin[0], f.Origin[1], f.Origin[2],
f.LookAt[0], f.LookAt[1], f.LookAt[2],
f.Up[0], f.Up[1], f.Up[2]);
}
}
}}
gluPerspectiveで視錘台を設定後,gluLookAtで視点を設定する.
なおrxFrustum構造体は光源設定に用いるだけでなく,カメラの...
光源からレンダリングして,シャドウマップを作成するコード...
#code(C){{
/*!
* シャドウマップ(デプステクスチャ)の作成
* @param[in] light 光源
* @param[in] fpDraw 描画関数ポインタ
*/
void MakeShadowMap(rxFrustum &light, void (*fpDraw)(void*...
{
glBindFramebuffer(GL_FRAMEBUFFER, m_iFBODepth); // FBOに...
glEnable(GL_TEXTURE_2D);
glUseProgram(0);
// ビューポートをシャドウマップの大きさに変更
glViewport(0, 0, m_fDepthSize[0], m_fDepthSize[1]);
glClear(GL_DEPTH_BUFFER_BIT);
// デプス値以外の色のレンダリングを無効にする
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
double light_proj[16];
double light_modelview[16];
light.W = m_fDepthSize[0];
light.H = m_fDepthSize[1];
SetFrustum(light);
// 光源視点のモデルビュー行列,プロジェクション行列を取得
glMatrixMode(GL_PROJECTION);
glGetDoublev(GL_PROJECTION_MATRIX, light_proj);
glMatrixMode(GL_MODELVIEW);
glGetDoublev(GL_MODELVIEW_MATRIX, light_modelview);
glPolygonOffset(1.1f, 4.0f);
glEnable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_LIGHTING);
if(self_shading){
glDisable(GL_CULL_FACE);
}
else{
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
}
fpDraw(func_obj);
glDisable(GL_POLYGON_OFFSET_FILL);
const double bias[16] = { 0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0 };
// テクスチャモードに移行
glMatrixMode(GL_TEXTURE);
glActiveTexture(GL_TEXTURE7);
glLoadIdentity();
glLoadMatrixd(bias);
// 光源中心座標となるようにテクスチャ行列を設定
// テクスチャ変換行列にモデルビュー,プロジェクションを...
glMultMatrixd(light_proj);
glMultMatrixd(light_modelview);
// 現在のモデルビューの逆行列をかけておく
GLfloat camera_modelview_inv[16];
CalInvMat4x4(camera_modelview, camera_modelview_inv);
glMultMatrixf(camera_modelview_inv);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// 無効にした色のレンダリングを有効にする
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
}}
手順を以下に示す.
+FBOを有効にする(8行目)
+シャドウマップの大きさでビューポートを設定(14行目)
+デプスバッファを初期化(16行目)
+レンダリングしたいのはデプス値のみなので,glColorMaskで...
+光源を視点として設定(25行目)
+光源を視点とした場合のプロジェクション,モデルビュー行列...
+z-ファイティングを防ぐためにポリゴンオフセットを設定(34-...
+ライティングをOFFにし,光源に対して裏の面に影をつけたく...
+シーン描画(45行目, 引数にvoid*を設定しているのはクラスの...
+テクスチャモードに移行,GL_TEXTURE7をアクティブにする(55...
+テクスチャ行列にバイアスをかけて,クリップ空間の範囲[-1,...
+テクスチャ行列に6で確保したプロジェクション,モデルビュ...
+頂点シェーダで座標にモデルビュー行列をかけるが,オブジェ...
+プロジェクション,モデルビュー行列をリセット(71-74行目)...
+FBOを無効にする(76行目)
+4で無効にした色のレンダリングを有効にする(79行目)
この関数を実行すると,シャドウマップがFBOに関連づけられた...
テクスチャ行列には光源を視点とする変換が格納される.
**シャドウマップを考慮してレンダリング [#i1873a0d]
作成したシャドウマップをバインドしてシーンをレンダリング...
このとき,GLSLによりレンダリングを行う.
#code(C){{
/*!
* 影付きでシーン描画
* @param[in] camera 視点
* @param[in] fpDraw 描画関数のポインタ
*/
void RenderSceneWithShadow(rxFrustum &camera, void (*fpDr...
{
// 視点設定
SetFrustum(camera);
glEnable(GL_TEXTURE_2D);
// デプステクスチャを貼り付け
glActiveTexture(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D, m_iTexDepth);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
fpDraw(func_obj);
glBindTexture(GL_TEXTURE_2D, 0);
}
}}
SetFrustumで視点を設定し,シャドウマップテクスチャを貼り...
この描画に用いるGLSLコードを以下に示す.まず,バーテック...
#code(C){{
// フラグメントシェーダに値を渡すための変数
varying vec4 vPos;
varying vec3 vNrm;
varying vec4 vShadowCoord; //!< シャドウデプスマップの参...
void main(void)
{
// フラグメントシェーダでの計算用(モデルビュー変換のみ)
vPos = gl_ModelViewMatrix*gl_Vertex; // 頂点位置
vNrm = normalize(gl_NormalMatrix*gl_Normal); // 頂点法線
vShadowCoord = gl_TextureMatrix[7]*gl_ModelViewMatrix*gl...
// 描画用
gl_Position = gl_ProjectionMatrix*vPos; // 頂点位置
gl_FrontColor = gl_Color; // 頂点色
gl_TexCoord[0] = gl_MultiTexCoord0; // 頂点テクスチャ座標
}
}}
vPosとvNrmはフォンシェーディングに用いるものでシャドウマ...
11行目で頂点位置(gl_Vertex)にGL_TEXTURE7のテクスチャ行列(...
頂点を光源座標系に変換し,vShadowCoordに格納,フラグメン...
注意として,gl_TextureMatrix[7]には視点移動などのためのモ...
ここでは単純にglTranslateやglRotateによるオブジェクトの移...
フラグメントシェーダは以下.
#code(C){{
// バーテックスシェーダから受け取る変数
varying vec4 vPos;
varying vec3 vNrm;
varying vec4 vShadowCoord;
// GLから設定される定数(uniform)
uniform sampler2D tex; //!< 模様
uniform sampler2D depth_tex; //!< デプス値テクスチャ
uniform float shadow_ambient; //!< 影の濃さ
/*!
* 影生成のための係数(影のあるところで1, それ以外で0)
* @return 影係数(影のあるところで1, それ以外で0)
*/
float ShadowCoef(void)
{
// 光源座標
vec4 shadow_coord1 = vShadowCoord/vShadowCoord.w;
// 光源からのデプス値(視点)
float view_d = shadow_coord1.z;//-0.0001;
// 格納された光源からの最小デプス値を取得
float light_d = texture2D(depth_tex, shadow_coord1.xy).z;
// 影で0,日向で1
float shadow_coef = 1.0;
if(vShadowCoord.w > 0.0){
shadow_coef = light_d < view_d ? 0.0 : 1.0;
}
return shadow_coef;
}
void main(void)
{
// 表面反射色
vec4 light_col = PhongShading();
// 影影響係数
float shadow_coef = ShadowCoef();
// 出力
gl_FragColor = shadow_ambient*shadow_coef*light_col+(1.0...
}
}}
ShadowCoef関数(15-33行目)で影の影響を計算する.
まず,wで割ることで光源座標値を計算する(18行目).
頂点シェーダでこの処理を行うと不正確な値となるので注意
(フラグメントシェーダに渡されるときに補間された値を使って...
光源座標値のzがその位置における光源からの距離となる(21行...
シャドウマップを生成するときにglCullFace(GL_FRONT)を使わ...
view_d == light_dの場所でstitchingが発生する.コメントア...
次に,シャドウマップを参照して光源からみたときの最小デプ...
この値を光源からの距離と比較することで影で0,日向で1とな...
main関数(35-45行目)では[[GLSLによるフォンシェーディング]]...
表面色を算出(38行目),ShadowCoef関数で求めた係数をかける...
**実行結果 [#e4e38151]
実行結果のスクリーンショットを以下に示す(クリックで拡大).
#ref(shadowmap_result.jpg,,50%)
左下のはシャドウマップ.
**ソースコード [#sf7424cc]
Visual Studio 2010用のソースコードを以下に置く(要GLUT,GLE...
#ref(glsl_shadowmap_v2.zip)
Ver2(2013.5.22更新)
-オブジェクト描画側でglTranslateなどを使うと影の位置がお...
-呼び出し側の処理の簡易化
終了行:
GLSLを使いシャドウマッピングで影をつける.
----
#contents
----
**シャドウマッピング(Shadow mapping)について [#c4b5a7a8]
物体の影をつける代表的なものとしてシャドウボリューム法と...
シャドウボリューム法は光源から各頂点へのベクトルを伸ばし,
交差によってできる三角形領域の演算処理で影領域を求める方...
影をつけるのには一般的にステンシルバッファが用いられる.
この方法ではモデルの頂点数が増えた場合に計算量がとても多...
また,透過テクスチャなどの影響は考慮できない.
一方,シャドウマッピング法は光源からシーンをレンダリング...
視点からレンダリングしたときにそのデプス値を比較すること...
各デプス値について下図に示す.シャドウマップ内のデプス値...
影領域ではdc > dlとなる.下図では物体自身のシェーディング...
シェーディングに影響しないようにしたい場合はdlを求める際...
#ref(shadowmap.jpg,,100%)
シャドウマップを生成する際にテクスチャを考慮すれば,透過...
ここではGLSLを使ってシャドウマッピングで影付きのレンダリ...
**FBO生成 [#i8b09ae7]
光源からのレンダリング結果を格納するためにFBOを用いる.
FBOについては[[OpenGL - FBO]]を参照.
FBO確保のコードは以下.
#code(C){{
GLuint m_iFBODepth; //!< 光源から見たときのデプスを格納...
GLuint m_iTexDepth; //!< m_iFBODepthにattachするテクスチャ
double m_fDepthSize[2]; //!< デプスを格納するテクスチャの...
/*!
* シャドウマップ用FBOの初期化
* @param[in] w,h シャドウマップの解像度
*/
void InitShadow(int w, int h)
{
m_fDepthSize[0] = w;
m_fDepthSize[1] = h;
// デプス値テクスチャ
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &m_iTexDepth);
glBindTexture(GL_TEXTURE_2D, m_iTexDepth);
// テクスチャパラメータの設定
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL...
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL...
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLA...
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLA...
GLfloat border_color[4] = {1, 1, 1, 1};
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR,...
// テクスチャ領域の確保(GL_DEPTH_COMPONENTを用いる)
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, m_fDe...
GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// FBO作成
glGenFramebuffersEXT(1, &m_iFBODepth);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_iFBODepth);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
// デプスマップテクスチャをFBOに接続
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHME...
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
}}
まず,GLSLから参照するためのテクスチャ(GL_TEXTURE_2D)を作...
フォーマットがGL_DEPTH_COMPONENTになっていること以外は通...
34行目からFBOを作成して,テクスチャと関連づけている.
引数のw,hでシャドウマップの解像度を設定する.解像度が高い...
**シャドウマップの生成 [#ef07c150]
光源を視点に設定し,シャドウマップを生成する.
まず,光源の広がり方などを設定するために以下の視錘台構造...
#code(C){{
struct rxFrustum
{
double Near;
double Far;
double FOV; // deg
double W, H;
Vec3 Origin;
Vec3 LookAt;
Vec3 Up;
};
}}
FOV(視野角),Near,Farやアスペクト比を求めるためのW,Hの他に,
視点位置,注視点,上方向ベクトルを格納する.
rxFrustumの情報を使って視点,視錘台を設定する関数は以下.
#code(C){{
/*!
* プロジェクション行列,視点位置の設定
* @param[in] f 視錘台
*/
void SetFrustum(const rxFrustum &f)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(f.FOV, (double)f.W/(double)f.H, f.Near, f...
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(f.Origin[0], f.Origin[1], f.Origin[2],
f.LookAt[0], f.LookAt[1], f.LookAt[2],
f.Up[0], f.Up[1], f.Up[2]);
}
}
}}
gluPerspectiveで視錘台を設定後,gluLookAtで視点を設定する.
なおrxFrustum構造体は光源設定に用いるだけでなく,カメラの...
光源からレンダリングして,シャドウマップを作成するコード...
#code(C){{
/*!
* シャドウマップ(デプステクスチャ)の作成
* @param[in] light 光源
* @param[in] fpDraw 描画関数ポインタ
*/
void MakeShadowMap(rxFrustum &light, void (*fpDraw)(void*...
{
glBindFramebuffer(GL_FRAMEBUFFER, m_iFBODepth); // FBOに...
glEnable(GL_TEXTURE_2D);
glUseProgram(0);
// ビューポートをシャドウマップの大きさに変更
glViewport(0, 0, m_fDepthSize[0], m_fDepthSize[1]);
glClear(GL_DEPTH_BUFFER_BIT);
// デプス値以外の色のレンダリングを無効にする
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
double light_proj[16];
double light_modelview[16];
light.W = m_fDepthSize[0];
light.H = m_fDepthSize[1];
SetFrustum(light);
// 光源視点のモデルビュー行列,プロジェクション行列を取得
glMatrixMode(GL_PROJECTION);
glGetDoublev(GL_PROJECTION_MATRIX, light_proj);
glMatrixMode(GL_MODELVIEW);
glGetDoublev(GL_MODELVIEW_MATRIX, light_modelview);
glPolygonOffset(1.1f, 4.0f);
glEnable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_LIGHTING);
if(self_shading){
glDisable(GL_CULL_FACE);
}
else{
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
}
fpDraw(func_obj);
glDisable(GL_POLYGON_OFFSET_FILL);
const double bias[16] = { 0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0 };
// テクスチャモードに移行
glMatrixMode(GL_TEXTURE);
glActiveTexture(GL_TEXTURE7);
glLoadIdentity();
glLoadMatrixd(bias);
// 光源中心座標となるようにテクスチャ行列を設定
// テクスチャ変換行列にモデルビュー,プロジェクションを...
glMultMatrixd(light_proj);
glMultMatrixd(light_modelview);
// 現在のモデルビューの逆行列をかけておく
GLfloat camera_modelview_inv[16];
CalInvMat4x4(camera_modelview, camera_modelview_inv);
glMultMatrixf(camera_modelview_inv);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// 無効にした色のレンダリングを有効にする
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
}}
手順を以下に示す.
+FBOを有効にする(8行目)
+シャドウマップの大きさでビューポートを設定(14行目)
+デプスバッファを初期化(16行目)
+レンダリングしたいのはデプス値のみなので,glColorMaskで...
+光源を視点として設定(25行目)
+光源を視点とした場合のプロジェクション,モデルビュー行列...
+z-ファイティングを防ぐためにポリゴンオフセットを設定(34-...
+ライティングをOFFにし,光源に対して裏の面に影をつけたく...
+シーン描画(45行目, 引数にvoid*を設定しているのはクラスの...
+テクスチャモードに移行,GL_TEXTURE7をアクティブにする(55...
+テクスチャ行列にバイアスをかけて,クリップ空間の範囲[-1,...
+テクスチャ行列に6で確保したプロジェクション,モデルビュ...
+頂点シェーダで座標にモデルビュー行列をかけるが,オブジェ...
+プロジェクション,モデルビュー行列をリセット(71-74行目)...
+FBOを無効にする(76行目)
+4で無効にした色のレンダリングを有効にする(79行目)
この関数を実行すると,シャドウマップがFBOに関連づけられた...
テクスチャ行列には光源を視点とする変換が格納される.
**シャドウマップを考慮してレンダリング [#i1873a0d]
作成したシャドウマップをバインドしてシーンをレンダリング...
このとき,GLSLによりレンダリングを行う.
#code(C){{
/*!
* 影付きでシーン描画
* @param[in] camera 視点
* @param[in] fpDraw 描画関数のポインタ
*/
void RenderSceneWithShadow(rxFrustum &camera, void (*fpDr...
{
// 視点設定
SetFrustum(camera);
glEnable(GL_TEXTURE_2D);
// デプステクスチャを貼り付け
glActiveTexture(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D, m_iTexDepth);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
fpDraw(func_obj);
glBindTexture(GL_TEXTURE_2D, 0);
}
}}
SetFrustumで視点を設定し,シャドウマップテクスチャを貼り...
この描画に用いるGLSLコードを以下に示す.まず,バーテック...
#code(C){{
// フラグメントシェーダに値を渡すための変数
varying vec4 vPos;
varying vec3 vNrm;
varying vec4 vShadowCoord; //!< シャドウデプスマップの参...
void main(void)
{
// フラグメントシェーダでの計算用(モデルビュー変換のみ)
vPos = gl_ModelViewMatrix*gl_Vertex; // 頂点位置
vNrm = normalize(gl_NormalMatrix*gl_Normal); // 頂点法線
vShadowCoord = gl_TextureMatrix[7]*gl_ModelViewMatrix*gl...
// 描画用
gl_Position = gl_ProjectionMatrix*vPos; // 頂点位置
gl_FrontColor = gl_Color; // 頂点色
gl_TexCoord[0] = gl_MultiTexCoord0; // 頂点テクスチャ座標
}
}}
vPosとvNrmはフォンシェーディングに用いるものでシャドウマ...
11行目で頂点位置(gl_Vertex)にGL_TEXTURE7のテクスチャ行列(...
頂点を光源座標系に変換し,vShadowCoordに格納,フラグメン...
注意として,gl_TextureMatrix[7]には視点移動などのためのモ...
ここでは単純にglTranslateやglRotateによるオブジェクトの移...
フラグメントシェーダは以下.
#code(C){{
// バーテックスシェーダから受け取る変数
varying vec4 vPos;
varying vec3 vNrm;
varying vec4 vShadowCoord;
// GLから設定される定数(uniform)
uniform sampler2D tex; //!< 模様
uniform sampler2D depth_tex; //!< デプス値テクスチャ
uniform float shadow_ambient; //!< 影の濃さ
/*!
* 影生成のための係数(影のあるところで1, それ以外で0)
* @return 影係数(影のあるところで1, それ以外で0)
*/
float ShadowCoef(void)
{
// 光源座標
vec4 shadow_coord1 = vShadowCoord/vShadowCoord.w;
// 光源からのデプス値(視点)
float view_d = shadow_coord1.z;//-0.0001;
// 格納された光源からの最小デプス値を取得
float light_d = texture2D(depth_tex, shadow_coord1.xy).z;
// 影で0,日向で1
float shadow_coef = 1.0;
if(vShadowCoord.w > 0.0){
shadow_coef = light_d < view_d ? 0.0 : 1.0;
}
return shadow_coef;
}
void main(void)
{
// 表面反射色
vec4 light_col = PhongShading();
// 影影響係数
float shadow_coef = ShadowCoef();
// 出力
gl_FragColor = shadow_ambient*shadow_coef*light_col+(1.0...
}
}}
ShadowCoef関数(15-33行目)で影の影響を計算する.
まず,wで割ることで光源座標値を計算する(18行目).
頂点シェーダでこの処理を行うと不正確な値となるので注意
(フラグメントシェーダに渡されるときに補間された値を使って...
光源座標値のzがその位置における光源からの距離となる(21行...
シャドウマップを生成するときにglCullFace(GL_FRONT)を使わ...
view_d == light_dの場所でstitchingが発生する.コメントア...
次に,シャドウマップを参照して光源からみたときの最小デプ...
この値を光源からの距離と比較することで影で0,日向で1とな...
main関数(35-45行目)では[[GLSLによるフォンシェーディング]]...
表面色を算出(38行目),ShadowCoef関数で求めた係数をかける...
**実行結果 [#e4e38151]
実行結果のスクリーンショットを以下に示す(クリックで拡大).
#ref(shadowmap_result.jpg,,50%)
左下のはシャドウマップ.
**ソースコード [#sf7424cc]
Visual Studio 2010用のソースコードを以下に置く(要GLUT,GLE...
#ref(glsl_shadowmap_v2.zip)
Ver2(2013.5.22更新)
-オブジェクト描画側でglTranslateなどを使うと影の位置がお...
-呼び出し側の処理の簡易化
ページ名: