缩放到3D中的屏幕空间选择框

时间:2012-05-11 04:40:58

标签: math opengl 3d directx zoom

我希望知道能够以3D缩放到屏幕空间选择框/窗口的最佳算法。

我现在有点工作但是当目标的距离很大时它似乎没有正确放大。

目前,它的工作原理是确定选择框相对于视口宽度/高度的比例,并将该比例应用于相机到目标的距离/范围。

2 个答案:

答案 0 :(得分:15)

实际上并非那么简单。看看这张照片(简单来说就是2D投影):

frustum1

蓝色区域是当前相机的视锥体。黄色区域是由屏幕的矩形选择覆盖的蓝色平截头体的一部分。目的是制作一个最能代表黄色区域的新平截头体。问题是新的视锥体应该以何种方式适应黄色区域。

下图中显示了一种可能性:

frustum2

新相机的视锥体呈紫色,相机的眼睛位于绿线上。假设新相机具有与旧相机相同的属性(fovy,znear,zfar,aspect),我们可以计算其新位置和方向。

现在进行一些计算:

近平面的高度和宽度:

h = 2 * tan(fovy/2) * znear
w = aspect * h

矩形的屏幕空间坐标:

rectangle = ( x0, y0, x1, y1 )

矩形的屏幕空间中心:

rcenter = ( (x0+x1)/2, (y0+y1)/2 )

另一张澄清下一次计算的图片:

frustum3

位于近平面上的视图空间矢量,从近平面的中心指向矩形的中心:

center = ( (rcenter.x / screen_width  - 0.5) * w,
           (0.5 - rcenter.y / screen_height) * h, 0 )

然后我们必须将此向量转换为世界空间:

centerWS = center.x * camera_right_dir + center.y * camera_up_dir

相机的新方向(dir2n):

dir1 = camera_dir * znear
dir2 = dir1 + centerWS
dir2n = normalize(dir2)

相机的新位置(pos2):

我做了一些假设,以简化计算。 近似新旧近平面是平行的,所以:

(w, h) / dist = (w * (x1-x0)/screen_width, h * (y1-y0)/screen_height) / znear
(1, 1) / dist = ( (x1-x0)/screen_width, (y1-y0)/screen_height) / znear
(1/dist, 1/dist) = ( (x1-x0)/screen_width, (y1-y0)/screen_height) / znear

因此:

dist = znear * screen_width / (x1-x0)

哪一个应该等于:

dist = znear * screen_height / (y1-y0)

只有当矩形具有与屏幕相同的比例时才是这样,您可以通过在用户绘制时锁定矩形的比例来保证,或者您只需使用矩形的宽度(x1-x0)并忽略它的高度为(y1-y0),反之亦然。

最后:

pos2 = pos1 + dir2n * (dist-znear)

答案 1 :(得分:1)

我的理解是你在屏幕上绘制一个矩形以与窗口边界对齐,并让该矩形内的所有内容都放大。

如果我是对的,我们在这里要做的是将近平面与绘制矩形的假想平面对齐。

要做到这一点,我们必须使用一些三角函数。 假设我们对齐矩形的顶部和底部:

我们应该计算近平面的高度:
H = tan(fovy/2) * nearPlane; --------(1)

近平面上绘制矩形的高度:

fraction = WindowHeight / rectangle height;  
h = H * fraction; ---------(2)

要将近平面与假想平面对齐,摄像机必须向前移动。 假设D是前进的距离,然后是几何,
h / nearPlane = H / (nearPlane+D) --------(3)

使用等式(2),等式(3)可以减少为:

fraction / nearPlane = 1 / (nearPlane+D)

将D表示为:

D = (nearPlane / fraction)  - nearPlane; 

D = nearPlane * (1-fraction)/fraction;

现在将相机向前移动D.应该这样做。

如果矩形不是中心对齐的,则计算稍微复杂一些。