我正在寻找一个算法,以适应一个边界框内的一个视口(在我的例子中,一个DirectX场景)。我知道在正射相机中对包围球进行中心化的算法,但是对于一个边框和一个透视相机,我需要同样的算法。我不能仅仅更改FOV,因为这个应用程序有FOV作为用户可编辑的变量,所以它必须移动相机。
我有大部分数据:
问题:
我如何找到相机的位置,以使它尽可能完美地填充视口(但如果纵横比离1.0很远,它只需要填充一个屏幕轴)?
我尝试过其他一些东西:
救命啊!
发布于 2010-05-19 14:34:11
有许多可能的相机位置+方向,其中包围框将适合在视野中的圆顶。但是任何程序都会选择一个特定的摄像机位置和方向。
如果你考虑包围球,一种解决办法是
有了包围盒,您可以考虑一个较早的步骤,首先定位相机垂直于中心的最大(或最小,无论你喜欢)的立方体面。
我没有DirectX的经验,但移动和改变相机的寻找方向,以一个特定的点中心应该是容易的。最困难的部分是做决定移动多远来查看物体的数学运算。
数学
如果您知道物体在世界坐标中的边界大小s (我们对像素或相机坐标不感兴趣,因为它们取决于您的距离),那么如果您知道透视投影的x和y视场角a,则可以计算相机到边界形状所需的距离d。
frustum ------
------ ***** -
----- * * |
-=== ) FOV a *bounding box | BB size s
camera ----- * * |
------ ***** -
------
|-------------------|
distance d因此,数学是tan(a/2) = (s/2) / d => d = (s/2) / tan(a/2),它将给出相机应该从最近的边界面放置的距离。
发布于 2015-09-29 05:54:20
我知道上面有一些很好的答案,但我想加入一个简单的解决方案,以适应相机内的包围球。它假设要保持相机目标和前向矢量相同,并简单地调整相机距离以达到目标。
注意到, --这不会给你最好的拟合,但是它会给你一个近似的拟合,显示所有的几何图形,并且只在几行代码中显示,并且没有屏幕到世界的转换

// 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 sameBoundingBox在C#中的实现如下所示。重要的一点是中心和角落的财产。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;
}
}
}发布于 2010-05-19 14:45:14
因为你有一个包围框,你应该有一个描述它的方向的基础。似乎您想要将相机定位在与描述盒最小尺寸的基向量一致的线上,然后滚动相机,使最大尺寸是水平的(假设您有OBB而不是AABB)。这假设高宽比大于1.0;如果不是,则需要使用垂直维度。
我要做的是:
boxWidth / (2 * tan(horizontalFov / 2))。请注意,boxWidth是框的最大维度的宽度。boxCenter + scaledBasis,看着boxCenter。编辑:
所以我认为,你得到的是,你有相机在一个任意的位置,看看某处,你有一个AABB在另一个位置。如果不将摄像机移到盒的一侧,则需要:
如果是这样的话,您还需要做更多的工作;下面是我的建议:
Unproject的两个相对的角屏幕空间包围框进入世界空间。对于Z值,使用您的AABB最近的世界空间点到相机。https://stackoverflow.com/questions/2866350
复制相似问题