学習課題として、単純なボクセル レイキャスターを書こうとしています。これは、物事が正確にどのように機能するかを理解するまで、今のところ純粋に CPU ベースです。
これで、透視投影カメラが世界を移動できるようになり、(ほとんどの場合、調査が必要なアーティファクトを除いて) 透視補正された「世界」の 3 次元ビューをレンダリングできるようになりました。これは基本的に空ですが、スタンフォード バニーのボクセル キューブが含まれています。
だから私はカメラを上下に動かしたり、左右に機銃掃射したり、「前後に歩いたり」できるカメラを持っています。ここに私の問題があります。
スクリーンショット: (1) ボクセルのレイキャスティング中... ...(2) カメラはそのまま... ...(3) 厳密に軸合わせ。
今、私は数日間、ローテーションを機能させようとしています。行列と 3D 回転の背後にある基本的なロジックと理論は、理論的には非常に明確です。それでも、カメラが回転したときに「2.5 レンダリング」しか達成できませんでした... Google ストリートビューのように魚眼のように見えます: 立体的な世界表現を持っていても、何を試しても私のように見えます最初に「正面図」からレンダリングを作成し、次にそのフラット レンダリングをカメラの回転に従って回転させます。言うまでもなく、光線の回転は特に必要ではなく、エラーが発生しやすいことは今ではわかっています。
それでも、可能な限り単純化されたレイキャスト レイの位置と方向のアルゴリズムを使用した最新のセットアップでは、私の回転は依然として同じ魚眼のようなフラット レンダー回転スタイルの外観を生成します。
カメラは「右に 39 度回転しました」 -- スクリーン 2 の立方体の左側の青い影がこの回転では見えないことに注意してください。
もちろん、私はこれを認識しています。最初に持っていたような単純な軸に沿った回転なしのセットアップでは、光線は単純に正の z 方向を小さなステップで横断し、左または右と上に発散します。ピクセル位置と投影行列に応じて、または下のみ。「カメラを右または左に回転させる」(つまり、Y 軸を中心に回転させる) と、まさにそのステップが適切な回転行列によって単純に変換されますよね? したがって、前方トラバーサルの場合、Z ステップはカムが回転するほど少し小さくなり、X ステップの「増加」によって相殺されます。しかし、ピクセル位置ベースの水平 + 垂直発散の場合、x ステップの分数を増やす必要があり、z ステップに「追加」する必要があります。どういうわけか、私が実験した多くのマトリックスのどれも、
これが私の基本的なレイごとの事前トラバーサル アルゴリズムです。Go の構文ですが、疑似コードとして使用します。
- fxとfy : ピクセル位置 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に従って、それらは「基本的にほとんど正しい」(きれいではありませんが)-軸が整列/回転していない場合。