🌐

OpenGLでキューブを描画 GLFW入門 その1

2024/11/06に公開1

環境

mac

macだとOpenGLの制限やGLMがうまく見つかんなかったりするから手動でやっていきます

GLADここからGIPをダウンロードして
作業デレクトリで解凍

目次

MakeFileの作成
advent_ogl/
├── build/
├── main.cpp <=3
├── CMakeLists.txt <= 1
└── glad/
    ├── CMakeLists.txt <=2
    ├── include/
    └── src/

1

目次の1の部分です

cmake
CmakeList
cmake_minimum_required(VERSION 3.12)

# プロジェクト名の設定
project(advent_gl)

# C++11の設定
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 必須ライブラリの存在チェック
find_package(glfw3 REQUIRED)

# GLMのパスを手動で指定する windows linuxではここが変わります
find_path(GLM_INCLUDE_DIR glm/glm.hpp PATHS /opt/homebrew/include /opt/homebrew/Cellar/glm/1.0.1/include)

# GLMが見つかった場合、インクルードディレクトリを追加
if (GLM_INCLUDE_DIR)
    include_directories(${GLM_INCLUDE_DIR})
else()
    message(FATAL_ERROR "GLM not found")
endif()

# glad関係
include_directories(glad/include)
add_subdirectory(glad)

# コンパイルオプション
add_compile_options(-O2 -Wall)

# 実行ファイルの指定
add_executable(advent_gl main.cpp)

# 実行ファイルにリンクするライブラリの指定
target_link_libraries(advent_gl glad glfw ${CMAKE_DL_LIBS})

cmake

目次の2の部分です

CmakeList
cmake_minimum_required(VERSION 3.12)

# gladという名前でCMakeに認識させるライブラリを作成
# 静的ライブラリとしてコンパイル。含まれるソースを指定。
add_library(glad STATIC
    src/glad.c
)
main.cpp

目次の3の部分です

main.cpp
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>

// ウィンドウサイズの定義
const unsigned int WINDOW_WIDTH = 1440;
const unsigned int WINDOW_HEIGHT = 810;

// カメラの位置と向きを管理する変数
glm::vec3 cameraPosition(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp(0.0f, 1.0f, 0.0f);

// 移動速度の設定
float moveSpeed = 0.1f;  // 移動速度を調整

// シェーダーのソースコード
const char* vertexShaderSource = R"(
#version 410 core
layout(location = 0) in vec3 aPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);
}
)";

const char* fragmentShaderSource = R"(
#version 410 core
out vec4 FragColor;
void main()
{
    FragColor = vec4(1.0, 0.5, 0.2, 1.0); // オレンジ色
}
)";

void keyHandler(GLFWwindow*, int, int, int, int);
unsigned int compileShader(unsigned int type, const char* source);
unsigned int createShaderProgram();

int main()
{
    // GLFWの初期化
    if (!glfwInit()) {
        std::cerr << "Failed to initialize GLFW." << std::endl;
        return -1;
    }

    // OpenGLのバージョンとプロファイルの設定
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

    // ウィンドウの作成
    GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "advent_gl", nullptr, nullptr);
    if (!window)
    {
        std::cerr << "Failed to create window." << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetKeyCallback(window, keyHandler);

    // GLADの初期化
    if (!gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress)))
    {
        std::cerr << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // ビューポートの設定
    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

    // 深度テストの有効化
    glEnable(GL_DEPTH_TEST);

    // 背景色の設定
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

    // シェーダープログラムの作成
    unsigned int shaderProgram = createShaderProgram();

    // キューブの頂点データ
    float vertices[] = {
        // 前面
        -0.5f, -0.5f,  0.5f,
         0.5f, -0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f,  0.5f,
        // 背面
        -0.5f, -0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,
         0.5f,  0.5f, -0.5f,
        -0.5f,  0.5f, -0.5f
    };
    unsigned int indices[] = {
        // 前面
        0, 1, 2, 2, 3, 0,
        // 背面
        4, 5, 6, 6, 7, 4,
        // 左側
        4, 0, 3, 3, 7, 4,
        // 右側
        1, 5, 6, 6, 2, 1,
        // 下側
        4, 5, 1, 1, 0, 4,
        // 上側
        3, 2, 6, 6, 7, 3
    };

    // VAO, VBO, EBOの作成
    unsigned int VAO, VBO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // 描画ループ
    while (!glfwWindowShouldClose(window))
    {
        // バッファのクリア
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // シェーダープログラムの使用
        glUseProgram(shaderProgram);

        // 行列の設定
        glm::mat4 model = glm::mat4(1.0f);
        glm::mat4 view = glm::lookAt(cameraPosition, cameraPosition + cameraFront, cameraUp);
        glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 0.1f, 100.0f);

        unsigned int modelLoc = glGetUniformLocation(shaderProgram, "model");
        unsigned int viewLoc = glGetUniformLocation(shaderProgram, "view");
        unsigned int projLoc = glGetUniformLocation(shaderProgram, "projection");

        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
        glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

        // キューブを描画
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);

        // バッファのスワップとイベント処理
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // リソース解放
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glDeleteProgram(shaderProgram);

    glfwTerminate();
    return 0;
}

void keyHandler(GLFWwindow *window, int key, int scancode, int action, int mods)
{
    if (action == GLFW_PRESS || action == GLFW_REPEAT)
    {
        if (key == GLFW_KEY_ESCAPE)
        {
            glfwSetWindowShouldClose(window, GLFW_TRUE);
        }
        else if (key == GLFW_KEY_W)  // 前進
        {
            cameraPosition += moveSpeed * cameraFront;
        }
        else if (key == GLFW_KEY_S)  // 後退
        {
            cameraPosition -= moveSpeed * cameraFront;
        }
        else if (key == GLFW_KEY_A)  // 左移動
        {
            cameraPosition -= glm::normalize(glm::cross(cameraFront, cameraUp)) * moveSpeed;
        }
        else if (key == GLFW_KEY_D)  // 右移動
        {
            cameraPosition += glm::normalize(glm::cross(cameraFront, cameraUp)) * moveSpeed;
        }
        else if (key == GLFW_KEY_SPACE)  // 上昇
        {
            cameraPosition += moveSpeed * cameraUp;
        }
        else if (key == GLFW_KEY_LEFT_SHIFT)  // 下降
        {
            cameraPosition -= moveSpeed * cameraUp;
        }
    }
}

unsigned int compileShader(unsigned int type, const char* source)
{
    unsigned int shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, nullptr);
    glCompileShader(shader);

    int success;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        char infoLog[512];
        glGetShaderInfoLog(shader, 512, nullptr, infoLog);
        std::cerr << "Error compiling shader: " << infoLog << std::endl;
    }

    return shader;
}

unsigned int createShaderProgram()
{
    unsigned int vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
    unsigned int fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);

    unsigned int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    int success;
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        char infoLog[512];
        glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
        std::cerr << "Error linking shader program: " << infoLog << std::endl;
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return shaderProgram;
}


最後に


macの場合

ライブラリをダウンロード
brew install glfw
brew install glm
brew install cmake
作成してビルド
mkdir build
cd build
cmake .
make
実行
 ./advent_gl

Discussion

nyanchu - okabenyanchu - okabe

これは、cmakeの部分を変更したら、クロスプラットフォームになると思います