MSYS2のMINGW64 → pacman やOpenGL関連ライブラリがインストール可能 な環境でGLSLを描画できた。その6

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(OpenGLShapes)

set(CMAKE_CXX_STANDARD 17)

# GLFW
find_package(glfw3 REQUIRED)

# OpenGL
find_package(OpenGL REQUIRED)

# GLEW(手動で入れた場合)
find_path(GLEW_INCLUDE_DIR GL/glew.h)
find_library(GLEW_LIBRARY NAMES GLEW glew32 glew glew_s)

# stb_image(ヘッダオンリーなので include だけでOK)
include_directories(${CMAKE_SOURCE_DIR})
include_directories(${CMAKE_SOURCE_DIR}/external)

# ソース
add_executable(OpenGLShapes
    main.cpp
    shapes.cpp
    shader.cpp
)

target_include_directories(OpenGLShapes PRIVATE
    ${GLEW_INCLUDE_DIR}
    ${OPENGL_INCLUDE_DIR}
    ${CMAKE_SOURCE_DIR}
)

target_link_libraries(OpenGLShapes
    glfw
    ${GLEW_LIBRARY}
    ${OPENGL_gl_LIBRARY}
)

# Windows用 GLEW は glew32s のこともあるので注意

main.cpp

#include <iostream> // Required for std::cout
#include <string>   // Required for std::string
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
#include "shader.h"
#include "shapes.hpp"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

GLuint createVAO(const std::vector<float>& vertices, const std::vector<unsigned int>& indices) {
    GLuint VAO, VBO, EBO;
    glGenVertexArrays(1,&VAO);
    glGenBuffers(1,&VBO);
    glGenBuffers(1,&EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER,VBO);
    glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(float), vertices.data(), GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);

    // position
    glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,8*sizeof(float),(void*)0);
    glEnableVertexAttribArray(0);
    // normal
    glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,8*sizeof(float),(void*)(3*sizeof(float)));
    glEnableVertexAttribArray(1);
    // texcoord
    glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,8*sizeof(float),(void*)(6*sizeof(float)));
    glEnableVertexAttribArray(2);

    glBindVertexArray(0);
    return VAO;
}
void print(const std::string& message) {
    std::cout << message << std::endl;
}
int main() {
    if (!glfwInit()) {
        std::cerr << "GLFW初期化失敗\n";
        return -1;
    }

    GLFWwindow* window = glfwCreateWindow(800,600,"OpenGL 3D Shapes with Textures",NULL,NULL);
    if (!window) {
        std::cerr << "ウィンドウ作成失敗\n";
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glewExperimental = true;
    if(glewInit() != GLEW_OK) {
        std::cerr << "GLEW初期化失敗\n";
        return -1;
    }
    glEnable(GL_DEPTH_TEST);

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

    // シェイプ作成
    std::vector<float> boxVertices, sphereVertices, torusVertices;
    std::vector<unsigned int> boxIndices, sphereIndices, torusIndices;

    createBox(boxVertices, boxIndices);
    createSphere(sphereVertices, sphereIndices);
    createTorus(torusVertices, torusIndices);

    GLuint vaoBox = createVAO(boxVertices, boxIndices);
    GLuint vaoSphere = createVAO(sphereVertices, sphereIndices);
    GLuint vaoTorus = createVAO(torusVertices, torusIndices);

    // テクスチャ読み込み関数
    auto loadTexture = [](const char* path) -> GLuint {
        int width, height, nrChannels;
        stbi_set_flip_vertically_on_load(true); // テクスチャ上下反転して読み込み(OpenGL標準に合わせる)
        unsigned char* data = stbi_load(path, &width, &height, &nrChannels, 0);
        if (!data) {
            std::cerr << "Failed to load texture: " << path << std::endl;
            return 0;
        }
        GLuint textureID;
        glGenTextures(1, &textureID);
        glBindTexture(GL_TEXTURE_2D, textureID);

        GLenum format = GL_RGB;
        if (nrChannels == 1)
            format = GL_RED;
        else if (nrChannels == 3)
            format = GL_RGB;
        else if (nrChannels == 4)
            format = GL_RGBA;

        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        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 textureID;
    };

    GLuint texBox = loadTexture("../texture_1.png");
    GLuint texSphere = loadTexture("../texture_2.png");
    GLuint texTorus = loadTexture("../texture_3.png");

    if (texBox == 0 || texSphere == 0 || texTorus == 0) {
        std::cerr << "テクスチャの読み込みに失敗しました。\n";
        return -1;
    }

    shader.use();
    shader.setInt("texture1", 0);
    //----------------------mouse----------------------------------
    double mouseX, mouseY;
    int winW, winH;
    //----------------------mouse----------------------------------
    // 行列初期化
    glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.f/600.f, 0.1f, 100.f);
    glm::mat4 view = glm::lookAt(glm::vec3(3,3,3), glm::vec3(0,0,0), glm::vec3(0,1,0));

    while(!glfwWindowShouldClose(window)) {

        //----------------------mouse----------------------------------
        glfwGetCursorPos(window, &mouseX, &mouseY);
        glfwGetWindowSize(window, &winW, &winH);
        //mouseY = winH - mouseY;  // 上下反転
        mouseX = mouseX/winW;  //
        mouseY = mouseY/winH;  //
        
        GLint mouseLoc = glGetUniformLocation(shader.ID, "u_mouse");
        glUniform2f(mouseLoc, (float)mouseX, (float)mouseY);
        //print(std::string("mouseX=") + std::to_string(mouseX));
        //----------------------mouse----------------------------------


        // 行列初期化
        glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.f/600.f, 0.1f, 100.f);
        glm::mat4 view = glm::lookAt(glm::vec3(3+mouseX*5,3+mouseY*5,3), glm::vec3(0,0,0), glm::vec3(0,1,0));


        glClearColor(0.1f,0.1f,0.1f,1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        shader.use();
        shader.setMat4("projection", glm::value_ptr(projection));
        shader.setMat4("view", glm::value_ptr(view));

        // ボックス描画
        glm::mat4 model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(-2.0f,0.0f,0.0f));
        shader.setMat4("model", glm::value_ptr(model));
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texBox);
        glBindVertexArray(vaoBox);
        glDrawElements(GL_TRIANGLES, (GLsizei)boxIndices.size(), GL_UNSIGNED_INT, 0);

        // 球描画
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(0.0f,0.0f,0.0f));
        shader.setMat4("model", glm::value_ptr(model));
        glBindTexture(GL_TEXTURE_2D, texSphere);
        glBindVertexArray(vaoSphere);
        glDrawElements(GL_TRIANGLES, (GLsizei)sphereIndices.size(), GL_UNSIGNED_INT, 0);

        // トーラス描画
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(2.0f,0.0f,0.0f));
        shader.setMat4("model", glm::value_ptr(model));
        glBindTexture(GL_TEXTURE_2D, texTorus);
        glBindVertexArray(vaoTorus);
        glDrawElements(GL_TRIANGLES, (GLsizei)torusIndices.size(), GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(window);
        glfwPollEvents();



    }

    // 解放
    glDeleteVertexArrays(1, &vaoBox);
    glDeleteVertexArrays(1, &vaoSphere);
    glDeleteVertexArrays(1, &vaoTorus);
    glDeleteTextures(1, &texBox);
    glDeleteTextures(1, &texSphere);
    glDeleteTextures(1, &texTorus);

    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}

