26

ビューポート(私の場合はDirectXシーン)内にバウンディングボックスを収めるアルゴリズムを探しています。正投影カメラでバウンディング球を中心に配置するためのアルゴリズムについては知っていますが、バウンディングボックスと遠近法カメラでも同じことが必要になります。このアプリはユーザーが編集可能な変数としてFOVを持っているため、FOVを変更することはできません。そのため、カメラを移動する必要があります。

私はほとんどのデータを持っています:

  • カメラのアップベクトルがあります
  • バウンディングボックスの中心点があります
  • カメラポイントからボックスの中心までのルックアットベクトル(方向と距離)があります
  • カメラに垂直な平面にポイントを投影し、最大/最小のX座標とY座標が表示平面の内側または外側にあることを表す係数を取得しました。

私が抱えている問題:

  • バウンディングボックスの中心は、必ずしもビューポートの中心にあるとは限りません(つまり、投影後のバウンディング長方形です)。
  • 視野が投影を「歪める」ので(http://en.wikipedia.org/wiki/File:Perspective-foreshortening.svgを参照)、カメラを動かすためのスケールファクターとして係数を単純に使用することはできません。これは、オーバーシュートするためです。 /目的のカメラ位置をアンダーシュートします

ビューポートを可能な限り完全なピクセルで満たすようにカメラの位置を見つけるにはどうすればよいですか(アスペクト比が1.0から遠く離れている場合を除き、画面軸の1つを埋めるだけで済みます)。

私は他のいくつかのことを試しました:

  • バウンディング球と接線を使用して、カメラを移動するための倍率を見つけます。これはうまく機能しません。なぜなら、透視投影が考慮されていないためです。次に、平面と長いジオメトリがたくさんあるため、球は私の使用には不適切なバウンディングボリュームです。
  • 関数の呼び出しを繰り返して、カメラの位置のエラーをどんどん小さくしていきます。これはある程度機能しましたが、カメラの位置がオーバーシュートしすぎてエラー係数が増加するという奇妙なエッジケースに遭遇することがあります。また、これを行うとき、外接する長方形の位置に基づいてモデルを再センタリングしませんでした。それを確実に行うための確実で堅牢な方法を見つけることができませんでした。

助けてください!

4

7 に答える 7

37

バウンディング ボックスが視錐台の内側に収まる可能性のあるカメラの位置と方向は多数あります。ただし、どの手順でも、特定のカメラの位置と向きを 1 つ選択します。

球体の境界検討する場合、1 つの解決策は次のようになります。

  • まず、境界球の中心を見るように方向を変更します
  • 次に、境界球が錐台の内側に収まるように十分に後方に移動します (負の視線方向)。

バウンディング ボックスを使用すると、最初にカメラを最大 (または任意の最小) キューブ面の中心に垂直に配置するという初期のステップを考慮することができます。

私は DirectX の経験はありませんが、カメラの視線方向を特定のポイントの中心に移動および変更するのは簡単なはずです。難しいのは、オブジェクトを表示するために移動する距離を決定する計算を行うことです。

算数

カメラの向きからワールド座標でオブジェクトの境界サイズがわかっている場合s(ピクセルやカメラ座標は距離に依存するため、ピクセルやカメラ座標には関心がありません) d、カメラから境界までの必要な距離を計算できます。a透視投影の x および y フィールド オブ ビュー角度がわかっている場合は形状。

     frustum      ------            
            ------    *****          -  
       -----          *   *          |
   -===     ) FOV a   *bounding box  | BB size s
camera -----          *   *          |
            ------    *****          -
                  ------
  
  |-------------------|
        distance d

したがって、数学tan(a/2) = (s/2) / d=>d = (s/2) / tan(a/2) これにより、最も近い境界面からカメラを配置する必要がある距離が得られます。

于 2010-05-19T14:34:11.073 に答える
6

境界ボックスがあるので、その向きを説明する基準が必要です。ボックスの最小次元を表す基底ベクトルと一致する線上にカメラを配置し、最大次元が水平になるようにカメラを回転させたいようです (AABB ではなく OBB があると仮定します)。これは、アスペクト比が 1.0 より大きいことを前提としています。そうでない場合は、垂直寸法を使用することをお勧めします。

