【问题标题】:Basic GLSL: Two fragment shaders behind each other, but first one (drawing a texture) is overwritten基本 GLSL:两个片段着色器相互连接,但第一个(绘制纹理)被覆盖
【发布时间】:2017-10-19 08:23:00
【问题描述】:

我是 OpenGL ES 的半新手,看起来我缺少一个基本概念。 我在我的代码中使用了一些 QT 类,但它接近普通的 OpenGL ES。

我想为每个渲染帧执行以下操作:

  1. 渲染一个基于TRIANLGE_STRIP 且带有纹理的简单全屏矩形。您可以将其视为背景图像。这已经可以自己运行了。一个自己的顶点和片段着色器(由 QOpenGLShaderProgram 包装)用于渲染它。纹理最初来自 QOpenGLFramebufferObject,它本身有时会重新渲染,但不是每一帧。
  2. 在 (1.) 中绘制 TRIANGLE_STRIP 后,我想在顶部渲染另一个基本形状。目前底部还有一个小矩形。这使用了另一个顶点和框架着色器。这部分也可以单独工作。

我的问题是:这两个步骤一起不起作用。我只看到 (2.) 中屏幕底部的小矩形,但纹理消失了。应该显示纹理的区域用透明颜色填充。

我的假设是,两个框架着色器以某种方式相互冲突,或者我完全错过了状态的一些东西.. 我很高兴能提示这里缺少的内容。

提前致谢!

这是我的一些代码:

这是步骤(1)的顶点和帧着色器代码:

static const char* vertexShaderSource =
    "attribute highp vec4 triangleCoords;\n"
    "attribute lowp vec2 textureCoords;\n"
    "varying lowp vec2 v_textureCoords;\n"
    "void main() {\n"
    "   v_textureCoords = textureCoords;\n"
    "   gl_Position = triangleCoords;\n"
    "}\n";

static const char* fragmentShaderSource =
    "varying lowp vec2 v_textureCoords;\n"
    "uniform sampler2D sampler;\n"
    "void main() {\n"
    "   gl_FragColor = vec4(texture2D(sampler, v_textureCoords).rgb, 1.0);\n"
    "}\n";

m_textureProgram = new QOpenGLShaderProgram();
m_textureProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
m_textureProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);   

这是步骤(2)的顶点和帧着色器代码:

static const char* vertexShaderSource =
    "attribute highp vec4 position;\n"
    "uniform lowp vec4 color;\n"
    "void main() {\n"
    "   gl_Position = position;\n"
    "}\n";

static const char* fragmentShaderSource =
    "uniform lowp vec4 color;\n"
    "void main() {\n"
    "   gl_FragColor = color;\n"
    "}\n";

m_shapeProgram->addShaderFromSourceCode( QOpenGLShader::Vertex, vertexShaderSource );
m_shapeProgram->addShaderFromSourceCode( QOpenGLShader::Fragment, fragmentShaderSource );

还有主要的渲染功能,稍微精简了一点(我跳过了初始化部分,其中设置了着色器程序并绑定了属性位置):

m_context->makeCurrent(w);
glClear( GL_COLOR_BUFFER_BIT );

// Step (1.) begins here
m_textureProgram->bind();
glBindTexture(GL_TEXTURE_2D, textureId);
m_textureProgram->enableAttributeArray( LocationTriangleTextureCoords );
m_textureProgram->enableAttributeArray( LocationTextureCoords );
m_textureProgram->setAttributeArray( LocationTriangleTextureCoords, GL_FLOAT, s_triangleStripCoords, 2 );
m_textureProgram->setAttributeArray( LocationTextureCoords, GL_FLOAT, s_textureCoords, 2);
f.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
m_textureProgram->disableAttributeArray( LocationTriangleTextureCoords );
m_textureProgram->disableAttributeArray( LocationTextureCoords );
m_textureProgram->release();

