Gポイントポイ活 Amazon Yahoo 楽天

無料ホームページ 楽天モバイル[UNLIMITが今なら1円] 海外格安航空券 海外旅行保険が無料!

log

2012.05.20 C++:コーネルの箱

ファイル 398-1.jpg

GI計算周りの実装がいい加減だったようなので、コーネルボックス(のようなもの)に
シーンを変更してGIを修正させてみました。

フォトンマップは利用していないですが、MCRTの精度次第ではコースティクスも若干
表現できるということが分かりました。もう少し精度を上げようと思ったらMLT(Metro
polis light transport)当たりに改良するのもいいかもしれません。ただ、とりあえず
レイトレースはこの辺にしておこうとおもいます(見当しているのはオクルージョンマップ
生成用プログラムくらいです)。

Metropolis…で何故か思い出しましたが(関係ないです苦笑;)宇宙兄弟面白いです。
つい先ほどアニメを見て、やっぱり宇宙を題材にした作品って外れが少ないなぁと
感じました。後はサバイバル物。とりあえずですが自分が好きな宇宙ものとサバイバル
ものを以下に紹介してみたいと思います。

・ふたつのスピカ:宇宙ものの漫画。しっとりとした超名作だと思います。
・プラネテス:宇宙もの漫画。スペースデブリはこれで覚えました笑;アニメ版良いです。
・無人惑星サヴァイヴ:宇宙もの兼サバイバルアニメ。子供たちが過酷な無人惑星を
 生き抜くために知恵と勇気を発揮する処が素晴らしいです。
・サバイバル:ご存知さいとうたかを先生の漫画。ストイックすぎるサバイバル漫画。
・キャスト・アウェイ:ご存知トムハンクス主演のサバイバル映画。ウィルソーーン笑。
・漂流教室:楳図かずお先生のサバイバル兼SF漫画。非条理さがとても怖い漫画です。
・蠅の王:サバイバル小説。アニメ「無限のリヴァイアス」の原作のようなもの。おそらく
 サバイバルや漂流教室等の多作品にも影響を与えていそうな名作。

パッと思いつく限りではこんなところです。共通点はいずれも、過酷な環境を人間が切り
開いていくという点でしょうか。これらは全て自分が大好きな作品なので、宇宙兄弟にも
やはり期待しています。アニメ、どこまで放送するんだろうなあ。

2012.05.17 C++:テクスチャサンプリング

ファイル 397-1.jpgファイル 397-2.jpg

今度はテクスチャサンプリングを実装してみました。今回は、、特に解説するようなことは
ありません笑。余所様のサンプルコードを順に追ってるだけの簡単な作業です。

なんとなく、LWで色々四苦八苦してレンダリングするより自分でコーディングしたもので
レンダリングした方が、直感的に修正できて早くレンダリング出来そうかなという気が
しました(…いや、どうかなあ)。

それと、「テクスチャ」って思えば変な響きの単語だなとふと思ったので名前の由来に
ついて調べてみましたが、元々は音楽用語ということらしいです。今じゃもっぱらCG用語
っていう感じですが。言葉の意味が少しずつ変化して、元々の意味と正反対になった
言葉が日本語にもいくつかありますが、不思議といえば不思議だなあと思いました。

追記:
ついでにフォグも実装してみました。

2012.05.15 C++:Global Illumination

ファイル 396-1.jpg

前回の続きでGlobal Illumination(GI)を導入してみました。おそらくGIって何なのか
CGを扱っている人でもあまり詳しくない人も多い気がするので、ちょっと紹介してみたい
と思います(いつもながら、間違っている可能性があることも含めてご覧ください)。

