MSYS2のMINGW64 → pacman やOpenGL関連ライブラリがインストール可能 な環境でGLSLを描画できた。 FBX Viewerを作る Vol.3 テクスチャとカメラのタンブル、トラック、ドリー、ロール、ズーム

memo.txt

fbx_viewer/
├── CMakeLists.txt
├── include/
│   ├── glad/
│   ├── KHR/
│   ├── glfw/
│   ├── glm/
│   └── stb/
├── lib/
│   ├── glfw3.lib など
├── src/
│   ├── main.cpp
│   ├── shader.cpp
│   └── glad.c

├── shader.vert
├── shader.frag
├── model.fbx
└── texture.png




pacman -S mingw-w64-x86_64-glfw mingw-w64-x86_64-glew mingw-w64-x86_64-assimp mingw-w64-x86_64-glm

pacman -S mingw-w64-x86_64-glad

cd fbx_viewer
mkdir build && cd build
cmake -G "MinGW Makefiles" ..
mingw32-make
./fbx_viewer

shader.vert

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoord;

uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_proj;

out vec2 TexCoord;

void main() {
    gl_Position = u_proj * u_view * u_model * vec4(aPos, 1.0);
    TexCoord = aTexCoord;
}

shader.frag

#version 330 core
out vec4 FragColor;

in vec2 TexCoord;
uniform sampler2D u_texture;

void main() {
    FragColor = texture(u_texture, TexCoord);
}

src/main.cpp

#define GLFW_INCLUDE_NONE  // ← glad を使うので OpenGL ヘッダーを GLFW 側で除外
#include <glad/glad.h> 
#include <GLFW/glfw3.h>

#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <stb_image.h>

#include <iostream>
#include <vector>
#include "shader.h"

struct Vertex {
    glm::vec3 position;
    glm::vec3 normal;
    glm::vec2 texCoord;
};

std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
GLuint textureID;

float yaw = 0.0f, pitch = 0.0f, roll = 0.0f;
float zoom = 3.0f;
glm::vec2 lastMouse;
bool leftPressed = false, middlePressed = false, rightPressed = false;
glm::vec3 cameraOffset(0.0f);

void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
    if (button == GLFW_MOUSE_BUTTON_LEFT) leftPressed = (action == GLFW_PRESS);
    if (button == GLFW_MOUSE_BUTTON_MIDDLE) middlePressed = (action == GLFW_PRESS);
    if (button == GLFW_MOUSE_BUTTON_RIGHT) rightPressed = (action == GLFW_PRESS);
}

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
    zoom -= yoffset * 0.1f;
    if (zoom < 0.1f) zoom = 0.1f;
}

void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) {
    glm::vec2 current(xpos, ypos);
    glm::vec2 delta = current - lastMouse;
    lastMouse = current;

    if (leftPressed) {
        yaw += delta.x * 0.3f;
        pitch += delta.y * 0.3f;
    }
    if (middlePressed) {
        cameraOffset.x -= delta.x * 0.005f;
        cameraOffset.y += delta.y * 0.005f;
    }
    if (rightPressed) {
        roll += delta.x * 0.2f;
    }
}

bool loadFBX(const std::string& path) {
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(path,
        aiProcess_Triangulate |
        aiProcess_GenSmoothNormals |
        aiProcess_CalcTangentSpace |
        aiProcess_JoinIdenticalVertices);

    if (!scene || !scene->HasMeshes()) return false;

    const aiMesh* mesh = scene->mMeshes[0];
    vertices.reserve(mesh->mNumVertices);
    for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
        Vertex v;
        v.position = glm::vec3(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z);
        v.normal = glm::vec3(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z);
        if (mesh->HasTextureCoords(0)) {
            v.texCoord = glm::vec2(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y);
        } else {
            v.texCoord = glm::vec2(0.0f);
        }
        vertices.push_back(v);
    }

    for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
        aiFace& face = mesh->mFaces[i];
        for (unsigned int j = 0; j < face.mNumIndices; ++j) {
            indices.push_back(face.mIndices[j]);
        }
    }

    return true;
}

GLuint loadTexture(const char* path) {
    int w, h, ch;
    stbi_set_flip_vertically_on_load(true);
    unsigned char* data = stbi_load(path, &w, &h, &ch, 0);
    if (!data) {
        std::cerr << "Failed to load texture\n";
        return 0;
    }

    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    GLenum format = ch == 3 ? GL_RGB : GL_RGBA;
    glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    stbi_image_free(data);
    return tex;
}

