C++ 创建了红色/黄色瓷砖的棋盘格图案

C++ 创建了红色/黄色瓷砖的棋盘格图案,c++,opengl,texture-mapping,C++,Opengl,Texture Mapping,即使zpos=0.02f,也无法在GTX460/WinXP上重现该问题 听起来像是驱动程序/精度/固定功能问题 我要找的是渲染一个平铺,并且100%确保除了我想要的平铺之外,不会从该纹理渲染任何其他内容 您可以将每个瓷砖存储在单独的纹理中(我知道这是一种浪费),并使用GL\u CLAMP\u TO\u EDGE进行GL\u texture\u WRAP\S/GL\u texture\u WRAP\T 或者,您可以在每个平铺周围添加像素边框,通过向外复制边缘上的像素来“扩展”平铺。即,在瓷砖顶部边

即使zpos=0.02f,也无法在GTX460/WinXP上重现该问题

听起来像是驱动程序/精度/固定功能问题

我要找的是渲染一个平铺,并且100%确保除了我想要的平铺之外,不会从该纹理渲染任何其他内容

您可以将每个瓷砖存储在单独的纹理中(我知道这是一种浪费),并使用
GL\u CLAMP\u TO\u EDGE
进行
GL\u texture\u WRAP\S
/
GL\u texture\u WRAP\T

或者,您可以在每个平铺周围添加像素边框,通过向外复制边缘上的像素来“扩展”平铺。即,在瓷砖顶部边缘上方,将顶部边缘的副本放在左侧边缘的左侧,与瓷砖的右侧和底部边缘相同。这将浪费额外的纹理内存(因为每个平铺的宽度/高度将增加2个像素),但您永远看不到相邻的像素

它可能会被着色器修复吗

也许吧。 可以通过以下方式调整片段着色器中的纹理坐标(非GLSL伪代码):

在使用它们(纹理坐标)从纹理/采样器实际读取数据之前。但是,您需要知道瓷砖坐标和纹理大小。另一方面,没有什么可以阻止您将此数据编码为顶点属性/一致性

因此,要绕过此问题,您可以:

  • 使用更多纹理(切换纹理会浪费性能)
  • 浪费纹理内存
  • 使用着色器调整纹理协调浪费GPU电源

  • 决定权归你。

    这是基于提供的新示例。请注意,前面提到的信息仍然正确,因为亚像素精度是一个真正的问题(这就是为什么我把它留在这里)。然而,在新的情况下,这并不是随机线在达到亚像素极限之前出现的原因

    较低缩放级别的线条是由纹理坐标插值中的简单不精确造成的。您要传递的是半开范围:[0/w,16/w)。但如果插值器正好生成16/w,则它将从第16个纹理提取

    典型的解决方案是对纹理坐标应用小偏差:

    float tx2 = ((float)(xt+tilesize)/img_w) - (1.0f / 8192.0f);
    float ty2 = ((float)(yt+tilesize)/img_h) - (1.0f / 8192.0f);
    
    这也将消除亚像素问题,因为您正在对纹理坐标应用偏移

    它不会是“像素完美的”,但是如果它第一次是像素完美的,你就不会看到这个问题。在处理缩放和纹理时,像素完美总是相对的

    它将在指定的偏移范围内达到像素完美。8192中的1。以256x256图像为例,在像素的1/32范围内达到像素完美。您必须将平铺放大32倍,然后才能缩小一个像素

    如果你不需要把它放到图像编辑或处理应用程序中,或者通过计算像素就可以分辨出区别,我会非常惊讶)

    如果您选择较大的图像,可能需要较小的偏差。请注意,偏差本身的有效性是绝对的;偏差越小,再次看到问题的可能性越大。例如,偏差为1/32768时,我的Radeon HD-3300显示了问题。因此8192非常接近分母所能获得的最大值

    请注意,填充每个平铺的左上角也会起作用。就我个人而言,我会坚持使用偏移,除非您的平铺太多,以至于偏移会影响图像的渲染

    请注意,着色器提供了在不修改纹理坐标的情况下解决此问题的方法,只需将纹理坐标作为像素坐标传递,并将其夹持到边的正前方。这适用于任何纹理分辨率。阵列纹理将通过将每个分片放在阵列中其自己的条目中来工作

    这就是你的选择


    注意:我正在运行AMD HD-3300卡

    当非常接近对象时,出现的情况是纹理提取单元似乎没有亚像素精度。我可以判断,因为如果我将缩放停止的阈值更改为恰好发生的点,我可以扩展窗口的大小,然后它就会出现。因此,这就是apparent屏幕大小,这是诱导的效果

    通过将纹理大小增加到4096,我能够排除纹理坐标插值精度问题。这与问题出现的时间无关。因此,它必须位于纹理提取单元硬件本身,而不是纹理坐标插值单元。也就是说,插值的纹理坐标很好;当rdware做了一个数学运算,让texel从出现问题的地方获取数据


    经过一些实验后,当texel被映射到大约64-90个屏幕像素的大小时,问题似乎出现了。因此,在事情变得混乱之前,您似乎获得了大约6个亚像素位的精度。

    这是基于提供的新示例。请注意,前面提到的信息仍然正确,因为亚像素精度锡安是一个真正的问题(这就是为什么我把它留在那里)。然而,这并不是随机线在达到新情况下的亚像素限制之前出现的原因

    较低缩放级别的线条是由纹理坐标插值中的简单不精确造成的。您要传递的是半开放范围:[0/w,16/w]。但如果插值器正好生成16/w,则它将从第16个纹理提取

    典型的解决方案是对纹理坐标应用小偏差:

    float tx2 = ((float)(xt+tilesize)/img_w) - (1.0f / 8192.0f);
    float ty2 = ((float)(yt+tilesize)/img_h) - (1.0f / 8192.0f);
    
    这也将消除亚像素问题,因为您正在对纹理坐标应用偏移

    它不会是“像素完美的”,但是如果它第一次是像素完美的,你就不会看到这个问题。在处理缩放和纹理时,像素完美总是相对的

    它将在指定的偏差范围内达到像素完美。这是8192中的1。考虑到256x256图像的情况,这是在1/32范围内的像素完美
    void adjustCoords(float &s, float &t, int tilex, int tiley){
        float sMin = (0.5f + (float)tilex)/(float)image.width,
            sMax = ((float)(tilex + tilewidth) - 0.5f)/(float)image.width,
            tMin = (0.5f + (float)tiley)/(float)image.height,
            tMax = ((float)(tiley + tileheight) - 0.5f)/(float)image.height;
        s = min(max(s, sMin), sMax);
        t = min(max(t, tMin), tMax);
    }
    
    float tx2 = ((float)(xt+tilesize)/img_w) - (1.0f / 8192.0f);
    float ty2 = ((float)(yt+tilesize)/img_h) - (1.0f / 8192.0f);