GIというのはオブジェクトに当たった光が拡散して周囲のオブジェクトを照らす現象
のことです。これ位ならCGをやっている人の多くは分かっていることだと思います。
それではGIの計算方法について。オフラインレンダラで実装されているGI計算は
大きく2種類に分かれます。視点側から調べるモンテカルロレイトレーシング(MCRT)と
光源側から調べるフォトンマッピング法の2つです。モンテカルロレイトレーシングは
レイトレース計算内でGIを計算します。視点(スクリーンの各ピクセル)からレイを飛ばし
てオブジェクトと衝突した場合、レイトレーシングでは反射ベクトル方向や屈折ベクトル
方向に更にレイを飛ばして再帰的に色を求めますが、モンテカルロレイトレーシングでは
それだけでなく衝突点の法線方向付近に大量のランダムなレイを飛ばして再帰的にGI
色の計算も行います。はい、それだけです笑。つまり簡単にいうと複数方向に反射色を
求めてそれらの平均色をGI色としているということです。ちなみに上の画像ではこの方法
でGIを実装しています。画像クリックで拡大表示すると分かりますが、表面がざらついて
ます。これはランダムにレイをとばしているのでGI色が隣同士で大きく異なるためです。

で、この方法だと集光(コースティクス)が表現できません(しづらいです)。何故か?
そもそも集光という現象は光が透過物内を通過して光が屈折し、複数のレイが1点に
集まることによる現象ですが、モンテカルロレイトレーシングでは周囲に均等にレイを
飛ばすため、レイが集光側に飛ぶ密度が薄くなるためです。そこでこれ考慮したのが
フォトンマッピング法というやつです。フォトンマッピング法では光源側からレイを飛ばす
ので透過物を通過すると光がちゃんと偏って集光が表現できます(まだ実装していない
ので憶測ですが;)。ただこれだと視点方向以外にレイが飛んでしまい、それらのレイの
計算は実質無駄なので、単純にモンテカルロレイトレーシングと同じ数だけレイを飛ば
した場合、フォトンマッピング法の方が精度が落ちるはずだと思います。なので、まずは
モンテカルロレイトレーシングでGIを計算し、透過物が存在する場合は透過物方向に
光源側からレイを飛ばしてフォトンマッピング法で集光情報となるフォトンマップを計算し、
モンテカルロレイトレーシングによるバッファと合成するというのが一般的だと思います
(おそらくですが、双方向レイトレーシングとはこの手法を指しているんだと思います)。

他にもモンテカルロレイトレーシングを高速化したり改良したりするものがいくつかあります
が、ザックリと説明するとこんなところです(長くなりました笑)。

それにしても、こんな画像だとこの日誌を見た人に「3Dソフトでレンダリングすれば
それまでじゃん」と思われていそうですね。願わくば、3Dソフトではまだ出来ていない様な
ことがやれたらいいなと考えているのですが、、なんとも夢見がちな話だな苦笑。

2012.05.15 C++:レイトレース

ファイル 395-1.jpg

今回はflipcode様やt-pot様のサイト等を参考にしつつ、CPUによるレイトレースの
プログラムを組んでみました。とりあえず実装できているものを以下にまとめてみます。
・ディフューズ・スペキュラ
・反射・屈折
・アンビエントオクルージョン
・シャドウ
・背景グラデーション
・SuperSamplingによるアンチエイリアス

まだ2次拡散光やコースティクスが実装できていないし、球と平面、ボックスといった
プリミティブでしかレイトレース出来ないのでまだまだ基礎の基礎といった感じです
(それでもレイトレース部分の実装は結構複雑ですが…)。
制作の中の一部分にだけレイトレ計算できないかなぁと考えたりしているのですが、
出来たとしても当分先の話になりそうだ笑。

2012.05.14 C++:ぷちアップデート


前回実装したシャドウマップの改良やクロスシミュレーション等の実装をしてみました。
実装内容については以下のような感じです。
・HWシャドウマップ+PCF
・CPUによるクロスシミュレーション
・万有引力の法則によるパーティクル運動