int main() {
    // GLFW 初期化
    if (!glfwInit()) return -1;

    // OpenGLバージョンの指定
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // ウィンドウ作成
    GLFWwindow* window = glfwCreateWindow(800, 600, "FBX Viewer", NULL, NULL);
    if (!window) {
        std::cerr << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }

    // コンテキストを現在にする
    glfwMakeContextCurrent(window);

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

    // 続き
    glfwSetCursorPosCallback(window, cursor_position_callback);
    glfwSetMouseButtonCallback(window, mouse_button_callback);
    glfwSetScrollCallback(window, scroll_callback);


    glfwSetCursorPosCallback(window, cursor_position_callback);
    glfwSetMouseButtonCallback(window, mouse_button_callback);
    glfwSetScrollCallback(window, scroll_callback);

    Shader shader("../shader.vert", "../shader.frag");

    if (!loadFBX("../model.fbx")) {
        std::cerr << "Failed to load model\n";
        return -1;
    }
    textureID = loadTexture("../texture.png");

    GLuint VAO, VBO, EBO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);

    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texCoord));
    glEnableVertexAttribArray(2);

    shader.use();
    shader.setInt("u_texture", 0);

    glEnable(GL_DEPTH_TEST);

    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
        glClearColor(0.2f, 0.2f, 0.25f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glm::mat4 view(1.0f);
        view = glm::translate(view, glm::vec3(0, 0, -zoom));
        view = glm::rotate(view, glm::radians(pitch), glm::vec3(1, 0, 0));
        view = glm::rotate(view, glm::radians(yaw), glm::vec3(0, 1, 0));
        view = glm::rotate(view, glm::radians(roll), glm::vec3(0, 0, 1));
        view = glm::translate(view, cameraOffset);

        glm::mat4 proj = glm::perspective(glm::radians(45.0f), 800.f / 600.f, 0.1f, 100.0f);
        glm::mat4 model(1.0f);

        shader.setMat4("u_model", model);
        shader.setMat4("u_view", view);
        shader.setMat4("u_proj", proj);

        glBindTexture(GL_TEXTURE_2D, textureID);
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(window);
    }

    glfwTerminate();
    return 0;
}

src/shader.h

#ifndef SHADER_H
#define SHADER_H

#include <glad/glad.h>
#include <glm/glm.hpp>
#include <string>

class Shader {
public:
    Shader(const char* vertexPath, const char* fragmentPath);
    void use() const;
    GLuint getID() const;

    // Uniform setters
    void setInt(const std::string &name, int value) const;
    void setMat4(const std::string &name, const glm::mat4 &mat) const;

private:
    GLuint ID;
    std::string loadShaderSource(const char* path);
    GLuint compileShader(const char* source, GLenum type);
};

#endif

src/shader.cpp


#include "shader.h"
#include <fstream>
#include <sstream>
#include <iostream>
#include <glm/gtc/type_ptr.hpp>

Shader::Shader(const char* vertexPath, const char* fragmentPath) {
    std::string vertexCode = loadShaderSource(vertexPath);
    std::string fragmentCode = loadShaderSource(fragmentPath);

    GLuint vertex = compileShader(vertexCode.c_str(), GL_VERTEX_SHADER);
    GLuint fragment = compileShader(fragmentCode.c_str(), GL_FRAGMENT_SHADER);

    ID = glCreateProgram();
    glAttachShader(ID, vertex);
    glAttachShader(ID, fragment);
    glLinkProgram(ID);

    int success;
    glGetProgramiv(ID, GL_LINK_STATUS, &success);
    if (!success) {
        char infoLog[512];
        glGetProgramInfoLog(ID, 512, NULL, infoLog);
        std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }

    glDeleteShader(vertex);
    glDeleteShader(fragment);
}

std::string Shader::loadShaderSource(const char* path) {
    std::ifstream file(path);
    std::stringstream buffer;
    buffer << file.rdbuf();
    return buffer.str();
}

GLuint Shader::compileShader(const char* source, GLenum type) {
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);

    int success;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        char infoLog[512];
        glGetShaderInfoLog(shader, 512, NULL, infoLog);
        std::cerr << "ERROR::SHADER::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    return shader;
}

void Shader::use() const {
    glUseProgram(ID);
}

GLuint Shader::getID() const {
    return ID;
}

void Shader::setInt(const std::string &name, int value) const {
    glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}

void Shader::setMat4(const std::string &name, const glm::mat4 &mat) const {
    glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, glm::value_ptr(mat));
}

src/stb_image.cpp

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

src/glad.c

