ビューポート(私の場合はDirectXシーン)内にバウンディングボックスを収めるアルゴリズムを探しています。正投影カメラでバウンディング球をセンタリングするためのアルゴリズムについては知っていますが、バウンディングボックスとパースペクティブカメラでも同じことが必要になります。このアプリにはユーザーが編集可能な変数としてFOVがあるため、FOVを変更することはできません。そのため、カメラを移動する必要があります。
私はほとんどのデータを持っています:
私が抱えている問題:
ビューポートを可能な限り完全なピクセルで満たすようにカメラの位置を見つけるにはどうすればよいですか(アスペクト比が1.0から遠い場合は例外で、画面軸の1つを埋めるだけで済みます)。
私は他のいくつかのことを試しました:
助けてください!
バウンディングボックスが視錐台の内側に収まる可能性のあるカメラの位置と向きは多数あります。ただし、どのような手順でも、特定のカメラの位置と向きが1つ選択されます。
wouldがバウンディング球を検討する場合、1つの解決策は次のようになります。
バウンディングボックスを使用すると、最初にカメラを最大の(または最小の)立方体の面の中心に垂直に配置する初期のステップを検討できます。 。
DirectXの使用経験はありませんが、カメラの視線方向を移動して特定のポイントを中心に変更するのは簡単です。難しいのは、オブジェクトを表示するためにどこまで移動するかを決定する計算を行うことです。
カメラの向きから世界座標でのオブジェクトの境界サイズs
がわかっている場合(ピクセルやカメラ座標は距離に依存するため、これらには関心がありません)、必要な距離を計算できます。透視投影のxおよびy視野角d
がわかっている場合は、カメラのa
を境界形状に合わせます。
_ frustum ------
------ ***** -
----- * * |
-=== ) FOV a *bounding box | BB size s
camera ----- * * |
------ ***** -
------
|-------------------|
distance d
_
したがって、 math はtan(a/2) = (s/2) / d
=> d = (s/2) / tan(a/2)
です。これにより、最も近い境界面からカメラを配置する距離がわかります。
上記の優れた答えがいくつかあることは知っていますが、カメラの錐台内の境界球に合うように、とてつもなく単純なソリューションを追加したいと思いました。これは、カメラのターゲットとフォワードベクトルを同じに保ち、ターゲットまでのカメラの距離を調整することを前提としています。
注、これは最適ではありませんが、近似フィットが得られ、すべてのジオメトリが数行のコードで表示され、画面から世界への変換は行われません
// Compute camera radius to fit bounding sphere
// Implementation in C#
//
// Given a bounding box around your scene
BoundingBox bounds = new BoundingBox();
// Compute the centre point of the bounding box
// NOTE: The implementation for this is to take the mid-way point between
// two opposing corners of the bounding box
Vector3 center = bounds.Center;
// Find the corner of the bounding box which is maximum distance from the
// centre of the bounding box. Vector3.Distance computes the distance between
// two vectors. Select is just Nice syntactic sugar to loop
// over Corners and find the max distance.
double boundSphereRadius = bounds.Corners.Select(x => Vector3.Distance(x, bounds.Center)).Max();
// Given the camera Field of View in radians
double fov = Math3D.DegToRad(FieldOfView);
// Compute the distance the camera should be to fit the entire bounding sphere
double camDistance = (boundSphereRadius * 2.0) / Math.Tan(fov / 2.0);
// Now, set camera.Target to bounds.Center
// set camera.Radius to camDistance
// Keep current forward vector the same
C#でのBoundingBoxの実装は以下のとおりです。重要なポイントは、CenterプロパティとCornersプロパティです。 Vector3は、3コンポーネント(X、Y、Z)ベクトルのかなり標準的な実装です。
public struct BoundingBox
{
public Vector3 Vec0;
public Vector3 Vec1;
public BoundingBox(Vector3 vec0, Vector3 vec1)
{
Vec0 = vec0;
Vec1 = vec1;
}
public Vector3 Center
{
get { return (Vec0 + Vec1)*0.5; }
}
public IList<Vector3> Corners
{
get
{
Vector3[] corners = new[]
{
new Vector3( Vec0.X, Vec0.Y, Vec0.Z ),
new Vector3( Vec1.X, Vec0.Y, Vec0.Z ),
new Vector3( Vec0.X, Vec1.Y, Vec0.Z ),
new Vector3( Vec0.X, Vec0.Y, Vec1.Z ),
new Vector3( Vec1.X, Vec1.Y, Vec0.Z ),
new Vector3( Vec1.X, Vec0.Y, Vec1.Z ),
new Vector3( Vec0.X, Vec1.Y, Vec1.Z ),
new Vector3( Vec1.X, Vec1.Y, Vec1.Z ),
};
return corners;
}
}
}
バウンディングボックスがあるので、その方向を説明する基礎が必要です。ボックスの最小寸法を表す基底ベクトルと一致する線上にカメラを配置し、最大寸法が水平になるようにカメラを回転させたいようです(AABBではなくOBBがあると仮定します)。これは、アスペクト比が1.0より大きいことを前提としています。そうでない場合は、垂直方向の寸法を使用することをお勧めします。
私が試みること:
boxWidth / (2 * tan(horizontalFov / 2))
です。 boxWidth
は、ボックスの最大寸法の幅であることに注意してください。boxCenter + scaledBasis
に置き、boxCenter
を見ます。編集:
ですから、あなたが得ているのは、どこかを見ている任意の位置にカメラがあり、別の位置にAABBがあるということだと思います。カメラをボックスの側面に向けて動かさずに、次のことを行います。
この場合、もう少し作業が必要になります。これが私が提案するものです:
Unproject
します。 Z値の場合は、AABBの最も近いワールドスペースポイントをカメラに使用します。現時点では手元にありませんが、欲しい本は http://www.Amazon.com/Jim-Blinns-Corner-Graphics-Pipeline/dp/1558603875/ref=ntt_at_ep_dpi_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]; }
}
}
このリンクを確認してください https://msdn.Microsoft.com/en-us/library/bb197900.aspx
フロート距離= sphere.radius/sin(fov/2);
float3 eyePoint = sphere.centerPoint-距離* camera.frontVector;