前回のシャドウマップでは影がガタガタだったので、PCFで影を滑らかにしています。
PCFというのはシャドウマップのサンプリング時に周囲のピクセルからもサンプリング
することで影をぼかすテクニックのことで、実は前回の画像でも微妙にPCFを使って
たりする(4回サンプリング)のですが、今回はサンプリング数を8回に増やしてみました。
それとシャドウマップテクスチャのフィルタがPOINTになっていたのでLINEARに変更
することでボケ具合をほんのり上げられるようになりました。

さて、今度はクロスについてですが。これはまだまだ課題が多いです。実装方法として
は最も一般的なバネ・ダンパモデルで実装しましたが、これは"頂点単位にまず移動
計算を行い、隣接頂点との距離が伸びたり縮んだりしている場合は戻す方向に外力
を加える"という、布が伸びることが前提の実装方法なのでどうしても布が伸びる問題
が起こってしまいます。さらに布を細かくしたりして頂点間隔が変化すると外力の
大きさも変化してしまうという問題もあったりします。
クロスシミュは「風ノ旅ビト」の影響で、自分でどこまで出来るかなといった感じで試し
てみたのですが。。パラメータがちょっと大きすぎたりするだけで布が爆発したり、
汎用的な実装はかなり難しいということが分かりました。動画でもフレームレートが
30FPSを若干下回る時がありますが、これはクロスシミュが概ねの原因です。
また、クロスはデルタ時間が大きすぎると布が爆発してしまうのでFPSが下がっても
デルタ時間を上げないように設定しているのですが、これが原因でFPS低下時に
布がゆっくり移動してしまう現象が動画で見られます。本当はソフトボディ辺りも挑戦
したいところなのですが、、さてどうしたもんか。

後、最後の万有引力についてはお遊びで実装してみました笑。

それと話が変わりますが。先月当たりに普及したS.M.A.R.Tウイルスという奴に感
自分のPCが感染してしまいました。感染当初はVCを開きながら衝突判定のサイトや
ブログを巡っていただけなのですが。どうもブログ経由から感染したりするようです。
更にWindows7のアップデートを怠っているPCにのみ感染するということなので、、
最近アップデートをしていないそこのあなた!是非是非アップデートしましょう。

ちなみに感染した時は勝手に再起動してファイルが画面から全て消えます。自分はこれ
で「えっ!?バックアップとってないのにデータ消えたっ!?」とかなり焦りました;ただ実際は
ファイルが全て隠しファイルになっているだけなので、もし感染してもHDDを初期化
せず、ネット上の解決策なりを読んで復活させることをお勧めすます。
ほんと…ウィルス怖いなぁ。

2012.04.23 C++:シャドウマップことはじめ

ファイル 393-2.jpg

これまでは影の表現は頂点カラーによる位置によるモデルの明度調節と丸影で表現
させていましたが、セルフシャドウにも挑戦したいなと思ったのでシャドウマップを実装
してみることにしました。

シャドウマップはカラーバッファに深度値を格納するタイプが現在は一般的な感じ(?)
ですが、深度バッファをそのまま利用するハードウェアシャドウマップというのがあるので、
今回はそちらを実装してみました。ちなみになぜこちらを選んだかというと、カラーバッファ
を描画しなくて済む上に倍速深度レンダリングが期待できるので、前者よりも高速な描画
が期待できると思ったためだったりします。

ここで、「へぇ、こんな方法があるなら遅延レンダリングでも深度バッファを描画せずに
済むね」と思う方もいるでしょう。何せ自分がそうでしたから笑;結論からいうと遅延レン
ダリングで深度バッファを用いてサンプリングするのはDirectX9(というより昨今のGPU)
では不可能です。サンプリング自体は可能ですが、サンプリング時に0か1の値を返す
というよくわからない仕様になっているので遅延レンダリングには利用できない、という訳
です。まぁシャドウマップの場合はシャドウマップより深度が上(1)か下(0)かが分かれば
いいため、シャドウマップ用に設けられているんだろうなと思いました。

