スポンサーリンク

GLSLのUniform Buffer Object (UBO) をとりあえず試す

GLSLのUBO。普通のUniform変数はlinkしたプログラムごとに設定するが、UBOは全てのプログラムで共通の変数を使うことができる。

今回はとりあえず動かすことに成功したのでひとまずコードを張っておきたい。

なおシェーダの準備などは作り置きの関数を使用。

GLSLのシェーダ関係の処理を関数化(C++)

ソースコード(C++)

#include <iostream>

#include <Windows.h>
#include "prepare_shader.hpp"
#include <gl/GL.h>
#include <gl/GLU.h>
#include <gl/freeglut.h>
#include <cassert>

#pragma comment(lib,"glew32.lib")

//ウィンドウの幅と高さ
int width, height;

GLuint buf_points1;
GLuint buf_points2;


GLuint programIDR;
GLuint programIDG;

GLuint uniformBufferID;
struct CMatrices {
  GLfloat mproj[16];
  GLfloat mmodel[16];
} _matrices;

void GetZRotate(GLfloat* m, GLfloat rad);

// シェーダとデータの設定
void init() {

  std::vector<GLfloat> points;

  GLfloat s=0.0;
  GLfloat v = 0.8;

  push_3(points, 0 + s, 0,   0);//座標 XYZ
  push_3(points, 0 + s, v,   0);
  push_3(points, v + s, 0,   0);
  prepare_buffer(&buf_points1, points.data(), points.size() * sizeof(GLfloat), GL_STATIC_DRAW);

  s = 0.1;
  points.clear();
  push_3(points, 0 + s, 0, 0);//座標 XYZ
  push_3(points, 0 + s, v, 0);
  push_3(points, v + s, 0, 0);
  prepare_buffer(&buf_points2, points.data(), points.size() * sizeof(GLfloat), GL_STATIC_DRAW);


  GLuint vtxShader;
  GLuint flagShaderR;
  GLuint flagShaderG;
  const char* vtxfile = "default.vert";
  const char* fragfileR = "default-R.frag";
  const char* fragfileG = "default-G.frag";

  std::string verr;
  std::string ferr;
  prepare_shader_byfile(&vtxShader, GL_VERTEX_SHADER, vtxfile, &verr);
  prepare_shader_byfile(&flagShaderR, GL_FRAGMENT_SHADER, fragfileR, &ferr);
  prepare_shader_byfile(&flagShaderG, GL_FRAGMENT_SHADER, fragfileG, &ferr);

  std::cout << verr << std::endl;
  std::cout << ferr << std::endl;

  std::string linkerr;
  link_program(&programIDR, { vtxShader ,flagShaderR }, nullptr, &linkerr);
  link_program(&programIDG, { vtxShader ,flagShaderG }, nullptr, &linkerr);

  loadidentity44(_matrices.mproj);
  loadidentity44(_matrices.mmodel);

  // UBOを作成
  glGenBuffers(1, &uniformBufferID);
  glBindBuffer(GL_UNIFORM_BUFFER, uniformBufferID);
  glBufferData(GL_UNIFORM_BUFFER, sizeof(CMatrices), &_matrices, GL_DYNAMIC_DRAW); //UBOの内容を書き込み
  glBindBuffer(GL_UNIFORM_BUFFER, 0);

}
//描画関数
void disp(void) {

  glViewport(0, 0, width, height);

  glClearColor(0.2, 0.2, 0.2, 1);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  static int angle = 0;
  GetZRotate(_matrices.mmodel, angle++ * (3.14159 / 180.0));

  glBindBuffer(GL_UNIFORM_BUFFER, uniformBufferID);
  glBufferData(GL_UNIFORM_BUFFER, sizeof(CMatrices), &_matrices, GL_DYNAMIC_DRAW);
  glBindBuffer(GL_UNIFORM_BUFFER, 0);

  GLuint block_index_r = glGetUniformBlockIndex(programIDR, "Matrices");
 GLuint block_index_g = glGetUniformBlockIndex(programIDG, "Matrices");
GLuint index = 0; //この数字はGL_MAX_UNIFORM_BUFFER_BINDINGS未満ならなんでもいい assert(index < GL_MAX_UNIFORM_BUFFER_BINDINGS);
  glUseProgram(programIDR);//使用するプログラムを変更
  glBindBufferBase(GL_UNIFORM_BUFFER, index, uniformBufferID);
  glUniformBlockBinding(programIDR, block_index_r, index);
  {
    auto bindbufP = EnableAndBindFArrayBuffer(0, buf_points1, 3, GL_FLOAT);//prepare_shader.hpp
    glDrawArrays(GL_TRIANGLES, 0, 3);
  }


glUseProgram(programIDG);//使用するプログラムを変更 glBindBufferBase(GL_UNIFORM_BUFFER, index, uniformBufferID); glUniformBlockBinding(programIDG, block_index_g, index); { auto bindbufP = EnableAndBindFArrayBuffer(0, buf_points2, 3, GL_FLOAT);//prepare_shader.hpp glDrawArrays(GL_TRIANGLES, 0, 3); }

glUseProgram(0); glFlush(); }
//ウィンドウサイズの変化時に呼び出される
void reshape(int w, int h) {
  width = w; height = h;

  disp();
}

void timer(int value) {
  glutPostRedisplay();
  glutTimerFunc(50, timer, 0);
}

//エントリポイント
int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitWindowPosition(100, 50);
  glutInitWindowSize(500, 500);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);

  glutCreateWindow("sample");
  glutDisplayFunc(disp);
  glutReshapeFunc(reshape);

  glutTimerFunc(10, timer, 0);

  glewInit();

  init();

  glutMainLoop();

  return 0;
}


//! @brief X軸回転行列を作成する
//! @param [out] m 結果を格納する要素数16の配列
//! @param [in] rad 回転角(ラジアン)
//! @return なし
void GetZRotate(GLfloat* m, GLfloat rad) {
  m[0] = cos(rad);
  m[1] = sin(rad);
  m[2] = 0;
  m[3] = 0;

  m[4] = -sin(rad);
  m[5] = cos(rad);
  m[6] = 0;
  m[7] = 0;

  m[8] = 0;
  m[9] = 0;
  m[10] = 1;
  m[11] = 0;

  m[12] = 0;
  m[13] = 0;
  m[14] = 0;
  m[15] = 1;

}

シェーダプログラム

default.vert

#version 460 core

layout (location = 0) in vec3 coord;

out vec4 vColor;

//Uniformブロック std140はメモリ配置方法
layout (std140) uniform Matrices {
  mat4 ProjectionMatrix;
  mat4 ModelViewMatrix;
};

void main()
{
  gl_Position = ProjectionMatrix * ModelViewMatrix * vec4(coord, 1.0);
}

default-g.frag

#version 460 core

in vec4 vColor;

out vec4 FragColor;

void main()
{
  FragColor[0] = 0.0;
  FragColor[1] = 1.0;
  FragColor[2] = 0.0;
  FragColor[3] = 1.0;
} 

default-r.frag

#version 460 core

in vec4 vColor;

out vec4 FragColor;

void main()
{
  FragColor[0] = 1.0;
  FragColor[1] = 0.0;
  FragColor[2] = 0.0;
  FragColor[3] = 1.0;
} 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: