Bur*_*rre 23 3d zoom perspective
我正在寻找一种算法来适应视口内的边界框(在我的例子中是一个DirectX场景).我知道用于在正交相机中居中定界球的算法,但是对于边界框和透视相机需要相同的算法.我不能只改变视觉因为这个应用程序有FOV作为用户可编辑变量,所以它必须移动相机.
我有大部分数据:
我遇到的问题:
如何找到相机位置,使其尽可能完美地填充视口(例外情况是,如果宽高比远离1.0,它只需要填充其中一个屏幕轴)?
我尝试过其他一些东西:
请帮忙!
cat*_*try 34
有许多可能的相机位置+方向,其中边界框将适合视锥体内.但任何程序都会选择一个特定的摄像机位置和方向.
如果你会考虑边界球,一个解决方案可能是
使用边界框,您可以考虑先将相机定位在垂直于最大(或最小,任何您喜欢的)立方体面的中心的步骤.
我没有使用DirectX的经验,但移动和改变相机的视线方向以使某个点居中应该很容易.困难的部分是做数学决定移动查看对象的距离.
如果您s从相机的方向知道世界坐标中的对象的边界大小(我们对像素或相机坐标不感兴趣,因为这些坐标取决于您的距离),您可以计算d相机到边界所需的距离如果您知道a透视投影的x和y视场角,则为shape .
frustum ------
------ ***** -
----- * * |
-=== ) FOV a *bounding box | BB size s
camera ----- * * |
------ ***** -
------
|-------------------|
distance d
Run Code Online (Sandbox Code Playgroud)
因此,数学是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
Run Code Online (Sandbox Code Playgroud)
在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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
由于您有一个边界框,因此您应该有一个描述它的方向的基础.您似乎想要将摄像机放置在与描述盒子最小尺寸的基础向量重合的线上,然后滚动摄像机以使最大尺寸为水平(假设您有OBB而不是AABB).这假定纵横比大于1.0; 如果没有,你会想要使用垂直维度.
我会尝试什么:
boxWidth / (2 * tan(horizontalFov / 2)).请注意,这boxWidth是框的最大尺寸的宽度.boxCenter + scaledBasis看着boxCenter.编辑:
所以我认为你得到的是你将相机放在任意位置看着某个地方,而你在另一个位置有一个AABB.如果不将相机移动到盒子的一侧,您需要:
如果是这种情况,你会有更多的工作; 这是我的建议:
Unproject屏幕空间的两个对立角落将盒子装入世界空间.对于Z值,请使用AABB与相机最接近的世界空间点.