そして肝心の速度ですが。セルフシャドウの生成はエフェクトの中でもかなり重い部類
なので、古いPCだとさすがに処理落ちするだろうなと思っていましたが。なんと、古いXP
のPCでも800x600の解像度で30FPSが常時キープ出来たので期待以上の出来栄え
でした(まぁシャドウマップの生成はキャラだけで背景は描画してませんが;)。まだ影が
ガタガタしていて課題も残りますが、何より処理落ちしていないことが嬉しかったりします。

2012.04.18 C++:ボクセルのテクスチャ

ファイル 392-1.jpgファイル 392-2.jpg

ボクセルにテクスチャを適応させてみました。頂点バッファにUVを持たせるだけだった
のですぐに実装できましたが、ボクセルが他のモデルとなじんで見栄えが断然よくなり
ました。ちなみにテクスチャはちゃちゃっと確認するためにMineCraftの以下のMod
パックをお借りしましたが、MineCraft以外で使用してよいとも駄目と記載されていない
微妙な感じなので、以降は自作のテクスチャを用意しようと思います。

・上の画像:PainterlyPack
・下の画像:Eldpack

それとたまたま誤作動をさせて気が付いたことがあったのでメモ。D3DVERTEXELE
MENT9で頂点デクラレーションを定義した場合、オフセットバイトを指定して各変数の
場所(?)をGPUに伝える訳ですが、自分の環境ではメモリ領域が重複している場合でも
普通に実行されることが分かりました。てっきりCreateVertexDeclaration()のところで
作成に失敗するとばかり思ってましたが、GPUにそのまま渡されるようです。ちょっと面白い
感じですが渡った場合の動作は未定義だろうし、やはり使用しない方が無難かな。

2012.04.17 お気に入り:ボリュームテクスチャを利用したAO

西川善司さんの記事に興味深いものを見つけたのを思い出したのでちょっとメモ。
アンビエントオクルージョンをSSAOではなくボリュームテクスチャを用いて実装するという
手法。実はこの方法は自分がSSAOを実装するよりも前から思いついていた手法で、
それなりに高速なAOが期待できそうだと思っていのですが、自分が考えた方法はシーン
全体のAO情報を1つのボリュームテクスチャで格納するというVRAM容量的にかなり無謀
な考えな上に、「テクスチャに元のモデルのAOを計算した場合、モデルが真っ黒になる
だろこれは…」と思ってすぐに実装するのをやめたのでした。

で、この記事を読み「黒くなる?なら1ピクセル分先でサンプリングすりゃいいじゃん」という
発想を読んで、その手があったかぁと感心してしまいました。ちょっと考えれば気づきそうな
感じだと思いますが、当時はすぐにSSAOに移行してしまいましたからね。VRAMの問題
を克服するためにモデルごとに小さいサイズのボリュームテクスチャを使用するというのも
自分にとっては斬新でした。ほんと、こういう柔軟な発想ができるようになりたいものです。

2012.04.17 C++:ボクセルの頂点ライティング


ボクセルのライティングを面単位から頂点単位に変更してみました。頂点単位のライティ
ングの実装部分は面単位のライティング強度から隣接情報を取得しているだけなので
理論的にはすごく簡単なのですが、「隣接ブロックがあるかどうか調べ、ある場合は隣接
ブロックの面の先のブロックを調べ、、」といった感じで条件分岐が結構多くなってしまい
ました。まぁ、ライティングの再計算の実装部分も必要最小限のブロックだけを再計算する
ように設定したので速度的には全然問題無いですが、コードがごちゃごちゃして見づらく
なってきたのが少し厄介だなあと思いました。
後はライティングの他に遮蔽計算を実装したり、キャラクターの位置のブロックのライティ
ング強度を取得してそれに合わせてキャラクターを暗くしたりしてみました。

面単位の計算についても、以前説明した平均サンプリングの実装を変更して、明度が0の
ブロックの隣に明度0以外のブロックがある場合はそれらのブロックの内最も明るいブロッ
クの明るさ-2の明るさになるように設してみました。ちなみに-1でもいいののですが、-1
だと遠くまで光が届きすぎる感じだったので-2に設定しています。とりあえずこれでかなり
MineCraftっぽい見た目になったので、次はテクスチャを貼ろうと思います。

