2

我的问题涉及使用 OpenGL 渲染文本——文本被渲染成纹理,然后绘制到四边形上。问题是纹理边缘的像素被绘制成部分透明的。纹理的内部很好。

我正在计算纹理坐标以击中我的纹理像素的中心,使用 NEAREST(非)插值,将纹理环绕设置为 CLAMP_TO_EDGE,并设置投影矩阵以将我的顶点放置在视口像素的中心。还是看到了问题。

我正在使用他们的纹理实用程序开发 VTK。这些是用于加载纹理的 GL 调用,由调试器逐步确定:

glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Create and bind pixel buffer object here (not shown, lots of indirection in VTK)...
glTexImage2D( GL_TEXTURE_2D, 0 , GL_RGBA, xsize, ysize, 0, format, GL_UNSIGNED_BYTE, 0);
// Unbind PBO -- also omitted
glBindTexture(GL_TEXTURE_2D, id);
glAlphaFunc (GL_GREATER, static_cast<GLclampf>(0));
glEnable (GL_ALPHA_TEST);
// I've also tried doing this here for premultiplied alpha, but it made no difference:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();

渲染代码:

  float p[2] = ...; // point to render text at

  int imgDims[2] = ...; // Actual dimensions of image
  float width = ...; // Width of texture in image
  float height = ...; // Height of texture in image

  // Prepare the quad
  float xmin = p[0];
  float xmax = xmin + width - 1;
  float ymin = p[1];
  float ymax = ymin + height - 1;
  float quad[] = { xmin, ymin,
                   xmax, ymin,
                   xmax, ymax,
                   xmin, ymax };

  // Calculate the texture coordinates.
  float smin = 1.0f / (2.0f * (imgDims[0]));
  float smax = (2.0 * width - 1.0f) / (2.0f * imgDims[0]);
  float tmin = 1.0f / (2.0f * imgDims[1]);
  float tmax = (2.0f * height - 1.0f) / (2.0f * imgDims[1]);

  float texCoord[] = { smin, tmin,
                       smax, tmin,
                       smax, tmax,
                       smin, tmax };

  // Set projection matrix to map object coords to pixel centers
  // (modelview is identity)
  GLint vp[4];
  glGetIntegerv(GL_VIEWPORT, vp);
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  float offset = 0.5;
  glOrtho(offset, vp[2] + offset,
          offset, vp[3] + offset,
          -1, 1);

  // Disable polygon smoothing. Why not, I've tried everything else?
  glDisable(GL_POLYGON_SMOOTH);

  // Draw the quad
  glColor4ub(255, 255, 255, 255);
  glEnableClientState(GL_VERTEX_ARRAY);
  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  glVertexPointer(2, GL_FLOAT, 0, points);
  glTexCoordPointer(2, GL_FLOAT, 0, texCoord);
  glDrawArrays(GL_QUADS, 0, 4);
  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  glDisableClientState(GL_VERTEX_ARRAY);

  // Restore projection matrix
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();

出于调试目的,我用红色覆盖了最外层的纹素,用绿色覆盖了下一层纹素(否则很难看到大部分为白色的文本图像中发生了什么)。

我已经使用 gDEBugger 检查了内存中的纹理,它看起来和预期的一样——纹理区域周围有明亮的红色和绿色边框(额外的空白空间被填充以使其大小成为 2 的幂)。以供参考:

好像素!

这是最终渲染图像的样子(放大 20 倍——黑色像素是在调试边框下渲染的文本的残余)。淡红色边框,但仍然是粗体的绿色内边框:

像素差!

因此,受影响的只是像素的外边缘。我不确定是颜色混合还是 alpha 混合把事情搞砸了,我很茫然。我注意到角落像素是边缘像素的两倍,也许这很重要......也许这里有人可以发现错误?

4

2 回答 2

0

可能是“像素完美”问题。OpenGL 将线的中心定义为光栅化为像素的点。中间正好是 1 个整数和下一个整数之间的一半……让像素 (x,y) 显示“完美像素”……将你的坐标固定为:

