programming
Hatena::Diary My Categories
こっちにも色々書いていることがありますんであわせてどうぞ.
An Effect File Filled With Default Values
DirectX 9.0 SDK Update (Summer 2004)でのDirectX Graphicsのデフォルトステートを全て記述したエフェクトファイルです.
ただし2つ目以降のLight設定・Shader定数・2つ目以降のWorld行列(頂点ブレンディング用のもの)に関しては数が不定なため設定していません.ご注意を.
sampler defaultSampler = sampler_state { AddressU = Wrap; AddressV = Wrap; AddressW = Wrap; BorderColor = 0; MagFilter = Point; MaxAnisotropy = 1; MaxMipLevel = 0; MinFilter = Point; MipFilter = None; MipMapLodBias = 0.0f; SRGBTexture = false; //<ヘルプ未記載> ElementIndex = 0; // DmapOffset のデフォルト値には混乱があって,D3DSAMPLERSTATETYPE Enumerated Type では 0 となっている. // いくつかのドライバも 0 を返すようだが,Debug Runtime の自己診断は 256 が正しいとしている. DMapOffset = 256; //</ヘルプ未記載> }; stateblock defaultState = stateblock_state { //<ヘルプ未記載> PatchEdgeStyle = Discrete; // DebugMonitorToken = 0; // 一度しかセットできない PositionDegree = Cubic; NormalDegree = Linear; ScissorTestEnable = false; AntialiasedLineEnable = false; MinTessellationLevel = 1.0f; MaxTessellationLevel = 1.0f; AdaptiveTess_X = 0.0f; AdaptiveTess_Y = 0.0f; AdaptiveTess_Z = 1.0f; AdaptiveTess_W = 0.0f; EnableadAptiveTessellation = false; TwoSidedStencilMode = false; CCW_StencilFail = Keep; CCW_StencilZFail = Keep; CCW_StencilPass = Keep; CCW_StencilFunc = Always; ColorWriteEnable1 = 0x0000000f; ColorWriteEnable2 = 0x0000000f; ColorWriteEnable3 = 0x0000000f; BlendFactor = 0xffffffff; SRGBWriteEnable = false; SeparateAlphaBlendEnable = false; SrcBlendAlpha = One; DestBlendAlpha = Zero; BlendOpAlpha = Add; BlendOpAlpha = Add; //</ヘルプ未記載> // -------------------------------------------------------------------------------- // ライティングステート // -------------------------------------------------------------------------------- LightAmbient[0] = float4(0.0f, 0.0f, 0.0f, 0.0f); LightAttenuation0[0] = 0.0f; LightAttenuation1[0] = 0.0f; LightAttenuation2[0] = 0.0f; LightDiffuse[0] = float4(1.0f, 1.0f, 1.0f, 0.0f); LightDirection[0] = float3(0.0f, 0.0f, 1.0f); LightEnable[0] = false; LightFalloff[0] = 0.0f; LightPhi[0] = 0.0f; LightPosition[0] = float3(0.0f, 0.0f, 1.0f); LightRange[0] = 0.0f; LightSpecular[0] = float4(1.0f, 1.0f, 1.0f, 0.0f); LightTheta[0] = 0.0f; LightType[0] = Directional; // -------------------------------------------------------------------------------- // マテリアルステート // -------------------------------------------------------------------------------- MaterialAmbient = float4(0.0f, 0.0f, 0.0f, 0.0f); MaterialDiffuse = float4(0.0f, 0.0f, 0.0f, 0.0f); MaterialEmissive = float4(0.0f, 0.0f, 0.0f, 0.0f); MaterialPower = 0.0f; MaterialSpecular = float4(0.0f, 0.0f, 0.0f, 0.0f); // -------------------------------------------------------------------------------- // ピクセル パイプライン レンダリング ステート // -------------------------------------------------------------------------------- AlphaBlendEnable = false; AlphaFunc = Always; AlphaRef = 0; AlphaTestEnable = false; BlendOp = Add; ColorWriteEnable = 0x0000000f; DepthBias = 0; DestBlend = InvSrcAlpha; DitherEnable = false; FillMode = Solid; LastPixel = true; ShadeMode = Gouraud; SlopeScaleDepthBias = 0.0f; SrcBlend = One; StencilEnable = false; StencilFail = Keep; StencilFunc = Always; StencilMask = 0xffffffff; StencilPass = Keep; StencilRef = 0; StencilWriteMask = 0xffffffff; StencilZFail = Keep; TextureFactor = 0xffffffff; Wrap0 = 0; Wrap1 = 0; Wrap2 = 0; Wrap3 = 0; Wrap4 = 0; Wrap5 = 0; Wrap6 = 0; Wrap7 = 0; Wrap8 = 0; Wrap9 = 0; Wrap10 = 0; Wrap11 = 0; Wrap12 = 0; Wrap13 = 0; Wrap14 = 0; Wrap15 = 0; // ZEnable = true; // 深度ステンシルバッファが作られなかったときにはfalse ZFunc = LessEqual; ZWriteEnable = true; // -------------------------------------------------------------------------------- // 頂点パイプライン レンダリング ステート // -------------------------------------------------------------------------------- Ambient = 0; AmbientMaterialSource = Material; Clipping = true; ClipPlaneEnable = 0; ColorVertex = True; CullMode = CCW; DiffuseMaterialSource = Color1; EmissiveMaterialSource = Material; FogColor = 0; FogDensity = 1.0f; FogEnable = false; FogEnd = 1.0f; FogStart = 0.0f; FogTableMode = None; FogVertexMode = None; IndexedVertexBlendEnable = false; Lighting = true; LocalViewer = true; MultiSampleAntialias = true; MultiSampleMask = 0xffffffff; NormalizeNormals = false; PatchSegments = 0.0f; PointScale_A = 1.0f; PointScale_B = 0.0f; PointScale_C = 0.0f; PointScaleEnable = false; // PointSize = 1.0f; // Driver dependent PointSize_Min = 1.0f; PointSize_Max = 64.0f; PointSpriteEnable = false; RangeFogEnable = false; SpecularEnable = false; SpecularMaterialSource = Color2; TweenFactor = 0.0f; VertexBlend = Disable; // -------------------------------------------------------------------------------- // サンプラ ステージ ステート // -------------------------------------------------------------------------------- Sampler[0] = (defaultSampler); Sampler[1] = (defaultSampler); Sampler[2] = (defaultSampler); Sampler[3] = (defaultSampler); Sampler[4] = (defaultSampler); Sampler[5] = (defaultSampler); Sampler[6] = (defaultSampler); Sampler[7] = (defaultSampler); Sampler[8] = (defaultSampler); Sampler[9] = (defaultSampler); Sampler[10] = (defaultSampler); Sampler[11] = (defaultSampler); Sampler[12] = (defaultSampler); Sampler[13] = (defaultSampler); Sampler[14] = (defaultSampler); Sampler[15] = (defaultSampler); // -------------------------------------------------------------------------------- // テクスチャ ステート // -------------------------------------------------------------------------------- Texture[0] = null; Texture[1] = null; Texture[2] = null; Texture[3] = null; Texture[4] = null; Texture[5] = null; Texture[6] = null; Texture[7] = null; // -------------------------------------------------------------------------------- // ピクセル シェーダ ステート // -------------------------------------------------------------------------------- PixelShader = null; // -------------------------------------------------------------------------------- // 頂点シェーダ ステート // -------------------------------------------------------------------------------- VertexShader = null; // -------------------------------------------------------------------------------- // テクスチャ ステージ ステート // -------------------------------------------------------------------------------- AlphaOp[0] = SelectArg1; AlphaArg0[0] = Current; AlphaArg1[0] = Texture; AlphaArg2[0] = Current; ColorArg0[0] = Current; ColorArg1[0] = Texture; ColorArg2[0] = Current; ColorOp[0] = Modulate; BumpEnvLScale[0] = 0.0f; BumpEnvLOffset[0] = 0.0f; BumpEnvMat00[0] = 0.0f; BumpEnvMat01[0] = 0.0f; BumpEnvMat10[0] = 0.0f; BumpEnvMat11[0] = 0.0f; ResultArg[0] = Current; TexCoordIndex[0] = PassThru | 0; TextureTransformFlags[0] = Disable; AlphaOp[1] = Disable; AlphaArg0[1] = Current; AlphaArg1[1] = Texture; AlphaArg2[1] = Current; ColorArg0[1] = Current; ColorArg1[1] = Texture; ColorArg2[1] = Current; ColorOp[1] = Disable; BumpEnvLScale[1] = 0.0f; BumpEnvLOffset[1] = 0.0f; BumpEnvMat00[1] = 0.0f; BumpEnvMat01[1] = 0.0f; BumpEnvMat10[1] = 0.0f; BumpEnvMat11[1] = 0.0f; ResultArg[1] = Current; TexCoordIndex[1] = PassThru | 1; TextureTransformFlags[1] = Disable; AlphaOp[2] = Disable; AlphaArg0[2] = Current; AlphaArg1[2] = Texture; AlphaArg2[2] = Current; ColorArg0[2] = Current; ColorArg1[2] = Texture; ColorArg2[2] = Current; ColorOp[2] = Disable; BumpEnvLScale[2] = 0.0f; BumpEnvLOffset[2] = 0.0f; BumpEnvMat00[2] = 0.0f; BumpEnvMat01[2] = 0.0f; BumpEnvMat10[2] = 0.0f; BumpEnvMat11[2] = 0.0f; ResultArg[2] = Current; TexCoordIndex[2] = PassThru | 2; TextureTransformFlags[2] = Disable; AlphaOp[3] = Disable; AlphaArg0[3] = Current; AlphaArg1[3] = Texture; AlphaArg2[3] = Current; ColorArg0[3] = Current; ColorArg1[3] = Texture; ColorArg2[3] = Current; ColorOp[3] = Disable; BumpEnvLScale[3] = 0.0f; BumpEnvLOffset[3] = 0.0f; BumpEnvMat00[3] = 0.0f; BumpEnvMat01[3] = 0.0f; BumpEnvMat10[3] = 0.0f; BumpEnvMat11[3] = 0.0f; ResultArg[3] = Current; TexCoordIndex[3] = PassThru | 3; TextureTransformFlags[3] = Disable; AlphaOp[4] = Disable; AlphaArg0[4] = Current; AlphaArg1[4] = Texture; AlphaArg2[4] = Current; ColorArg0[4] = Current; ColorArg1[4] = Texture; ColorArg2[4] = Current; ColorOp[4] = Disable; BumpEnvLScale[4] = 0.0f; BumpEnvLOffset[4] = 0.0f; BumpEnvMat00[4] = 0.0f; BumpEnvMat01[4] = 0.0f; BumpEnvMat10[4] = 0.0f; BumpEnvMat11[4] = 0.0f; ResultArg[4] = Current; TexCoordIndex[4] = PassThru | 4; TextureTransformFlags[4] = Disable; AlphaOp[5] = Disable; AlphaArg0[5] = Current; AlphaArg1[5] = Texture; AlphaArg2[5] = Current; ColorArg0[5] = Current; ColorArg1[5] = Texture; ColorArg2[5] = Current; ColorOp[5] = Disable; BumpEnvLScale[5] = 0.0f; BumpEnvLOffset[5] = 0.0f; BumpEnvMat00[5] = 0.0f; BumpEnvMat01[5] = 0.0f; BumpEnvMat10[5] = 0.0f; BumpEnvMat11[5] = 0.0f; ResultArg[5] = Current; TexCoordIndex[5] = PassThru | 5; TextureTransformFlags[5] = Disable; AlphaOp[6] = Disable; AlphaArg0[6] = Current; AlphaArg1[6] = Texture; AlphaArg2[6] = Current; ColorArg0[6] = Current; ColorArg1[6] = Texture; ColorArg2[6] = Current; ColorOp[6] = Disable; BumpEnvLScale[6] = 0.0f; BumpEnvLOffset[6] = 0.0f; BumpEnvMat00[6] = 0.0f; BumpEnvMat01[6] = 0.0f; BumpEnvMat10[6] = 0.0f; BumpEnvMat11[6] = 0.0f; ResultArg[6] = Current; TexCoordIndex[6] = PassThru | 6; TextureTransformFlags[6] = Disable; AlphaOp[7] = Disable; AlphaArg0[7] = Current; AlphaArg1[7] = Texture; AlphaArg2[7] = Current; ColorArg0[7] = Current; ColorArg1[7] = Texture; ColorArg2[7] = Current; ColorOp[7] = Disable; BumpEnvLScale[7] = 0.0f; BumpEnvLOffset[7] = 0.0f; BumpEnvMat00[7] = 0.0f; BumpEnvMat01[7] = 0.0f; BumpEnvMat10[7] = 0.0f; BumpEnvMat11[7] = 0.0f; ResultArg[7] = Current; TexCoordIndex[7] = PassThru | 7; TextureTransformFlags[7] = Disable; // -------------------------------------------------------------------------------- // トランスフォーム ステート // -------------------------------------------------------------------------------- // float の 4 × 4 行列。D3DTS_ プレフィックスが付かない、D3DTS_PROJECTION と同じ値。 ProjectionTransform = float4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); // float の 4 × 4 行列。D3DTS_ プレフィックスが付かない、D3DTRANSFORMSTATETYPE と同じ値。 TextureTransform[0] = float4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); TextureTransform[1] = float4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); TextureTransform[2] = float4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); TextureTransform[3] = float4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); TextureTransform[4] = float4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); TextureTransform[5] = float4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); TextureTransform[6] = float4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); TextureTransform[7] = float4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); // float の 4 × 4 行列。D3DTS_ プレフィックスが付かない、D3DTS_VIEW と同じ値。 ViewTransform = float4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); // float の 4 × 4 行列。 WorldTransform[0] = float4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); };
実際に利用する際は以下のようにincludeするとよいでしょう.後から設定したステートにより上書きされるので,必要な箇所のみ記述することになります.
#include <default.fx> // 適当な描画設定の例 technique T0 { pass P0 { StateBlock = (defaultState); CullMode = None; Lighting = false; ZEnable = false; ColorOp[0] = SelectArg2; AlphaOp[0] = SelectArg2; } }
FPS Control
隙間ドキュメントプロジェクトその1.
(ゲームプログラミング業界の)本やWeb資料に記述が足りていないなぁと思っていることをメモ代わりに書いてみるプロジェクト.
シューティングゲームのプログラミング等でしばしば問題になるインターバルタイミング制御に関して.
ネットワークの品質がバンド幅とレイテンシに代表されるように,FPS制御という仕組みも"平均速度の固定"と"インターバルの分散の縮小"を,必要に応じて分けて考える必要があるのではないかと思います.BBXではさんざん書いていますが,まず一口に時間精度といっても瞬間的な時間ゆらぎと長期的な時間ゆらぎでは意味も意図も異なるという問題があります.
つまり,フレーム間のインターバルがどの程度ゆらぐか?(短期誤差)と,ステージ全体を何秒で再生したか?(長期誤差)は問題の性質が全然違います.
もはや過去のものとなりつつあるカセットテープで言えば,ワウ・フラッターとテープ速度の関係ですね.
例えば1msecの精度の時刻関数を使って以下のようなSpin-wait-loopを書くと,「正確な」60FPSが実現できないことが気になるという人がいます.
// spin wait loop while( (GetCurrentTime() - lastTime) < 17 ) { //wait }
これがもし長期誤差を気にしていて,6000フレームのステージを正確に100秒で再生したいというのであれば,時刻関数の1msecという精度は十分です.
この場合はスピンループのロジックを適当に変更すれば対応可能でしょう.
しかし例えば何かのゲームの移植などで,レバー入力のタイミングを正確に1/60秒単位で制御したいという場合では,本質的に時刻関数の精度による制限を受けます.
16msec〜17msecというのはだいたい6%前後の揺らぎですが,これがゲームに影響を及ぼすかどうかの判断はもちろん開発者が下す必要があります.
そしてもしもっと揺らぎを減らしたければ,より高精度の時刻を取得するための方法がどうしても必要になります.
1msecの精度で十分かという議論を見ていると,背後にこれらの目的の違いがあることが多いように見えます.
ちなみに入力系を最優先してインターバル制御を考える場合,タイミング待ちは描画の部分ではなく入力データ取得直前にやるのが正しいのかもしれません.
この辺の議論も不足している気がします.
では具体的にWindowsで使える時刻取得関数(いかこれを指してタイマーと呼ぶ)にはどのようなものがあるのでしょうか?
以前BBXで回答する際にGameDev.netのこのスレッドを見つけて読んでみたのですが,QueryPerformanceCounterに関してはいくつか興味深い記述がありました.
上記投稿にMSDNの記述もふまえ,代表的な3つの関数についてまとめてみたものが以下です.
- GetTickCount
- タイマー割り込みのたびにGetSystemTimeAdjustmentだけ増加.
49.71日問題有り. - timeGetTime
- 最高1ms精度.
timeBeginPeriodもチェックのこと.
49.71日問題有り. - QueryPerformanceCounter
- 精度はHALに依存.(必ずしもCPUクロックカウンタを使わないことに注意)
・Programmable Interval Timer 使用時: 〜1µsec
・ACPI Power-management Timer 使用時: 〜0.3µsec
・HPET 使用時:100 ns以下
・RDTSC 使用時:100 ns以下
関数自体はSMPやSpeedStep環境下でも正しく動くことが保証される.(今後マルチコアCPUで動的にCPU数が変化するようになってもサポートが期待できる)
ただしイレギュラーな方法でクロックを変えるとTSC使用時に問題が発生することがある.(Crystal Dew Worldより『クロック周波数の測定手法』)
またPort I/Oを使用する場合はウェイトが大きい.
Q274323に関する問題もある.
また,最終的な目的が待機である場合,ポーリングではなく待機命令(Sleep,SetWaitableTimer)を直接利用するという選択肢もあります.
An Improvement of the Effects Framework in the DirectX 9.0 SDK Update (Summer 2003).
DirectX 9.0 SDK Update (Summer 2003) の変更点のうち,嬉しいこと属性のものから1つご紹介.
今回の変更でエフェクトファイルの文法が拡張されて,複数のテクニックで共通するステート設定をまとめて記述できるようになってます.
下は旧来のエフェクトファイルの例です.
technique T0 { pass P0 { VertexShader = null; // ライティング ステート LightEnable[0] = true; LightType[0] = Directional; LightAmbient[0] = { 0.0f, 0.0f, 0.0f, 0.0f }; LightDiffuse[0] = { 1.0f, 1.0f, 1.0f, 1.0f }; LightDirection[0] = { 1.0f, 1.0f, 1.0f, 1.0f}; // 頂点パイプライン レンダリング ステート Ambient = 0xffffffff; CullMode = CCW; DiffuseMaterialSource = Material; Lighting = true; NormalizeNormals = true; // ピクセル パイプライン レンダリング ステート AlphaBlendEnable = false; AlphaFunc = GreaterEqual; BlendOp = Add; DestBlend = InvSrcAlpha; SrcBlend = SrcAlpha; ZEnable = true; ZFunc = LessEqual; } } technique T1 { pass P0 { VertexShader = null; // ライティング ステート LightEnable[0] = true; LightType[0] = Directional; LightAmbient[0] = { 0.0f, 0.0f, 0.0f, 0.0f }; LightDiffuse[0] = { 1.0f, 1.0f, 1.0f, 1.0f }; LightDirection[0] = { 1.0f, 1.0f, 1.0f, 1.0f}; // 頂点パイプライン レンダリング ステート Ambient = 0xffffffff; CullMode = None; DiffuseMaterialSource = Material; Lighting = true; NormalizeNormals = true; // ピクセル パイプライン レンダリング ステート AlphaBlendEnable = true; AlphaFunc = GreaterEqual; BlendOp = Add; DestBlend = One; SrcBlend = SrcAlpha; ZEnable = false; ZFunc = LessEqual; } }
ご覧のように,各テクニックごとに共通するステート設定をまとめられないので,テクニック間でどのようにステートが異なるか分かりにくいです.
よく考えればプリプロセッサでも作ってメモリ上で展開すればいいわけで,実はそれ程困ったことでもなかったかという気もしますが,とにかく新しいライブラリではこれを以下のように記述することが可能になりました.
// 共通部分をステートブロックとしてまとめる stateblock defaultState = stateblock_state { VertexShader = null; // ライティング ステート LightEnable[0] = true; LightType[0] = Directional; LightAmbient[0] = { 0.0f, 0.0f, 0.0f, 0.0f }; LightDiffuse[0] = { 1.0f, 1.0f, 1.0f, 1.0f }; LightDirection[0] = { 1.0f, 1.0f, 1.0f, 1.0f}; // 頂点パイプライン レンダリング ステート Ambient = 0xffffffff; CullMode = CCW; DiffuseMaterialSource = Material; Lighting = true; NormalizeNormals = true; // ピクセル パイプライン レンダリング ステート AlphaBlendEnable = false; AlphaFunc = GreaterEqual; BlendOp = Add; DestBlend = InvSrcAlpha; SrcBlend = SrcAlpha; ZEnable = true; ZFunc = LessEqual; }; technique T0 { pass P0 { StateBlock = (defaultState); } } technique T1 { pass P0 { StateBlock = (defaultState); // 後から設定したものが有効なので,ここでオーバーライド AlphaBlendEnable = true; CullMode = None; DestBlend = One; ZEnable = false; } }
テクニックの数が増えてきたときに威力を発揮しそうです.
プログラムとデータを同じファイルに記述するか分離するかという問題としてエフェクトファイルを考えるとなかなか興味深いわけですが,それについてはまた今度.
DrawIndexedPrimitive(s) Parameters
引数視覚化.DirectX9仕様.
仕事で作ったプレゼン資料は公開できないので適当に作り直したもの.
いつか配色やり直そう.
D3DXMatrixRotate*
ときどき行列を書き下して検討する必要があるので作ってみたMathematicaによるリファレンス実装.
ベクトルは行ベクトルで,行列は左作用.左手系.
恐らく大多数の人間にとって使い道のない代物.