2015-05-05 52 views
1

我在實現QOpenGLWidget中的滾動時遇到了問題。爲了清楚我希望滾動條改變在opengl小部件中呈現的內容,而不是滾動小部件本身。基於this論壇回答我一直在試圖實現一個QAbstractScrollArea的子類。我發現,當opengl小部件被設置爲qabstractscrollarea的視口時,沒有任何東西被渲染,只有黑屏。在QAbstractScrollArea中使用QOpenGLWidget作爲視口

爲了說明這一點,我創建了一個基於Qt中分佈的hellogl2示例項目的基本示例。

mainwindow.cpp中,當glwidget設置爲畫布的視口時,不會發生渲染。

m_scrollCanvas->setViewport(m_glWidget); 

但是,當該行被註釋掉時,會顯示opengl小部件。

有沒有人知道爲什麼opengl widet沒有顯示,當它被設置爲QAbstractScrollArea的視口?

的main.cpp

#include "mainwindow.h" 
#include <QApplication> 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    MainWindow w; 
    w.show(); 

    return a.exec(); 
} 

mainwindow.cpp

#include "mainwindow.h" 
#include "scrollcanvas.h" 
#include "glwidget.h" 

MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
{ 
    m_scrollCanvas = new ScrollCanvas(this); 
    m_glWidget = new GLWidget(m_scrollCanvas); 
    m_scrollCanvas->setViewport(m_glWidget); 
    setCentralWidget(m_scrollCanvas); 
} 

MainWindow::~MainWindow() 
{ 

} 

mainwindow.h

#include <QMainWindow> 
#include "glwidget.h" 
#include "scrollcanvas.h" 

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    MainWindow(QWidget *parent = 0); 
    ~MainWindow(); 

private: 
    ScrollCanvas * m_scrollCanvas; 
    GLWidget * m_glWidget; 

}; 

glwidget.h

#include <QOpenGLWidget> 
#include <QOpenGLVertexArrayObject> 
#include <QOpenGLBuffer> 
#include <QOpenGLShaderProgram> 
#include <QMatrix4x4> 
#include <qopengl.h> 
#include <QVector> 
#include <QVector3D> 

class Logo 
{ 
public: 
    Logo(); 
    const GLfloat *constData() const { return m_data.constData(); } 
    int count() const { return m_count; } 
    int vertexCount() const { return m_count/6; } 

private: 
    void quad(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4); 
    void extrude(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); 
    void add(const QVector3D &v, const QVector3D &n); 

    QVector<GLfloat> m_data; 
    int m_count; 
}; 

class GLWidget : public QOpenGLWidget 
{ 
public: 
    GLWidget(QWidget * parent); 
    ~GLWidget(); 

protected: 
    void resizeGL(int w, int h); 
    void paintGL(); 
    void initializeGL(); 

private: 
    void setupVertexAttribs(); 
    Logo m_logo; 
    QOpenGLVertexArrayObject m_vao; 
    QOpenGLBuffer m_logoVbo; 
    QOpenGLShaderProgram *m_program; 
    int m_projMatrixLoc; 
    int m_mvMatrixLoc; 
    int m_normalMatrixLoc; 
    int m_lightPosLoc; 
    QMatrix4x4 m_proj; 
    QMatrix4x4 m_camera; 
    QMatrix4x4 m_world; 
}; 

glwidget.cpp

#include "glwidget.h" 



GLWidget::GLWidget(QWidget *parent) : QOpenGLWidget(parent), m_program(0) 
{ 
} 

GLWidget::~GLWidget() 
{ 
    m_logoVbo.destroy(); 
    delete m_program; 
    m_program = 0; 
} 

static const char *vertexShaderSourceCore = 
    "#version 150\n" 
    "in vec4 vertex;\n" 
    "in vec3 normal;\n" 
    "out vec3 vert;\n" 
    "out vec3 vertNormal;\n" 
    "uniform mat4 projMatrix;\n" 
    "uniform mat4 mvMatrix;\n" 
    "uniform mat3 normalMatrix;\n" 
    "void main() {\n" 
    " vert = vertex.xyz;\n" 
    " vertNormal = normalMatrix * normal;\n" 
    " gl_Position = projMatrix * mvMatrix * vertex;\n" 
    "}\n"; 

static const char *fragmentShaderSourceCore = 
    "#version 150\n" 
    "in highp vec3 vert;\n" 
    "in highp vec3 vertNormal;\n" 
    "out highp vec4 fragColor;\n" 
    "uniform highp vec3 lightPos;\n" 
    "void main() {\n" 
    " highp vec3 L = normalize(lightPos - vert);\n" 
    " highp float NL = max(dot(normalize(vertNormal), L), 0.0);\n" 
    " highp vec3 color = vec3(0.39, 1.0, 0.0);\n" 
    " highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);\n" 
    " fragColor = vec4(col, 1.0);\n" 
    "}\n"; 

