2009年12月10日木曜日

リアルタイムレイトレーシング事始め

『Javaではじめるレイトレーシング入門』という面白い書籍を見つけたので、レイトレーシングに挑戦。大まかな仕組みをつかんだところで、C++で書き起こしてみることに。先生にお借りした『CによるCGレイトレーシング』がかなり参考になった。

とりあえず、カメラとスクリーンはワールド空間に固定して、球体を描画。シェーディングはランバートで。画素数は500*500です。



我が家のポンコツマシン(Northwood Celeron 2.4GHz)で実行したところ、Debugで600ミリ秒、Releaseで93ミリ秒というなんとも情けない結果に終わった。FPS換算だと1~10FPSとかちょっと…。というかまだオブジェクト1個だし、屈折とかテクスチャリングとかやってないし!

言い訳すると有り合わせのクラスをパチ組みしただけなので、無駄な呼び出しというか、OOPっぽい書き方になってるのが遅れの原因か。ローカルに作ったワーク変数が、空のコンストラクタを呼び出してたりいろいろ無駄がありそう。

とはいえ、一番の原因はアルゴリズム部分でしょうね。きっとまだ無駄な判定やってるに違いない、今から見なおそう。

TODO:
飽和加算とか。

<追記 2009.12.10@2:10am>
320*240で10fps@Debug, 60fps@Releaseを達成できました。
500*500は3fps@Debug, 13fps@Releaseが今のところ限界…。

ベクトルの正規化がかなり足を引っ張っていたようです。0割防止のため、ノルムが0の時は割り算を行わないという処理をやっていたのですが…。
01Vector3 &Vector3::normalize()
02{
03    float len = x*x+y*y+z*z;//ノルムの平方
04    //以下len = sqrt(len);と同じ
05    __asm{
06        fld len
07        fsqrt
08        fstp len//お行儀が悪いがlenを使いまわす
09    }
10 
11    //0割防止
12    if(len < FLT_EPSILON){
13        x=y=z=0;
14    }
15    else{
16        float denom = 1.f / len;
17        x *= denom;
18        y *= denom;
19        z *= denom;
20    }
21    return *this;
22}
上記のif文の評価式をlen >= EPSILONにして、ブロックを入れ替えた方がジャンプが減る分確率的に速くなる…気がする。てかここでごっそり速くなった。
1if(len >= FLT_EPSILON){
2    float denom = 1.f / len;
3    x *= denom;
4    y *= denom;
5    z *= denom;
6}
7else{
8    x=y=z=0;
9}

0 件のコメント:

コメントを投稿