当PNG图像加载到纹理上时,图像变得模糊。

6
我在Photoshop中创建了一个带有透明度的png图像,并将其加载到OpenGL程序中。我已经将其绑定到纹理上,在程序中图片看起来模糊,我不确定原因所在。

alt text http://img685.imageshack.us/img685/9130/upload2.png

alt text http://img695.imageshack.us/img695/2424/upload1e.png

加载代码

// Texture loading object
nv::Image title;

// Return true on success
if(title.loadImageFromFile("test.png"))
{
    glGenTextures(1, &titleTex);
    glBindTexture(GL_TEXTURE_2D, titleTex);
    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
    glTexImage2D(GL_TEXTURE_2D, 0, title.getInternalFormat(), title.getWidth(), title.getHeight(), 0, title.getFormat(), title.getType(), title.getLevel(0));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
}

else
    MessageBox(NULL, "Failed to load texture", "End of the world", MB_OK | MB_ICONINFORMATION);

显示代码
glEnable(GL_TEXTURE_2D);    
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, titleTex);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTranslatef(-800, 0, 0.0);
glColor3f(1,1,1);

glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex2f(0,0);
    glTexCoord2f(0.0, 1.0); glVertex2f(0,600);
    glTexCoord2f(1.0, 1.0); glVertex2f(1600,600);
    glTexCoord2f(1.0, 0.0); glVertex2f(1600,0);
glEnd();
glDisable(GL_BLEND);    
glDisable(GL_TEXTURE_2D);

编辑:我不认为我在拉伸每个像素时应该是坐标系中的两个。

int width=800, height=600;
int left = -400-(width-400);
int right = 400+(width-400);
int top = 400+(height-400);
int bottom = -400-(height-400);
gluOrtho2D(left,right,bottom,top);

PNG文件中纹理的尺寸是多少(以像素为单位,高度和宽度)? - andand
看起来可能与图像的缩放有关。在游戏窗口中调整大小会改变质量吗? - andand
因为我的gluOrtho2D,当窗口大小改变时,所有的东西都是相同的大小。 - Chris
1
我应该检查OpenGL的定义,但据我所知,您无法保证此代码不会被重新调整大小。我最好的选择是最终渲染阶段将假定您的图像对于目标来说“稍微”小了一点,并尝试基于1:1和1:4 mipmap进行调整大小。 - KillianDS
5个回答

4

OpenGL通常要求纹理本身的大小是2的幂,因此可能发生的情况是您的纹理被缩放到尺寸为2的幂的大小,然后被缩放回原始大小 -- 在被缩放两次的过程中,您会失去一些质量。

显然,您只想显示位图而不进行任何缩放,也不将其包裹到另一个对象的表面上,或者类似于纹理的其他操作。如果是这种情况,我建议将其作为位图显示,而不是纹理(例如,参见glRasterPos2iglBitmap)。


我很想知道是哪个实现在做这个。据我所知,这不符合GL的规范。要么支持NPOT纹理,应该能够正确加载它们;要么不支持,glTexImage调用应该失败。 另外,glBitmap默认情况下具有将数据在每次调用时传输的不良副作用。请确保使用缓冲区对象来避免这种情况(GL_PIXEL_UNPACK_BUFFER)。 - Bahbar
@Bahbar:请注意,并非所有涉及的内容都是OpenGL本身的一部分——他的nv::Image::LoadImageFromFile完全是独立的——我猜这就是它进行POT大小初始转换的原因(无论是最初还是在将其加载并用作纹理时进行的转换)。 - Jerry Coffin
这可能是由于视频驱动程序引起的。我一直在开发一个基于OpenGL的2D游戏,许多ATI GPU不支持NPOT纹理。尽管它们没有被缩放,但它们仍然会像屏幕截图中一样变得模糊。基本上,你有两个选择。使PNG具有POT维度或者使用不同的GPU。 - leeor_net

3
为什么你要在启动屏幕上的静态图像中使用mipmapping和各向异性过滤呢?看起来这张图片不太可能被旋转(各向异性过滤是为了解决此问题),也不需要快速调整大小多次(这是 mipmapping 可以解决的问题)。
如果纹理被拉伸:尝试在GL_MAG_FILTER中使用GL_NEAREST,在这种情况下它可以给出更好的结果(GL_LINEAR更精确,但有模糊的特性)。
如果纹理被最小化:同样的道理,尝试使用 GL_NEAREST_MIPMAP_NEAREST,甚至更好的方法是尝试不使用mipmaps和GL_NEAREST(或GL_LINEAR,哪个能给您最好的结果)。

无法让任何一个变得更好 :( - Chris
你完全没有任何不同吗?例如,由于混合,我怀疑白色边框仍然会很“丑陋”,但是盒子内的文本应该很清晰。如果所有这些都不改变图像,那么我可能错了,您的纹理没有被调整大小。您是否尝试将其呈现到稍微大一点的屏幕(例如824x618的屏幕)并使用GL_NEAREST进行MAG? - KillianDS
它不同了,但看起来并不更好。 - Chris

2
我建议您将png图像的分辨率设定为2的幂次方,例如1024x512,并将要绘制的部分放在它的左上角,仍保持屏幕的分辨率。然后,将纹理坐标重新缩放为800.0/1024.0和600.0/512.0,以从纹理中获取正确的部分。我相信问题出在glTexImage2D有时可以处理宽度或高度不是2的幂次方的情况,但可能会缩放输入图像,从而过滤图像。
处理方法的实例可以查看 这里 (一个iPhone-OpenGLES项目,截取非2的幂数的屏幕部分并将其绘制到512x512的纹理中,并重新缩放GL_TEXTURE矩阵(第123行),而不是手动调整纹理坐标)。 这里 是另一篇提到此方法的帖子。

1
这里有一个假设:
你的窗口大小为800x600(也许你的帧缓冲区也是如此),但由于窗口两侧的装饰,你的客户区域并非如此。
因此,当帧缓冲区被复制到窗口的客户区域时,它会被重新调整大小。你能检查一下你的窗口创建代码吗?

这是我的创建窗口代码,其中具有相同的变量CreateGLWindow(“Star Racer”,width,height) - Chris
实际上,这种想法是错误的。当您创建一个窗口时,客户区域会根据您需要的大小进行创建。框架随后由Windows添加。因此,如果他说他将窗口创建为800x600,则其客户区域确实为800x600。我不知道Linux,但我知道至少MacOS X和Windows足够聪明,可以正确地管理它。为了证明这一点,快速复制/粘贴到任何图像编辑器中,就会显示他发布的图像为816x638。这将是800x600 + 窗口框架。 - leeor_net

0
  • 注意窗口客户区域的确切大小。仔细检查它是否符合您的预期
  • 注意像素对齐规则。您可能需要在x/y坐标中添加0.5以命中像素中心。DirectX的说明可以在这里找到 - OpenGL的规则可能不同。

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