歪んだ:シンプルなCPUベースのボクセルレイキャスター/レイトレーサーの回転カメラ


7

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のとおり、これらは「基本的にはほぼ正しい」(かなりではありません)—軸合わせ/非回転の場合です。


興味深い...#1と#2の間でスクリーンショットを省略したような印象を受けますが、そうですか?
ユーザーが見つかりません

回答:


2

Go言語での疑似コードは私にとって大きな謎なので、私のアプローチについて説明します:)

まず、遠近法射影行列は必要ありません。現在のビューレイを作成するために必要なのは次のとおりです。

  • カメラの位置
  • カメラアップベクトル
  • カメラはベクトルを見て
  • 画面上の現在のピクセル

私たちの無料のカメラが正しく動作すると仮定しましょう。次に、ベクトルを取り、グラムシュミットプロセスを実行します。これにより、直交カメラの基礎が得られます。でGLSLこのステップは次のようになります。

vec3 cameraW = normalize(cameraPosition - cameraLookAt);
vec3 cameraU = normalize(cross(cameraUp, cameraW));
vec3 cameraV = cross(cameraW, cameraU);

わかりました。この基準は、画面上のすべてのピクセルに共通です。さらに、カメラを移動または回転させるまでは不変です。現在のピクセルのビューレイを計算するには、次の操作を行う必要があります。

vec3 rayOrigin = cameraPosition;
vec3 rayDirection = normalize(p.x * cameraU + p.y * cameraV - cameraViewPlaneDistance * cameraW);

where p—は現在のピクセルの座標です。

この後、ビューレイがあります。レイトレーシングやレイマーチングを行うのに最適な時期です。

フリーカメラに戻りましょう。前方または後方に移動するには、カメラ位置をターゲットベクトルの方向にシフトするだけです。左または右に移動するには、カメラの回転行列から右ベクトルを抽出し、それをターゲットベクトルと位置ベクトルに追加します。

カメラを回転させるには、カメラ回転行列を使用します。最初のカメラ回転行列は単位行列です。ヨー、ピッチ、ロールの3つのフロートがあります。ユーザーがマウスを動かすと、このフロートは回転角度を累積します。更新時には、この回転をカメラの回転行列に適用する必要があります。上軸周りの回転に対応するヨーを取りましょう。まず、回転行列からアップベクトルを抽出してから、新しい回転行列を作成します。結局、カメラの回転行列と新しい行列を乗算します。ここで、glmライブラリを使用するいくつかのC ++コード:

vec3 up(cameraRotation[0][1], cameraRotation[1][1], cameraRotation[2][1]);
cameraRotation *= glm::rotate(mat4(1.0), yaw, up);

お役に立てれば..

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.