|
|||
|
さて、デモといえばなんだか派手っちいエフェクト。オマケにこの僕は当代きってのブラーマニア(ぼかし狂)ときており、PhotoshopのBlur機能はもう隅から隅まで使いまくりというありさまで、ここまできたらもうちょい派手なエフェクトもぜひとも欲しい。そんな気持ちで作ったのが右の画面のような放射ブラー(Radial Blur)なのです。 こういうのをエフェクトとして使ってるデモはけっこうみますが、半分は単なるフェイクのようですね。掲示板で^Cさんが教えてくださった、Javaデモ、forwardのオープニングもフェイクのようです(添付されていたGIFファイルをみてわかりました)。しかしここまで見事にやられるとフェイクとは全然気づかず、関心してしまいました。 でもフェイクを多用しすぎるとテクニックのデモというよりは単なる紙芝居になってしまうし、そもそも意味がないのでFinalRealityのタイトルロゴのようリアルタイムで計算する方法をなぞってみることにしました。敵を制するには敵を知れ、ということですね。 さて、この放射ブラーはそもそもどういうものなのかというと、この画面写真のように中央から周囲にむかって光の尾を引くような効果をさします。 このような効果は放射状にぼかしをかけることで実現できます。それゆえ「放射ブラー」とよばれているわけです。 これはカメラのシャッタースピードを遅くして、シャッターがあいている時間にズームレンズを操作する、スローシャッター効果とほぼ同じです。この技法はスピード感と立体感を演出できるので時々使われているのをみますが、立体感をうまく出すには単に放射状にぼかしをかけるだけでは不十分です。 このやりかたはOh!Xの1992年2月号の中野修一氏の記事を参考にしました(バックナンバーを貸してくれた平松クンthanx)。それによると、サンプリングするピクセルの座標を求めている式は次のようになります。
y = 127+j-(sgn(j)*(k*k)/l)*abs(j)/49 このとき、xとyはサンプリング点の座標で、これは図のオレンジの点にあたります。iとjは色を求めたいピクセルの座標で、これは図の赤い点にあたります。sgnというのはX-BASICの関数で、これはsgn(a)のとき、aの内容が正なら1、負なら-1を返す関数のようです。kは図で言うとオレンジ色の点の何番めに位置するかの数です。これは好きなだけ増やしたりできますが、増やしすぎてもわけがわからくなるだけです。absはご存知絶対値を求める関数です。lは適当な定数です。 この式を使うと、画面の中心付近(kが小さいとき)は細かく、画面から離れる(kが大きいとき)にしたがっておおざっぱにサンプリングすることになり、これを平均すると、必然的に画面中心方向が細かくなり、強調されることになります。 127というのはマジックナンバーで、おそらくこれはX68000の256x256という画面モードを使っているのでしょう。つまり画面の中心座標は(127,127)なわけです。 さて、当然ですがこれを素直に実装するとさすがの最新鋭CPUであるPentiumIIでも、画面がでてくるまでに数秒かかる場合があり、とても実用に耐えません。そこである疑念が生まれました。「果たして放射ブラーというのはここまで実直に計算しているのだろうか」と。 というのも、実直に計算すればするほど墓穴を掘るだけで、とても駄目です。さらにFinalRealityなどでは中心を左右にゆらしていかにも後ろから光があたっているような効果を出しています。 左右にゆらすということは、静的な計算もフェイクも事実上使えないわけで、これにはどう対処すべきだろうか真剣に考えてみました。 すると、おかしなことに気づいたのです。 FinalRealityのタイトル部分はいきなりブラーがかかるのではなく、少しじわっと出てきます。つまり厳密な計算でいえば放射ブラーとは違うわけです。 そこで考えたのが、毎回まじめに計算するのをやめて、セル・オートマトンのように前回の結果(状態)を利用する方法です。 まず、先の式を分解してテーブルを作りました。といっても、640x480のテーブルを作ったら爆発的なことになってしまいますしあまりにも頭が悪いので式の性質に着目し、X用のテーブルとY用のテーブルをわけてつくることにしました。
右はテーブルをつくっている部分の抜粋です。 X軸用のテーブルとY軸用のテーブルを別に用意していますが、これは中心とする座標がxとyで違うためです。完全な正方形画面ならば同じテーブルが使えます。 これらのテーブルはサンプリング点の座標を求めるものです。これで余分な計算はなくなり、ただのぼかしと同じことになります。ここでは念のためにひとつの点について32個もサンプリング点を計算していますが、実際につかっているのは最大で4つの点です。まぁ試行錯誤の跡ということです。 0から1024まで変化させて計算しているのは、あとで中心を左右に振るためです。また、2の累乗にしておくと二次元配列のアドレス計算が簡略化できて高速になるためでもあります。 中央を左右にふり、アニメーションさせるにはテーブルをつくりなおすのではなく、それぞれの点について適用するテーブルのインデックスにゲタをはかせます。 実際の計算ルーチンではこのテーブルから適当な点を選んで加算し、平均をとっているだけです。他の部分ではフィードバック処理などをしていますがDirectDrawの機能を使っているだけなので省略します。 また、ごらんのように計算を中央部からやるかそれとも外周部からやるかによって計算結果が著しくかわります(フィードバックするからです)。これは本来、二つの計算バッファを用意して毎回切り替えるのですが、今回はそれを嫌って中央部から外苑部にむけて計算を行うように二つのループを作っています。 詳しくはソースコードをごらんください。 いやぁ、なかなか奥が深かったですね。仕事の合間につくっていたのですが、作り上げるのに半日も費やしてしまいました。他にやることがあるだろーに(^^; |
|