TOP

ABOUT

PROGRAM

DIALY







ステンシルシャドウ

 1.はじめに
 影関係は手をつけていなかったので,ステンシルバッファを用いた影の作成をしてみました。



 2.ステンシルシャドウ
 今回はステンシルバッファを用いた,影の作成を行ないます。
まずは,graphics.PreferredDepthStencilFormatにステンシルのフォーマットを格納することを行ないます。

00052:          public Game1()
00053:          {
00054:              graphics = new GraphicsDeviceManager(this);
00055:              Content.RootDirectory = "Content";
00056:              graphics.PreferredDepthStencilFormat = SelectStencilMode();
00057:          }

SelectStencilMode()というメソッドですが,これは独自に作ったメソッドで,よさそうなステンシルのフォーマットから順に使えるかどうか調べて,使える場合そのフォーマットを返して,使えない場合はつぎによさげなフォーマットチェックして・・・ということを行なっています。

00059:          /// <summary>
00060:          ///  Name : SelectStencilMode()
00061:          ///  Desc : ステンシルフォーマットをチェック
00062:          /// </summary>
00063:          /// <returns>ステンシルのフォーマット</returns>
00064:          private static DepthFormat SelectStencilMode()
00065:          {
00066:              GraphicsAdapter adapter = GraphicsAdapter.DefaultAdapter;
00067:              SurfaceFormat format = adapter.CurrentDisplayMode.Format;
00068:              
00069:              if (adapter.CheckDepthStencilMatch(DeviceType.Hardware, format, format, DepthFormat.Depth24Stencil8))
00070:                  return DepthFormat.Depth24Stencil8;
00071:              
00072:              else if (adapter.CheckDepthStencilMatch(DeviceType.Hardware, format, format, DepthFormat.Depth24Stencil8Single))
00073:                  return DepthFormat.Depth24Stencil8Single;
00074:              
00075:              else if (adapter.CheckDepthStencilMatch(DeviceType.Hardware, format, format, DepthFormat.Depth24Stencil4))
00076:                  return DepthFormat.Depth24Stencil4;
00077:              
00078:              else if (adapter.CheckDepthStencilMatch(DeviceType.Hardware, format, format, DepthFormat.Depth15Stencil1))
00079:                  return DepthFormat.Depth15Stencil1;
00080:              
00081:              else
00082:                  throw new InvalidOperationException("デフォルトアダプターに対するステンシルバッファが見つかりませんでした");
00083:          }
00084:  

フォーマットのチェックが終わったら,LoadContent()メソッド内で平面投影するための投影行列を作成します。すでにInitialize()メソッド内でPlane構造体であるwallPlaneの設定をしてあります。
投影行列の作成にはMatrix.CreateShadow()メソッドを使います。


このMatrix.CreateShadow()メソッドは上のような光源と平面から下のような行列を計算します。



基本的には影の行列はこれでいいのですが,実際にこの行列を使うと下の画像のようにポリゴンが重なりあって汚くなってしまうので,平面の法線ベクトル方向にちょっとだけずらして重なるのを避けるようにします。



コードにすると下のような感じです。
00141:              // ライトの方向ベクトル
00142:              shadowLightDir = quadEffect.DirectionalLight0.Direction;
00143:  
00144:              // 投影行列を作成
00145:              Shadow = Matrix.CreateShadow(shadowLightDir, wallPlane) 
00146:                          * Matrix.CreateTranslation(wall.Normal / 100.0f); // 法線方向にちょっとずらす


描画処理ですが,まずはいつもどおりに描画します。

00196:          /// <summary>
00197:          /// This is called when the game should draw itself.
00198:          /// </summary>
00199:          /// <param name="gameTime">Provides a snapshot of timing values.</param>
00200:          protected override void Draw(GameTime gameTime)
00201:          {
00202:              graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
00203:  
00204:              // TODO: Add your drawing code here
00205:  
00206:              /////////////////////////////////////
00207:              // 通常描画
00208:              /////////////////////////////////////
00209:  
00210:              // 地面を描画
00211:              DrawQuad();
00212:  
00213:              // モデルを描画
00214:              foreach (ModelMesh mesh in model.Meshes)
00215:              {
00216:                  foreach (BasicEffect effect in mesh.Effects)
00217:                  {
00218:                      effect.EnableDefaultLighting();
00219:                      effect.View = View;
00220:                      effect.Projection = Projection;
00221:                      effect.World = World;
00222:                  }
00223:                  mesh.Draw();
00224:              }

次にステンシルバッファを用いて影の描画を行っていきます。
まず,ステンシルバッファをクリアして,ステンシルを有効にします。続いて,ステンシルバッファの参照値や比較関数の設定を行います。

00226:              /////////////////////////////////////
00227:              // 影の描画
00228:              /////////////////////////////////////
00229:  
00230:              // ステンシルバッファを0にする
00231:              GraphicsDevice.Clear(ClearOptions.Stencil, Color.Black, 0, 0);
00232:              GraphicsDevice.RenderState.StencilEnable = true;
00233:  
00234:              // ステンシルバッファの値が0なら描画
00235:              GraphicsDevice.RenderState.ReferenceStencil = 0;
00236:              GraphicsDevice.RenderState.StencilFunction = CompareFunction.Equal;
00237:  
00238:              // 描画可能ならステンシルバッファをインクリメント
00239:              GraphicsDevice.RenderState.StencilPass = StencilOperation.Increment;
00240:              

あとは,半透明の影を作るために,アルファブレンディングの設定をします。
ブレンディングの設定が終わったら,影となるモデルの描画を行います。描画する際はライティングを無効にしておくのを忘れずに。

00241:              // 半透明の影を作るためにアルファブレンディングを設定
00242:              GraphicsDevice.RenderState.AlphaBlendEnable = true;
00243:              GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
00244:              GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
00245:  
00246:              // モデルを描画(ライティングなしで)
00247:              foreach (ModelMesh mesh in model.Meshes)
00248:              {
00249:                  foreach (BasicEffect effect in mesh.Effects)
00250:                  {
00251:                      effect.AmbientLightColor = Color.Black.ToVector3();
00252:                      effect.Alpha = 0.65f;
00253:                      effect.DirectionalLight0.Enabled = false;
00254:                      effect.DirectionalLight1.Enabled = false;
00255:                      effect.DirectionalLight2.Enabled = false;
00256:                      effect.View = View;
00257:                      effect.Projection = Projection;
00258:                      effect.World = World * Shadow;
00259:                  }
00260:                  mesh.Draw();
00261:              }
とりあえず,ステンシルバッファを使って影を作ってみました。


 Download
本ソースコードおよびプログラムを使用したことによる如何なる損害も製作者は責任を負いません。
本ソースコードおよびプログラムは自己責任でご使用ください。
プログラムの作成にはMicrosoft Visual Studio 2005 SP1 Professional, XNA Game Studio 2.0を用いています。