Как создать окно QT и использовать чистый профиль ядра OpenGL внутри?

#c #qt #opengl

#c #qt #opengl

Вопрос:

Я не хочу использовать QOpenGLWidget из-за старой версии OpenGL внутри. Я не понимаю, в чем разница между получением qopengglфункций из контекста и прямой инициализацией qopenglфункций_4_5_core. Я вижу, что я не получаю все функции из контекста, и не понимаю, почему. Итак, как получить из контекста все функции? Например, glPolygonMode() недоступен в qopenglфункциях, полученных из контекста, и в QOpenGLExtraFunctions, также полученных из контекста. Кто-нибудь может объяснить, как использовать чистый современный OpenGL с QT?

Это мой код: openglwidget.cpp

 
#include "openglwindow.h"

#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLExtraFunctions>
#include <QOpenGLFunctions_4_5_Core>
#include <QDebug>
#include <QTimer>
#include <sys/time.h>

static const char* vertexShaderSource =
        "#version 450 coren"
        "layout (location = 0) in vec3 aPos;n"
        "out vec4 vertexColor;n"
        "void main()n"
        "{n"
        "gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);n"
        "vertexColor = vec4(0.5, 0.0, 0.0, 1.0);n"
        "}";
/*static const char* fragmentShaderSource =
        "#version 450 coren"
        "out vec4 FragColor;n"
        "in vec4 vertexColor;n"
        "void main()n"
        "{n"
        "FragColor = vertexColor;n"
        "}";*/

static const char* fragmentShaderSource =
        "#version 450 coren"
        "out vec4 FragColor;n"
        "uniform vec4 ourColor;n"
        "void main()n"
        "{n"
        "FragColor = ourColor;n"
        "}";

void OpenGLWindow::GenTriangleBuffer()
{
    float vertices[] = {
                        -0.5f, -0.5f, 0.0f,
                        0.5f, -0.5f, 0.0f,
                        0.0f, 0.5f, 0.0f
                       };
    this->m_funcs->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
}

void OpenGLWindow::GenRectangleBuffer()
{
    float vertices[] = {
                        0.5f, 0.5f, 0.0f, // top right
                        0.5f, -0.5f, 0.0f, // bottom right
                        -0.5f, -0.5f, 0.0f, // bottom left
                        -0.5f, 0.5f, 0.0f // top left
                        };
    unsigned int indices[] = { // note that we start from 0!
                                0, 1, 3, // first triangle
                                1, 2, 3 // second triangle
                             };
    this->m_funcs->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    this->m_funcs->glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
                                GL_STATIC_DRAW);

}

OpenGLWindow::OpenGLWindow(QScreen* screen)
    : QWindow(screen)
{
    setSurfaceType(QWindow::OpenGLSurface);
    QSurfaceFormat format;
    format.setDepthBufferSize( 24 );
    format.setMajorVersion(4);
    format.setMinorVersion(5);
    format.setProfile(QSurfaceFormat::CoreProfile);
    format.setSamples(4);
    setFormat(format);
    create();

    // Create an OpenGL context
    this->m_context = new QOpenGLContext;
    this->m_context->setFormat(format);
    this->m_context->create();

    // Make the context current on this window
    this->m_context->makeCurrent(this);

    /*QSet<QByteArray> extensions = m_context->extensions();
    //std::sort(extensions);
    qDebug() << "Supported extensions (" << extensions.count() <<")";

    foreach (const QByteArray amp;extension, extensions) {
      qDebug() << "    " << extension;
    }*/

    // Obtain a functions object and resolve all entry points
    // m_funcs is declared as: QOpenGLFunctions_4_5_Core* m_funcs
    this->m_funcs = new QOpenGLFunctions_4_5_Core; /*m_context->functions();*/
    //this->m_extra_func = m_context->extraFunctions();
    this->m_funcs->initializeOpenGLFunctions();


    //set window geometry
    this->setGeometry(100, 100, 800, 600);
    //set OpenGL render size

    this->m_funcs->glViewport(this->geometry().x(),
                        this->geometry().y(),
                        this->geometry().width(),
                        this->geometry().height());

    qDebug() << "--- Window geometry: {n" << this->geometry().x() << ", "
           << this->geometry().y() << ", " << this->geometry().width()
           << ", " << this->geometry().height() << "nt} ";
    QTimer *timer = new QTimer(this);
    connect(timer, amp;QTimer::timeout, this, this->render);
    timer->start(500);


    //*OPENGL TRINGLE INITIALIZATION*//
    unsigned int VBO, vertexShader, fragmentShader, EBO;
    this->m_funcs->glGenVertexArrays(1, amp;VAO);
    this->m_funcs->glGenBuffers(1, amp;VBO);
    this->m_funcs->glGenBuffers(1, amp;EBO);
    this->m_funcs->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    this->m_funcs->glBindVertexArray(VAO);
    this->m_funcs->glBindBuffer(GL_ARRAY_BUFFER, VBO);
    this->m_funcs->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    GenTriangleBuffer();

    vertexShader = this->m_funcs->glCreateShader(GL_VERTEX_SHADER);
    this->m_funcs->glShaderSource(vertexShader, 1, amp;vertexShaderSource, NULL);
    this->m_funcs->glCompileShader(vertexShader);
    int success;
    char infoLog[512];
    this->m_funcs->glGetShaderiv(vertexShader, GL_COMPILE_STATUS, amp;success);
    if(!success)
    {
        this->m_funcs->glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILEDn" <<
        infoLog;
    }

    fragmentShader = this->m_funcs->glCreateShader(GL_FRAGMENT_SHADER);
    this->m_funcs->glShaderSource(fragmentShader, 1, amp;fragmentShaderSource, NULL);
    this->m_funcs->glCompileShader(fragmentShader);
    this->m_funcs->glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, amp;success);
    if(!success)
    {
        this->m_funcs->glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILEDn" <<
        infoLog;
    }

    shaderProgram = this->m_funcs->glCreateProgram();
    this->m_funcs->glAttachShader(shaderProgram, vertexShader);
    this->m_funcs->glAttachShader(shaderProgram, fragmentShader);
    this->m_funcs->glLinkProgram(shaderProgram);
    this->m_funcs->glGetProgramiv(shaderProgram, GL_LINK_STATUS, amp;success);
    if(!success) {
        this->m_funcs->glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILEDn" <<
        infoLog;
    }

    this->m_funcs->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float),
                                        (void*)0);
    this->m_funcs->glEnableVertexAttribArray(0);

    this->m_funcs->glDeleteShader(vertexShader);
    this->m_funcs->glDeleteShader(fragmentShader);
}


