透视投影,标准可视体积

Posted

技术标签:

【中文标题】透视投影,标准可视体积【英文标题】:Perspective Projection, Canonical Viewing Volume 【发布时间】:2020-05-06 06:29:41 【问题描述】:
Vector3d nearC(0,0,0 -w);
Vector3d farC(0,0,0-x);
double width = y/2;
double height = z/2;
double angleOfHeight = atan(height/w);
double angleOfWidth = atan(width/w);
double adjustedHeight = tan(angleOfHeight) * x;
double adjustedWidth = tan(angleOfWidth) * x;

nearC[0] - width, nearC[1] - height, nearC[2]
nearC[0] - width, nearC[1] + height, nearC[2]
nearC[0] + width, nearC[1] + height, nearC[2]
nearC[0] + width, nearC[1] - height, nearC[2]
farC[0] - adjustedWidth, farC[1] - adjustedHeight, farC[2]
farC[0] - adjustedWidth, farC[1] + adjustedHeight, farC[2]
farC[0] + adjustedWidth, farC[1] + adjustedHeight, farC[2]
farC[0] + adjustedWidth, farC[1] - adjustedHeight, farC[2]

以上是我在视图坐标中的截锥体。查看矩阵是:

 0   0  -1   0
 0   1   0  -1
 1   0   0 -10
 0   0   0   1

一切都对,我们有一张纸。

我一辈子都想不出如何在标准观看量中获得这种截锥体。我已经完成了我能找到的每一个透视投影。当前是这样的:

        s,        0,                      0,                     0,
        0,        s,                      0,                     0,
        0,        0,             -(f+ne)/(f-ne),            2*f*ne/(f-ne),
        0,        0,                      1,                     0;

double s = 1/tan(angleOfView * 0.5 * M_PI / 180);

我错过了一个步骤或什么,对吧?还是几步?

很抱歉现在听起来如此绝望,在这方面已经旋转了一段时间。

任何帮助表示赞赏。

【问题讨论】:

不清楚你想要达到什么目的......以及问题出在哪里尝试更多地描述你的问题 我正在尝试实现这样的目标:scratchapixel.com/lessons/3d-basic-rendering/… 将视锥体映射到该 -1,1 规范视图。但我就是应付不来哈哈。 究竟知道什么?你的第一个代码/表是一团糟。 我有从世界坐标到查看坐标的翻译。那是从第一个块开始的,它给出了平截头体的 8 个角。下面的矩阵是从世界坐标到观察坐标的转换。现在我正试图将截锥体的这 8 个角放入一个 -1,1 盒子中。 w 是到远窗格的距离。 x 是到近窗格的距离。所有这些都是为了得到平截头体而进行的计算。 **对不起,x 远,w 近。 基本上我已经完成了三角函数和从世界坐标到查看坐标的第一次转换,但其他所有矩阵都让我望而却步。不能工作正交,不能工作规范观看量。 【参考方案1】:

避免从透视投影开始。旧 GL 中常用的方式是使用gluPerspective

为此,我们需要znear,zfar,FOV 和视图纵横比。欲了解更多信息,请参阅:

Calculating the perspective projection matrix according to the view plane

我习惯使用FOVxx 轴上的视角)。要计算,您需要从上方查看 xz 平面(在相机空间中)查看您的视锥体:

所以:

tan(FOVx/2) = znear_width / 2*focal_length
FOVx = 2*atan(znear_width / 2*focal_length)

焦距可以通过计算平截头体边缘线的交点来计算。或者通过使用三角形相似度。第二个更容易写:

zfar_width/2*(|zfar-znear|+focal_length) = znear_width/2*(focal_length)
zfar_width/(|zfar-znear|+focal_length) = znear_width/(focal_length)
focal_length = (|zfar-znear|+focal_length)*znear_width/zfar_width
focal_length - focal_length*znear_width/zfar_width = |zfar-znear|*znear_width/zfar_width 
focal_length*(1-(znear_width/zfar_width)) = |zfar-znear|*znear_width/zfar_width 
focal_length = (|zfar-znear|*znear_width/zfar_width) / (1-(znear_width/zfar_width))

这就是我们所需要的:

focal_length = (|zfar-znear|*znear_width/zfar_width) / (1-(znear_width/zfar_width))
FOVx = 2*atan(znear_width / 2*focal_length)        
FOVx*=180.0/M_PI; // convert to degrees
aspect=znear_width/znear_height;
gluPerspective(FOVx/aspect,aspect,znear,zfar);

请注意|zfar-znear| 是平面之间的垂直距离!!!因此,如果您没有轴对齐的,那么您需要使用点积和法线来计算...

【讨论】:

非常感谢朋友。我现在试试这个。顺便说一句,你看起来很酷哈哈。 你好,伙计,我知道了。嗯,这是我已经真正做到的,只是我自己完成了。但是现在我如何获得规范的视图量?不知道你会得到这个哈哈。 @Sean 您只需将模型视图和投影矩阵相乘......其中模型视图表示从渲染模型空间到视图空间的转换。从您在问题中得到的内容来看,您的截锥体是轴对齐,因此只需沿 z 轴平移即可。当心 gluPerspective 正在查看-Z 方向,因此甚至可能旋转 180 度或翻转/镜像 ....

以上是关于透视投影,标准可视体积的主要内容,如果未能解决你的问题,请参考以下文章

投影方式- Unity3D游戏开发培训

Shadowmap 适用于正射投影,但不适用于透视投影

视觉高级篇21 # 如何添加相机,用透视原理对物体进行投影?

视觉高级篇21 # 如何添加相机,用透视原理对物体进行投影?

计算机图形学-MVP变换之投影(Projection)变换

SharpGL之透视投影和摄像机