1

学習課題として、単純なボクセル レイキャスターを書こうとしています。これは、物事が正確にどのように機能するかを理解するまで、今のところ純粋に CPU ベースです。

これで、透視投影カメラが世界を移動できるようになり、(ほとんどの場合、調査が必要なアーティファクトを除いて) 透視補正された「世界」の 3 次元ビューをレンダリングできるようになりました。これは基本的に空ですが、スタンフォード バニーのボクセル キューブが含まれています。

だから私はカメラを上下に動かしたり、左右に機銃掃射したり、「前後に歩いたり」できるカメラを持っています。ここに私の問題があります。

スクリーンショット: (1) ボクセルのレイキャスティング中... ...(2) カメラはそのまま... ...(3) 厳密に軸合わせ。

今、私は数日間、ローテーションを機能させようとしています。行列と 3D 回転の背後にある基本的なロジックと理論は、理論的には非常に明確です。それでも、カメラが回転したときに「2.5 レンダリング」しか達成できませんでした... Google ストリートビューのように魚眼のように見えます: 立体的な世界表現を持っていても、何を試しても私のように見えます最初に「正面図」からレンダリングを作成し、次にそのフラット レンダリングをカメラの回転に従って回転させます。言うまでもなく、光線の回転は特に必要ではなく、エラーが発生しやすいことは今ではわかっています。

それでも、可能な限り単純化されたレイキャスト レイの位置と方向のアルゴリズムを使用した最新のセットアップでは、私の回転は依然として同じ魚眼のようなフラット レンダー回転スタイルの外観を生成します。

カメラは「右に 39 度回転しました」 -- スクリーン 2 の立方体の左側の青い影がこの回転では見えないことに注意してください。

もちろん、私はこれを認識しています。最初に持っていたような単純な軸に沿った回転なしのセットアップでは、光線は単純に正の z 方向を小さなステップで横断し、左または右と上に発散します。ピクセル位置と投影行列に応じて、または下のみ。「カメラを右または左に回転させる」(つまり、Y 軸を中心に回転させる) と、まさにそのステップが適切な回転行列によって単純に変換されますよね? したがって、前方トラバーサルの場合、Z ステップはカムが回転するほど少し小さくなり、X ステップの「増加」によって相殺されます。しかし、ピクセル位置ベースの水平 + 垂直発散の場合、x ステップの分数を増やす必要があり、z ステップに「追加」する必要があります。どういうわけか、私が実験した多くのマトリックスのどれも、

これが私の基本的なレイごとの事前トラバーサル アルゴリズムです。Go の構文ですが、疑似コードとして使用します。

  • fxfy : ピクセル位置 x と y
  • rayPos : ワールド空間でのレイ開始位置の vec3 (以下のように計算)
  • rayDir : レイ トラバーサル中に各ステップで rayPos に追加される xyz ステップの vec3
  • rayStep : 一時的な vec3
  • camPos : ワールド空間でのカメラ位置の vec3
  • camRad : ラジアン単位のカメラ回転の vec3
  • pmat : 典型的な透視投影行列

アルゴリズム/擬似コード:

// 1: rayPos is for now "this pixel, as a vector on the view plane in 3d, at The Origin"
rayPos.X, rayPos.Y, rayPos.Z = ((fx / width) - 0.5), ((fy / height) - 0.5), 0

// 2: rotate around Y axis depending on cam rotation. No prob since view plane still at Origin 0,0,0
rayPos.MultMat(num.NewDmat4RotationY(camRad.Y))

// 3: a temp vec3. planeDist is -0.15 or some such -- fov-based dist of view plane from eye and also the non-normalized, "in axis-aligned world" traversal step size "forward into the screen"
rayStep.X, rayStep.Y, rayStep.Z = 0, 0, planeDist

// 4: rotate this too -- 0,zstep should become some meaningful xzstep,xzstep
rayStep.MultMat(num.NewDmat4RotationY(CamRad.Y))

// set up direction vector from still-origin-based-ray-position-off-rotated-view-plane plus rotated-zstep-vector
rayDir.X, rayDir.Y, rayDir.Z = -rayPos.X - me.rayStep.X, -rayPos.Y, rayPos.Z + rayStep.Z

// perspective projection
rayDir.Normalize()
rayDir.MultMat(pmat)

// before traversal, the ray starting position has to be transformed from origin-relative to campos-relative
rayPos.Add(camPos)

私はトラバーサルとサンプリングの部分をスキップしています - 画面#1から#3に従って、それらは「基本的にほとんど正しい」(きれいではありませんが)-軸が整列/回転していない場合。

4

1 に答える 1

4

システムをピンホール カメラとしてイメージすると、はるかに簡単になります。画像を表す長方形の表面から光線を放つ代わりに、点から画像平面となる長方形を通ってシーンに光線を放ちます。すべての一次光線の原点は同じである必要がありますが、方向はわずかに異なります。方向は、通過させたいイメージ プレーン内のピクセルによって、基本的な三角関数を使用して決定されます。最も単純な例を作るために、ポイントがカメラにあり、イメージ プレーンが z 軸に沿って 1 単位、高さと幅が 2 単位であるとします。そうすれば、左上隅のピクセルは (0,0,0) から (-1, -1, 1) に移動する必要があります。(-1、-1、1) を正規化して方向を取得します。(あなたはしません

次に、これが最も重要なことですが、透視投影をしようとしないでください。これは、すべての頂点を画面上のポイントにマップするスキャン変換技術に必要ですが、レイ トレーシングでは、レイは 1 つのポイントから空間に広がるだけでそれを実現します。始点 (カメラの位置、この例では原点) からイメージ プレーンを通る方向は、まさにトレースする必要のある方向です。代わりに正射投影が必要な場合 (これはほとんど必要ありません)、すべての光線の方向を同じにし、開始位置をイメージ プレーン全体で変化させることでこれを実現します。

そうすれば、良い出発点が得られます。次に、光線の方向を計算するために画像平面を反復処理する前に、原点を中心に画像平面を回転させるか、光線の方向を直接回転させることにより、カメラの回転を追加することを再度試みることができます。方向を直接回転させても問題ありません。方向とは、光線が原点から始まる場合に光線が通過する位置にすぎないことを念頭に置くと、方向の回転と光線が通過するポイントの回転がまったく同じことを行うことが簡単にわかります。

于 2012-06-28T21:25:55.957 に答える