QtとC++とOpenGLで立方体をGLSLで表示だよ

I wrote: 2017/06/03

以前2回ほど立方体を表示させてましたが、それらは非常に古い方法なので今回はGLSLで立方体を表示させてみました!

ちょっと解説
まず立方体といっても6つの三角形で3面を作っているだけで、視点を変えれば立方体に見えないです笑。透視投影変換などの変換処理については以前ならglMatrixMode、glloadidentity、glFrustumなどを使って表現していましたが、それらはとっくの昔に非推奨になっているので、自力で行います٩( 'ω' )و

で、肝心の頂点シェーダとフラグメントシェーダ部分はファイルにして読み込むようにしています。各シェーダを読み込む「readShader(自作)」はここに載せると全体ソースが長くなるので可読性重視で省略!加えて、MyPCのOpenGLのバージョンが2.1(古い!)なので、各シェーダの書き方が古いので注意!

以下は実行結果とソース。
41

 

/***** 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);  // 立方体自体の色
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 <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);
    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);
    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(); 
}

シェーディングって難しい(;´ρ`)