用QOpenGLWidget绘制模型,点击屏幕外的地方或者改变窗口尺寸时已绘制好的模型消失,但是背景仍然正常绘制

代码如下:

void OpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    f = QOpenGLContext::currentContext()->functions(); 
    f->glEnable(GL_DEPTH_TEST);

    this->initializeShaders();

}

void OpenGLWidget::initializeShaders()
{
    this->m_ModelShader = new QOpenGLShaderProgram(this);
    // 加载着色器程序
    /*--------m_ModelShader------------*/
    if (!m_ModelShader->addShaderFromSourceFile(QOpenGLShader::Vertex, \
        ModelvertexShaderPath))
            qDebug() << "Failed to load Vert shader:" << m_ModelShader->log();
    if (!m_ModelShader->addShaderFromSourceFile(QOpenGLShader::Fragment, \
        ModelfragmentShaderPath))
            qDebug() << "Failed to load fragment shader:" << m_ModelShader->log();
    if (!m_ModelShader->link())
        std::cout << "ERROR: failed to link: " << m_ModelShader->log().toStdString();

}

void OpenGLWidget::resizeGL(int w, int h)
{
    this->SCR_WIDTH = w;
    this->SCR_HEIGHT = h;
    this->SelectProjection(this->operatePro);
}

void OpenGLWidget::paintGL()
{
    f = QOpenGLContext::currentContext()->functions();
    f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    f->glClearColor(0.0f, 0.5f, 0.7f, 1.0f);
    if (isValid())
        switch (RenderModel)
        {
            case Model://平滑渲染
            {
                makeCurrent();
                m_VAO = new QOpenGLVertexArrayObject(this);
                m_VBO = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
                m_EBO = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);

                this->DrawModelData();

                m_ModelShader->bind();
                {
                    m_VAO->bind();
                    m_EBO->bind();
                    this->setModelShaderMatrix();
                    // 绘制
                    f->glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
                }
                m_ModelShader->release();
                break;
            }
            case Line://平滑渲染加渲染模型线框
            {
                break;
            }
            case Points://渲染模型线框
            {
                break;
            }
        }
}


void OpenGLWidget::DrawModelData()
{

    this->m_ModelShader->bind();
    /*--------------------------初始化------------------*/
    if (!m_VAO->create())
        std::cerr << "ERROR: faild to create vertex array object" << std::endl;
    if (!m_VBO->create())
        std::cerr << "ERROR: failed to create vertex buffer object" << std::endl;
    if (!m_EBO->create())
        std::cerr << "ERROR: failed to create index buffer object" << std::endl;

    /*-------------------顶点数组绑定------------------*/
    m_VAO->bind();
    if (!m_VBO->bind())
    {
        std::cerr << "ERROR: failed to bind vertex buffer object" << std::endl;

    }//将与该对象相关联的缓存绑定到当前OpenGL环境
    m_VBO->allocate(&meshes[0], meshes.size() * sizeof(Vertex));

    if (!m_EBO->bind())
    {
        std::cerr << "ERROR: failed to bind index buffer object" << std::endl;
    }
    m_EBO->allocate(&indices[0], sizeof(unsigned int) * indices.size());

    int vertexLocation = m_ModelShader->attributeLocation("aPos"); // 位置属性的位置为 0
    int normalLocation = m_ModelShader->attributeLocation("aNormal"); // 法线属性的位置为 1
    glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Position));
    glEnableVertexAttribArray(vertexLocation);
    
    glVertexAttribPointer(normalLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
    glEnableVertexAttribArray(normalLocation);
    //this->m_ModelShader->enableAttributeArray(vertexLocation);
    //this->m_ModelShader->setAttributeBuffer(vertexLocation, GL_FLOAT, offsetof(Vertex, Position), 3, sizeof(Vertex));

    //this->m_ModelShader->enableAttributeArray(normalLocation);
    //this->m_ModelShader->setAttributeBuffer(normalLocation, GL_FLOAT, offsetof(Vertex, Normal), 3, sizeof(Vertex));
    m_VBO->release();
    m_EBO->release();
    m_VAO->release();
    m_ModelShader->release();
}

