Pygame 投影 3D 点 平行投影

532 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情

投影 3D 点

在 3D 空间中存储点就像创建三个值的元组或 Vector3 对象一样简单,但我们无法在 Pygame 的绘图函数中使用任何一个,因为它们都采用坐标作为 2D 点。要在3D坐标上绘制任何东西,我们首先必须将其投影到2D屏幕上。

平行投影

将 3D 坐标转换为 2D 坐标的一种方法是简单地丢弃 z 分量,即称为平行投影。清单 8-5 显示了一个非常简单的函数,我们可以使用该函数将 3D 坐标转换为具有平行投影的 2D 坐标。清单 8-5.执行并行投影的函数

image.png

尽管并行投影操作快速简便,但它们在游戏中并不常用,因为忽略 z 分量不会给人留下深度印象。使用平行投影渲染的3D场景有点像通过具有高放大倍率的变焦镜头观看;世界看起来很平坦,不同距离的物体似乎彼此相邻。图 8-4 显示了使用平行投影渲染的立方体。

image.png

一般来说,游戏和3D计算机图形中更常见的投影是透视投影,因为它考虑了物体与观看者的距离。透视投影复制了远离观察者的对象看起来比近距离对象小的方式。使用透视投影渲染的对象也会向地平线变窄,这种效果称为透视收缩(参见图 8-5)。清单 8-6 是一个函数,它使用透视投影投影投影 3D 坐标并返回结果。

image.png

与简单的平行投影相比,透视投影涉及的数学运算要多一些。perspective_project函数将 x 和 y 坐标乘以 d 值(我们将在后面讨论),然后除以 z 分量。

它还会否定 y 分量 (-y),因为 y 轴在 2D 中的方向相反。perspective_project中的 d 值是观看距离,即从摄像机到 3D 世界单位中的单位直接与屏幕上的像素对应的距离。例如,如果我们在坐标(10,5,100)处有一个对象,

投影的观看距离为100,我们将其向右移动一个单元(11,5,100),然后它似乎在屏幕上只移动了一个像素。如果其 z 值小于 100,它将相对于屏幕移动不同的距离。

图 8-6 显示了观看距离与

屏幕。假设玩家(由笑脸指示)直接坐在屏幕前方,则观看距离将大约是从屏幕到玩家头部的距离(以像素单位表示)。

image.png

视野

那么我们如何为观看距离(d)选择一个好的值呢?我们可以只是尝试找到一个使3D场景看起来令人信服的值,但是我们可以通过从视野(fov)计算d来消除猜测,这是场景的角度范围,在某一时刻是可见的。对于人类来说,fov是从左眼到右眼的范围,大约是180度。图8-7显示了视场角和观看距离之间的关系。当视场角增加(变宽)时,随着更多场景变得可见,观看距离会减小。当fov减小(变窄)时,情况正好相反;观看距离增加,可见的场景较少。

image.png

视场是定义 3D 场景中有多少透视的更好方法,但我们仍然需要透视投影中的 d 值。要从 fov 计算 d,我们需要使用一点三角函数。清单 8-7 是一个函数,它采用 fov 加上屏幕宽度,并使用数学模块中的 tan 函数来计算观看距离。

提示 您可以通过在互联网上查找公式来完成很多3D图形,但有时您可能需要自己计算一些数学。如果数学不是你的强项,不要让它吓到你 - 你只需要基础知识,特别是在三角学中。

image.png

我通常使用45到60度之间的值来表示我的fov,这给出了一个自然的视角。较高的值可能对赛车游戏有好处,因为增加的视角夸大了速度的影响。对于策略游戏来说,值越低越好,因为它们显示了更多的场景。

您可能还想根据游戏中发生的情况调整fov。通过快速缩小fov,使摄像机放大,然后在玩家开火时将其移回,可以实现出色的狙击步枪效果。