フォグの深度をプログラムできることを知ったときに、真っ先に考えたのがこの効果です。
アニメで、黒い輪が縮まりながらシーンを切り替える画面を見ると思いますが、
その3次元版を狙ってみました。
ここまでくると、フォグに見えませんね。
今回のソースは、次のものです(DirectX8.1用です)。
まぁ、いつものように適当にファイルが入っています。
前回と頂点シェーダプログラムと、draw.cpp が変化しています。
vs.vsh | 頂点シェーダープログラム。久しぶりに、ここに新しい要素が入る。 |
draw.cpp | メインの描画部分。 |
draw.h | 描画の各関数の定義。特に意味無いので出番無し。 |
main.h | 基本的な定数など。今回も出番無し。 |
main.cpp | 描画に関係しないシステム的な部分。変更が無いので、出番無し。 |
load.h | ファイルの読み込み。 |
load.cpp | ファイルの読み込み。 |
bg.cpp | 地面+天円柱の描画。今回説明無し。 |
あと、いつもの様に、モデルと、実行ファイル及び、プロジェクトファイルが入っています。
やってることは簡単です。
深度を中心からの距離にとり、フォグを計算します。
今回の描画ソースファイルは、前回と違い描画部分の変更しかありません。
フォグのかかり始めと終わりの距離を調整し、必要な定数を設定します。
0211: //----------------------------------------------------------------------------- 0212: // Name: Render() 0213: // Desc: 毎フレームの描画 0214: //----------------------------------------------------------------------------- 0215: VOID Render(LPDIRECT3DDEVICE8 lpD3DDev) 0216: { 0217: DWORD cnt = timeGetTime()%10000; 0218: float t = (float)cnt/1000.0f; 0219: 0220: float Near; 0221: float Far; 0222: float max = 100.0f; 0223: 0224: // 頂点シェーダーのフォグに関するパラメータ 0225: if(t < 3.0f){ 0226: // フェードイン 0227: t /= 3.0f; 0228: Near = max*(t-0.15f); 0229: Far = max*(t-0.0f); 0230: }else 0231: if( t < 5.0f){ 0232: // 明るい 0233: Near = max-0.1f; 0234: Far = max; 0235: }else 0236: if( t < 8.0f){ 0237: // フェードアウト 0238: t = 8.0f-t; 0239: t /= 3.0f;// これで、tは1.0fから0.0fと動くので、フェードインの逆になる 0240: Near = max*(t-0.15f); 0241: Far = max*(t-0.0f); 0242: }else{ 0243: // 暗い 0244: Near = -0.1f; 0245: Far = 0.0f; 0246: } 0247: if(Far-Near<0.1f)Near=Far-0.1f; 0248: lpD3DDev->SetVertexShaderConstant(16, &D3DXVECTOR4(-1.0f/(Far-Near), Far/(Far-Near), 0.0f, 0.0f), 1); 0249: 0250: D3DXMATRIX mWorld, mView, mProj, m; 0251: 0252: // ビュー行列 0253: D3DXVECTOR3 eye = D3DXVECTOR3(0.0f,MeshRadius,2.5f*MeshRadius); 0254: D3DXVECTOR3 lookAt = D3DXVECTOR3(0.0f, 0.0f, 0.0f); 0255: D3DXVECTOR3 up = D3DXVECTOR3(0.0f, 1.0f, 0.0f); 0256: // 通常表示 0257: D3DXMatrixLookAtLH(&mView, &eye, &lookAt, &up); 0258: D3DXMatrixPerspectiveFovLH(&mProj 0259: ,60.0f*PI/180.0f // 視野角 0260: ,(float)WIDTH/(float)HEIGHT // アスペクト比 0261: ,0.01f,100.0f // 最近接距離,最遠方距離 0262: ); 0263: lpD3DDev->SetVertexShaderConstant(15, &D3DXVECTOR4(eye.x, eye.y, eye.z 0264: , (float)sqrt(eye.x*eye.x+eye.y*eye.y+eye.z*eye.z)), 1); 0265: 後は、通常のモデル描画
ほとんどが時間に応じてフォグのかかる範囲を調整する部分ですが、図でかくと
の様になります。
わずかにフォグのかかりはじめる部分を手前にして、ぼやける幅を作っています。
シェーダープログラムは、ワールド座標での原点からの距離を求めて、その距離をフォグの係数にしています。
0001: ; c0-3 -- world + ビュー + 透視変換行列 0002: ; c4-7 -- world 0003: ; c12 -- (0.0, 0.5, 1.0, 2.0) 0004: ; c13 -- ライトのベクトル (w成分は環境光の強さ) 0005: ; c14 -- ライトの色(メッシュの色) 0006: ; c15 -- 視点 0007: ; c16 -- (-1/(far-near), far/(far-near), 0,0) 0008: ; 0009: ; v0 頂点の座標値 0010: ; v3 法線ベクトル (w成分は1.0f) 0011: ; v7 テクスチャ座標 0012: 0013: vs.1.0 0014: 0015: ;座標変換 0016: dp4 oPos.x, v0, c0 0017: dp4 oPos.y, v0, c1 0018: dp4 oPos.z, v0, c2 0019: dp4 oPos.w, v0, c3 0020: 0021: ; ランバート diffuse 0022: dp4 r0.w, v3, c13 ; l・n 0023: mul oD0, c14, r0.w ; ライトの色(メッシュの色付き)をつける 0024: 0025: mov oT0, v7 0026: 0027: ; フォグの計算 0028: dp4 r0.x, v0, c4 0029: dp4 r0.y, v0, c5 0030: dp4 r0.z, v0, c6 0031: 0032: dp3 r1.x, r0, r0 0033: rsq r1.y, r1.x 0034: mul r1.z, r1.x, r1.y ; r1 = (|R|^2, 1/|R|, |R|) 0035: 0036: mad oFog.x, r1.z, c16.x, c16.y ; fog = (far-|R|)/(far-near)
フォグを使った自明でないエフェクトを作ってみました。
空間に存在する塵の濃さは考えていないので、ボリュームフォグとは違うものなのですが、
変わった演出として使えると思います。