TL; DR —私の最初のシンプルなソフトウェアボクセルレイキャスターでは、カメラの回転を機能させることができません。結果は歪んでいます。フラットレンダリングのように、正しく回転しますが、歪みがあり、奥行きがありません。(軸が揃っている、つまり回転していない間、奥行きと視差は予想どおりです)。
簡単なボクセルレイキャスターを学習課題として記述しようとしています。これは純粋にCPUベースで、物事が正確にどのように機能するかを理解するまでは、今のところ、OpenGLは生成されたビットマップをできるだけ頻繁に画面に表示するために(ab)使用されています。
これで、透視投影カメラが世界を移動できるようになり、(ほとんどの場合、調査が必要なアーティファクトを差し引いて)「世界」の透視的に正しい3次元ビューをレンダリングできます。スタンフォードバニーのボクセルキューブが含まれています。
それで、私は上下に移動でき、左右に移動でき、「前方/後方に歩く」ことができるカメラを持っています。これまでのところ、軸はすべて揃っていて、カメラは回転していません。ここに私の問題があります。
スクリーンショット#1:カメラがまだ厳密に軸合わせされている場合の正しい奥行き。回転しない。
今私はローテーションを機能させるために数日間努力してきました。行列と3D回転の背後にある基本的な論理と理論は、理論的には非常に明確です。それでも、カメラが回転したときに「2.5レンダリング」を達成したのは、Googleストリートビューのような魚眼のようなものだけです。ボリュメトリックな世界の表現を持っているにもかかわらず、私が何をしようとも、最初のように見えます「正面図」からレンダリングを作成し、カメラの回転に従ってそのフラットレンダリングを回転させます。言うまでもありませんが、光線を回転させることは特に必要ではなく、エラーが発生しやすいことはわかっています。
それでも、私の最新の設定では、可能な限り最も単純化されたレイキャストレイの位置と方向のアルゴリズムにより、私の回転は同じ魚目状のフラットレンダー回転スタイルの外観を生成します。
スクリーンショット#2:カメラが「39度右に回転」—画面2の立方体の青い影付きの左側がこの回転では見えないことに注目してください。
もちろん、私はこれに気づいています。最初のように単純なaxis-aligned-no-rotation-setupで、光線は単純に正の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のとおり、これらは「基本的にはほぼ正しい」(かなりではありません)—軸合わせ/非回転の場合です。