📘

OpenGLで図形を表示する方法

2024/11/12に公開

OpenGLを使った基本図形の描画

OpenGLで図形を描画する方法について、頂点データを用いた四角形の描画手順について解説します。

必要なヘッダーのインクルード

まず、OpenGLの機能を使用するために必要なヘッダーをインクルードします。GLEWとGLFWを使用してOpenGLの拡張機能を簡単に扱えるようにします。

#include <iostream>
#include <sstream>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>

ウィンドウサイズの設定

ウィンドウの幅と高さを指定します。これは、後でGLFWウィンドウの作成時に使用されます。

int Width = 800, Height = 600;

頂点シェーダーとフラグメントシェーダーのソースコード

頂点シェーダーとフラグメントシェーダーは、OpenGLのグラフィックスパイプラインで使用されます。頂点シェーダーは頂点の位置を設定し、フラグメントシェーダーはピクセルの色を決定します。

const GLchar* vertexShaderSrc =
"#version 330 core \n"
"layout (location = 0) in vec3 pos;"
"uniform vec2 posOffset;"
"void main()"
"{"
"    gl_Position = vec4(pos.x + posOffset.x, pos.y + posOffset.y, pos.z, 1.0f);"
"}";

const GLchar* fragmentShaderSrc =
"#version 330 core \n"
"uniform vec4 vertColor;"
"out vec4 frag_color;"
"void main()"
"{"
"    frag_color = vertColor;"
"}";

キー入力のコールバック関数

GLFWを使って、ESCキーが押されたらウィンドウを閉じるコールバック関数を設定しま

void glfw_onKey(GLFWwindow* window, int key, int scancode, int action, int mode) {
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
}

メイン関数

GLFWを初期化し、ウィンドウを作成します。

glfwInit();
GLFWwindow* gWindow = glfwCreateWindow(Width, Height, "Window", NULL, NULL);
glfwMakeContextCurrent(gWindow);
glewExperimental = GL_TRUE;
glewInit();
glfwSetKeyCallback(gWindow, glfw_onKey);

頂点データとインデックスデータの設定

四角形を描画するための頂点データとインデックスデータを設定します。

GLfloat vertices[] = {
    -0.5f,  0.5f, 0.0f,  // Top left
     0.5f,  0.5f, 0.0f,  // Top right
     0.5f, -0.5f, 0.0f,  // Bottom right
    -0.5f, -0.5f, 0.0f   // Bottom left 
};

GLuint indices[] = {
    0, 1, 2,  // First Triangle
    0, 2, 3   // Second Triangle
};

バッファと頂点配列オブジェクトの生成

頂点データとインデックスデータをGPUに送るために、バッファと頂点配列オブジェクトを生成します。

GLuint vbo, ibo, vao;

glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);

glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

シェーダーのコンパイルとリンク

シェーダーをコンパイルし、プログラムにリンクします。

GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vertexShaderSrc, NULL);
glCreateShader(vs);

GLint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fragmentShaderSrc, NULL);
glCreateShader(fs);

GLint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vs);
glAttachShader(shaderProgram, fs);
glLinkProgram(shaderProgram);
GLchar infoLog[512];
glGetProgramInfoLog(shaderProgram, sizeof(infoLog), NULL, infoLog);
std::cout << infoLog << std::endl;
glDeleteShader(vs);
glDeleteShader(fs);

メインループ

ウィンドウが閉じられるまで、以下の処理をループします。

背景色の設定と画面のクリア

シェーダープログラムの使用

時間に応じた色と位置のオフセットの変更

四角形の描画

while (!glfwWindowShouldClose(gWindow)) {
    glfwPollEvents();
    glClearColor(0.f, 0.5f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(shaderProgram);

    GLfloat time = (GLfloat)glfwGetTime();
    GLfloat blueColor = (sin(time) / 2) + 0.5f;
    glm::vec2 posoffset;
    posoffset.x = sin(time) / 2;
    posoffset.y = cos(time) / 2;

    GLint posOffsetLoc = glGetUniformLocation(shaderProgram, "posOffset");
    glUniform2f(posOffsetLoc, posoffset.x, posoffset.y);

    GLint vertColorLoc = glGetUniformLocation(shaderProgram, "vertColor");
    glUniform4f(vertColorLoc, 0.0f, 0.0f, blueColor, 1.0f);

    glBindVertexArray(vao);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

    glfwSwapBuffers(gWindow);
}

後片付けと終了

使用したシェーダープログラム、バッファ、VAOを削除し、GLFWを終了します。

glDeleteProgram(shaderProgram);
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ibo);

glfwTerminate();
return 0;

Discussion