~下の画像をクリックすると、飛ばすレイの数を指数関数的に増やした場合の変化をアニメーションとして見れます(最初のほうの色がおかしいのはgifの変換のせいです)。藤田さんから「遅っせーよ(意訳)」というコメントをいただきました。いうことで、高速化を少し頑張ろうと思い、拡散反射光に関して光源からの寄与を直接評価する直接照明の技法を取り入れて見ました。今回のプログラムは、次のものです。DirectX9.0c)まぁ、いつものように適当にファイルが入っています。色を統一的に処理する(予定の)ための色クラスあと、実行ファイル、リソースファイル、プロジェクトファイルが入っています。■何やってるの?今回は、拡散反射の評価方法が今までと違います。レイを(反射係数を出力に乗算して)別の方向に飛ばしていました。今回は、拡散反射面にレイがあったら、レイを2つに分岐させます。1つは、光源方向に飛ばし、もうひとつは、今までと同じようにランダムに飛ばします。2つめのレイは直接光源に飛ぶものは無視します。今回のモデルは、光源が3つの3角形からなっています。3角形の何所を目指して飛ぶのかランダムに決定して飛ばします。交差せずに光源に届いたら、光源の寄与を追加します。結果がランダムになるのは半影の部分なので、ほとんどの場所で1発目のレイで寄与が求まります(被写界深度の効果は1発では決まりません)。レイの寄与ですが、立体角の定義が役に立ちます。立体角は、物体を1[m]はなれたところから見たときの面積です。光源の面積を反射面までの距離で割れば、光源が反射面の視界を覆う立体角がわかります(この計算は近似的なものです。曲がった空間への射影を考えなくてはならないので、正確な結果を得るためには、光源の3角形を細かく分割して、それぞれを射影したときの面積を計算するなどしなくてはなりません)。光源のつよさになります。ここで、θは光源へ飛ばしたレイと光源の法線ベクトルのなす角度で、dは反射面から光源上の点までの距離です。V(x,x')は可視関数で、xからx'へレイを飛ばしたときに何もぶつからずに飛べれば1、さえぎられれば0となる関数です。プログラムでは、次のようになっています。これは、今までと同じようにレイを飛ばして、レイが光源に直接あたった場合にその強さを0にします。このフラグがたっているときには、光源にレイがあたったときにその強さを0にします。立っているときには、放射する面(光源)にあたったときに、色を黒で返します。前回の方法のマルチスレッド化ではスレッドを作成するオーバーヘッドがかかるので、ワークパイルの手法を使うほうが良いよと教えていただきました。ワークパイルパターンとは、スレッドを複数常に立ち上げておき、各スレッドでは仕事があるかを常に監視して、仕事あまっていたらその仕事を受けとって処理します。起動されたスレッドのフローチャートを書いてみると、次のようなものでしょうか。終了処理が必要になることを考えて、終了条件が成立していたら終わって、そうでなければ処理をすることにします。終了条件が成立しなければ、仕事があるか調べて、あれば仕事をします。なければ(仕事がないのにCPUを100%消費しないように)少し休みます。これが1ループになって、終了条件が満たされるまで回りつづけます。実際の関数では、ラップしたクラスを作ってます。}あっ、仕事がなくなるまで終了判定をとおらないや。いうのがありますが、こいつは仕事を管理するスレッドの管理人です。仕事を溜め込んで、各スレッドから仕事の要求が着たら、まだ実行されていない仕事を割り当てます。溜め込める仕事の量は、初期化時に指定できるようにしてあります。こちらだと、スレッドに関するオーバーヘッドがほとんど無いので、細かい仕事も割り振れていい感じですね。最終的な結果ができるまでの時間はほとんど変わらないんですよね。他の経路に関しても効率の良い計算方法を考えないと。もどるimagire@gmail.com。