0
votes

I'm working on a viewer in Qt to show images with lines or text on top. I have organized images, lines and text on several layers, each layer is a GL_QUADS. If I stack images in z and then draw a layer on top with lines, it all works as expected. But I want to draw more lines on several other layers at the same z as the first lines layer, and that's the result: lines layers conflict.

I don't understand why each lines layer erase previous overlapped lines layer (but don't corrupt underlying images). Moreover if I draw another layer at the same z as lines layer but with some text, this is the result: text layer issue.

Text layer create a hole in all undelying layers and you can see the background.

Lines and text are painted with QPainter on a QImage this way:

m_img = new QImage(&m_buffer[0], width, height, QImage::Format_RGBA8888);
m_img->fill(Qt::transparent);

QPen pen(color);
pen.setWidth(2);
m_painter.begin(m_img);
m_painter.setRenderHints(QPainter::Antialiasing, true);
m_painter.setPen(pen);
m_painter.drawLines(lines);
m_painter.end();

QFont font;
int font_size = font.pointSize() * scale;
if (font_size > 0) { font.setPointSize(font_size); }
QPen pen(color);
m_painter.begin(m_img);
m_painter.setRenderHints(QPainter::Antialiasing, true);
m_painter.setFont(font);
m_painter.setPen(pen);
for(int index = 0; index < messages.size(); index++)
    m_painter.drawText(positions.at(index), messages.at(index));
m_painter.end();

and textures:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, d->width(), d->height(), 0, GL_RGBA,  GL_UNSIGNED_BYTE, d->data());

This is my texture setup():

GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST/*GL_LINEAR*/);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST/*GL_LINEAR*/);
opengl_error_check(__FILE__, __LINE__);

This is my initializeGL():

glClearColor(0.0, 0.25, 0.5, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_MULTISAMPLE);
glEnable(GL_DEPTH_TEST);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_FLAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

Finally I have set QGLFormat(QGL::AlphaChannel) in my QGLWidget.

I know that there is a problem of z-fighting using overlapping planes at the same z, but as far as I know it should matter only if the overlapping textures are not transparent. In my case some artifacts may be expected where lines crosses, but I don't understand why lines disappear. And since I use the same way to draw lines and text, I don't understand why text layer influence images while lines not.

Last note: I have printed pixel values in all textures right before glTexImage2D() and values are as expected.

I'm pretty sure there is some obvious mistake, can someone point me where I'm wrong?

1
Any other suggestion? I've tried with several blending options but did non work. Also ordering objects in painting process ignoring depth is not an option for my application...joaulo

1 Answers

2
votes

OpenGL works by "painter" principle. Unless you use Z-ordering (aka depth test), what is drawn last is drawn on top. It works like splattering paint on the wall, hence the term. Nota bene: depth test is off by default, in general, it does slow rendering down.

If you use Z-ordering, OpenGL will "hide" fragments which fall into area of "window space" (color buffer), where "paint" with bigger Z value already exist. Thus , there is no depth-based "automatic" transparency in OpenGL: to emulate transparency you must paint things in proper order, with proper blending mode. That may prove to be problem, if objects intersect or self-intersect. Creating complex scenes with transparency and shadows requres technique called deferred rendering.

If you paint with same Z, result again depends on blending and if color is solid, you'll just overpaint what is already there, just like if depth test is off.

PS. There is not enough data about text issue, I don't see any text there but it looks like you do painting on top of OpenGL's output. Which widget is is, QGLWidget, or QOpenGLWindget? In fact, those two source write into separate passes, and font is draw by Qt using platform-depenadant means, so text might be overwritten? It's not recomended to use Qt's painter output with OpenGL, you may need to look into use of libraries to output text in OpenGL.