Использование QPainter поверх OpenGL в QGLWidget при использовании шейдеров

Многие из пользователей Qt (в частности, 4.6) знакомы с примером Overpainting, представленным в руководствах по OpenGL. Я пытаюсь сделать что-то очень похожее, но используя шейдеры для чистых данных OpenGL вместо старого конвейера с фиксированными функциями.

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

Я создаю приложение для 3D-активов, следовательно, сетку. Чтобы сделать его действительно очевидным, когда он работает, в верхнем левом углу виджета должен появиться большой красный прямоугольник, но это не так.

3D работает нормально, но QPainter ничего не выводит на экран. Единственная реальная разница, которую я вижу между моей и документацией, заключается в том, что все расчеты матриц проекций и преобразований скрыты в других функциях, а затем загружаются в шейдер через glUniform. Предположительно, поскольку QPainter разбивает 2D-активы на треугольники, это означает, что шейдеры QPainter не имеют доступа к моим матрицам проекции/преобразования, поэтому мой красный треугольник начинает рисоваться, но, возможно, где-то за кадром.


person cmannett85    schedule 30.11.2010    source источник


Ответы (2)


Вызовите beginNativePainting() перед выполнением вызовов OpenGL. Также может потребоваться glPush/Pop состояния OpenGL. Попробуйте что-то вроде следующего:

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 ) );
person baysmith    schedule 30.11.2010
comment
Все еще не повезло, 3D-данные не затронуты, но данные QPainter не отображаются. Мне интересно, будет ли быстрее/проще отображать в пиксельный буфер, загружать его в QPainter в качестве фонового растрового изображения, а затем «рисовать» поверх перед рисованием на экране? Или это намного медленнее, чем кажется? - person cmannett85; 30.11.2010
comment
Появляются ли данные QPainter, если вы не выполняете 3D-рисунок? - person baysmith; 30.11.2010
comment
Я заполнил функцию paintEvent() только вызовами QPainter (как в примере с 2D-рисованием в документах), и на экране ничего не появилось, за исключением того, что виджет заполнен черным. - person cmannett85; 30.11.2010
comment
Что-то не в исходном фрагменте кода вызывает проблему. - person baysmith; 01.12.2010
comment
Решено! После вашего последнего комментария мне удалось отследить это до того, что я не отвязал VBO после того, как VAO сетки был отвязан, что, по-видимому, полностью испортило инструкции вершин, которые вызывал QPainter. Большое тебе спасибо! - person cmannett85; 02.12.2010

Я публикую этот ответ, чтобы усилить и прояснить то, что я считаю истинным решением, найденным cmannet85 (комментарий к ответу baysmith выше), которое заключается в очистке OpenGL. привязки вершинного буфера перед вызовом кода QPainter.

У меня была почти идентичная проблема: мне нужно было переключаться между использованием функций QPainter и функций OpenGL. Как выяснил cmannet85, одна из причин заключается в том, что если функции OpenGL оставляют связанные буферы вершин позади, они мешают использованию QPainter OpenGL.

Я смог решить проблему, добавив этот оператор в конце всех частей моего кода OpenGL ES 2.0, который вызывал glBindBuffer:

glBindBuffer(GL_ARRAY_BUFFER,0);

Второй параметр 0 отвязывает буфер.

Не было необходимости в каких-либо других изменениях, таких как добавление вызовов beginNativePainting ... endNativePainting и т. д.

person Graham Asher    schedule 21.11.2017