纹理采样坐标用于渲染精灵。

12

假设我们有一张纹理(这种情况下是8x8像素),我们想要将其用作精灵表。其中一个子图像(精灵)是纹理内的4x3子区域,就像这张图片中所示:

enter image description here

(显示了四个角的规范化纹理坐标)

现在,基本上有两种方法可以为一个4px x 3px大小的四边形分配纹理坐标,使其有效地成为我们要寻找的精灵; 第一种最直接的方法是在子区域的角落采样纹理:

enter image description here

// Texture coordinates

GLfloat sMin = (xIndex0                  ) / imageWidth;
GLfloat sMax = (xIndex0 + subregionWidth ) / imageWidth;
GLfloat tMin = (yIndex0                  ) / imageHeight;
GLfloat tMax = (yIndex0 + subregionHeight) / imageHeight;

尽管在最初实现这种方法时(大约在2010年左右),我意识到精灵看起来略微“扭曲”。经过一番搜索,我看到了一个在cocos2d论坛上的帖子,解释了渲染精灵时采样纹理的“正确方法”:

enter image description here

// Texture coordinates

GLfloat sMin = (xIndex0                   + 0.5) / imageWidth;
GLfloat sMax = (xIndex0 + subregionWidth  - 0.5) / imageWidth;
GLfloat tMin = (yIndex0                   + 0.5) / imageHeight;
GLfloat tMax = (yIndex0 + subregionHeight - 0.5) / imageHeight;

我修复了代码后,感到满意了一段时间。但是在某个时候,我开始觉得我的精灵看起来不好,我相信这可能与iOS 5的引入有关。经过一些测试,我切换回“蓝色”方法(第二张图片),现在它们似乎看起来不错,但并非总是如此。

我是不是疯了,或者iOS 5有什么变化与GL ES纹理映射有关?也许我还做错了其他事情?(例如,顶点位置坐标略微偏移?错误的纹理设置参数?)但我的代码库没有改变,所以也许我从一开始就错了……

我的意思是,至少对于我的代码来说,“红色”方法曾经是正确的,但现在“蓝色”方法给出了更好的结果,这让我感觉很奇怪。

现在,我的游戏看起来还可以,但我觉得有些地方必须尽快解决……

有什么想法/经验/意见吗?

补充说明

要渲染上面的精灵,我会在正交投影中绘制一个4x3的四边形,每个顶点分配了在之前提到的代码中暗示的纹理坐标,如下所示:

// Top-Left Vertex
{ sMin, tMin };

// Bottom-Left Vertex
{ sMin, tMax };

// Top-Right Vertex
{ sMax, tMin };

// Bottom-right Vertex
{ sMax, tMax };

原始的四边形从(-0.5, -0.5)到(+0.5, +0.5)创建; 即它是屏幕中心的单位正方形,然后缩放到子区域的大小(在这种情况下为4x3),并将其中心定位于整数(x,y)坐标。我闻到了这个也有关系,特别是当宽度、高度或两者都不是偶数时?

附录2

我也发现了这篇文章,但我还在努力理解(这里是凌晨4点) http://www.mindcontrol.org/~hplus/graphics/opengl-pixel-perfect.html


注释:就我个人而言,我认为在iOS4和iOS5之间纹理的行为并没有发生改变(这应该是GL ES1.1/2.0规范的一部分);只是因为我的经验给我留下了这样的印象。我知道肯定是错的,但仍然感到困惑... - Nicolas Miari
1个回答

10
这幅图片看起来比表面更加复杂,纹理坐标并不是影响纹理采样的唯一因素。在您的情况下,我认为蓝色可能是您想要的。
最终您想要的是在每个像素中心对纹理进行采样。您不希望在两个纹素之间的边界上取样,因为这会通过“线性”采样将它们组合在一起,或者根据浮点计算方式四舍五入而任意选择其中之一。
话虽如此,您可能认为不应该将纹理坐标设置在(0,0),(1,1)和其他角落,因为这些都在纹素边界上。然而,需要注意的重要事项是OpenGL在片段中心采样纹理。
以2x2像素监视器和2x2像素纹理为例,如果从(0, 0)到(2, 2)绘制矩形,则覆盖了4个像素。如果在此矩形上进行纹理映射,则需要从纹理中取4个样本。
如果您的纹理坐标从0到1,则OpenGL将插值这些坐标,并从每个像素的中心抽样,其中左下角的纹理坐标从左下角像素的底部左侧开始。这将最终生成纹理坐标对(0.25, 0.25), (0.75,0.75), (0.25, 0.75),和(0.75, 0.25)。这样就将样本放在每个纹素的中心,这正是您想要的。
如果像红色示例一样将纹理坐标偏移半个像素,则会导致插值不正确,最终采样位置偏离纹素中心。
长话短说,您需要确保像素与纹素正确对齐(不要在非整数像素位置绘制精灵),并且不要按任意量缩放精灵。
如果蓝色正方形给您带来了糟糕的结果,您可以提供一张示例图片或描述您如何绘制它吗?

图片胜过千言万语:

img


此外,如果我指定了纹理坐标(比如说)0.0,它将从纹理图像中的第一个像素和“外部”(即黑色 - 假设没有环绕)之间进行采样,并在“最近”模式下为“颜色”或“黑色”,在“线性”模式下则是两者的混合(您似乎也提到了这一点)...? - Nicolas Miari
1
@ranReloaded,我添加了一张图片,希望能更好地解释。如果这样更有意义,请告诉我。 - Tim
1
是的,听起来是这样。如果你说你正在从-0.5到0.5绘制一个四边形,然后进行缩放,它可能会出现在非像素边界上。请确保所有四边形顶点都位于整数像素边缘上。 - Tim
请确认一下:精灵渲染的纹理参数是“最近邻过滤”,没有包裹,对吗?我有遗漏什么吗? - Nicolas Miari
我是说也许有一些其他的纹理参数/配置我忘记了。我想应该没有,但为了确保... - Nicolas Miari
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接