そういえば、ずっと前の話になりますが。他所様のブログで「ミップマップを使わないと
テクスチャのサンプリング数が多くなるので重くなる」的な発言を(確か)したことを思い
出しましたが、、今振り返ってみると嘘をついています;自分の日誌でもこの情報の信憑
性はありませんとか、正確にあっているかどうかは分かりませんとか書いているので、
「あぁ、この人いい加減なこと言ってんなぁ」って思われた方も多いでしょうね。申し訳ない
です。ブログ先で訂正を述べてもいいのですが、何せかなり前の記事ですからね;
とりあえず、もやもやした感じになりそうだったのでここで述べておきました。

ちなみにどこがどう違うのかというと、シェーダのピクセルからその位置に相当するテク
スチャのピクセルをサンプリングする訳ですから、サンプリング数は多くなるはずはありま
せん。けれどミップマップを使わずに遠景のテクスチャに巨大サイズのものを使うと重くなり
ます、何故か?これはGPUにもCPUと同じようにキャッシュというものが(おそらくブロック
単位で、あくまでおそらくです苦笑)かグリッドだか分かりませんが(苦笑)存在していて、
定数用メモリとテクスチャメモリはキャッシュされる可能性があり、サイズが小さい分
キャッシュに格納されている可能性が高くなるため速度が変わる、というのが正解だと
思われます。メモリとキャッシュの速度差はだいたい100倍程度らしいですがもちろん自分
は詳しくないので断言しません。GPUの設計者でも無ければ、この先GPUの設計も自分
が言ったような設計に変わるなんてことも十分考えられますからね笑。

以前から、頂点バッファにデータを格納してアクセスするよりグローバル変数に格納して
アクセスすると重くなるなということに気づいていましたが。これもそれが原因だろうと
思われます。まぁ、他人のソースコードとか見ると前者の方法をとっている人が多いので
知っている人多いんだろうなと思ってメモしてませんでしたが。

さて、この日誌ではなるべく間違った情報を流さないようにはしていますが、絶対に正しい
とは言い切れるものではないので。間違っていた場合はもやもやするのでその都度訂正
したいなと改めて思いました。

2012.04.15 C++:ボクセルのライティング

ファイル 389-1.jpg

今回はボクセルのブロックを面単位でライティングするようにしてみました。まだ未完成な
ところが多いですが、ライティングの実装方法については以下の手順で実装させています。

・まず始めに全ブロックの空間ライティング度合いを初期化する。ブロックが存在する場合は
0、ブロックが存在しない場合は最大値(15)で初期化する。
・自身のブロックの隣接5ブロックの空間ライティング値を取得して平均サンプリング・・・(a)。
 cf.上からライトを照射することを想定しているので下ブロックはサンプリングしない。
・(a)の処理を光が伝わる最大ブロック数n(ここでは16)だけ繰り返す。
・各面のライティング度合いはその面の先のブロックの空間ライティング値となる。

こんな感じです。で、これでMineCraftっぽくなるかなぁと試してみましたが、、画像の感じ
になってしまいました。遮蔽している感じはでているため決して悪くはないですが、Mine
Craftでは太陽光が直接伝わるブロックの横のブロックは明るくなるはず(分かりやすく
いうと、マリオの側面は画像より明るくなるはず)なので、このアルゴリズムだとまだ
未完成という訳です。…さて、それよりも問題なのがライティング計算にかかる時間です。

上の計算だと(a)の部分を16回繰り返していますが、(a)の部分は現在500*20*500
ブロック分計算しているため全部で500*20*500*16=80,000,000ブロック分CPUで
計算していることになります。なのでブロック情報を更新すると2秒程度画面が固まる
ようになってしまいました苦笑;重すぎっ!

変更させる周辺だけ情報を更新するようにすれば高速化できるようになりますが。
さてさて、これからどうアルゴリズムを改良しようかな。。