Qt CreatorとGLSLを組み合わせれば新しい扉が開く

255, 2019-11-25

目次

Qt CreatorでGLSL

Qt CreatorでGLSLを使ってみたのでメモ。

結果

Qt Creatorと回る三角形【GLSL】

プロジェクト

IDEで個人的に困るのがプロジェクト構成のメモり方。
画像にした。

Qt CreatorでGLSLを試したときの構成
  • main.cpp
  • dialog.h
  • dialog.cpp

はデフォルトのファイル。

mygl.*

// mygl.hpp

/**
 * Attribute and Uniform Reference: http://doc.qt.io/qt-5/qopenglshaderprogram.html
 */

#ifndef MYGL_H
#define MYGL_H

#pragma comment(lib, "OpenGL32.lib")
#pragma comment(lib, "glu32.lib")

#include <QGL>
#include <QGLWidget>

#include <QGLBuffer>
#include <QGLShaderProgram>
#include <QMatrix4x4>

#include <QDebug>
#include <QWidget>
#include <QTimer>
#include <QMap>

struct Attribute {
    int location;
    int size;
};

struct Uniform {
    int location;
};

class MyGL : public QGLWidget
{
    Q_OBJECT

public:
    MyGL(QWidget* parent = nullptr);

    virtual void initializeGL();
    virtual void paintGL();
    virtual void resizeGL(int w, int h);

private:
    bool prepareShaderProgram(
            QString const& vertexShaderPath,
            QString const& fragmentShaderPath);

private:
    QTimer timer_;
    QGLShaderProgram program_;
    QGLBuffer vertexBuffer_;

    QMatrix4x4 mvpMat_,
               pMat_,
               vMat_,
               mMat_;

    QMap<QString, Attribute> attribs_;
    QMap<QString, Uniform> uniforms_;
};

#endif // MYGL_H
// mygl.cpp

#include "mygl.h"

MyGL::MyGL(QWidget* parent)
    : QGLWidget(parent)
    , timer_()
    , program_()
    , vertexBuffer_(QGLBuffer::VertexBuffer)
    , mvpMat_()
    , pMat_()
    , vMat_()
    , mMat_()
    , attribs_()
    , uniforms_()
{
    connect(&timer_, SIGNAL(timeout()), this, SLOT(updateGL()));
    timer_.start(16.666666);
}

void MyGL::initializeGL()
{
    // Init OpenGL
    glClearColor( 0.5f, 0.5f, 0.5f, 1.0f);

    // Triangle vertices for VBO
    float points[] {
         0.0f, 1.0f, 0.0f, 1.0f,
        -1.0f, 0.0f, 0.0f, 1.0f,
         1.0f, 0.0f, 0.0f, 1.0f,
    };

    // Ready VBO
    vertexBuffer_.create();
    vertexBuffer_.setUsagePattern(QGLBuffer::StaticDraw);
    if (!vertexBuffer_.bind()) {
        qWarning() << "VBO: Failed to bind";
        return;
    }

    // Set vertices to VBO
    vertexBuffer_.allocate(points, 3 * 4 * sizeof(float));

    // Shader Program from source files
    if (!prepareShaderProgram(":/my.vs", ":/my.fs")) {
        qWarning() << "Failed to prepareShaderProgram";
        return;
    }
    if (!program_.bind()) {
        qWarning() << "Program: Failed to bind";
        return;
    }

    // Enable Attribute in Shader Program
    program_.setAttributeBuffer("vertex_in_vs", GL_FLOAT, 0, 4);
    program_.enableAttributeArray("vertex_in_vs");

    // Get Location from Shader Program
    attribs_["frame"].location = program_.attributeLocation("frame");
    attribs_["frame"].size = 1;
    uniforms_["mvpMat"].location = program_.uniformLocation("mvpMat");
}

void MyGL::paintGL()
{
    static float frame = 0.0f;

    // Viewport
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glViewport( 0, 0, size().width(), size().height());

    // Projection
    auto w = static_cast<double>(size().width());
    auto h = static_cast<double>(size().height());

    pMat_.setToIdentity();
    pMat_.perspective(60.f, w/h, 0.001f, 120.0f);

    // Viewing
    vMat_.setToIdentity();
    vMat_.lookAt({0,0,5}, {0,0,0}, {0,1,0});

    // Update MVP Matrix
    mvpMat_ = pMat_ * vMat_;

    // Modeling
    static float angle = 0.f;
    mMat_.setToIdentity();
    mMat_.rotate(angle, 0.f, 0.f, 1.f);
    angle += 1.f;
    if (angle >= 360.f)
        angle = 0.f;

    // Update MVP Matrix
    mvpMat_ *= mMat_;

    // Render
    program_.setAttributeValue(attribs_["frame"].location, frame);
    program_.setUniformValue(uniforms_["mvpMat"].location, mvpMat_);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    frame += 1.f;
}

void MyGL::resizeGL(int w, int h)
{
    glViewport( 0, 0, w, h);
}

bool MyGL::prepareShaderProgram(const QString &vertexShaderPath, const QString &fragmentShaderPath)
{
    bool res;

    // Add shader from source files
    res = program_.addShaderFromSourceFile(QGLShader::Vertex, vertexShaderPath);
    if (!res) {
        qWarning() << program_.log();
    }
    res = program_.addShaderFromSourceFile(QGLShader::Fragment, fragmentShaderPath);
    if (!res) {
        qWarning() << program_.log();
    }

    // Link
    res = program_.link();
    if (!res) {
        qWarning() << "Failed to link: " << program_.log();
    }

    return res;
}

Qtがクラスを用意してくれているおかげでスッキリと書ける。
オペレーターのオーバーロードで行列の演算も見た目がわかりやすい。キュート。

シェーダー

Vertex Shader

// my.vs
attribute vec4 vertex_in_vs;
attribute float frame;
uniform mat4 mvpMat;
varying float varFrame;

void main(void) {
    varFrame = frame;
    gl_Position = mvpMat * vertex_in_vs;
}

Fragment Shader

// my.fs
#version 330
layout(location = 0, index = 0) out vec4 fragColor;
varying float varFrame;

void main(void) {
    fragColor = vec4(abs(cos(varFrame/100.0)), abs(cos(varFrame/200.0)), abs(cos(varFrame/300.0)), 1.0);
}

シェーダーはリソースに登録する。

Reference

投稿者名です。64字以内で入力してください。

必要な場合はEメールアドレスを入力してください(全体に公開されます)。

投稿する内容です。

スポンサーリンク

スポンサーリンク

スポンサーリンク

スポンサーリンク