Using QPainter over OpenGL in QGLWidget when using

2019-03-25 16:28发布

问题:

Many of you Qt (4.6 specifically) users will be familiar with the Overpainting example supplied in the OpenGL tutorials, I'm trying to do something very similar but using shaders for the pure OpenGL data, instead of the old fixed-function pipeline.

//  Set background and state.
makeCurrent();
qglClearColor( bgColour_ );

glEnable( GL_DEPTH_TEST );
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

if ( smoothLines_ ) {
    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    glEnable( GL_LINE_SMOOTH );
    glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
}

//  Clear the buffers.
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUseProgram( shader_ );

//  Draw the grid.
try {
    glLineWidth( 2.0f );
    manager_->setColour( centreColour_ );
    grid_->draw( oE_GLGrid::Centre );

    glLineWidth( 1.5f );
    manager_->setColour( majorColour_ );
    grid_->draw( oE_GLGrid::Major );

    glLineWidth( 1.0f );
    manager_->setColour( minorColour_ );
    grid_->draw( oE_GLGrid::Minor );
} catch( oE_GLException& e ) {
    cout << "OpenGL Error: " << e.what() << endl;
    return;
}

//  Reset OpenGL state for overlays.
glDisable( GL_DEPTH_TEST );
if ( smoothLines_ ) {
    glDisable( GL_BLEND );
    glDisable( GL_LINE_SMOOTH );
}

//  Draw the overlays.
QPainter p( this );
p.beginNativePainting();
p.fillRect( 10, 10, 100, 100,
        QColor( 255, 0, 0 ) );
p.endNativePainting();

I'm building a 3D asset application hence the grid stuff. To make it really obvious when it works, a big red rectangle should appear in the top left corner of the widget - but it doesn't.

The 3D works fine, but QPainter gets nothing to the screen. The only real difference I can see between mine and the docs is that the all the projection and transformation matrix calculations are hidden away in other functions and then uploaded to the shader via glUniform. Presumably as QPainter splits the 2D assets into triangles, this means that QPainter's shaders don't have access to my projection/transformation matrices, so my red triangle is begin drawn - but perhaps somewhere offscreen.

回答1:

Call beginNativePainting() before making OpenGL calls. A glPush/Pop of the OpenGL state may also be necessary. Try something like the following:

QPainter p( this );
p.beginNativePainting();

// Maybe necessary
glPushAttrib(GL_ALL_ATTRIB_BITS);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();

// Put OpenGL code here

// Necessary if used glPush-es above
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopAttrib();

p.endNativePainting();

p.fillRect( 10, 10, 100, 100,
        QColor( 255, 0, 0 ) );


回答2:

I'm posting this answer to strengthen and clarify what I regard as the true solution, found by cmannet85 (comment to answer by baysmith above), which is to clean up OpenGL vertex buffer bindings before calling QPainter code.

I had an almost identical problem, in that I needed to switch between using QPainter functions and OpenGL functions. As cmannet85 found out, one cause is that if OpenGL functions leave bound vertex buffers behind, they interfere with QPainter's use of OpenGL.

I was able to fix the problem by adding this statement at the end of all the parts of my OpenGL ES 2.0 code which called glBindBuffer:

glBindBuffer(GL_ARRAY_BUFFER,0);

A second parameter of 0 unbinds the buffer.

There was no need for any other changes such as adding calls to beginNativePainting ... endNativePainting, etc.