VAOを使ったレンダリング
Vertex Array Objects(VAO)は、VBOとAttribute設定を包括するものとしてとらえることができます。
OpenGL ES 2.0では、VAOの使用が推奨されています。
OpenGL ES 2.0では、VAOの使用が推奨されています。
今回のサンプルは、VBOのみを使ったCube描画を改変したものです。

環境
- OpenGL 3.2
- GLUT(freeglut) 2.6.0
- GLEW 1.5.7
- GLM 0.9.0.6
VAOを使う
void glGenVertexArrays(GLsizei n, GLuint *arrays);
void glDeleteVertexArrays(GLsizei n, const GLuint *arrays);
void glBindVertexArray(GLuint array);
VAOでは、次のステートを保持することができます。
- glVertexAttribPointer
- glEnableVertexAttribArray
なので、glDrawArraysもしくはglDrawElementsによるレンダー時、glBindVertexArrayを呼ぶだけで済むのでクライアント<->GPU間のやりとりが減り高速描画が期待できます。
プログラム
VAOを使うことで、glDrawElementsを使うときの設定がシンプルになります。
VBOのみを使っていたCube描画に比べて、Cubeクラスのrender()関数の中が記述が簡単になっていることを確認してください。
VBOのみを使っていたCube描画に比べて、Cubeクラスのrender()関数の中が記述が簡単になっていることを確認してください。
#include <cstdlib>
#include <iostream>
#include "load_shader.h"
#include <GL/glew.h>
#include <GL/glut.h>
// OpenGL Mathematics Library
#include <glm/glm.hpp>
#include <glm/gtc/matrix_projection.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform2.hpp>
#include <glm/gtc/type_ptr.hpp>
void reshape(int w, int h);
void init();
void timer(int t );
void display();
struct ShaderContext {
GLuint programObject;
GLint modelMatrixLocation;
GLint viewMatrixLocation;
GLint projectionMatrixLocation;
GLint positionLocation;
GLint normalLocation;
};
class Cube
{
private:
struct Vertex_t {
GLfloat position[3]; // (vx,vy,vz)
GLfloat normal[3]; // (nx,ny,nz)
};
GLuint vao[1]; // Vertex array buffer objects
GLuint eao[1]; // array buffer objects for elements
GLint positionLocation;
GLint normalLocation;
GLuint numIndecies;
glm::mat4 modelMat;
glm::vec3 position;
glm::vec3 size;
glm::vec3 angle_axis;
float angle;
public:
void setup(const ShaderContext *context)
{
GLuint offset;
GLuint vbo[1];
Vertex_t vertex[] = { // position(x,y,z) , normal(x,y,z)
{ { -0.5f, -0.5f, -0.5f }, { +0.0f, -1.0f, +0.0f } },
{ { -0.5f, -0.5f, +0.5f }, { +0.0f, -1.0f, +0.0f } },
{ { +0.5f, -0.5f, +0.5f }, { +0.0f, -1.0f, +0.0f } },
{ { +0.5f, -0.5f, -0.5f }, { +0.0f, -1.0f, +0.0f } },
{ { -0.5f, +0.5f, -0.5f }, { +0.0f, +1.0f, +0.0f } },
{ { -0.5f, +0.5f, +0.5f }, { +0.0f, +1.0f, +0.0f } },
{ { +0.5f, +0.5f, +0.5f }, { +0.0f, +1.0f, +0.0f } },
{ { +0.5f, +0.5f, -0.5f }, { +0.0f, +1.0f, +0.0f } },
{ { -0.5f, -0.5f, -0.5f }, { +0.0f, +0.0f, -1.0f } },
{ { -0.5f, +0.5f, -0.5f }, { +0.0f, +0.0f, -1.0f } },
{ { +0.5f, +0.5f, -0.5f }, { +0.0f, +0.0f, -1.0f } },
{ { +0.5f, -0.5f, -0.5f }, { +0.0f, +0.0f, -1.0f } },
{ { -0.5f, -0.5f, +0.5f }, { +0.0f, +0.0f, +1.0f } },
{ { -0.5f, +0.5f, +0.5f }, { +0.0f, +0.0f, +1.0f } },
{ { +0.5f, +0.5f, +0.5f }, { +0.0f, +0.0f, +1.0f } },
{ { +0.5f, -0.5f, +0.5f }, { +0.0f, +0.0f, +1.0f } },
{ { -0.5f, -0.5f, -0.5f }, { -1.0f, +0.0f, +0.0f } },
{ { -0.5f, -0.5f, +0.5f }, { -1.0f, +0.0f, +0.0f } },
{ { -0.5f, +0.5f, +0.5f }, { -1.0f, +0.0f, +0.0f } },
{ { -0.5f, +0.5f, -0.5f }, { -1.0f, +0.0f, +0.0f } },
{ { +0.5f, -0.5f, -0.5f }, { +1.0f, +0.0f, +0.0f } },
{ { +0.5f, -0.5f, +0.5f }, { +1.0f, +0.0f, +0.0f } },
{ { +0.5f, +0.5f, +0.5f }, { +1.0f, +0.0f, +0.0f } },
{ { +0.5f, +0.5f, -0.5f }, { +1.0f, +0.0f, +0.0f } }
};
GLuint indices[] = {
0, 2, 1,
0, 3, 2,
4, 5, 6,
4, 6, 7,
8, 9, 10,
8, 10, 11,
12, 15, 14,
12, 14, 13,
16, 17, 18,
16, 18, 19,
20, 23, 22,
20, 22, 21
};
numIndecies = sizeof(indices)/sizeof(GLuint);
// Create VBO
glGenBuffers(1, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW);
// Create and bind VAO
glGenVertexArrays(1, vao);
glBindVertexArray(vao[0]);
{
offset = 0;
glVertexAttribPointer(context->positionLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex_t), (const void*)offset);
offset += 3 * sizeof(GLfloat);
glVertexAttribPointer(context->normalLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex_t), (const void*)offset);
// Enable Attribute
glEnableVertexAttribArray(context->positionLocation);
glEnableVertexAttribArray(context->normalLocation);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// Delete VBO
glDeleteBuffers(1, vbo);
// Create Index Buffer
glGenBuffers(1, eao);
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, numIndecies*sizeof(GLuint), indices, GL_STATIC_DRAW);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
angle = 0.0;
}
void render()
{
glBindVertexArray(vao[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao[0]);
glDrawElements(GL_TRIANGLES, numIndecies, GL_UNSIGNED_INT, 0);
}
void update() {
modelMat = glm::mat4(1.0f);
modelMat = glm::translate(modelMat, position);
modelMat *= glm::rotate(angle, angle_axis);
}
glm::mat4 getMatrix() {
return modelMat;
}
void setAngle(float a, float ax, float ay, float az) {
angle = a;
angle_axis = glm::vec3(ax, ay, az);
}
void setPosition(float x, float y, float z) {
position = glm::vec3(x, y, z);
}
void setSize(float x, float y, float z) {
size = glm::vec3(x, y, z);
}
};
///////////////////////////////////////////////////////////////////////////////
//
// gloval variables
//
ShaderContext context;
glm::mat4 projectionMatrix;
glm::mat4 viewMatrix;
Cube cube; // Model
//
// initialize
//
void init()
{
//
// GL initialize
//
glClearColor(0.5, 0.5, 0.5, 1.0);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
viewMatrix = glm::lookAt(
glm::vec3(3.0f, 4.0f, 5.0f), // eye
glm::vec3(0.0f, 0.0f, 0.0f), // center
glm::vec3(0.0f, 1.0f, 0.0f) // up
);
//
// GLSL initialize
//
context.programObject = createProgram( "simple.vert", "simple.frag" );
context.modelMatrixLocation = glGetUniformLocation(context.programObject, "u_modelMatrix");
context.viewMatrixLocation = glGetUniformLocation(context.programObject, "u_viewMatrix");
context.projectionMatrixLocation = glGetUniformLocation(context.programObject, "u_projectionMatrix");
context.positionLocation = glGetAttribLocation(context.programObject, "a_position");
context.normalLocation = glGetAttribLocation(context.programObject, "a_normal");
glBindFragDataLocation(context.programObject, 0, "fragColor");
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
projectionMatrix = glm::perspective(30.0f, (float)w/(float)h, 1.0f, 100.0f);
}
void timer(int t)
{
glutPostRedisplay();
glutTimerFunc(t, timer, 17);
}
//
// Main Loop
//
void display()
{
static float angle = 0.0;
cube.setAngle(angle, 0.0f, 1.0f, 0.0f);
cube.update();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(context.programObject);
glUniformMatrix4fv(context.viewMatrixLocation, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(context.projectionMatrixLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
//
// Draw Cube
//
glUniformMatrix4fv(context.modelMatrixLocation, 1, GL_FALSE, glm::value_ptr(cube.getMatrix()));
cube.render();
glUseProgram(0);
glutSwapBuffers();
angle += 1.0;
if (angle > 180.0) angle = 0.0;
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(400, 300);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("OpenGL with GLEW");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutTimerFunc(100, timer, 17);
GLenum err;
//glewExperimental = GL_TRUE;
err = glewInit();
if (err != GLEW_OK) {
std::cerr << "GLEW error : " << glewGetErrorString(err) << "\n";
std::exit(1);
}
if (!glewIsSupported("GL_VERSION_3_2")) {
std::cerr << "OpenGL 3.2 not supported.\n";
std::exit(1);
}
init();
//
// setup Cube
//
cube.setup(&context);
cube.setAngle(0.0, 0.0f, 1.0f, 0.0f);
cube.setPosition(0.0, 0.0, 0.0);
glutMainLoop();
return 0;
}
添付ファイル