QtとC++とOpenGLで金の三角形をGLSLで表示

I wrote: 2017/06/02

 QtとC++OpenGLを使って金の三角形をGLSLで表示してみました。
普通の三角形を表示しても面白みがないので金の三角形にしました。

GLSLについて勉強しながらコーディングしてましたが、ネット上には古い情報と新しい情報が入り乱れてるし、GLSL自体の難易度が高いし、私みたいな若輩者にとっては理解や取捨選択するのが非常に大変!、シェーディングって難しい(´;ω;`)

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

 

#include <QApplication>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QVector>
#include <QDebug>
#include <glm/gtc/matrix_transform.hpp>
/************************
* 描画クラス
***********************/
class SampleGL {
public:
  GLuint vbo;
  GLuint program;
  GLuint vao;
  GLint   vertexId;
  GLint   mvpId;
  glm::mat4 model;
  glm::mat4 projection;
  glm::mat4 view;
  glm::mat4 Mvp;
 
  QVector<float> position = {
    -1.5f, -1.5f, 0.0f,
   1.5f, -1.5f, 0.0f,
   0.0f,  1.5f, 0.0f 
  };  
 
public:
  void init() {
    /*******************************************************
* VertexShaderとFragmentShaderを定義
     *   実際はshader.vert、shader.fragのように外部ファイルにする
     *   それとMyPCのOpenGLのバージョンが悲しいことに2.1なので、
     *   非推奨のattribute、varying、gl_FragColorを使ってます
     *   本来はin、outそしてgl_FragColorは自分で定義します
     * 金色について
     *   金は特殊な色なのでちょっと計算する必要があります
     *   以下の計算は超省略してるので正確な金色ではないです
     ******************************************************/
    const char *vCode =
"attribute vec3 vertex;" 
"varying vec3 color;"
"uniform mat4 MVP;"
"const vec3 lightColor = vec3(0.4, 0.4, 0.4);"
"void main() {"
"vec3 ambient = vec3(0.24725, 0.1995, 0.0745);"
"vec3 diffuse = vec3(0.75164,  0.60648,  0.22648);"
"vec3 specular = vec3(0.628281, 0.555802,0.366065);"
"vec3 lightDir = normalize(vec3(4.0, 4.0, 3.0));"
"color = vec3(dot(lightDir, vertex)) * lightColor * diffuse;"
"color += specular + diffuse;"
    "gl_Position = MVP * vec4(vertex, 1.0);"
"}";
 
const char *frCode =
"varying vec3 color;"
"void main() {"
"gl_FragColor = vec4(color, 1.0);"
"}";
// VertexShaderをコンパイル(本当はエラーチェックも!)
    GLuint vshader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vshader, 1, &vCode, NULL);
    glCompileShader(vshader);
    // FragmentShaderをコンパイル(本当はエラーチェックも!)
    GLuint fshader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fshader, 1, &frCode, NULL);
    glCompileShader(fshader);
 
    program = glCreateProgram(); // 各シェーダとリンク
    glAttachShader(program, vshader);
    glAttachShader(program, fshader);
    glLinkProgram(program);
// シェーダの"vertex"と"MVP"のインデックスを取得
    vertexId = glGetAttribLocation(program, "vertex");
    mvpId = glGetUniformLocation(program, "MVP");
 
glGenVertexArrays(1, &vao); // VAO
  glBindVertexArray(vao);
 
    glGenBuffers(1, &vbo); // VBO
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*position.size(),
position.constData(), GL_STATIC_DRAW);
    glVertexAttribPointer(vertexId, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(vertexId);
  }
 
  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(1,4,7), 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_TRIANGLE_STRIP, 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(); 
}

擬似的な金色ですが、個人的には上出来なので良しとします٩( 'ω' )و
金のambientとdiffuseとspecularとshinenessは以下より引用しました。
http://devernay.free.fr/cours/opengl/materials.html