shader.cpp

#include "shader.h"
#include <fstream>
#include <sstream>
#include <iostream>

Shader::Shader(const char* vertexPath, const char* fragmentPath) {
    std::string vertexCode, fragmentCode;
    std::ifstream vShaderFile, fShaderFile;
    vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    try {
        vShaderFile.open(vertexPath);
        fShaderFile.open(fragmentPath);
        std::stringstream vShaderStream, fShaderStream;
        vShaderStream << vShaderFile.rdbuf();
        fShaderStream << fShaderFile.rdbuf();
        vShaderFile.close();
        fShaderFile.close();
        vertexCode = vShaderStream.str();
        fragmentCode = fShaderStream.str();
    } catch(std::ifstream::failure& e) {
        std::cerr << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ\n";
    }

    const char* vShaderCode = vertexCode.c_str();
    const char* fShaderCode = fragmentCode.c_str();

    GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex, 1, &vShaderCode, NULL);
    glCompileShader(vertex);
    checkCompileErrors(vertex, "VERTEX");

    GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment, 1, &fShaderCode, NULL);
    glCompileShader(fragment);
    checkCompileErrors(fragment, "FRAGMENT");

    ID = glCreateProgram();
    glAttachShader(ID, vertex);
    glAttachShader(ID, fragment);
    glLinkProgram(ID);
    checkCompileErrors(ID, "PROGRAM");

    glDeleteShader(vertex);
    glDeleteShader(fragment);
}

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

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

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

void Shader::setFloat(const std::string &name, float value) const {
    glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}

void Shader::setVec2(const std::string &name, float x, float y) const {
    glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
}

