在 3D 世界中查找视口矩形 Space (Opengl)

Find ViewPort Rectangle in 3D world Space (Opengl)

我需要有关矩阵变换的帮助,以在 3d 坐标(世界 Space)中找到我的视口的角点。

我做了一些测试,但找不到解决方案。

第一步: 我有可用的投影和模型矩阵(也有 ViewPort 大小)。为了找到我的 "Screen" 的中心,我使用了这个: OpenGL.UnProject(0.0, 0.0, 0.0) <- 这个函数告诉我 3D 屏幕的中心在哪里 space(正确!) 另一种方法是乘以 Coordinate (0, 0, 0) * ProjectionMtx.Inverse.

第 2 步: 现在我需要例如视口的左上角,如何找到世界中的 3D 点 space? 也许我应该使用视口大小,但是如何?

这是我的取消项目方法:

        double[] mview = new double[16];
        GetDouble(GL_MODELVIEW_MATRIX, mview);
        double[] prj = new double[16];
        GetDouble(GL_PROJECTION_MATRIX, prj);
        int[] vp = new int[4];
        GetInteger(GL_VIEWPORT, vp);
        double[] r = new double[3];
        gluUnProject(winx, winy, winz, mview, prj, vp, ref r[0], ref r[1], ref r[2]);

例如: 如果我的相机在 (-40,0,0) 和我的视口 [0,0,1258,513] 并且我取消投影我的近平面点我有这个结果:

left_bottom_near =>X=-39.7499881839701,Y=-0.0219584744091603,Z=0.946276352352364 right_bottom_near =>X=-39.7499881839701,Y=-0.0219584744091603,Z=0.946446903614738
left_top_near =>X=-39.7499881839701,Y=-0.0217879231516134,Z=0.946276352352364
right_top_near =>X=-39.7499881839701,Y=-0.0217879231516134,Z=0.946446903614738

我可以理解我的点的 X 值,即我的相机位置的 x 世界值,但是,Y 和 Z 呢?看不懂。

gluUnProject 从 window 坐标转换到世界 space(或模型 space)。
视图矩阵从世界 space 转换为视图 space.
投影矩阵从视图 space 转换为归一化设备 space。归一化设备space是一个立方体,左、下、近为(-1, -1, -1),右、上、远为(1, 1, 1)。
最后,标准化设备 space 中的 xy 坐标映射到视口(window 坐标)。视口由 glViewport. The z component is maped to the glDepthRange 定义(默认 [0.0, 1.0]。gluUnProject 与所有这些步骤相反。

orthographic projection the viewing volume is a cuboid. At Perspective projection the viewing volume is a frustum。投影矩阵从视图 space 转换为归一化设备 space.
您在视口上看到的是标准化设备 space 到其 xy 平面的投影。

一般情况下,可以将window坐标的8个角点反投影得到视体的角点。为此,您必须知道视口矩形和深度范围。 我假设 viwport 的大小为 window (0, 0, widht, height) 并且深度范围为 [0.0, 1.0]:

left   = 0.0;
right  = width;
bottom = 0.0;
top    = height; 

left_bottom_near  = gluUnProject(left,   bottom, 0.0)
right_bottom_near = gluUnProject(right,  bottom, 0.0)
left_top_near     = gluUnProject(left,   top,    0.0)
right_top_near    = gluUnProject(right,  top,    0.0)
left_bottom_far   = gluUnProject(left,   bottom, 1.0)
right_bottom_far  = gluUnProject(right,  bottom, 1.0)
left_top_far      = gluUnProject(left,   top,    1.0)
right_top_far     = gluUnProject(right,  top,    1.0)