图像说千言万语,那么两个呢?我有这个地图艺术:
为了将其实际用作地图,我将此纹理缩放6次。然而,这并没有像预期的那样:
所有OpenGL代码都在我的自制2D OpenGL渲染库中,由于OpenGL是状态机,因此很难实际记录整个渲染过程。但这里是+/-我做的(代码是Python):
width, height = window.get_size()
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glPushMatrix()
glLoadIdentity()
glOrtho(0.0, width, height, 0.0, 0.0, 1.0)
glMatrixMode(GL_MODELVIEW)
glPushMatrix()
glLoadIdentity()
# displacement trick for exact pixelization
glTranslatef(0.375, 0.375, 0.0)
glDisable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(self.texture.target) # GL_TEXTURE_2D
glBindTexture(self.texture.target, self.texture.id)
glTexParameteri(self.texture.target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(self.texture.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glPushMatrix()
glTranslatef(self.x, self.y, 0.0) # self.x and self.y are negative int offsets
glScalef(self.scale_x, self.scale_y, 1.0) # scale_x and scale_y are both 6
glBegin(GL_QUADS)
glTexCoord2i(0, 0)
glVertex2i(0, 0)
glTexCoord2i(0, 1)
glVertex2i(0, self.texture.height)
glTexCoord2i(1, 1)
glVertex2i(self.texture.width, self.texture.height)
glTexCoord2i(self.texture.width, 0)
glVertex2i(self.texture.width, 0)
glEnd()
glPopMatrix()
glDisable(self.texture.target)
但是,当我使用GL_TEXTURE_RECTANGLE_ARB时,不会发生这种“模糊”错误。我也希望能够使用GL_TEXTURE_2D,所以有人可以指出如何阻止这种情况发生吗?
答案 0 :(得分:7)
如有疑问 - 请用相同尺寸的黑色棋盘(黑色/白色1px)替换您的纹理。它会让你很好地了解将要发生的事情 - 它是统一的灰色(位移是错误的)还是会产生波浪(缩放是错误的)。
确保没有自动生成和使用的mip-map。
通常,您不需要任何特殊位移,纹素与正确设置的glOrtho匹配像素。
另一个重要问题 - 使用PowerOfTwo纹理,因为较旧的GPU可以使用各种方案来支持NPOT纹理(对用户透明地缩放或填充),这可能导致这种模糊。
要手动处理NPOT纹理,您需要使用清晰的像素填充它们,直到下一个POT尺寸,并将因子glTextCoord2f(u,v)
缩放您的UV值npotSize / potSize
。请注意,这与平铺不兼容,但从您的艺术来看,您不需要它。
答案 1 :(得分:4)
# displacement trick for exact pixelization glTranslatef(0.375, 0.375, 0.0)
不幸的是,这还不够,因为您还需要缩放纹理。对于未缩放的未翻译纹理矩阵,要从尺寸 N 的纹理中处理某个像素 i ,您需要应用公式
(2i + 1)/(2N)
您可以从中导出缩放和平移 - 或直接确定纹理坐标。
好吧,假设您的纹理宽度为300像素,并且您希望精确地处理20到250的像素,那么为身份纹理矩阵选择的纹理坐标将是
(2*20 + 1)/(2*300) = 41/600 = 0.0650
和
(2*250 + 1)/(2*300) = 501/600 = 0.8350
但您也可以通过纹理矩阵应用变换。您希望将像素0 ... 299(对于300像素宽度,索引从0到300-1 = 299)映射到0 ... 1。那么让我们来看看这些数字:
(2*0 + 1)/(2*300) = 1/600 =~= 0.0017 = a
(2*299 + 1)/(2*300) = 599/600 =~= 0.9984 = b
b-a =~= 0.9967
因此,您必须将范围0 ... 1缩小0.9967并将宽度偏移0.0017。高度←→t坐标的计算方法相同。请记住,转换的顺序很重要。您必须先进行缩放然后在执行变换时进行平移,因此在矩阵乘法中,首先乘以平移:
// for a texture 300 pixels wide
glTranslatef(0.0017, …, …);
glScale(0.9967, …, …);
如果您想使用像素而不是范围0 ... 1,请进一步将比例除以纹理宽度。
很大的抱怨:
OpenGL-3完全放弃了整个矩阵操作函数,并期望您提供它准备好使用矩阵和着色器。对于OpenGL片段着色器,有一个很好的函数texelFetch
,您可以使用它来直接获取具有绝对坐标的纹理像素。使用它会使事情很多更容易!