我的问题是使用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混合是不是搞砸了,我很茫然。我注意到角落像素的颜色是边缘像素的两倍,也许这很重要......也许这里有人可以发现错误?
答案 0 :(得分: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;
这可能是弄乱混合的原因。我在纹理调制方面遇到了同样的问题......在底部和右边缘有一条稍微有点暗淡的线条或一系列像素。
答案 1 :(得分:0)
好的,过去几天我一直在努力。很少有想法根本不起作用。唯一有效的是承认这个“完美像素”存在并试图欺骗它。不好我不能投票给你答案宇宙培根。但你的答案,即使它看起来不错 - 会在像Games这样的特殊程序中毁掉一切。我的回答 - 改善了你的。
以下是解决方案:
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();
}
Step2:如果你打算使用“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个像素,有时,需要做一个较小的步骤,但纹理看起来还不错,而且,它是 - - 一个伟大的进步!
很抱歉有一个真正的大答案。我还在研究一个好的解决方案。一旦我找到更好更短的东西 - 这将被我删除。