https://glad.dav1d.de/    でとってくる
    Language/Generator: C/C++
    Specification: gl
    APIs: gl=3.3
    Profile: core
  Extensions:Add All

include/stb_image.h https://github.com/nothings/stb/blob/master/stb_image.h

glad/glad.h

https://glad.dav1d.de/    でとってくる
    Language/Generator: C/C++
    Specification: gl
    APIs: gl=3.3
    Profile: core
  Extensions:Add All

KHR/khrplatform.h

https://glad.dav1d.de/    でとってくる
    Language/Generator: C/C++
    Specification: gl
    APIs: gl=3.3
    Profile: core
  Extensions:Add All

external/glad/src/glad.c

https://glad.dav1d.de/    でとってくる
    Language/Generator: C/C++
    Specification: gl
    APIs: gl=3.3
    Profile: core
  Extensions:Add All

external/glad/CMakeLists.txt

からっぽ

external/stb_image/stb_image.cpp

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

cmd


furcr@furcraea_built MINGW64 ~
$ cd c:

furcr@furcraea_built MINGW64 /c
$ cd glsl_sample

furcr@furcraea_built MINGW64 /c/glsl_sample
$ cd fbx_viewer_3_uv_texture_dorry

furcr@furcraea_built MINGW64 /c/glsl_sample/fbx_viewer_3_uv_texture_dorry
$ cd build

furcr@furcraea_built MINGW64 /c/glsl_sample/fbx_viewer_3_uv_texture_dorry/build
$ pacman -S mingw-w64-x86_64-glfw mingw-w64-x86_64-glew mingw-w64-x86_64-assimp mingw-w64-x86_64-glm
warning: mingw-w64-x86_64-glfw-3.4-1 is up to date -- reinstalling
warning: mingw-w64-x86_64-glew-2.2.0-3 is up to date -- reinstalling
warning: mingw-w64-x86_64-assimp-6.0.2-1 is up to date -- reinstalling
warning: mingw-w64-x86_64-glm-1.0.1-1 is up to date -- reinstalling
resolving dependencies...
looking for conflicting packages...

Packages (4) mingw-w64-x86_64-assimp-6.0.2-1  mingw-w64-x86_64-glew-2.2.0-3
             mingw-w64-x86_64-glfw-3.4-1  mingw-w64-x86_64-glm-1.0.1-1

Total Installed Size:  38.25 MiB
Net Upgrade Size:       0.00 MiB

:: Proceed with installation? [Y/n]
(4/4) checking keys in keyring                               [###############################] 100%
(4/4) checking package integrity                             [###############################] 100%
(4/4) loading package files                                  [###############################] 100%
(4/4) checking for file conflicts                            [###############################] 100%
(4/4) checking available disk space                          [###############################] 100%
:: Processing package changes...
(1/4) reinstalling mingw-w64-x86_64-glfw                     [###############################] 100%
(2/4) reinstalling mingw-w64-x86_64-glew                     [###############################] 100%
(3/4) reinstalling mingw-w64-x86_64-assimp                   [###############################] 100%
(4/4) reinstalling mingw-w64-x86_64-glm                      [###############################] 100%

furcr@furcraea_built MINGW64 /c/glsl_sample/fbx_viewer_3_uv_texture_dorry/build
$ pacman -S mingw-w64-x86_64-glad
error: target not found: mingw-w64-x86_64-glad

furcr@furcraea_built MINGW64 /c/glsl_sample/fbx_viewer_3_uv_texture_dorry/build
$ cmake -G "MSYS Makefiles" ..
-- The C compiler identification is GNU 15.1.0
-- The CXX compiler identification is GNU 15.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (1.2s)
-- Generating done (0.0s)
-- Build files have been written to: C:/glsl_sample/fbx_viewer_3_uv_texture_dorry/build

furcr@furcraea_built MINGW64 /c/glsl_sample/fbx_viewer_3_uv_texture_dorry/build
$ mingw32-make
[ 20%] Building CXX object CMakeFiles/fbx_viewer.dir/src/main.cpp.obj
[ 40%] Building CXX object CMakeFiles/fbx_viewer.dir/src/shader.cpp.obj
[ 60%] Building C object CMakeFiles/fbx_viewer.dir/src/glad.c.obj
[ 80%] Building CXX object CMakeFiles/fbx_viewer.dir/src/stb_image.cpp.obj
[100%] Linking CXX executable fbx_viewer.exe
[100%] Built target fbx_viewer

furcr@furcraea_built MINGW64 /c/glsl_sample/fbx_viewer_3_uv_texture_dorry/build
$ ./fbx_viewer

コメントを残す

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