void OpenGLWindow::resizeEvent(QResizeEvent *)
{
    /*qDebug() << "--- Window RESIZED, new geometry: {n" << this->geometry().x() << ", "
           << this->geometry().y() << ", " << this->geometry().width()
           << ", " << this->geometry().height() << "nt} ";*/
    if(this->m_funcs)
        this->m_funcs->glViewport(0,
                                  0,
                                  this->geometry().width(),
                                  this->geometry().height());
}

void OpenGLWindow::moveEvent(QMoveEvent *)
{
    /*qDebug() << "--- Window MOVED, new geometry: {n" << this->geometry().x() << ", "
           << this->geometry().y() << ", " << this->geometry().width()
           << ", " << this->geometry().height() << "nt} ";*/
    if(this->m_funcs)
        this->m_funcs->glViewport(0,
                                  0,
                                  this->geometry().width(),
                                  this->geometry().height());

}



void OpenGLWindow::render()
{
    timeval tim;
    gettimeofday(amp;tim,NULL);
    float timeValue = tim.tv_usec;;
    float greenValue = (sin(timeValue) / 2.0f)   0.5f;
    int vertexColorLocation = this->m_funcs->glGetUniformLocation(shaderProgram, "ourColor");


    this->m_funcs->glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    this->m_funcs->glClear(GL_COLOR_BUFFER_BIT);
    this->m_funcs->glUseProgram(shaderProgram);
    this->m_funcs->glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

    this->m_funcs->glBindVertexArray(VAO);
    this->m_funcs->glDrawArrays(GL_TRIANGLES, 0, 3);
    //this->m_funcs->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    this->m_context->swapBuffers(this);

}

void OpenGLWindow::exposeEvent(QExposeEvent *event)
{
    if (this->isExposed())
        this->render();
}

bool OpenGLWindow::event(QEvent *event)
{
    switch (event->type()) {
        case QEvent::UpdateRequest:
            this->render();
            return true;
        default:

            return QWindow::event(event);
        }
}


void OpenGLWindow::keyPressEvent(QKeyEvent *)
{

}

void OpenGLWindow::keyReleaseEvent(QKeyEvent *)
{

}


OpenGLWindow::~OpenGLWindow()
{

}
 

openglwidget.h

 #ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QWindow>

class QOpenGLFunctions;
class QOpenGLContext;
class QOpenGLExtraFunctions;
class QOpenGLFunctions_4_5_Core;

class OpenGLWindow : public QWindow
{
    Q_OBJECT
public:
    explicit OpenGLWindow(QScreen *screen = nullptr);
    ~OpenGLWindow();

public:
    virtual void render();

private:
    QOpenGLContext* m_context = nullptr;
    /*QOpenGLFunctions* m_funcs = nullptr;*/
    QOpenGLFunctions_4_5_Core* m_funcs = nullptr;
    QOpenGLExtraFunctions* m_extra_func = nullptr;
    unsigned int shaderProgram{}, VAO{};
    void GenTriangleBuffer();
    void GenRectangleBuffer();
protected:
    void resizeEvent(QResizeEvent *) override;
    void moveEvent(QMoveEvent *) override;

    void keyPressEvent(QKeyEvent *) override;
    void keyReleaseEvent(QKeyEvent *) override;

    void exposeEvent(QExposeEvent *event) override;
    bool event(QEvent *event) override;
};
#endif // GLWIDGET_H
 

main.cpp

 
#include <QApplication>
#include "openglwindow.h"
#include <QWindow>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    OpenGLWindow w(nullptr);
    w.show();
    return a.exec();
}

 

Комментарии:

1. Я не уверен, что действительно понимаю проблему. example code Демонстрируется, как связать a QOpenGLWidget с функциями из определенного профиля — наследовать от обоих QOpenGLWidget и QOpenGLFunctions_4_5_Core . Разве это не то, что вы ищете?

2. Возможно, но в чем разница между получением функций из контекста и QOpenGLFunctions_4_5_Core ?

3. Я могу вручную установить контекст на версию ядра 4.5, но я не получаю все функции, объявленные в QOpenGLFunctions_4_5_Core

4. Кроме того, вам важно знать, я использую QT 6.2, в нем нет функции context->versionFunctions<T>() . Вы отправили документацию для QT 5.15

Ответ №1:

Попробуйте сделать так, чтобы ваш OpenGLWindow наследует от

общедоступный QOpenGLWidget, защищенные функции QOpenGL

вот так:

class OpenGLWindow : public QOpenGLWidget, protected QOpenGLFunctions_4_5_Core { ... };