QtとC++とOpenGLで立方体をGLSLで表示だよ
I wrote: 2017/06/03
以前2回ほど立方体を表示させてましたが、それらは非常に古い方法なので今回はGLSLで立方体を表示させてみました!
ちょっと解説
まず立方体といっても6つの三角形で3面を作っているだけで、視点を変えれば立方体に見えないです笑。透視投影変換などの変換処理については以前ならglMatrixMode、glloadidentity、glFrustumなどを使って表現していましたが、それらはとっくの昔に非推奨になっているので、自力で行います٩( 'ω' )و
で、肝心の頂点シェーダとフラグメントシェーダ部分はファイルにして読み込むようにしています。各シェーダを読み込む「readShader(自作)」はここに載せると全体ソースが長くなるので可読性重視で省略!加えて、MyPCのOpenGLのバージョンが2.1(古い!)なので、各シェーダの書き方が古いので注意!
以下は実行結果とソース。
/***** foo.vert *****/
attribute vec3 vertex;
attribute vec3 normal;
varying vec3 color;
uniform mat4 MVP;
const vec3 lightColor = vec3(0.8, 0.8, 0.8); // 当てる光の色
const vec3 matColor = vec3(1.0, 1.0, 1.0); // 立方体自体の色
const vec3 matColor = vec3(1.0, 1.0, 1.0); // 立方体自体の色
void main() {
vec3 lightDir = normalize(vec3(4.0, 4.0, 3.0)); // 光の方向
color = vec3(dot(lightDir, vertex)) * lightColor * matColor;
color *= normal; // 法線を適用
gl_Position = MVP * vec4(vertex, 1.0);
}
/***** foo.frag *****/
varying vec3 color;
void main() {
gl_FragColor = vec4(color, 1.0);
}
/***** Sample.cpp *****/
#include <QApplication>
#include <QApplication>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QVector>
#include <glm/gtc/matrix_transform.hpp>
#include "readShader.h"
/***** 描画クラス *****/
class SampleGL {
public:
GLuint vbo[2];
GLuint program;
GLuint vao;
GLint vertexId, normalId, mvpId;
glm::mat4 model, projection, view, Mvp;
QVector<float> position = { // 座標
0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f,
0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f,
1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f,
0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
QVector<float> normal = { // 法線
0.6f, 0.6f, 0.6f,
0.6f, 0.6f, 0.6f,
0.6f, 0.6f, 0.6f,
0.6f, 0.6f, 0.6f,
0.6f, 0.6f, 0.6f,
0.6f, 0.6f, 0.6f,
0.4f, 0.4f, 0.4f,
0.4f, 0.4f, 0.4f,
0.4f, 0.4f, 0.4f,
0.4f, 0.4f, 0.4f,
0.4f, 0.4f, 0.4f,
0.4f, 0.4f, 0.4f,
0.8f, 0.8f, 0.8f,
0.8f, 0.8f, 0.8f,
0.8f, 0.8f, 0.8f,
0.8f, 0.8f, 0.8f,
0.8f, 0.8f, 0.8f,
0.8f, 0.8f, 0.8f
};
public:
void init() {
// readShader(自作)を呼び、各シェーダファイルを読む
QOpenGLFunctions *func = QOpenGLContext::currentContext()->functions();
program = readShader(func, "./foo.vert", "./foo.frag");
// シェーダの"vertex"と"normal"と"MVP"のインデックスを取得
vertexId = glGetAttribLocation(program, "vertex");
normalId = glGetAttribLocation(program, "normal");
mvpId = glGetUniformLocation(program, "MVP");
glGenVertexArrays(1, &vao); // VAO
glBindVertexArray(vao);
glGenBuffers(2, vbo); // VBO
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*position.size(),
position.constData(), GL_STATIC_DRAW);
position.constData(), GL_STATIC_DRAW);
glVertexAttribPointer(vertexId, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(vertexId);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*normal.size(),
normal.constData(), GL_STATIC_DRAW);
normal.constData(), GL_STATIC_DRAW);
glVertexAttribPointer(normalId, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(normalId);
}
void resize(int w, int h)
{
glViewport(0, 0, w, h);
glEnable(GL_DEPTH_TEST);
projection = glm::perspective(glm::radians(45.0f), w / (float)h, 0.1f, 100.f);
view = glm::lookAt(glm::vec3(2,2,4), glm::vec3(0,0,0), glm::vec3(0,1,0));
model = glm::mat4(1.0f);
Mvp = projection * view * model;
}
void paint() // 立方体を表示!
{
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glUniformMatrix4fv(mvpId, 1, GL_FALSE, &Mvp[0][0]);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, position.size() / 3);
glUseProgram(0);
}
};
/****** コントローラークラス ******/
class Sample : public QOpenGLWidget, protected QOpenGLFunctions {
private:
SampleGL *sampleGL;
public:
Sample(QWidget *parent = NULL) : QOpenGLWidget(parent) {
this->resize(400, 400); sampleGL = new SampleGL();
}
~Sample() { delete sampleGL; }
protected:
void initializeGL() { initializeOpenGLFunctions(); sampleGL->init(); }
void resizeGL(int w, int h){ sampleGL->resize(w, h); }
void paintGL() { sampleGL->paint(); }
};
int main (int argc, char* argv[]) {
QApplication appl(argc, argv);
Sample sample;
sample.show();
return appl.exec();
}
シェーディングって難しい(;´ρ`)