2016-07-18 8 views
0

私はレイトレーサを実行しており、現在の光線方向を計算するために、x軸とy軸の現在のピクセル値を使用して、開始される光線の位置を計算する遠近法補正を実装しました。 ここでは、コード片:新しいコードがレイトレーストレーサを遅くする理由は何ですか?

float fov = 60; 
float invWidth = 1/float(image.getWidth()); 
float invHeight = 1/float(image.getHeight()); 
float angle = (fov * M_PI * 0.5/180); 
float aspectratio = image.getWidth()/float(image.getHeight()); 
point camera = scene.getCamera(); 
for (int y=0; y<image.getHeight(); y++) { 
    for (int x=0; x<image.getWidth(); x++) { 
    ...... 
    ...... 
    float xx = (((x*invWidth) *2)-1) * angle * aspectratio; 
    float yy = (((y*invHeight)*2)-1) * angle; 
    Ray viewRay = { {camera.x, camera.y, camera.z}, {xx, yy, 1.0f}}; 

これまでのところ、とても良いそれが完璧に動作します。しかし、xxとyy(ピクセルの方向)の値はすべてのピクセルで計算する必要はなく、イメージの幅と長さに等しい数の2倍に過ぎないことに気付きました。 だから、このようにこれらの部分を書き直し:

float fov = 60; 
float invWidth = 1/float(image.getWidth()); 
float invHeight = 1/float(image.getHeight()); 
float angle = (fov * M_PI * 0.5/180); 
float aspectratio = image.getWidth()/float(image.getHeight()); 
float rays_x [image.getWidth()], rays_y [image.getHeight()]; 
for (int y=0; y<image.getHeight(); y++) 
    rays_y [y] = (((y*invHeight)*2)-1) * angle; 
for (int x=0; x<image.getWidth(); x++) 
    rays_x [x] = (((x*invWidth) *2)-1) * angle * aspectratio; 
point camera = scene.getCamera(); 
for (int y=0; y<image.getHeight(); y++) { 
    float yy = rays_y[y]; 
    for (int x=0; x<image.getWidth(); x++) { 
    ...... 
    ...... 
    Ray viewRay = { {camera.x, camera.y, camera.z}, {rays_x[x], yy, 1.0f}}; 

私は基本的に光線の方向を予め計算し、アレイにそれらを記憶します。私はパフォーマンスのわずかな改善を期待しました。悲観的なケースでは何もなかったかもしれませんが、WORSTになることは決して予想されませんでした。 シーンをレンダリングする前に私は1.67を撮っていましたが、今は1.74です!大規模な落下ではなく、私が今より多くの仕事を減らすことを期待しているのを見て驚くべきことです。私はコンパイラの最適化(-O3と-Fast-Math)を無効にし、2つのアプローチでテストしました。 9.03から9.05になる前に、今は9.06から9.15になります。

どうすれば問題を調査する必要がありますか?私は、1024×4 = 4096 +(768 * 1024)しかないので、私は決してそれを疑うことはできませんが、レイ・イテレーションとrays_y [y] 4)= 7168バイトとなる。任意のアイデアをいただければ幸いです。

float yy = (((y*invHeight)*2)-1) * angle; 

定数データである、とだけループごとに一度に計算する必要があります

+0

私の回答は役に立ちましたか?パフォーマンスはどのようになっていますか?それ以上の助けが必要ですか? –

+0

正しい方法で実装しているかどうかは分かりませんが、ループ外の変数を初期化することもできます: 'float xx、xxstart = -angle * aspectratio、yy = -angle、xstep = angle * aspectratio * 2 * invwidth 、ystep = angle * 2 * invheight; 'そして、ループ内の値を更新する:' xx = xxstart; ... yy + = ystep; ... xx + = xstep; '。 –

答えて

0

コンパイラは、この1つはことを理解するであろう。

したがって、事前計算されたyyはパフォーマンスの浪費です。 (アスペクト比すなわちinvWidth * 2角度*)

事前計算済みxxはしかし助けることができるが、式は多くの定数データをconstains場合性能は、キャッシュミスに増加しないことがあり、さらに悪いことがあります。

float xx = (((x*invWidth) *2)-1) * angle * aspectratio; 
0

方向を事前に計算すると、トレーサーが加速します。しかし、明らかに最初にルックアップテーブルを作成するオーバーヘッドがあります。あなたのコードでは、スタック上にテーブルを作成し、すべてのフレームの方向を再計算します。以前はやっていなかった配列から読み込む必要があり、メモリ割り当てのオーバーヘッドがあるため、これはやや遅くなります。代わりにヒープ(メソッドの外側のポインタとして)にルックアップ配列を作成し、方向を1回だけ事前計算することをお勧めします。 方向はフレーム間で変更されない値に依存するため、フレームごとに方向を計算する必要はありません。

このような何か:

float *rays_x, *rays_y; 

void compute_directions() 
{ 
    rays_x = new float[image.getWidth()]; 
    rays_y = new float[image.getHeight()]; 
    for (int y=0; y<image.getHeight(); y++) 
     rays_y[y] = (((y*invHeight)*2)-1) * angle; 
    for (int x=0; x<image.getWidth(); x++) 
     rays_x[x] = (((x*invWidth) *2)-1) * angle * aspectratio; 
} 

void render() 
{ 
    float fov = 60; 
    float invWidth = 1/float(image.getWidth()); 
    float invHeight = 1/float(image.getHeight()); 
    float angle = (fov * M_PI * 0.5/180); 
    float aspectratio = image.getWidth()/float(image.getHeight()); 
    point camera = scene.getCamera(); 
    for (int y=0; y<image.getHeight(); y++) { 
    float yy = rays_y[y]; 
    for (int x=0; x<image.getWidth(); x++) { 
     ...... 
     ...... 

あなたは明らかにあなたがcompute_directionsでそれらにアクセスできるように、どこか別の場所に角度やアスペクト比を移動する必要があります。 memoroyの漏れを防ぐためにもう必要がない場合は、delete []を使用してポインタを削除することを忘れないでください。

+0

スタック上のメモリ割り当てのオーバーヘッドはごくわずかですが、スタックポインタを動かすだけです。とにかくこれが起こっている可能性があります。ちょうど別の番号である可能性があります。 –

+0

@Colin__s True、少し答えを修正しました... –

0

あなたの説明から判断すると、それはあなたの任意のパフォーマンスの向上が得られないかもしれないいくつかのメモリ検索に計算をシフト(非常に高速に計算されているように見えるいくつかの値を事前計算することにより、勘にを最適化だ - また、これはありますハンク!)。

最適化に関するいくつかの基本的なルール:プロフィール:

  • 何を最適化しようとする前に。
  • 何かを最適化した後:profile。

プログラムの実際の所要時間を知る前に、最適化によるパフォーマンスの向上は期待できません。

Linuxの場合、GCCs -pg switch and gprofを使用できます。 perfvalgrindを使用することもできます(たとえば、callgrindを使用して特定の関数の呼び出し数を知ることができます)。

perf wikiもチェックしてください。

関連する問題