Microsoft Corporation
May 28, 2002
日本語版最終更新日 2002 年 6 月 10 日
Driving DirectX へようこそ。前回のコラムでは、MSDN ShaderWorkshop ソース ダウンロードに付属している頂点シェーダの練習問題について解説しました。これらの練習問題は、頂点パイプラインにおける各種の一般的なタスクを紹介しながら、エフェクト ファイルと頂点シェーダの柔軟性と利点を明らかにするという 2 つの目的を持っていました。エフェクト ファイルは D3DX のきわめて便利なコンポーネントですが、頂点シェーダのレッスンは、エフェクト ファイルとは直接関係のない、あらゆる Direct3D8 プログラマに役立つ機能を紹介していたと言えるでしょう。今月のコラムでは、MSDN ShaderWorkshop シリーズの最終回として、ピクセル シェーダの便利なタスクを扱う最後の 5 つの練習問題を紹介することにします。
ピクセル シェーダの練習問題
このセクションでは、Meltdown Shader Workshop イベントの、いずれもピクセル シェーダに関連する最後の 5 つの練習問題の背後にある概念を説明します。ただしその前に、練習問題は、仮の命令の後に、'?' の文字を含んだ命令がコメントアウトされた形式になっていることを思い出してください。個々の '?' は 1 つの置換文字を表しているので、3 文字の '?' は 3 文字の命令ニーモニックを、4 文字の '?' は状態またはグローバルを、2 文字の '?' は定数を表していることになります。個々の練習問題では、'?' の置換ヒントを含んだ行を示した後に、解答を示しています。練習問題のエフェクト ファイルのソースは MSDN ShaderWorkshop ダウンロードに含まれているので、それを参照しながら読み進めてください。
まず最初に、各練習問題の目的を簡単に述べておきます。
- 練習問題 7 では、すでにおなじみのエフェクト ファイル機能にピクセル シェーダの追加方法概要を知るために、エフェクト ファイルの中でピクセル シェーダを使ってマルチテクスチャ レンダリングを行います。初期状態ではテクスチャ ブレンディングが行われていないので、これを修正することが練習問題となります。
- 練習問題 8 の目標は、テクスチャリングとライティングを同時に行うことです。頂点シェーダからのライティングの項を、ピクセル シェーダの中でテクスチャとブレンドする必要があります。これで、テクスチャリングとライティングの基本的なタスクを理解したことになります。
- 練習問題 9 の目標は、ピクセル シェーダ ツールボックスにバンプ マッピングを追加することです。具体的には、これは (エンボスまたは EMBM スタイルのバンプ マッピングではなく) dot3 スタイルのバンプ マッピングで、ディフューズとスペキュラの両方を扱います。
- 練習問題 10 の目標は、非等方バンプ マッピングを実装することです。これはWolfgang Heidrich と Hans-Peter Seidel によって始められた研究 (Realistic, Hardware accelerated shading and lighting, Proceedings of SIGGRAPH 99) から派生した高度なテクニックです。このテクニックは、ブラッシュド メタルの外見やベルベットの外見をオブジェクトに与えます。
- 練習問題 11 の目標は、do-it-yourself (DIY) ライティング モデルを研究することです。シェーダ ワークショップのこの練習問題は、昨年 11 月の「ピクセル単位のライティング」の記事で説明した DIY のコンセプトを扱っています。
では、さっそく練習問題に取りかかりましょう。
練習問題 7: マルチ テクスチャリング
最初のピクセル シェーダの練習問題では、最初の頂点シェーダの練習問題と同様に、肩慣らしとして、遅い直球を投げる練習をします。この練習問題は、単に基本的なマルチ テクスチャリングを実行します。この練習問題を通して、ピクセル パイプラインとピクセル シェーダのためのエフェクト ファイルの構文に慣れることができます。
次の図 1 は、スタートアップ時の練習問題 7 の外見を示しています。球体に、モジュレートしていないベース テクスチャが適用されています。
.jpg)
図 1. EX7.FX の練習問題の出発点となるイメージ
この練習問題は、次に示す行を含んでいます。練習問題の目的は、これを完成させることです。
練習問題 7
mov r0,t0
//mov r0,t1 // 1 の代わりに 2 を試してみる
//xxx r0,t1,t0; // 興味深い効果を得るためにブレンドする
1 つ目の仮の行は、t0 のテクスチャを適用して、何らかのイメージを表示しています。次の行は、テストの目的に、単に t1 のテクスチャを適用したときにどのような結果が得られるかを調べるためのものです。最後の行が本当の練習問題の行で、t0 と t1 にどのような演算を適用すべきかを尋ねています。
解答 7: マルチ テクスチャリング
練習問題 7 の解答は、次の図 2 に示すようなイメージを生成します。
.jpg)
図 2. EX7.FX の解答のイメージ
これは、t0 を t1 でモジュレートした結果を示しています。固定機能パイプラインでは Mod 演算子を使いましたが、ピクセル シェーダでは、2 つの texel 値の乗算には mul 命令を使います。次に完成した mul 命令を示します。_x2 出力修飾子が使用されていることに注目してください。これは、生成されるイメージが暗くなりすぎないように、結果に 2 を掛けます。
解答 7
mul_x2 r0,t1,t0; // 興味深い効果を得るためにブレンドする
1 未満の 2 つの数値 (この例ではソース texel 値) を掛け合わせると、必ず元よりも小さい値が得られます。そこで、結果に 2 を掛けることで、2 つのテクスチャを組み合わせたイメージが暗くなりすぎないようにしています。実際に修飾子を外して実験してみてください。これ自体が有用な練習問題となります。
練習問題8: テクスチャとライト
練習問題 8 では、テクスチャリングにライティングを追加します。ここでは、頂点シェーダはディフューズ値とスペキュラ値を計算し、2 つのテクスチャとテクスチャ座標を渡します。次の図 3 は出発点となるイメージを示しています。これは練習問題 7 の結果とよく似ています。学習の成果が徐々に積み重なっていくのを見るのは楽しいことではありませんか?
.jpg)
図 3. EX8.FX の練習問題の出発点となるイメージ
この練習問題の目標は、頂点シェーダによって計算された値を正しく使用するように、ピクセル シェーダを変更することです。この計算値はハードウェアによって繰り返し処理され、ピクセル シェーダに渡されます。練習問題には以下の行が含まれています。
Exercise 8
//??? r0,r1,v0; // ディフューズのモジュレート
//??? r1,r1,v1; // スペキュラのモジュレート
//??? r0,r0,v1; // 両者をブレンド
この練習問題の目標は、これらの行を完成させることです。これには、ディフューズおよびスペキュラ値をモジュレートし、これらの値を最終的な結果にブレンドすることが含まれます。
解答 8: テクスチャとライト
練習問題 8 の解答は、図 4 に示すイメージを生成します。この結果は、ライトのディフューズ コンポーネントとスペキュラ コンポーネントの両方によってモジュレートしたテクスチャを含んでいます。マウスの右ボタンを使用して、ライトの位置を操作できます。
その後には、解答の命令を示しています。
.jpg)
図 4. EX8.FX の解答のイメージ
Solution 8
mul r0,r1,v0; // ディフューズのモジュレート
mul r1,r1,v1; // スペキュラのモジュレート
add r0,r0,v1; // 両者をブレンド
まず、ディフューズ カラー v0 を、mul 命令を使って、ベース テクスチャ t0 によってモジュレートします。次に、スペキュラ カラー v1 を、mul 命令を使って、ディテール テクスチャによってモジュレートします。最後に、結果を足し合わせます。ここでは、練習問題 7 とは異なり 2 つの mul を使用しているため、add を使用しています。
最後の add を mul または mul_x2 に置き換え、その前の 2 つの mul にも _x2 修飾子を付けてみると面白いでしょう。より小さな値 (mul) または大きな値 (add) を生成する演算を続けて実行したときにどのような値が得られるのか、だいたいの感触をつかむことができます。
練習問題 9: dot3 バンプ マッピング
練習問題 9 では、ピクセル シェーディング ツールキットのテクスチャリングとライティングに、dot3 バンプ マッピングを追加します。この練習問題には 3 つの部分があり、練習問題 9a はディフューズ ライティングが行われたテクスチャに対してバンプ マッピングを行います。次の図 5 は、練習問題の最初の部分で、テクスチャが適用されていない、ライティングとバンプ マッピングが行われた地球を示しています。
.jpg)
図 5. EX9a.FX のイメージ
.jpg)
図 6. EX9b.FX のイメージ
この練習問題は、dp3 内積命令の使用方法と、入力にバイアスをかけて適切な範囲に収める _bx2 修飾子の使い方を示しています。これは次の練習問題の重要な命令であり、ベース テクスチャに対してモジュレートを行う方法を理解しておく必要があります。これは比較的簡単ですが、徐々に難しくなっていくので気を抜かないようにしてください。
練習問題 9a
dp3 r0,t1_bx2,v0_bx2;
//??? r0,??,?? // ベース カラー テクスチャに対してモジュレート
練習問題 9b は、練習問題 9a のディフューズ ライティングの補足として、スペキュラ ライティングを使用します。練習問題 9b では、乗算の繰り返しによってスペキュラを実行します。図 6 はこの練習問題のデフォルトの外見を示しており、テクスチャを適用していないスペキュラ ハイライトが見えています。やはり dp3 内積命令を使い、ここではハーフアングル式を使用して、スペキュラを計算しています。この練習問題は、dp3 の結果の使い方に焦点を当てています。結果の累乗の計算が部分的に行われているので、これを完成させ、出力のピクセル カラー値を書き出すことが求められます。ここでは、最後の数個の命令が鍵となっています。
練習問題 9b
dp3 r0,t1_bx2,v0_bx2; // 内積(法線、ハーフアングル)
mul r1,r0,r0; // 累乗を計算
mul r0,r1,r1;
//mul r1,r0,??
//mul ??,r1,r1
練習問題 9c では、テクスチャのテーブル ルックアップによってスペキュラが行われています。次の図 7 は、この練習問題のデフォルトの外見を示しています。
.jpg)
図 7. EX9c.FX のイメージ
この練習問題は、tex3x2pad/tex3x2tex の命令シーケンスを使って、従属読み込みテーブルのルックアップを実行し、やはりその結果の使い方に焦点を当てています。この練習問題の鍵となる命令は、置換文字だけで構成されており、ベース カラーにライトを掛けることを要求していますが、これはピクセル シェーディング ツールキットですでにおなじみの命令でしょう。
練習問題 9c
tex t0 // 法線のサンプル
texm3x2pad t1, t0_bx2 // ライトの輝度のルックアップ
texm3x2tex t2, t0_bx2
tex t3 // ベース カラーのサンプル
mov r0,t2 // ピクセル単位のライトの輝度
//??? ??,??,?? // ベース カラーにライトを掛ける
解答 9: dot3 バンプ マッピング
練習問題 9a の解答は簡単です。次の図 8 は、解答の外見を示しています。北アフリカにライトを適用した、バンプ マップを適用した地球が表示されています。
.jpg)
図 8. EX9a.FX の解答のイメージ
次に示す、この練習問題の鍵となる命令は、texel に dp3 ディフューズ ライティング計算の結果を掛け、ディフューズ ライティングの結果によってテクスチャ カラーをモジュレートしています。
解答 9a
dp3 r0,t1_bx2,v0_bx2; // 内積(ライト, 法線)
mul r0,t0,r0 // ベース カラーに対してモジュレート
練習問題 9b は、スペキュラを使用して、テクスチャのモジュレートに使うライティング値を計算します。次の図 9 に示す結果では、やはり北アフリカにライトが当てられています。
.jpg)
図 9. EX9b.FX の解答のイメージ
次に示す解答の命令は、スペキュラ値を4回かけています。この方法でスペキュラ バンプ マッピングを行うと、1.1 のシェーダの精度の制限と、入力ハーフアングルの精度の制限のせいで、予期せぬ結果が生じます (つまり、シェーダが高精度であっても、入力が 8 ビットしかないならば意味がありません)。練習問題 9c の方が、よい結果を出せます。dot3 がより高い精度で行われるだけでなく、頂点シェーダから入力されるテクスチャ座標 (この例ではハーフアングル) が、補間されたカラーよりもはるかに高い精度を持っています (テクスチャ座標はチャネル 1 つにつき 24 ビットを持てますが、カラーは 8 ビットしか持てません)。注意深く見ると、この乗算の繰り返しによって生じたバンディングの予期せぬ結果が見えるはずです。画面ショットでは実際の画面ほどはっきりとはわかりませんが、かなり目障りで、視覚効果のフィーリングを損なう原因となります。これを解決するのが練習問題 9c です。
解答 9b
dp3 r0,t1_bx2,v0_bx2; // 内積(法線、ハーフ)
mul r1,r0,r0; // 4 回くりかえす
mul r0,r1,r1;
mul r1,r0,r0;
mul r0,r1,r1;
mul r0,t0,r0 // スペキュラの結果によって texel をモジュレート
練習問題 9c では、スペキュラ値を、テクスチャに格納されているルックアップ テーブルをもとに計算します。結果として得られたイメージを図 10 に示します。予期せぬ結果は劇的に改善されています。
.jpg)
図 10. EX9c.FX の解答のイメージ
この解答では、次に示すように、t3 のベース texel カラーと、r0 のテーブル ルックアップを使って計算された値の間でブレンディングを行っています。r0 の中の結果を計算するためには、「トリッキー」なテクスチャ アドレシング演算子の 1 つ、この例では texm3x2tex を使用する必要があります。texm3x2tex のドキュメンテーションはかなり整備されており、次に示す解答に似たコード例が含まれています。
解答 9c
tex t0 //法線のサンプル
texm3x2pad t1, t0_bx2 //テーブルでルックアップ
texm3x2tex t2, t0_bx2
tex t3 //ベース カラーのサンプル
mov r0,t2
mul r0,r0,t3 //項をブレンド
ここでは、テクスチャ アドレシング演算子の使い方を少し詳しく見てみました。ピクセル シェーダの興味深い用途の多くには、このテクスチャ アドレシング演算子が関わってくるからです。ほとんどの場合、個々の命令のドキュメンテーションには、最も典型的な使用方法を示すコード例が含まれています。従属読み込みの便利さにまだ触れていない人にとっては、貴重な情報源となるでしょう。
練習問題 10: 非等方ライティング
非等方ライティングは興味深いトピックです。Wolfgang Heidrich と Hans-Peter Seidel の研究 (Realistic, hardware-accelerated shading and lighting. Siggraph 1999, Annual Conference Proceedings, 1999) 以来、さまざまな研究者たちが、サテン、ワイヤのスプール、ブラッシュド メタルといったサーフェイスのシミュレーションを可能にするテクニックを開発してきました。このテクニックは、基本的にはスペキュラ エフェクトです。Meltdown 2001 のスライドでは、Chas Boyd がこのテクニックについて解説し、部分的な情報を提供しています。MSDN Shader Workshop は完全な情報を提供します。
この練習問題の面白い点は、練習問題 9c で扱ったテクスチャ アドレシングのテクニックをベースにしているところです。次の図 11 は、この練習問題の、まったく面白みのないデフォルト イメージを示しています。
.jpg)
図 11. EX10.FX の練習問題の出発点となるイメージ
次に示す練習問題のコードは、texm3x3pad、tex3x3pad、tex3x3tex の命令シーケンスを使って、キューブ マップ従属読み込みを行っています。その後、このキューブ マップ ルックアップの結果を使って、最終的なピクセル カラーが計算されます。目標は、置換文字を含んでいる命令が示しているように、このソース カラーの取得先を指定することです。
練習問題 10
tex t0
//texm3x3pad t1, t0_bx2 //3x3 トランスフォーム
//texm3x3pad t2, t0_bx2 //これらは u = 内積(ライト、法線)
//texm3x3tex t3, t0_bx2 //v = 内積(ハーフ、法線)
//w = 何らかの正の数値
//のテクスチャ座標を生成する
//mov r0,??;
//mad r0,c0,t3.a,r0; //アルファはディフューズを含んでいるので、加算を行う
mov r0, t0
解答 10: 非等方ライティング
次の図 12 は、このテクニックを使って、輝くサテンに似た結果を生成する方法を示しています。このテクニックは、練習 9 の tex3x2tex と似た従属読み込みのテクスチャ ルックアップを使用していますが、ルックアップ テーブル テクスチャでは、Wolfgang Heidrich と Hans-Peter Seidel の論文に記されているライティング公式に基づくまったく違った関数を使用しています。
sqrt(1- <L,T>)*sqrt(1-<V,T>) -<L,T>*<V,T>
このテクニックでは、<L,T> と <V,T> の2 つの内積が入力として必要になります。T は接線ベクトル、L はライト ベクトル、V はビュー ベクトルです。
これを念頭に置いた上で、このテクニックでは 2 つの手続き型テクスチャが鍵を握ることになります。法線値を持つテクスチャ マップと、非等方ライティング値を持つテクスチャ マップです。
法線マップ (実際には接線マップ、または髪の毛の向き - これが毛皮だった場合、個々の接線は、そのポイントでの毛の向きになります) は、必要となる <L,T> と <V,T> の 2 つの内積への法線入力を提供するために使います。この毛皮マップは法線から得られる接線ベクトルをもとに、手続き的に作成したものであることに注意してください。毛皮マップはアーティストから提供してもらうのが理想的です。
非等方マップはキューブ マップです。なぜキューブ マップなのでしょうか? 3x2 の演算子を使用すると、内積の結果は [-1,1] の範囲になりますが、標準テクスチャは範囲 [0,1] で参照されます。テクスチャ座標値を再マッピングする巧妙な方法は存在しないので、その結果として予期せぬ結果が生じます。このジレンマは標準的なテクスチャでは解決できませんが、キューブ マップを使用した場合には、テクスチャ座標の符号が、キューブ マップのどの面をアドレシングしているかを示しているので、解決が可能です。
.jpg)
図 12. EX10.FX の解答のイメージ
このようにサテン マップは、実際には、非等方ライティング評価法を使って計算し、tex3x3tex 命令シーケンスの結果を使ってサンプリングするキューブ マップなのです。
解答 10
tex t0
texm3x3pad t1, t0_bx2 //3x3 トランスフォーム
texm3x3pad t2, t0_bx2 //これらは u = 内積(ライト、法線)
texm3x3tex t3, t0_bx2 //v = 内積(ハーフ、法線)
//w = 何らかの正の数値
//のテクスチャ座標を生成する
mov r0,t3;
mad r0,c0,t3.a,r0; //アルファはディフューズを含んでいるので、
// スペキュラへの加算を行う
この解答のソース コードからは、サテン マップを表すキューブ マップが、tex3x3tex 命令シーケンスから得られた u-v-w テクスチャ座標を使ってどのようにサンプリングされるかがわかります。結果として得られた texel 値は r0 に格納され、定数と、テクスチャ アルファに格納されているディフューズに基づいて最終的なカラーを計算する mad 命令で使います。これは複雑な処理ですが、練習問題のシェーダ命令の解答の本質はここにあります。
法線マップ (ここでは実際には接線マップ) は D3DXCreateTexture を使って作成し、別のテクスチャ (元の法線) から ComputeBinormalMap を使って計算します。次のシーケンスを使います。
// 法線テクスチャから従法線マップをセットアップ
D3DXCreateTexture(m_pd3dDevice,desc.Width,desc.Height,0,0,
D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &m;_pBiNormalMap);
ComputeBinormalMap(m_pBiNormalMap,m_pNormalMap);
ComputeBinormalMap のテクスチャの個々のレベルについて、x および z 要素を次のように交換します。
//要素を操作して、新たな従法線マップを得る
HRESULT CMyD3DApplication::ComputeBinormalMap(
LPDIRECT3DTEXTURE8 pTarget, LPDIRECT3DTEXTURE8 pSource)
{
DWORD i,j,dwLevel,dwNumLevels;
HRESULT hr;
D3DSURFACE_DESC Desc;
DWORD *pPlace1,*pPlace2;
unsigned char x,y,z,t;
D3DLOCKED_RECT SourceLock,DestLock;
dwNumLevels = pSource->GetLevelCount();
for(dwLevel = 0;dwLevel < dwNumLevels;dwLevel++)
{
pSource->GetLevelDesc(dwLevel,&Desc;);
hr = pTarget->LockRect(dwLevel,&DestLock;,NULL,0);
hr = pSource->LockRect(dwLevel,&SourceLock;,NULL,0);
for(i = 0;i < Desc.Height;i++)
{
pPlace1=DestLock.pBits+ i*DestLock.Pitch);
pPlace2=SourceLock.pBits+ i*SourceLock.Pitch);
for(j = 0;j < Desc.Width;j++)
{
// x と z を交換
x = (unsigned char) ((*pPlace2)>>16) & 0xFF;
y = (unsigned char) ((*pPlace2)>> 8) & 0xFF;
z = (unsigned char) ((*pPlace2)>> 0) & 0xFF;
t = x;
x = z;
z = 255-t;
*pPlace1 = (x<<16) | (y <<8) | (z );
pPlace1++;
pPlace2++;
}
}
pTarget->UnlockRect(dwLevel);
pSource->UnlockRect(dwLevel);
}
return S_OK;
}
サテンのルックアップに使うキューブ マップは、コールバックから自動的にテクスチャの格納を行う便利な D3DXFillCubeMap メソッドを使って計算します。ここではコールバックとして LineLightEval を使用します。
// サテン マップの作成
float fPower = 40.0f;
D3DXCreateCubeTexture(m_pd3dDevice,256,0,0,
D3DFMT_A8R8G8B8,D3DPOOL_MANAGED, m_pSatinMap2);
D3DXFillCubeTexture(m_pSatinMap2,LineLightEval,&fPower;);
LineLightEval コールバックは、目的の結果を得るために、累乗関数を実装しています。
//非等方ライティングの計算
void LineLightEval(D3DXVECTOR4 *col,D3DXVECTOR3 *input,
D3DXVECTOR3 *sampSize, void *pPower)
{
float fSin1,fSin2,fMix = .2f;
float x,y;
x = input->x;//*2-1;
y = input->y;//*2-1;
// z は無視
fSin1 = sqrtf(1-x*x);
fSin2 = sqrtf(1-y*y);
col->x = powf((fSin1*fSin2 - x*y),*((float*)pPower));
col->y = col->x;
col->z = col->x;
// ディフューズの輝度
col->w = fSin1;
}
これで非等方ライティング モデルの解説は終わりです。
練習問題 11: DIY ライティング
これが最後の練習問題です。ここまでで、テクスチュアリングおよびライティング テクニックのための基本的なピクセル シェーダ タスク、バンプ マッピングのための高度なピクセル シェーダ タスク、および非等方のような特殊なライティング モデルを習得したので、次は本当に難しい仕事に取りかかることにしましょう。Driving DirectX の「ピクセル単位のライティング」の記事では、まずピクセル シェーダにおける標準的なライティング タスクについて解説しました。その後、半球ライティング モデルを実装することで、カスタム ライティング モデル、あるいは do-it-yourself (DIY) ライティング モデルを定義し、実装する方法を示しました。この流れの本質は、何らかの物理モデルを決定し、最終的な外見に重要な貢献を行う項を選択するというという手続きにあります。
練習問題 11 は、半球 DIY ライティング テクニックを実装し、これを標準ライティング テクニックと組み合わせて、きわめて迫力のあるイメージをリアルタイムで生成します。次の図 13 は、基本半球、あるいは「エリア」ライティングを使ったスカル モデルを示しています。
.jpg)
図 13. EX11a.FX のイメージ
この練習問題では、まずより優れたエリア ライティングを適用し、次に標準ディフューズ ライティング項を追加することで、この外見を大きく改善します。
次に示す、練習問題 11a の鍵となる命令は、基本エリア ライティング イメージを暗くするための遮蔽項の適用です。この方法でイメージを暗くしないと、眼窩と歯の裏が明るく光る不適切なイメージになってしまいます。
練習問題 11a
//??? ??,??,?? // スカイカラー項を暗くする
mul oD0,r0,c9 // 次にオブジェクトのカラーに対してモジュレートする
.jpg)
図 14. EX11b.FX のイメージ
練習問題 11b の目標は、標準のディレクショナル ディフューズ ライティング項を追加することです。図 14 は、この練習問題の出発点を示しています。次に示す、練習問題 11b の鍵となる命令は、スカイカラー項を暗くする mul と、エリアおよびディフューズ ライト項を結合する mad です。
練習問題 11b
//mul r2,??,?? // スカイカラー項を暗くする
dp3 r1,r9,-c16 // ライト ベクトルとの内積を計算
//mad ??,r1,??,r2 // ライト ディフューズと結合
では、最後の練習問題の解答に進みましょう。
解答 11: DIY ライティング
次の図 15 は、練習問題 11a を解いた結果を示しています。この図から、遮蔽項、つまり光を暗くする項が、視覚的なクオリティに大きく貢献していることがわかるでしょう。次に示す解答の命令シーケンスは、以前に計算した線形補間値を使ってスカイカラー項を暗くした後に、定数のオブジェクト カラーに対してモジュレーションを実行しています。
.jpg)
図 15. EX11a.FX の解答のイメージ
解答 11a
// 2 つの空のカラーの間で線形補間を行う
mad r0,r1,r0,c42 // 線形補間
…
mul r0,r0,r1 // スカイカラー項を暗くする
mul oD0,r0,c9 // オブジェクトのカラーに対してモジュレート
練習問題 11b では、標準ディフューズ ライティング項を追加しています。このコードの鍵となる命令を次に示します。スカイカラー項を暗くするための mul と、オブジェクト カラーに対するモジュレートを行う mad に注目してください。詳細については、前述の「ピクセル単位のライティング」の記事を参照してください。ここではスペースの関係上、詳しくは解説しません。
解答 11b
mul r2,r0,r1 // スカイカラー項を暗くする
dp3 r1,r9,-c16 // ライト ベクトルとの内積
…
mad r0,r1,c13,r2 // ライト ディフューズと結合
mul oD0,r0,c9 // オブジェクトのカラーに対してモジュレート
図 16 は、練習問題の解答から得られるイメージを示しています。遮蔽項と標準ディフューズ ライティング項が、結果として得られたイメージの現実味を大きく高めていることがわかります。このように、カスタム ライティング テクニックと標準ライティング テクニックを組み合わせることで、非常にきれいなイメージを得ることができます。
これが最後の練習問題でした。これまでの 3 つの記事では、かなりの量の情報を提供してきました。読者の皆さんにとって、基本的な頂点シェーダとピクセル シェーダのタスクは、もはや不思議なものではなくなったことでしょう。
.jpg)
図 16. EX11b.FX の解答のイメージ
最後に
このコラムの執筆に際して、Dan Baker と Mike Burrows 各氏のご協力に感謝します。モデルを提供していただいた Viewpoint Datalabs と Lightwave に感謝します。
Remember, Microsoft maintains active mailing lists as forums for like-minded developers to share information:
ご意見をお寄せください。感想、質問、トピックに関するアイデア、コラムのトピックに関しての皆さんのやり方を示すリンクなどを (日本語で) directxj@microsoft.com まで送ってください。ただし、個別に返答したり、サポートに関する質問に回答したりすることはできませんので、あらかじめご了承ください。
Microsoft では、同じ目的の開発者が情報を共有できるようなフォーラムとして、活発なメーリング リストを運営しています (英語)。
オーディオおよびビデオを扱う DirectXAV に関する話題は、 http://DISCUSS.MICROSOFT.COM/archives/DIRECTXAV.html
グラフィックス、ネットワーク、および入力を扱う DirectXDev に関する話題は、 http://DISCUSS.MICROSOFT.COM/archives/DIRECTXDEV.html を参照してください。
Driving DirectX