void Shader::setVec3(const std::string &name, float x, float y, float z) const {
    glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}

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

void Shader::checkCompileErrors(GLuint shader, std::string type) {
    GLint success;
    GLchar infoLog[1024];
    if (type != "PROGRAM") {
        glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
        if (!success) {
            glGetShaderInfoLog(shader, 1024, NULL, infoLog);
            std::cerr << "| ERROR::SHADER-COMPILATION_ERROR of type: " << type << "\n"
                      << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
        }
    } else {
        glGetProgramiv(shader, GL_LINK_STATUS, &success);
        if (!success) {
            glGetProgramInfoLog(shader, 1024, NULL, infoLog);
            std::cerr << "| ERROR::PROGRAM-LINKING_ERROR of type: " << type << "\n"
                      << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
        }
    }
}

shader.frag

#version 330 core

in vec2 TexCoord;
in vec3 Normal;
in vec3 FragPos;

out vec4 FragColor;
uniform vec2 u_mouse;      // 
uniform sampler2D texture1;
uniform vec3 lightPos;
uniform vec3 viewPos;

void main()
{
    // Lighting
    vec3 ambient = 0.2 * texture(texture1, TexCoord).rgb;

    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * texture(texture1, TexCoord).rgb;

    vec3 result = ambient + diffuse;
    FragColor = vec4(result, 1.0);
}

shader.h

#ifndef SHADER_H
#define SHADER_H

#include <string>
#include <GL/glew.h>

class Shader {
public:
    GLuint ID;
    Shader(const char* vertexPath, const char* fragmentPath);
    void use();
    void setBool(const std::string &name, bool value) const;
    void setInt(const std::string &name, int value) const;
    void setFloat(const std::string &name, float value) const;
    void setVec2(const std::string &name, float x, float y) const;
    void setVec3(const std::string &name, float x, float y, float z) const;
    void setMat4(const std::string &name, const float* mat) const;

private:
    void checkCompileErrors(GLuint shader, std::string type);
};

#endif

shader.vert

#version 330 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
layout (location = 2) in vec3 aNormal;

out vec2 TexCoord;
out vec3 Normal;
out vec3 FragPos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    FragPos = vec3(model * vec4(aPos, 1.0));
    Normal = mat3(transpose(inverse(model))) * aNormal;
    TexCoord = aTexCoord;
    gl_Position = projection * view * vec4(FragPos, 1.0);
}

shapes.cpp

#include "shapes.hpp"
#include <cmath>

void createBox(std::vector<float>& vertices, std::vector<unsigned int>& indices) {
    vertices = {
        // positions        // texcoords     // normals
        -1, -1, -1,  0, 0,   0,  0, -1,
         1, -1, -1,  1, 0,   0,  0, -1,
         1,  1, -1,  1, 1,   0,  0, -1,
        -1,  1, -1,  0, 1,   0,  0, -1,

        -1, -1,  1,  0, 0,   0,  0,  1,
         1, -1,  1,  1, 0,   0,  0,  1,
         1,  1,  1,  1, 1,   0,  0,  1,
        -1,  1,  1,  0, 1,   0,  0,  1,

        -1, -1, -1,  0, 0,  -1,  0,  0,
        -1,  1, -1,  1, 0,  -1,  0,  0,
        -1,  1,  1,  1, 1,  -1,  0,  0,
        -1, -1,  1,  0, 1,  -1,  0,  0,

         1, -1, -1,  0, 0,   1,  0,  0,
         1,  1, -1,  1, 0,   1,  0,  0,
         1,  1,  1,  1, 1,   1,  0,  0,
         1, -1,  1,  0, 1,   1,  0,  0,

        -1, -1, -1,  0, 0,   0, -1,  0,
        -1, -1,  1,  1, 0,   0, -1,  0,
         1, -1,  1,  1, 1,   0, -1,  0,
         1, -1, -1,  0, 1,   0, -1,  0,

        -1,  1, -1,  0, 0,   0,  1,  0,
        -1,  1,  1,  1, 0,   0,  1,  0,
         1,  1,  1,  1, 1,   0,  1,  0,
         1,  1, -1,  0, 1,   0,  1,  0,
    };

    indices = {
         0,  1,  2,  2,  3,  0,    // front
         4,  5,  6,  6,  7,  4,    // back
         8,  9, 10, 10, 11,  8,    // left
        12, 13, 14, 14, 15, 12,    // right
        16, 17, 18, 18, 19, 16,    // bottom
        20, 21, 22, 22, 23, 20     // top
    };
}