私が試みること:

  1. ボックスの最小寸法を見つけます。
  2. 関連する基底ベクトルを見つけます。
  3. カメラがあるべきボックスの中心からの距離によって基底ベクトルをスケーリングします。この距離はちょうどboxWidth / (2 * tan(horizontalFov / 2)). boxWidthボックスの最大寸法の幅であることに注意してください。
  4. boxCenter + scaledBasisを見てカメラを配置しboxCenterます。
  5. 必要に応じてカメラを回転させ、カメラのアップ ベクトルを適切なボックス基準ベクトルに合わせます。

編集:

つまり、あなたが得ているのは、どこかを見ている任意の位置にカメラがあり、別の位置に AABB があるということだと思います。カメラをボックスの側面に向けずに、次のことを行います。

  • 箱の真ん中を見てください
  • ボックスが最大量のスクリーン スペースを占めるように、カメラをルック ベクトルに沿って移動します。

この場合は、もう少し作業が必要です。ここに私が提案するものがあります:

  1. カメラを回転させて、バウンディング ボックスの中心を見ます。
  2. ボックスのすべてのポイントをスクリーン スペースに投影し、スクリーン スペースで最小/最大バウンディング ボックスを見つけます (これは既にあります)。
  3. Unprojectこれで、スクリーン スペース バウンディング ボックスの向かい合う 2 つのコーナーがワールド スペースになります。Z 値には、AABB のカメラに最も近いワールド空間ポイントを使用します。
  4. これにより、カメラに最も近い AABB 上のポイントに配置された、カメラに面するワールド空間プレーンが得られます。
  5. 次に、既存の横向きの方法を使用して、カメラを適切な場所に移動し、この面をボックスの側面として扱います。
于 2010-05-19T14:45:14.400 に答える
1

これは私のエンジンから直接コピーされたもので、錐台の 6 つの側面のそれぞれを表す 6 つの平面を作成します。役に立つことを願っています。

internal class BoundingFrustum
    {
        private readonly float4x4 matrix = new float4x4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
        private readonly Plane[] planes;

        internal BoundingFrustum(float4x4 value)
        {
            planes = new Plane[6];
            for (int i = 0; i < 6; i++)
                planes[i] = new Plane();
            Setfloat4x4(value);
        }

        private void Setfloat4x4(float4x4 value)
        {
            planes[2].Normal.X = -value.M14 - value.M11;
            planes[2].Normal.Y = -value.M24 - value.M21;
            planes[2].Normal.Z = -value.M34 - value.M31;
            planes[2].D = -value.M44 - value.M41;
            planes[3].Normal.X = -value.M14 + value.M11;
            planes[3].Normal.Y = -value.M24 + value.M21;
            planes[3].Normal.Z = -value.M34 + value.M31;
            planes[3].D = -value.M44 + value.M41;
            planes[4].Normal.X = -value.M14 + value.M12;
            planes[4].Normal.Y = -value.M24 + value.M22;
            planes[4].Normal.Z = -value.M34 + value.M32;
            planes[4].D = -value.M44 + value.M42;
            planes[5].Normal.X = -value.M14 - value.M12;
            planes[5].Normal.Y = -value.M24 - value.M22;
            planes[5].Normal.Z = -value.M34 - value.M32;
            planes[5].D = -value.M44 - value.M42;
            planes[0].Normal.X = -value.M13;
            planes[0].Normal.Y = -value.M23;
            planes[0].Normal.Z = -value.M33;
            planes[0].D = -value.M43;
            planes[1].Normal.X = -value.M14 + value.M13;
            planes[1].Normal.Y = -value.M24 + value.M23;
            planes[1].Normal.Z = -value.M34 + value.M33;
            planes[1].D = -value.M44 + value.M43;
            for (int i = 0; i < 6; i++)
            {
                float num2 = planes[i].Normal.Length();
                planes[i].Normal = planes[i].Normal / num2;
                planes[i].D /= num2;
            }
        }

        internal Plane Bottom
        {
            get { return planes[5]; }
        }
        internal Plane Far
        {
            get { return planes[1]; }
        }
        internal Plane Left
        {
            get { return planes[2]; }
        }
        internal Plane Near
        {
            get { return planes[0]; }
        }
        internal Plane Right
        {
            get { return planes[3]; }
        }
        internal Plane Top
        {
            get { return planes[4]; }
        }
    }
于 2010-10-10T19:31:20.477 に答える
1

今手元にありませんが、欲しい本はhttp://www.amazon.com/Jim-Blinns-Corner-Graphics-Pipeline/dp/1558603875/ref=ntt_at_ep_dpi_1です

彼はこれに関する章全体を持っています

于 2010-08-03T23:36:30.960 に答える