Seite 1 von 1

Daten/Objekte in OpenGL laden und im Shader verfügbar machen

Verfasst: 30. April 2012 08:00
von Fr0z3n[On3]
Guten Tag,

ich versuche mich gerade an meinem ersten Projekt in Qt. Ich möchte nun eine einfache Ebene rendern, auf die ich auch eine Textur spannen kann. Zudem möchte ich die Shader selbst schreiben, d.h. die Vertices und Texturcoords müssen dort ebenfalls verfügbar sein.
Ich habe als Grundlage zunächst mit dem Beispiel HelloGL begonnen und mir versucht aus "Cube OpenGL ES 2.0 example" ein paar Sachen zusammenzuklauen... bisher nicht mit dem richtigen Erfolg. Nun, hier mal die entscheidenden Codestellen:

Das wurde nur leicht angepasst..

Code: Alles auswählen

void GLWidget::initializeGL()
{
    qglClearColor(qtPurple.dark());

    //logo = new QtLogo(this, 64);
    //logo->setColor(qtGreen.dark());

    initShaders();
    initGeometry();

    glEnable(GL_DEPTH_TEST);
    //glEnable(GL_CULL_FACE);
    //glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_MULTISAMPLE);
    static GLfloat lightPosition[4] = { 0.5, 5.0, 7.0, 1.0 };
    glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
}
Das hier ist noch identisch zum Beispielcode:

Code: Alles auswählen

void GLWidget::initShaders()
{
    // Overriding system locale until shaders are compiled
    setlocale(LC_NUMERIC, "C");

    // Compiling vertex shader
    if (!program->addShaderFromSourceFile(QGLShader::Vertex, ":/vshader.glsl"))
        close();

    // Compiling fragment shader
    if (!program->addShaderFromSourceFile(QGLShader::Fragment, ":/fshader.glsl"))
        close();

    // Linking shader pipeline
    if (!program->link())
        close();

    // Binding shader pipeline for use
    if (!program->bind())
        close();

    // Restore system locale
    setlocale(LC_ALL, "");

    //vertArr_loc = program->attributeLocation("a_position");
    //mvpMat_loc = program->uniformLocation("mvp_matrix");
}
initGeometry ist komplett neu. Ich bin mir vor allem bei den Buffer nicht sicher, ob sie das machen, was sie eigentlich sollten, damit es klappt...

Code: Alles auswählen

void GLWidget::initGeometry(){
    VertexData vertices[] = {
        // Vertex data for face 0
        {QVector3D(-1.0, -1.0,  0.0), QVector2D(0.0, 0.0)},  // v0
        {QVector3D( 1.0, -1.0,  0.0), QVector2D(1.0, 0.0)}, // v1
        {QVector3D(-1.0,  1.0,  0.0), QVector2D(0.0, 1.0)},  // v2
        {QVector3D( 1.0,  1.0,  0.0), QVector2D(1.0, 1.0)}, // v3
    };

    GLushort indices[] = {
         0,  1,  2,  3
    };

    vertexBuffer = QGLBuffer();
    vertexBuffer.create();
    vertexBuffer.allocate(vertices, sizeof(VertexData) * 4);

    indexBuffer = QGLBuffer(QGLBuffer::IndexBuffer);
    indexBuffer.create();
    indexBuffer.allocate(indices, sizeof(GLushort) * 4);
}
Dann hier noch die resize-Funktion. Habe ich mehr oder weniger aus dem Cube-Beispiel übernommen:

Code: Alles auswählen

void GLWidget::resizeGL(int w, int h)
{
    // Set OpenGL viewport to cover whole widget
    glViewport(0, 0, w, h);

    // Calculate aspect ratio
    qreal aspect = (qreal)w / ((qreal)h?h:1);

    // Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
    const qreal zNear = 3.0, zFar = 7.0, fov = 45.0;

    // Reset projection
    projection.setToIdentity();

    // Set perspective projection
    projection.perspective(fov, aspect, zNear, zFar);
}
So und zusetzt die eigentliche drawGL-Funktion.

Code: Alles auswählen

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //glLoadIdentity();
    QMatrix4x4 mv_mat;
    //glTranslatef(0.0, 0.0, -10.0);
    mv_mat.translate(0, 0, -10.0);
    //glRotatef(xRot / 16.0, 1.0, 0.0, 0.0);
    mv_mat.rotate(xRot / 16.0, 1.0, 0.0, 0.0);
    //glRotatef(yRot / 16.0, 0.0, 1.0, 0.0);
    mv_mat.rotate(yRot / 16.0, 0.0, 1.0, 0.0);
    //glRotatef(zRot / 16.0, 0.0, 0.0, 1.0);
    mv_mat.rotate(zRot / 16.0, 0.0, 0.0, 1.0);

    program->setUniformValue("mvp_matrix", projection * mv_mat);
    program->enableAttributeArray("a_position");
    vertexBuffer.bind();
    program->setAttributeBuffer("a_position", GL_FLOAT, 0, 3, 2);
    indexBuffer.bind();
    glDrawElements(GL_TRIANGLE_STRIP, indexBuffer.size(), sizeof(GLushort), &indexBuffer);
}
Insgesamt compiliert der Code und läuft auch - nur ist eben nichts außer der Hintergrundfarbe und die Regler zum drehen des Objektes sichtbar.
Im Vertex-Shader werden dann die Vertices aus a_position mit der mvp_matrix transformiert und Fragment-Shader alle betrachteten Fragmente auf weiß gesetzt. (War bisher zu Testzwecken, um zu sehen ob überhaupt etwas passiert.)

Mir fehlen also so ein bisschen die konkreten Befehle um das gewollte zu bewerkstelligen. Kann das Qt alleine oder muss ich da eventuell auch direkt mit openGL arbeiten?

Danke schon mal im Voraus.

Und falls es irgendwie zur Sache tut:
Ubuntu 10.04 64bit, Qt 4.7.4