void createSphere(std::vector<float>& vertices, std::vector<unsigned int>& indices, float radius, int sectorCount, int stackCount) {
    vertices.clear();
    indices.clear();

    for (int i = 0; i <= stackCount; ++i) {
        float stackAngle = M_PI / 2 - i * (M_PI / stackCount);
        float xy = radius * cosf(stackAngle);
        float z = radius * sinf(stackAngle);

        for (int j = 0; j <= sectorCount; ++j) {
            float sectorAngle = j * 2 * M_PI / sectorCount;

            float x = xy * cosf(sectorAngle);
            float y = xy * sinf(sectorAngle);

            float u = (float)j / sectorCount;
            float v = (float)i / stackCount;

            float nx = x / radius;
            float ny = y / radius;
            float nz = z / radius;

            vertices.insert(vertices.end(), {x, y, z, u, v, nx, ny, nz});
        }
    }

    for (int i = 0; i < stackCount; ++i) {
        for (int j = 0; j < sectorCount; ++j) {
            unsigned int first  = i * (sectorCount + 1) + j;
            unsigned int second = first + sectorCount + 1;

            indices.insert(indices.end(), {
                first, second, first + 1,
                second, second + 1, first + 1
            });
        }
    }
}

void createTorus(std::vector<float>& vertices, std::vector<unsigned int>& indices, float innerRadius, float outerRadius, int nsides, int rings) {
    vertices.clear();
    indices.clear();

    for (int i = 0; i <= rings; ++i) {
        float phi = 2 * M_PI * i / rings;
        float cosPhi = cosf(phi);
        float sinPhi = sinf(phi);

        for (int j = 0; j <= nsides; ++j) {
            float theta = 2 * M_PI * j / nsides;
            float cosTheta = cosf(theta);
            float sinTheta = sinf(theta);

            float x = (outerRadius + innerRadius * cosTheta) * cosPhi;
            float y = (outerRadius + innerRadius * cosTheta) * sinPhi;
            float z = innerRadius * sinTheta;

            float u = (float)i / rings;
            float v = (float)j / nsides;

            float nx = cosTheta * cosPhi;
            float ny = cosTheta * sinPhi;
            float nz = sinTheta;

            vertices.insert(vertices.end(), {x, y, z, u, v, nx, ny, nz});
        }
    }

    for (int i = 0; i < rings; ++i) {
        for (int j = 0; j < nsides; ++j) {
            unsigned int first = i * (nsides + 1) + j;
            unsigned int second = first + nsides + 1;

            indices.insert(indices.end(), {
                first, second, first + 1,
                second, second + 1, first + 1
            });
        }
    }
}

shapes.hpp

#ifndef SHAPES_HPP
#define SHAPES_HPP

#include <vector>

void createBox(std::vector<float>& vertices, std::vector<unsigned int>& indices);
void createSphere(std::vector<float>& vertices, std::vector<unsigned int>& indices, float radius = 1.0f, int sectorCount = 36, int stackCount = 18);
void createTorus(std::vector<float>& vertices, std::vector<unsigned int>& indices, float ringRadius = 0.7f, float tubeRadius = 0.3f, int ringSegments = 36, int tubeSegments = 18);

#endif

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

texture_1.png

texture_2.png

texture_3.png

cmd


furcr@furcraea_built MINGW64 ~
$ cd c:

furcr@furcraea_built MINGW64 /c
$ cd glsl_sample

furcr@furcraea_built MINGW64 /c/glsl_sample
$ cd glsl_sample_233_3texture

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

furcr@furcraea_built MINGW64 /c/glsl_sample/glsl_sample_233_3texture/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
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Found OpenGL: opengl32
-- Configuring done (1.9s)
-- Generating done (0.0s)
-- Build files have been written to: C:/glsl_sample/glsl_sample_233_3texture/build

furcr@furcraea_built MINGW64 /c/glsl_sample/glsl_sample_233_3texture/build
$ mingw32-make
[ 25%] Building CXX object CMakeFiles/OpenGLShapes.dir/main.cpp.obj
[ 50%] Building CXX object CMakeFiles/OpenGLShapes.dir/shapes.cpp.obj
[ 75%] Building CXX object CMakeFiles/OpenGLShapes.dir/shader.cpp.obj
[100%] Linking CXX executable OpenGLShapes.exe
[100%] Built target OpenGLShapes

furcr@furcraea_built MINGW64 /c/glsl_sample/glsl_sample_233_3texture/build
$ ./OpenGLShapes

コメントを残す

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