static const char *vertexShaderSource = 
    "attribute vec4 vertex;\n" 
    "attribute vec3 normal;\n" 
    "varying vec3 vert;\n" 
    "varying vec3 vertNormal;\n" 
    "uniform mat4 projMatrix;\n" 
    "uniform mat4 mvMatrix;\n" 
    "uniform mat3 normalMatrix;\n" 
    "void main() {\n" 
    " vert = vertex.xyz;\n" 
    " vertNormal = normalMatrix * normal;\n" 
    " gl_Position = projMatrix * mvMatrix * vertex;\n" 
    "}\n"; 

static const char *fragmentShaderSource = 
    "varying highp vec3 vert;\n" 
    "varying highp vec3 vertNormal;\n" 
    "uniform highp vec3 lightPos;\n" 
    "void main() {\n" 
    " highp vec3 L = normalize(lightPos - vert);\n" 
    " highp float NL = max(dot(normalize(vertNormal), L), 0.0);\n" 
    " highp vec3 color = vec3(0.39, 1.0, 0.0);\n" 
    " highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);\n" 
    " gl_FragColor = vec4(col, 1.0);\n" 
    "}\n"; 

void GLWidget::paintGL() 
{ 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glEnable(GL_DEPTH_TEST); 
    glEnable(GL_CULL_FACE); 

    m_world.setToIdentity(); 
    m_world.rotate(180.0f - (0/16.0f), 1, 0, 0); 
    m_world.rotate(0/16.0f, 0, 1, 0); 
    m_world.rotate(0/16.0f, 0, 0, 1); 

    QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); 
    m_program->bind(); 
    m_program->setUniformValue(m_projMatrixLoc, m_proj); 
    m_program->setUniformValue(m_mvMatrixLoc, m_camera * m_world); 
    QMatrix3x3 normalMatrix = m_world.normalMatrix(); 
    m_program->setUniformValue(m_normalMatrixLoc, normalMatrix); 

    glDrawArrays(GL_TRIANGLES, 0, m_logo.vertexCount()); 

    m_program->release(); 
} 
void GLWidget::initializeGL() 
{ 
    glClearColor(0, 0, 0, 1); 

    m_program = new QOpenGLShaderProgram; 
    m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource); 
    m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource); 
    m_program->bindAttributeLocation("vertex", 0); 
    m_program->bindAttributeLocation("normal", 1); 
    m_program->link(); 

    m_program->bind(); 
    m_projMatrixLoc = m_program->uniformLocation("projMatrix"); 
    m_mvMatrixLoc = m_program->uniformLocation("mvMatrix"); 
    m_normalMatrixLoc = m_program->uniformLocation("normalMatrix"); 
    m_lightPosLoc = m_program->uniformLocation("lightPos"); 

    // Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x 
    // implementations this is optional and support may not be present 
    // at all. Nonetheless the below code works in all cases and makes 
    // sure there is a VAO when one is needed. 
    m_vao.create(); 
    QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); 

    // Setup our vertex buffer object. 
    m_logoVbo.create(); 
    m_logoVbo.bind(); 
    m_logoVbo.allocate(m_logo.constData(), m_logo.count() * sizeof(GLfloat)); 

    // Store the vertex attribute bindings for the program. 
    setupVertexAttribs(); 

    // Our camera never changes in this example. 
    m_camera.setToIdentity(); 
    m_camera.translate(0, 0, -1); 

    // Light position is fixed. 
    m_program->setUniformValue(m_lightPosLoc, QVector3D(0, 0, 70)); 

    m_program->release(); 
} 
void GLWidget::resizeGL(int w, int h) 
{ 
    m_proj.setToIdentity(); 
    m_proj.perspective(45.0f, GLfloat(w)/h, 0.01f, 100.0f); 
} 

void GLWidget::setupVertexAttribs() 
{ 
    m_logoVbo.bind(); 
    glEnableVertexAttribArray(0); 
    glEnableVertexAttribArray(1); 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0); 
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat))); 
    m_logoVbo.release(); 
} 

#include <qmath.h> 

