基本 GLSL:两个片段着色器彼此相邻,但第一个(绘制纹理)被覆盖



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

我想按渲染帧执行以下操作:

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

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

我的假设是,两个frament着色器以某种方式相互冲突,或者我完全错过了状态。 我很高兴能得到这里缺少什么的提示。

提前感谢!

这是我的一些代码:

这是步骤 (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);

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

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

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

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

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

因此,可能发生的情况是在第二部分中设置了一些值,从而破坏了第一部分。例如:

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

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

不过,在您的代码中唯一引起注意的是

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

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

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

最新更新