了解 libGDX 投影矩阵

Posted

技术标签:

【中文标题】了解 libGDX 投影矩阵【英文标题】:Understanding the libGDX Projection Matrix 【发布时间】:2016-02-15 16:18:09 【问题描述】:

在过去的几周里,我一直在尝试学习 libGDX 库。我发现很难理解相机/视口关系系统,尤其是在我第一次尝试游戏开发时。我被告知要使用的一行代码以及 API 提到的代码是:

    batch.setProjectionMatrix(camera.combined);

尽管进行了 4 个小时的研究,但我仍然对这段代码的功能缺乏完整的了解。据我的基本理解,它“告诉”相机正在寻找的批次。我缺乏理解力令人沮丧和愤怒,如果有人能帮助我,我将不胜感激。代码 sn-p 的另一个问题是我不确定何时需要实现(在渲染方法、创建方法等中)。

【问题讨论】:

【参考方案1】:

考虑用相机拍照。例如。使用您的智能手机相机拍摄公园长凳的照片。当你这样做时,你会在智能手机的屏幕上看到公园里的长椅。这可能看起来很明显,但让我们看看这涉及到什么。

图片上长凳的位置是相对于您拍照时站立的位置。换句话说,它是相对于相机而言的。在典型的游戏中,您不会相对于对象放置对象。相反,您将它们放置在您的游戏世界中。在您的游戏世界和您的相机之间进行转换是使用矩阵完成的(这只是一种转换坐标的数学方法)。例如。当您将相机向右移动时,长凳会在照片上向左移动。这称为视图矩阵。

图片上长凳的确切位置还取决于长凳与相机之间的距离。至少,它是 3D 的(2D 非常相似,所以请继续阅读)。当它更远时,它更小,当它靠近相机时,它更大。这称为透视投影。您还可以进行正交投影,在这种情况下,对象的大小不会根据与相机的距离而改变。无论哪种方式,公园长椅的位置和大小都会转换为屏幕上像素的位置和大小。例如。公园里的长凳是两米宽,而照片上是 380 像素。这称为投影矩阵。

camera.combined 表示组合的视图和投影矩阵。换句话说:它描述了游戏世界中的事物应该在屏幕上渲染的位置。

调用batch.setProjectionMatrix(cam.combined); 指示批处理使用该组合矩阵。每当值更改时,您都应该调用它。这通常是在调用 resize 时以及在您移动或以其他方式更改相机时。

如果您不确定,那么您可以在 render 方法的开头调用它。

【讨论】:

【参考方案2】:

另一个答案很好,但我想另一种描述它的方式可能有助于点击。

您通常在“世界空间”中处理您的游戏,这是一个类似于现实世界的坐标系。在线性代数中,您可以将空间中的点从一个坐标系转换到另一个坐标系,方法是将点的坐标乘以表示两个坐标系之间关系的矩阵。

视图矩阵乘以一个点,将其从世界空间转换为相机空间(相机的视点)。投影矩阵用于将点从相机空间转换为屏幕空间(设备屏幕的平面 2D 矩形)。当您在 Libgdx 中的相机上调用 update() 时,它会将您对位置、方向、视口大小、视野等的最新更改应用于其视图和投影矩阵,以便它们可以在着色器中使用。

您很少需要在 2D 中处理相机空间中的内容,因此 SpriteBatch 不需要单独的视图和投影矩阵。它们可以组合成一个矩阵,直接从世界空间转换到屏幕空间,这已经在相机中自动完成,因此 camera.combined 矩阵。

SpriteBatch 有一个默认的内置着色器,可以将此投影矩阵乘以精灵的所有顶点,以便它们正确地映射到平面屏幕。

每当您移动相机或调整屏幕大小时,都应致电setProjectionMatrix

还有第三种类型的矩阵,称为模型矩阵,用于 3D 内容。模型矩阵描述模型在世界空间中的方向、比例和位置。所以乘以模型中的坐标,将它们从局部空间移动到世界空间。

【讨论】:

【参考方案3】:

以一个基本的横向卷轴游戏为例。当玩家移动到一边时,相机会平移以跟随他们。这意味着对象在世界中的位置不一定与它们在屏幕上的位置相对应,因为屏幕和世界是相对移动的。

这里有一个例子:假设你的屏幕是 100px*100px 正方形(出于某种原因)。您将一个对象放置在位置 (50, 0),所以它现在位于屏幕的中间和底部。现在假设您将播放器移到右侧,整个屏幕会平移以跟随播放器。这意味着您之前放置的对象应该在屏幕上向左移动。所以它仍然在世界上的 (50, 0) 处,因为它实际上并没有相对于风景的其余部分移动,但它现在应该被绘制在屏幕上的 (10, 0) 处,因为哪个部分屏幕所看到的世界发生了变化。这是“世界空间”(对象在世界中的位置)和“屏幕空间”(对象在实际显示器上绘制的位置)之间的区别。

当您尝试使用SpriteBatch 进行绘制时,默认情况下会假定世界空间坐标与屏幕空间坐标相同:当您说“在 (50, 0) 处绘制”时,它将在(50, 0) 在屏幕上。即使相机移动,它总是会在屏幕上的 (50, 0) 处绘制,因此当相机平移时,对象将跟随并停留在屏幕上的同一位置。

因为您通常不希望这样,所以您给SpriteBatch 一个投影矩阵,它是一个变换矩阵,告诉如何将屏幕空间坐标转换为世界空间坐标,反之亦然。这样,当您告诉批处理“在 (50, 0) 处绘制”时,它可以查看从相机获得的矩阵并看到,由于相机已经移动,因此世界中的 (50, 0) 实际上意味着 ( 10, 0) 在屏幕上,它会在正确的位置绘制你的精灵。

【讨论】:

以上是关于了解 libGDX 投影矩阵的主要内容,如果未能解决你的问题,请参考以下文章

如何正确使用 LIBGDX FrameBuffer

如何组成一个矩阵来执行世界坐标的等距(二元)投影?

剔除适用于从视图投影矩阵中提取平面,但不适用于投影矩阵

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

∑GL-透视投影矩阵的推导

∑GL-透视投影矩阵的推导