Logo::Logo() 
    : m_count(0) 
{ 
    m_data.resize(2500 * 6); 

    const GLfloat x1 = +0.06f; 
    const GLfloat y1 = -0.14f; 
    const GLfloat x2 = +0.14f; 
    const GLfloat y2 = -0.06f; 
    const GLfloat x3 = +0.08f; 
    const GLfloat y3 = +0.00f; 
    const GLfloat x4 = +0.30f; 
    const GLfloat y4 = +0.22f; 

    quad(x1, y1, x2, y2, y2, x2, y1, x1); 
    quad(x3, y3, x4, y4, y4, x4, y3, x3); 

    extrude(x1, y1, x2, y2); 
    extrude(x2, y2, y2, x2); 
    extrude(y2, x2, y1, x1); 
    extrude(y1, x1, x1, y1); 
    extrude(x3, y3, x4, y4); 
    extrude(x4, y4, y4, x4); 
    extrude(y4, x4, y3, x3); 

    const int NumSectors = 100; 

    for (int i = 0; i < NumSectors; ++i) { 
     GLfloat angle = (i * 2 * M_PI)/NumSectors; 
     GLfloat angleSin = qSin(angle); 
     GLfloat angleCos = qCos(angle); 
     const GLfloat x5 = 0.30f * angleSin; 
     const GLfloat y5 = 0.30f * angleCos; 
     const GLfloat x6 = 0.20f * angleSin; 
     const GLfloat y6 = 0.20f * angleCos; 

     angle = ((i + 1) * 2 * M_PI)/NumSectors; 
     angleSin = qSin(angle); 
     angleCos = qCos(angle); 
     const GLfloat x7 = 0.20f * angleSin; 
     const GLfloat y7 = 0.20f * angleCos; 
     const GLfloat x8 = 0.30f * angleSin; 
     const GLfloat y8 = 0.30f * angleCos; 

     quad(x5, y5, x6, y6, x7, y7, x8, y8); 

     extrude(x6, y6, x7, y7); 
     extrude(x8, y8, x5, y5); 
    } 
} 

void Logo::add(const QVector3D &v, const QVector3D &n) 
{ 
    GLfloat *p = m_data.data() + m_count; 
    *p++ = v.x(); 
    *p++ = v.y(); 
    *p++ = v.z(); 
    *p++ = n.x(); 
    *p++ = n.y(); 
    *p++ = n.z(); 
    m_count += 6; 
} 

void Logo::quad(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4) 
{ 
    QVector3D n = QVector3D::normal(QVector3D(x4 - x1, y4 - y1, 0.0f), QVector3D(x2 - x1, y2 - y1, 0.0f)); 

    add(QVector3D(x1, y1, -0.05f), n); 
    add(QVector3D(x4, y4, -0.05f), n); 
    add(QVector3D(x2, y2, -0.05f), n); 

    add(QVector3D(x3, y3, -0.05f), n); 
    add(QVector3D(x2, y2, -0.05f), n); 
    add(QVector3D(x4, y4, -0.05f), n); 

    n = QVector3D::normal(QVector3D(x1 - x4, y1 - y4, 0.0f), QVector3D(x2 - x4, y2 - y4, 0.0f)); 

    add(QVector3D(x4, y4, 0.05f), n); 
    add(QVector3D(x1, y1, 0.05f), n); 
    add(QVector3D(x2, y2, 0.05f), n); 

    add(QVector3D(x2, y2, 0.05f), n); 
    add(QVector3D(x3, y3, 0.05f), n); 
    add(QVector3D(x4, y4, 0.05f), n); 
} 

void Logo::extrude(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) 
{ 
    QVector3D n = QVector3D::normal(QVector3D(0.0f, 0.0f, -0.1f), QVector3D(x2 - x1, y2 - y1, 0.0f)); 

    add(QVector3D(x1, y1, +0.05f), n); 
    add(QVector3D(x1, y1, -0.05f), n); 
    add(QVector3D(x2, y2, +0.05f), n); 

    add(QVector3D(x2, y2, -0.05f), n); 
    add(QVector3D(x2, y2, +0.05f), n); 
    add(QVector3D(x1, y1, -0.05f), n); 
} 

scrollcanvas.h

#include <QAbstractScrollArea> 
class ScrollCanvas : public QAbstractScrollArea 
{ 
public: 
    ScrollCanvas(QWidget * parent) : QAbstractScrollArea(parent){} 
    ~ScrollCanvas(){} 
}; 
+0

運氣好嗎?我想我有同樣的問題。 –

回答

1

將溶液最終被非常簡單。首先我讓ScrollCanvas成爲GLWidget的一個朋友類,以允許我訪問受保護的函數。然後在執行ScrollCanvas我超載paintEventresizeEvent像這樣:

void ScrollCanvas::resizeEvent(QResizeEvent * event) 
{ 
    GLWidget * glw = dynamic_cast<GLWidget *>(viewport()); 
    glw->resizeEvent(event); 
} 

void ScrollCanvas::paintEvent(QPaintEvent *event) 
{ 
    GLWidget * glw = dynamic_cast<GLWidget *>(viewport()); 
    glw->paintEvent(event); 
} 
+0

你能分享如何使ScrollCanvas成爲GLWidget的朋友類嗎?在此先感謝 – zufryy

+0

我添加了以下'friend class ScrollCanvas'作爲'GLWidget'的私有成員 – cts