x=(int)x+0.5f; // x is a float.. makes 0.0 into 0.5, 16.343 into 16.5, etc. 
y=(int)y+0.5f;

这可能是搞乱混合的原因。我在纹理调制方面遇到了同样的问题……在底部和右侧边缘有一条稍微暗一点的线或一系列像素。

于 2013-09-22T05:19:16.810 回答
0

好的,这几天我一直在努力。几乎没有什么想法根本行不通。唯一有效的是承认这个“完美像素”的存在并试图欺骗它。糟糕的是,我不能为你的答案投赞成票宇宙培根。但是你的答案,即使它看起来不错——会有点破坏像游戏这样的特殊程序中的一切。我的回答——改进了你的。

这是解决方案:

Step1:制作一个绘制您需要的纹理的方法,并仅将其用于绘制。并将 0.5f 添加到每个坐标。看:

public void render(Texture tex,float x1,float y1,float x2,float y2)
{
    tex.bind();
    GL11.glBegin(GL11.GL_QUADS);
    GL11.glTexCoord2f(0,0);
    GL11.glVertex2f(x1+0.5f,y1+0.5f);
    GL11.glTexCoord2f(1,0);
    GL11.glVertex2f(x2+0.5f,y1+0.5f);
    GL11.glTexCoord2f(1,1);
    GL11.glVertex2f(x2+0.5f,y2+0.5f);
    GL11.glTexCoord2f(0,1);
    GL11.glVertex2f(x1+0.5f,y2+0.5f);
    GL11.glEnd();
}

步骤 2:如果您要使用“glTranslatef(somethin1,somethin2,0)”,那么制作一种克服“Translatef”并且不会让相机在分数距离上移动的方法会很好。因为如果相机移动的可能性很小,比如说,0.3 - 迟早你会再次看到这个问题(我想多次)。下一个代码使相机跟随具有 X 和 Y 的对象。相机永远不会从视线中丢失对象:

public void LookFollow(Block AF)
{
    float some=5;//changing me will cause camera to move faster/slower
    float mx=0,my=0;

    //Right-Left
    if(LookCorX!=AF.getX())
    {
        if(AF.getX()>LookCorX)
        {
            if(AF.getX()<LookCorX+2)
                mx=AF.getX()-LookCorX;
            if(AF.getX()>LookCorX+2)
                mx=(AF.getX()-LookCorX)/some;
        }
        if(AF.getX()<LookCorX)
        {
            if(2+AF.getX()>LookCorX)
                mx=AF.getX()-LookCorX;
            if(2+AF.getX()<LookCorX)
                mx=(AF.getX()-LookCorX)/some;
        }
    }

    //Up-Down
    if(LookCorY!=AF.getY())
    {
        if(AF.getY()>LookCorY)
        {
            if(AF.getY()<LookCorY+2)
                my=AF.getY()-LookCorY;
            if(AF.getY()>LookCorY+2)
                my=(AF.getY()-LookCorY)/some;
        }
        if(AF.getY()<LookCorY)
        {
            if(2+AF.getY()>LookCorY)
                my=AF.getY()-LookCorY;
            if(2+AF.getY()<LookCorY)
                my=(AF.getY()-LookCorY)/some;
        }
    }

    //Evading "Perfect Pixel"
    mx=(int)mx;
    my=(int)my;

    //Moving Camera
    GL11.glTranslatef(-mx,-my,0);

    //Saving up Position of camera.
    LookCorX+=mx;
    LookCorY+=my;
}
float LookCorX=300,LookCorY=200; //camera's starting position

结果——我们收到了一个移动得更锐利的相机,因为步长不能小于 1 个像素,有时,有必要做一个更小的步长,但纹理看起来还不错,而且,它 - 很棒进步!

对不起,一个真正的大答案。我仍在研究一个好的解决方案。一旦我找到更好更短的东西——这将被我抹去。

于 2015-04-04T02:16:40.090 回答