void OpenGLWidget::setModelShaderMatrix()
{
    // DirLight变量
    GLint ViewPos = glGetUniformLocation(m_ModelShader->programId(), "viewPos");
    GLint lightDir = glGetUniformLocation(m_ModelShader->programId(), "dirLight.direction");
    GLint lightAmb = glGetUniformLocation(m_ModelShader->programId(), "dirLight.ambient");
    GLint lightDif = glGetUniformLocation(m_ModelShader->programId(), "dirLight.diffuse");
    GLint lightSpe = glGetUniformLocation(m_ModelShader->programId(), "dirLight.specular");
    // Material变量
    GLint materAmb = glGetUniformLocation(m_ModelShader->programId(), "material.ambient");
    GLint materDif = glGetUniformLocation(m_ModelShader->programId(), "material.diffuse");
    GLint materSpe = glGetUniformLocation(m_ModelShader->programId(), "material.specular");
    GLint materShi = glGetUniformLocation(m_ModelShader->programId(), "material.shininess");
    GLint alpha = glGetUniformLocation(m_ModelShader->programId(), "alpha");

    GLint Model_model = glGetUniformLocation(m_ModelShader->programId(), "model");
    GLint Model_view = glGetUniformLocation(m_ModelShader->programId(), "view");
    GLint Model_proj = glGetUniformLocation(m_ModelShader->programId(), "projection");
    m_ModelShader->setUniformValue(ViewPos, m_Camera->getPosition());
    m_ModelShader->setUniformValue(lightAmb, Light_ambient);
    m_ModelShader->setUniformValue(lightDir, Light_direction);
    m_ModelShader->setUniformValue(lightDif, Light_diffuse);
    m_ModelShader->setUniformValue(lightSpe, Light_specular);

    m_ModelShader->setUniformValue(materAmb, Model_ambient);
    m_ModelShader->setUniformValue(materDif, Model_diffuse);
    m_ModelShader->setUniformValue(materSpe, Model_specular);
    m_ModelShader->setUniformValue(materShi, Model_shininess);
    m_ModelShader->setUniformValue(alpha, 1.0f);
    //视图、投影、模型矩阵
    this->m_view = m_Camera->GetViewMatrix();
    // 将QMatrix4x4转换为float数组
    m_ModelShader->setUniformValue(Model_view, m_view);
    m_ModelShader->setUniformValue(Model_proj, m_projection);

    // 设置模型矩阵
    m_scale_rate = max(0.75f / max_len, m_scale_rate);//以导入的最小模型为标准
    this->m_model.scale(m_scale_rate);
    this->m_model = m_scale * m_model;
    this->m_middle = QVector3D(this->bbox.centerPoint.x, this->bbox.centerPoint.y, this->bbox.centerPoint.z);
    this->m_model.translate(-m_middle);
    this->m_model = m_move * m_rotate * m_model;
    m_ModelShader->setUniformValue(Model_model, m_model);
}

【以下回答由 GPT 生成】

该问题可能是由于在改变窗口尺寸或点击屏幕外部时,OpenGL上下文被重建导致的。为了解决这个问题,你可以尝试在重新调整窗口尺寸或点击屏幕外部时重新初始化OpenGL的相关资源。

一个可能的解决方案如下:

void OpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    f = QOpenGLContext::currentContext()->functions(); 
    f->glEnable(GL_DEPTH_TEST);

    // 在这里添加一个标志,用于检查是否需要重新初始化OpenGL资源
    this->isOpenGLInitialized = false;

    // 将下面的代码移到resizeGL函数中
    // this->initializeShaders();
}

void OpenGLWidget::resizeGL(int w, int h)
{
    this->SCR_WIDTH = w;
    this->SCR_HEIGHT = h;

    // 在这里添加一个条件,仅当OpenGL未初始化时才进行初始化
    if (!this->isOpenGLInitialized)
    {
        this->initializeShaders();
        this->isOpenGLInitialized = true;
    }

    this->SelectProjection(this->operatePro);
}

// ...

通过添加一个isOpenGLInitialized标志来跟踪OpenGL是否已经初始化,当需要重新初始化时(例如改变窗口尺寸)才会执行初始化代码。这可以确保在重新调整窗口尺寸或点击屏幕外部时,模型不会消失。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^