LibGDX 游戏开发 之 各种坐标系
原文链接:https://github.com/libgdx/libgdx/wiki/Coordinate-systems
译者:重庆好爸爸 game4kids@163.com
谢绝转载
坐标系对比表 (译者注:为了方便查阅,因此译者做了个汇总表)
参数 | Touch coordinates | Screen or image coordinates | Pixmap and texture coordinates | Normalized render coordinates | Normalized texture (UV) coordinates | World coordinates |
---|---|---|---|---|---|---|
Unit | 像素 | 像素 | 不知道 | 1 | 1 | 应用相关, e.g. SI Units |
System | Y轴向下 | Y轴向上 | 不知道 | Y轴向上 | Y轴向上 | application specific,一般Y轴向上 |
Type | 整数 | 整数 | 不知道 | 浮点数 | 浮点数 | 浮点数 |
Range | 左上角(0,0); 右下角(Gdx.graphics.getWidth()-1, Gdx.graphics.getHeight()-1) | 左下角(0,0); 右上角(Gdx.graphics.getWidth()-1, Gdx.graphics.getHeight()-1) | 不知道 | (-1,-1) (左下角) to (+1,+1) (右上角) | (0,0) (左下角) to (1,1) (右上角) | 应用相关 |
Usage | 触摸/鼠标坐标系 | viewport, scissors & pixmap | 不知道 | shaders | shaders, mesh, texture region, sprite | 游戏逻辑 |
Dependence | 设备相关 | device/resource/asset specific | 不知道 | 无 | 无 | game/application |
触摸坐标系Touch coordinates
从物理屏幕(应用程序窗口)的左上角像素开始,坐标系的尺寸和物理屏幕(应用程序窗口)相同。
每个坐标(x,y)其实是一个2维数组元素的索引,每个坐标都表示屏幕上的一个物理像素。既然是索引,那么每个坐标(x,y)都是整数,而不能是分数。这个坐标系通常也最接近于设备和OS的物理实现。如果你熟悉Canvas Graphics或者一些图像编辑器,那么你应该对此坐标系很熟悉了。你可能甚至想把这个坐标系作为你的默认坐标系,但建议你不要这么做。
每当使用鼠标或触摸坐标时,您将使用此坐标系。 您通常希望尽快将这些坐标转换为更方便的坐标系。 例如camera.unproject()或viewport.unproject()等方法将它们转换为世界坐标(见下文)。
Screen,Image 坐标系
这是和OpenGL对应的触摸坐标系; 即:它用于指定(索引)物理屏幕的某个(或者某一部分)像素。 它也用作内存中图像的索引器。 同样,坐标分量必须是整数而不能是分数。
触摸和屏幕坐标之间的唯一区别是触摸坐标是y向下,而屏幕坐标是y-up。 因此,它们之间的转换是相当容易的:
y = Gdx.graphics.getHeight() - 1 - y;
通常使用这个坐标系的目的是需要指定要渲染的屏幕的某一部分。 例如,调用glViewport,glScissor或操纵Pixmap(见下文)。
在大多数情况下,你不需要使用这个坐标系,如果有的话,应该把游戏逻辑和坐标系隔离。camera.project()和viewport.project()方法可用于将世界单位转换为屏幕坐标。
Pixmap 和 texture coordinates
Pixmap坐标比较特殊。 Pixmap通常用于上传纹理数据。 例如,当将PNG图像文件加载到纹理时,首先将其解码(未压缩)到Pixmap(这是图像的原始像素数据),然后将作为纹理复制到GPU。 然后可以就使用纹理渲染到屏幕。也可以通过代码修改或创建Bitmap,例如在上传为纹理数据之前。
“问题”就是OpenGL希望纹理数据是一个Y轴向上的image坐标系。 然而,大多数图像格式存储的时候是Y轴向下的。 LibGDX不会在两者之间转换图像数据(这将涉及逐行复制图像),而是简单地复制数据。 这实际上导致从Pixmap加载的纹理上下颠倒。
为了解决此纹理上下颠倒的问题,SpriteBatch会在渲染时在y轴上翻转纹理(UV)坐标(见下文)。 同样,fbx-conv也可以在y轴上翻转纹理坐标。 但是,当您使用一个不是通过Bitmap图像加载的纹理(例如Framebuffer)时,可能会导致纹理出现在上下颠倒的问题。
归一化渲染坐标系 Normalized render coordinates
上面提到的坐标系有个很大的问题是:都是和设备强相关的。为了解决这个问题,OpenGL允许你在渲染的时候,使用和设备无关的坐标系,系统将自动映射到screen坐标系。该坐标系在[-1,-1]和[+ 1,+ 1]范围内.(0,0)精确地在屏幕或framebuffer(渲染目标)的中心。
Vertex shader在此坐标系中输出(gl_Position)其坐标。 但除此之外,你不应该在实际的应用中使用这个坐标系。 它有时候在教学中使用。
值得注意的是:归一化的时候长宽比。 也就是说:X方向的刻度不会与Y方向的刻度成比例。 它们都在-1的范围内到+1,无论屏幕的长宽比。
应用程序决定如何处理各种宽高比(见下文world unit)。
坐标是浮点数,不再是索引器。 设备(GPU)将使用rasterisation将这些坐标映射到实际的屏幕像素。 一个很好的文章(虽然针对DirectX也适用于OpenGL)有关可以找到的更多信息这里.
Normalized texture (UV) coordinates
如果normalized render 坐标系一样,
Likewise to the normalized render coordinates, OpenGL也使用Normalized texture (UV) 坐标系。 唯一的区别是这些范围从[0,0]到[1,1]。 根据指定的wrap 功能,该范围之外的值将被映射到该范围内。
这些坐标也称为** UV坐标**。 在许多用例中,你不必处理它们。 通常这些值存储在 mesh或者TextureRegion中。
normalized texture 坐标系的使用非常重要, 因为它使它们独立于资产大小。 或者换句话说:它允许您使用缩小或缩放版本替换您的资产,而无需修改UV坐标。 使用这个例子的是mipmap.
当渲染时,GPU将UV坐标转换为纹理像素(纹理像素)。 这被称为“纹理采样”,并且基于纹理过滤。
世界坐标系 World coordinates
一般来说,你的游戏逻辑应该使用一个最适合于游戏逻辑的坐标系。这个坐标系应该和设备或者资源的尺寸无关。比如:通常使用的单位是米。世界坐标在顶点着色器中转换为归一化渲染坐标。Camera or Viewport用来做这件事的。比如:
为了保持长宽比例,可能需要加上黑边。Camera用来计算Matrix,Matrix的作用是将世界坐标系转换为camera相关的坐标系,还会考虑camera的位置和旋转考虑进去。
它还计算投影matrix,它将世界坐标转换为[-1,-1]到[+ 1,+ 1]范围内的Normalized render坐标系。 在2D游戏中,您几乎不需要区分这两个matrix,而只需要combined transformation matrix。 您可以将此矩阵传递给着色器,例如通过调用spriteBatch.setProjectionMatrix(camera.combined)方法。
您可以拥有多个camera或viewport,同样,你也可以拥有多个世界坐标系。 一个典型的游戏至少有两个世界坐标系,分别是:
GUI/HUD 坐标系 GUI/HUD coordinates
按钮,标签等固定元素在屏幕上始终可见。 通常它们涉及渲染文本。 例如在超级马里奥,时钟总是在屏幕的右上角可见,当马里奥在游戏世界中移动时,时钟不会移动。
最常见的是scene2d用于HUD,这意味着您将使用Viewport来定义坐标系。 该坐标系统通常在接近设备分辨率的范围内,以便在呈现字体时给出最佳结果。 这些坐标称为banana units。 这个摄像机实际上从来没有移动或旋转,它固定在一个位置,使得世界坐标(0,0)位于屏幕的左下角。
Game 坐标系 Game coordinates
这是适合您的游戏最适合,并用于实现游戏逻辑。 保持最佳浮点精度值是一个好的做法。 例如,你的主角高1.8米,树高10米,如果你正在制作一个单位和距离很高的银河系游戏,你可能想要使用例如 公里。
相机用于查看您的游戏世界,就像在现实世界中使用摄像机时一样。 相机可以移动,旋转和缩放,以在屏幕上显示世界的另一部分。