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

zma*_*man 3 opengl math directx 3d zoom

我想知道能够在3D中缩放到屏幕空间选择框/窗口的最佳算法.

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

目前,它通过计算相对于视口宽度/高度的选择框的比例来工作,并将该比例应用于相机到其目标的距离/范围.

mil*_*aki 15

实际上并不是那么简单.看看这张图片(为了简单起见,这是一个2D投影):

frustum1

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

一种可能性如下图所示:

frustum2

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

现在一些计算:

近平面的高度和宽度:

h = 2 * tan(fovy/2) * znear
w = aspect * h
Run Code Online (Sandbox Code Playgroud)

矩形的屏幕空间坐标:

rectangle = ( x0, y0, x1, y1 )
Run Code Online (Sandbox Code Playgroud)

矩形的屏幕空间中心:

rcenter = ( (x0+x1)/2, (y0+y1)/2 )
Run Code Online (Sandbox Code Playgroud)

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

frustum3

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

center = ( (rcenter.x / screen_width  - 0.5) * w,
           (0.5 - rcenter.y / screen_height) * h, 0 )
Run Code Online (Sandbox Code Playgroud)

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

centerWS = center.x * camera_right_dir + center.y * camera_up_dir
Run Code Online (Sandbox Code Playgroud)

相机的新方向(dir2n):

dir1 = camera_dir * znear
dir2 = dir1 + centerWS
dir2n = normalize(dir2)
Run Code Online (Sandbox Code Playgroud)

相机的新位置(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
Run Code Online (Sandbox Code Playgroud)

因此:

dist = znear * screen_width / (x1-x0)
Run Code Online (Sandbox Code Playgroud)

哪个应该等于:

dist = znear * screen_height / (y1-y0)
Run Code Online (Sandbox Code Playgroud)

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

最后:

pos2 = pos1 + dir2n * (dist-znear)
Run Code Online (Sandbox Code Playgroud)