Qt OpenGL 纹理透明度问题

Posted

技术标签:

【中文标题】Qt OpenGL 纹理透明度问题【英文标题】:Qt OpenGL textures transparency issues 【发布时间】:2017-03-09 12:17:01 【问题描述】:

我正在使用 Qt 中的查看器来显示顶部带有线条或文本的图像。 我在几层上组织了图像、线条和文本,每一层都是一个 GL_QUADS。 如果我在 z 中堆叠图像,然后用线条在顶部绘制一个图层,则一切都按预期工作。 但我想在其他几个图层上绘制更多线条在与第一行图层相同的 z 上,这就是结果: lines layers conflict.

我不明白为什么每个线条层都会擦除先前重叠的线条层(但不会破坏底层图像)。 此外,如果我 在与线层相同的 z 处绘制另一层,但带有一些文本,结果如​​下: text layer issue.

文本层在所有底层图层中创建一个洞,您可以看到背景。

使用 QPainter 在 QImage 上以这种方式绘制线条和文本:

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();

和纹理:

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

这是我的纹理设置():

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__);

这是我的初始化GL():

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);

最后我在我的 QGLWidget 中设置了 QGLFormat(QGL::AlphaChannel)。

我知道在同一 z 上使用重叠平面存在 z-fighting 问题,但据我所知,只有当重叠纹理不透明时才有意义。在我的情况下,可能会在线条交叉的地方出现一些伪影,但我不明白为什么线条会消失。 而且由于我使用相同的方式来绘制线条和文本,我不明白为什么文本层会影响图像而线条不会。

最后一点:我在 glTexImage2D() 之前打印了所有纹理中的像素值,并且值符合预期。

我很确定有一些明显的错误,有人能指出我错在哪里吗?

【问题讨论】:

还有其他建议吗?我尝试了几种混合选项,但没有奏效。此外,在绘画过程中排序对象忽略深度不是我的应用程序的选项... 【参考方案1】:

OpenGL 的工作原理是“画家”。除非您使用 Z 排序(又名深度测试),否则最后绘制的内容将绘制在顶部。它的作用就像在墙上泼油漆一样,因此有了这个词。注意:深度测试默认是关闭的,一般来说,它确实会减慢渲染速度。

如果您使用 Z 排序,OpenGL 将“隐藏”落入“窗口空间”(颜色缓冲区)区域的片段,其中已经存在具有较大 Z 值的“绘制”。因此,在 OpenGL 中没有基于深度的“自动”透明度:要模拟透明度,您必须以正确的顺序使用正确的混合模式进行绘制。如果对象相交或自身相交,则可能会出现问题-相交。创建具有透明度和阴影的复杂场景需要一种称为延迟渲染的技术。

如果您使用相同的 Z 进行绘制,则结果再次取决于混合,如果颜色是纯色,您只需对已经存在的内容进行重绘,就像关闭深度测试一样。

PS。没有足够的关于文本问题的数据,我在那里看不到任何文本,但看起来你是在 OpenGL 的输出之上进行绘画的。哪个小部件是 QGLWidget 或 QOpenGLWindget?事实上,这两个源写入单独的通道,并且字体是由 Qt 使用平台依赖的方式绘制的,所以文本可能会被覆盖?不建议在 OpenGL 中使用 Qt 的painter 输出,您可能需要研究使用库在 OpenGL 中输出文本。

【讨论】:

谢谢@Swift,我正在尝试使用Z-ordering,正如您在initializeGL() 中看到的那样,我设置了glEnable(GL_DEPTH_TEST)。作为与透明纹理中的线条和文本相关的问题,我不关心它们的绘制顺序,但我希望纹理的“透明”部分不会在发生时擦除其他纹理的线条...... “关于文本问题的数据不足”是什么意思?文本由m_painter.drawText() 使用 QPainter 绘制。 QPainter 在缓冲区上创建的 QImage 上绘画。该缓冲区是我与glTexImage2D() 一起使用并设置到GL_QUADS 上的纹理。我可以为您提供更多信息,有什么帮助吗?您在链接“文本层问题”中看到问题了吗? @joaulo AH,那么它与深度测试的问题相同。您应该创建一个具有透明度的纹理 - 即使用 alpha 分量,并在绘制该四边形时使用混合模式。我认为,为此你应该在打印文本之前用透明颜色填充图像。从形式上讲,这是在 OpenGL 中创建“纹理”文本的合法方法,尽管比更复杂的方法要慢一些 @joaulo 如果您需要在 OpenGL 之上系统地输出文本,请尝试使用 QGraphics Screen 代替,您可以将 QOpenGLWinget 直接插入其中,而其他小部件或 graphicscrene 对象可能会覆盖它。这样做很慢,但至少很整洁,特别是如果您想要在图形顶部的按钮或透明小部件。透明度和 z 排序不起作用,您需要以适当的方式排序。 TRansparent 颜色不会删除任何东西,它会被添加到下面的 z 的颜色中,依此类推 是的,这就是我真正想要做的。 QImage(即纹理缓冲区)使用m_img = new QImage(&amp;m_buffer[0], width, height, QImage::Format_RGBA8888); 创建,然后:m_img-&gt;fill(Qt::transparent);。混合是这样处理的:glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 我已经看到它也是 QPainter 的默认设置。

以上是关于Qt OpenGL 纹理透明度问题的主要内容,如果未能解决你的问题,请参考以下文章

渲染具有透明度的纹理时 OpenGL 不需要的像素

OpenGL:渲染具有大量纹理透明度的模型,没有绘制顺序?

透明四边形上的OpenGL DECAL纹理?

OpenGL透明纹理问题

OpenGL 使纹理透明 VBO

在 Android 上使用 OpenGL ES 显示透明纹理的问题