[HMC]年間5250円で独自ドメイン付属、ウィルスチェックありのレンタルサーバ!
Last update : 2000/09/22
演出&エフェクト 第4回
サインカーブを使用して画像を揺らす その3 波紋
サンプルコードのダウンロード
  では、まずサンプルコードをダウンロードし、解凍して下さい。 私はVisual C++6.0でコンパイルしているので、をお持ちの方は Visual C++でプロジェクトファイルを開いて下さい(「effec_04.dsw」をダブルクリックすれば開けます)。 圧縮ファイルに含まれる「effec_04.exe」をダブルクリックし、実行してみて下さい(何かキーを押すと終了します)。 どうでしょう?画面が切り替わり、写真が波紋のような歪み方をすると思います(謎。 というわけで、今回もサインカーブを使用して画像を歪ませたいと思います。
今回は(も?)初心者には解りづらいかも
さて、今まで演出講座2・3回にてサインカーブを使用して地球を揺らしてきましたが、今回は 右の写真のように、写真を波紋のように歪めてみます。今まで真面目に演出講座2・3回を 勉強された方なら、おそらく写真を見ただけで「だいたいこうやっているのだろう」という見当は付いていると思います。

んー、ちょっと初心者にはきつい内容かもしれないので、こんなものもあるんだぁーぐらいに 流して下さい(爆。

というかゲーム関連で、波紋使うかどうかは謎です(^^;
まずは数学のお勉強
さて今回はプログラム中に「直線距離の算出」をするので、まずここでざっと説明しておきます。

左の図のように直角三角形がある場合、



という公式があります(ピタゴラスの定理だったか?)。 まぁ、高校1年くらいには習うと思いますが(詳しくは数学の先生に聞いて下さい)。

実際は、x座標,y座標があるので、点A(ax,ay)から点B(bx,by)の直線距離は 以下の図のようになります。



まぁ、パソコン上の座標はY軸の方向が逆になるのですが、今回は2乗しているため符号が必ずプラスになるので その辺を考える必要はありません。これを実際にC言語で記述すると、

みたいな感じになりますね。
DirectDraw初期化
  さて、サンプルコードを見ながら順番に説明していきます。今回は基本的な部分はWinMain()内で全て やっていますが、DirectDrawの初期化の部分も少し変更していますので注意して下さい。ちなみに DirectDraw関連の基本的なコードは「DirectDraw基礎 第13回」のサンプルコードを 使用しています(MODE Xを使用します)。

ではまず、グローバル変数としてlpGraphを宣言しておきます。これは写真を読み込んでおく場所として 使用します。
宣言しただけでは意味が無いので、StartDirectDraw自作関数内でオフスクリーンサーフェイスを作成します。
今回の場合、オフスクリーンサーフェイスへは、頻繁に直接アクセスするので DDSCAPS_SYSTEMMEMORYを指定して強制的にシステムメモリ内へ作成します (ビデオメモリ内サーフェイスへの直接アクセスは速度が遅い)。

さて、DirectDrawの設定はこれぐらいです。あ、ちなみに最後にlpGraphを 解放するのを忘れないようにして下さいね。
よく解らない解説
まず写真(bridge.bmp)をあらかじめ作成しておいたオフスクリーンサーフェイス (lpGraph)へ読み込んでおきます。

次に、高速化のためにサイン・コサインテーブルを作成します。
普通は360度で一周ですが、今回は256度で一周とします。 こうすることで fsin[BYTE(...)] と、BYTE型(unsigned char型)にキャストするだけで 不正なアクセスを防ぐことが出来ます。

次に、あらかじめ各座標毎に、中心からの距離・中心への角度(0-255度)を算出しておきます。これも高速化のためです。
距離の算出については、上の方でやりましたね?また、角度の算出については「
ゲーム制作基礎 第11回」でやりました。
まぁ、↑のは大体解ると思います。ゆれの大きさの部分に関しては前回・前々回と大体同じです。

次に、あらかじめ画像を読み込んでおいたサーフェイス(lpGraph)と、作業用サーフェイス(lpWork) をロックし、そのサーフェイスへの先頭アドレスを取得します。
サーフェイスのロックについては「DirectDraw基礎 第12回」で やりました。

そんでもって次のが心臓部。
ポインタいじりまくりですね。ポインタの概念がしっかり解っていないと理解出来ないと思います(^^;
まず、今までの演出は「転送先の座標を計算する」というパターンですが今回はこれでは穴が空くので逆に 「転送先が転送元の座標を計算する」方法でやっています。 ですから画面全体(320x240)について全て計算を行います。

おおまかに説明すると、「画面中心からの距離(p_length)+時間(count)」 を使ってサインカーブを参照し、ゆれの幅を計算します。その揺れの幅分だけ 転送元の座標を中央に向かってずらします。あとは転送元の色を転送先へ転送します(ぉ。
一通り終わったらロックを解除し、一度バックバッファへ転送し、フリップして画面に表示させます。
解ってしまえば簡単ですね(^^;

細かい部分で何か解らない事があれば掲示板へどうぞ。