// Step (2.) begins here:
m_shapeProgram->bind();
m_shapeProgram->setUniformValue( m_colorUniformId, m_color1 );
QPointF p0( -1, -0.7);
QPointF p1( -1, -1.0 );
QPointF p2( 0, -1.0 );
QPointF p3( 0, -0.7 );
GLfloat vertices[12] = { GLfloat(p0.x()), GLfloat(p0.y()),
                         GLfloat(p1.x()), GLfloat(p1.y()),
                         GLfloat(p2.x()), GLfloat(p2.y()),
                         GLfloat(p0.x()), GLfloat(p0.y()),
                         GLfloat(p3.x()), GLfloat(p3.y()),
                         GLfloat(p2.x()), GLfloat(p2.y())
                      };

m_buffer->bind();
m_buffer->write( 0, vertices, sizeof(vertices) );
m_shapeProgram->setAttributeBuffer( LocationShapePosition, GL_FLOAT, 0, 2 );
m_shapeProgram->enableAttributeArray( LocationShapePosition );
f.glDrawArrays( GL_TRIANGLES, 0, 6 );
m_shapeProgram->release();

// Done frame.
m_context->swapBuffers(w);

【问题讨论】:

    标签: c++ qt opengl-es


    【解决方案1】:

    既然你说这两个步骤独立工作正常,我会说问题一定出在其他地方。

    您的问题可能有点不清楚,但如果以下情况属实:

    • 您正在绘制一个带有纹理的全屏矩形,该纹理在单独绘制时正确显示(填满整个屏幕)
    • 您正在绘制一个非全屏较小的形状,该形状在单独绘制时正确显示(您会在未绘制形状的地方看到清晰的颜色)
    • 当您尝试渲染两者时,您应该会在背景中看到全屏纹理,并且具有小形状的部分应该显示小形状
    • 您的结果与只执行第二步完全相同(您会看到未绘制形状的清晰颜色)

    然后我看到 2 个可能的问题。首先(我很确定您必须检查过)可能是您正在清除两次渲染调用之间的颜色缓冲区。无论如何都要仔细检查。

    第二个是这两个程序在某种程度上发生了冲突。如果此代码在每一帧上执行,它可能是有意义的。一个快速的测试是只绘制一次,看看结果是否正确。

    所以可能发生的情况是在第二部分中设置了一些值,这会破坏第一部分。例如:

    如果纹理被第二部分破坏,那么下次调用时,每个提取的纹素可能会返回 (0,0,0,0) 的颜色,通过混合可能会产生透明背景,并且您认为您看到背景清除颜色。您可以通过修改纹理着色器以仅输出纯色来轻松测试这一点,以查看它是否在此处绘制。

    另一个问题可能是某些值设置为错误的程序,第一次调用的顶点数据被第二次调用覆盖。在这种情况下,纹理将正好位于小矩形的后面。你可以通过一个小矩形(半透明)来测试它,看看纹理是否显示在它后面。

    在你的代码中唯一引起注意的是

    m_textureProgram->release();
    m_shapeProgram->release();
    

    这是正确的吗?我希望着色器能够持久。如果不是,那么它们是在哪里创建的?

    您的假设似乎是第二部分以某种方式覆盖其他像素以清除缓冲区。我向你保证这是不可能的。绘制三角形时,无法影响其他像素(至少我猜没有几何着色器),只有点内的像素才会分配片段着色器,并且只有那些可以更改。

    【讨论】:

    • 谢谢,现在已经解决并且可以工作了。步骤 (2.) 中的第二个缓冲区从未被释放。所以缺少一个 m_buffer->release();在绘制第二个三角形之后。
    • 我仍然不确定你为什么不断创建和释放这些缓冲区。创建 1 个保存矩形数据的缓冲区,然后使用矩阵调整其大小。缓冲区应该是持久的,直到您不再需要它为止。在您的情况下,应该停止渲染。
    • 是的,你是对的。那部分只是一些原型设计,但肯定需要按照您的建议进行更改。
    猜你喜欢
    • 2021-04-07
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 2011-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多