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

MSYS2のMINGW64 → pacman やOpenGL関連ライブラリがインストール可能 な環境でGLSLを描画できた。 FBX Viewerを作る Vol.2 テクスチャ

memo.txt

fbx_viewer/
├── main.cpp
├── shader.h
├── vertex.glsl
├── fragment.glsl
├── model.fbx
├── texture.png
├── stb_image.h
├── stb_image.cpp
└── CMakeLists.txt


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

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(fbx_viewer)

set(CMAKE_CXX_STANDARD 17)

include_directories(
    ${PROJECT_SOURCE_DIR}
    ${PROJECT_SOURCE_DIR}/../
)

add_executable(fbx_viewer main.cpp stb_image.cpp)

# GLEW, GLFW, ASSIMP
find_package(OpenGL REQUIRED)
find_package(glfw3 REQUIRED)
find_package(assimp REQUIRED)

target_link_libraries(fbx_viewer
    OpenGL::GL
    glfw
    assimp
    glew32
)

main.cpp

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <stb_image.h>
#include <iostream>
#include <vector>
#include "shader.h"

struct Vertex {
    float position[3];
    float normal[3];
    float texcoord[2];
};

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

void processMesh(aiMesh* mesh) {
    for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
        Vertex v;
        memcpy(v.position, &mesh->mVertices[i], sizeof(float) * 3);
        memcpy(v.normal, &mesh->mNormals[i], sizeof(float) * 3);
        if (mesh->HasTextureCoords(0))
            memcpy(v.texcoord, &mesh->mTextureCoords[0][i], sizeof(float) * 2);
        else
            v.texcoord[0] = v.texcoord[1] = 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]);
        }
    }
}

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

    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);

    GLenum format = (nrChannels == 4) ? GL_RGBA : GL_RGB;
    glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);

    glGenerateMipmap(GL_TEXTURE_2D);
    stbi_image_free(data);

    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);

    return tex;
}

int main() {
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(800, 600, "FBX Viewer", nullptr, nullptr);
    glfwMakeContextCurrent(window);
    glewInit();

    Shader shader("../vertex.glsl", "../fragment.glsl");

    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile("../model.fbx",
        aiProcess_Triangulate | aiProcess_GenSmoothNormals |
        aiProcess_JoinIdenticalVertices | aiProcess_FlipUVs);

    if (!scene || !scene->HasMeshes()) {
        std::cerr << "Failed to load model: " << importer.GetErrorString() << std::endl;
        return -1;
    }

    processMesh(scene->mMeshes[0]);

    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(Vertex), 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);

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

    GLuint texture = loadTexture("../texture.png");
    shader.use();
    shader.setInt("u_texture", 0);

    glEnable(GL_DEPTH_TEST);

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

        shader.use();
        glBindTexture(GL_TEXTURE_2D, texture);
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

shader.h

#ifndef SHADER_H
#define SHADER_H

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <GL/glew.h>

class Shader {
public:
    GLuint ID;
    Shader(const char* vertexPath, const char* fragmentPath) {
        std::string vCode, fCode;
        std::ifstream vFile(vertexPath), fFile(fragmentPath);
        std::stringstream vStream, fStream;
        vStream << vFile.rdbuf();
        fStream << fFile.rdbuf();
        vCode = vStream.str();
        fCode = fStream.str();

        const char* vShaderCode = vCode.c_str();
        const char* fShaderCode = fCode.c_str();

        GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertex, 1, &vShaderCode, nullptr);
        glCompileShader(vertex);

        GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragment, 1, &fShaderCode, nullptr);
        glCompileShader(fragment);

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

        glDeleteShader(vertex);
        glDeleteShader(fragment);
    }

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

#endif

vertex.glsl

#version 330 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_normal;
layout(location = 2) in vec2 a_texcoord;

out vec2 v_texcoord;

void main() {
    gl_Position = vec4(a_position, 1.0);
    v_texcoord = a_texcoord;
}

fragment.glsl

#version 330 core
in vec2 v_texcoord;
out vec4 fragColor;

uniform sampler2D u_texture;

void main() {
    fragColor = texture(u_texture, v_texcoord);
}

stb_image.cpp  

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

stb_image.h  https://github.com/nothings/stb/blob/master/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

furcr@furcraea_built MINGW64 /c/glsl_sample/fbx_viewer
$ cd ..

furcr@furcraea_built MINGW64 /c/glsl_sample
$ cd fbx_viewer_uv_texture

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

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

furcr@furcraea_built MINGW64 /c/glsl_sample/fbx_viewer_uv_texture/build
$ mingw32-make
[ 33%] Building CXX object CMakeFiles/fbx_viewer.dir/main.cpp.obj
[ 66%] Building CXX object CMakeFiles/fbx_viewer.dir/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_uv_texture/build
$ ./fbx_viewer

texture.png

カメラがめりこんでる

MSYS2のMINGW64 → pacman やOpenGL関連ライブラリがインストール可能 な環境でGLSLを描画できた。 FBX Viewerを作る Vol.1

memo.txt

fbx_viewer/
├── main.cpp
├── shader.h
├── vertex.glsl
├── fragment.glsl
├── model.fbx
└── CMakeLists.txt

pacman -S mingw-w64-x86_64-assimp


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

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(fbx_viewer)

set(CMAKE_CXX_STANDARD 17)

find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)
find_package(GLFW3 REQUIRED)
find_package(assimp REQUIRED)

include_directories(
    ${OPENGL_INCLUDE_DIRS}
    ${GLEW_INCLUDE_DIRS}
    ${GLFW3_INCLUDE_DIRS}
    ${ASSIMP_INCLUDE_DIRS}
)

add_executable(fbx_viewer main.cpp shader.h)

target_link_libraries(fbx_viewer
    ${OPENGL_LIBRARIES}
    GLEW::GLEW
    glfw
    assimp
)

main.cpp

#include <GL/glew.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 <iostream>
#include <vector>
#include "shader.h"

struct Vertex {
    float position[3];
    float normal[3];
};

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

void processMesh(aiMesh* mesh) {
    for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
        Vertex v;
        memcpy(v.position, &mesh->mVertices[i], sizeof(float) * 3);
        memcpy(v.normal, &mesh->mNormals[i], sizeof(float) * 3);
        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]);
        }
    }
}

int main() {
    if (!glfwInit()) return -1;
    GLFWwindow* window = glfwCreateWindow(800, 600, "FBX Viewer", nullptr, nullptr);
    if (!window) return -1;
    glfwMakeContextCurrent(window);
    glewInit();

    Shader shader("../vertex.glsl", "../fragment.glsl");

    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile("../model.fbx",
        aiProcess_Triangulate |
        aiProcess_GenSmoothNormals |
        aiProcess_JoinIdenticalVertices |
        aiProcess_FlipUVs);

    if (!scene || !scene->HasMeshes()) {
        std::cerr << "Failed to load model: " << importer.GetErrorString() << std::endl;
        return -1;
    }

    processMesh(scene->mMeshes[0]);

    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(Vertex), 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);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 3));
    glEnableVertexAttribArray(1);

    glEnable(GL_DEPTH_TEST);

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

        shader.use();

        glm::mat4 model = glm::mat4(1.0f);
        glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 1.0f, 3.0f),
                                     glm::vec3(0.0f, 0.0f, 0.0f),
                                     glm::vec3(0.0f, 1.0f, 0.0f));
        glm::mat4 projection = glm::perspective(glm::radians(45.0f),
                                                800.0f / 600.0f, 0.1f, 100.0f);

        glUniformMatrix4fv(glGetUniformLocation(shader.ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
        glUniformMatrix4fv(glGetUniformLocation(shader.ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
        glUniformMatrix4fv(glGetUniformLocation(shader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));

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

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

shader.h

#ifndef SHADER_H
#define SHADER_H

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <GL/glew.h>

class Shader {
public:
    GLuint ID;
    Shader(const char* vertexPath, const char* fragmentPath) {
        std::string vCode, fCode;
        std::ifstream vFile(vertexPath), fFile(fragmentPath);
        std::stringstream vStream, fStream;
        vStream << vFile.rdbuf();
        fStream << fFile.rdbuf();
        vCode = vStream.str();
        fCode = fStream.str();
        const char* vShaderCode = vCode.c_str();
        const char* fShaderCode = fCode.c_str();

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

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

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

        glDeleteShader(vertex);
        glDeleteShader(fragment);
    }
    void use() { glUseProgram(ID); }
};

#endif

vertex.glsl

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

out vec3 FragPos;
out vec3 Normal;

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

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

fragment.glsl

#version 330 core
in vec3 FragPos;
in vec3 Normal;

out vec4 FragColor;

void main() {
    vec3 lightDir = normalize(vec3(0.5, 1.0, 0.3));
    float diff = max(dot(normalize(Normal), lightDir), 0.0);
    vec3 color = vec3(0.2, 0.3, 0.1) * diff;
    FragColor = vec4(color, 1.0);
}

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

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

furcr@furcraea_built MINGW64 /c/glsl_sample/fbx_viewer/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
-- Found OpenGL: opengl32
-- Found GLEW: C:/msys64/mingw64/lib/cmake/glew/glew-config.cmake
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
CMake Error at CMakeLists.txt:9 (find_package):
  By not providing "Findassimp.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "assimp", but
  CMake did not find one.

  Could not find a package configuration file provided by "assimp" with any
  of the following names:

    assimpConfig.cmake
    assimp-config.cmake

  Add the installation prefix of "assimp" to CMAKE_PREFIX_PATH or set
  "assimp_DIR" to a directory containing one of the above files.  If "assimp"
  provides a separate development package or SDK, be sure it has been
  installed.


-- Configuring incomplete, errors occurred!

furcr@furcraea_built MINGW64 /c/glsl_sample/fbx_viewer/build
$ pacman -S mingw-w64-x86_64-assimp
resolving dependencies...
looking for conflicting packages...

Packages (2) mingw-w64-x86_64-minizip-1.3.1-1  mingw-w64-x86_64-assimp-6.0.2-1

Total Download Size:    3.11 MiB
Total Installed Size:  12.02 MiB

:: Proceed with installation? [Y/n]
:: Retrieving packages...
 mingw-w64-x86_64-minizip-1...    83.1 KiB  32.7 KiB/s 00:03 [###############################] 100%
 mingw-w64-x86_64-assimp-6....     3.0 MiB   960 KiB/s 00:03 [###############################] 100%
 Total (2/2)                       3.1 MiB   882 KiB/s 00:04 [###############################] 100%
(2/2) checking keys in keyring                               [###############################] 100%
(2/2) checking package integrity                             [###############################] 100%
(2/2) loading package files                                  [###############################] 100%
(2/2) checking for file conflicts                            [###############################] 100%
(2/2) checking available disk space                          [###############################] 100%
:: Processing package changes...
(1/2) installing mingw-w64-x86_64-minizip                    [###############################] 100%
(2/2) installing mingw-w64-x86_64-assimp                     [###############################] 100%

furcr@furcraea_built MINGW64 /c/glsl_sample/fbx_viewer/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
-- Found OpenGL: opengl32
-- Found GLEW: C:/msys64/mingw64/lib/cmake/glew/glew-config.cmake
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Configuring done (1.8s)
-- Generating done (0.0s)
-- Build files have been written to: C:/glsl_sample/fbx_viewer/build

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

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

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

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

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(glsl_sample)

set(CMAKE_C_STANDARD 99)

add_executable(glsl_sample main.c)

include_directories("C:/msys64/mingw64/include/stb")

find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIRS})

# MSYS2パス用のヒント(MINGW64環境)
include_directories("C:/msys64/mingw64/include")
link_directories("C:/msys64/mingw64/lib")

target_link_libraries(glsl_sample glfw3 glew32 opengl32 gdi32)

main.c

#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

// ファイル読み込み
char* load_shader_source(const char* filepath) {
    FILE* file = fopen(filepath, "rb");
    if (!file) {
        fprintf(stderr, "Failed to open %s\n", filepath);
        exit(1);
    }
    fseek(file, 0, SEEK_END);
    long len = ftell(file);
    rewind(file);
    char* buffer = (char*)malloc(len + 1);
    fread(buffer, 1, len, file);
    buffer[len] = '\0';
    fclose(file);
    return buffer;
}

GLuint compile_shader(GLenum type, const char* source) {
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);
    GLint success;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        char infoLog[512];
        glGetShaderInfoLog(shader, 512, NULL, infoLog);
        fprintf(stderr, "Shader compile error: %s\n", infoLog);
        exit(1);
    }
    return shader;
}

int main() {
    if (!glfwInit()) {
        fprintf(stderr, "GLFW init failed\n");
        return -1;
    }

    GLFWwindow* window = glfwCreateWindow(800, 600, "GLSL Sample", NULL, NULL);
    if (!window) {
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);
    glewInit();

    char* vertexSource = load_shader_source("../shader.vert");
    char* fragmentSource = load_shader_source("../shader.frag");

    GLuint vertexShader = compile_shader(GL_VERTEX_SHADER, vertexSource);
    GLuint fragmentShader = compile_shader(GL_FRAGMENT_SHADER, fragmentSource);

    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glUseProgram(shaderProgram);

    double mouseX, mouseY;
    glfwGetCursorPos(window, &mouseX, &mouseY);

    int winW, winH;
    glfwGetWindowSize(window, &winW, &winH);
    //mouseY = winH - mouseY;  // 上下反転
    mouseX = mouseX/winW;  //
    mouseY = mouseY/winH;  //
    
    GLint mouseLoc = glGetUniformLocation(shaderProgram, "u_mouse");
    glUniform2f(mouseLoc, (float)mouseX, (float)mouseY);

    GLint resolutionLoc = glGetUniformLocation(shaderProgram, "u_resolution");

    GLint timeLoc = glGetUniformLocation(shaderProgram, "u_time");
    glUniform1i(glGetUniformLocation(shaderProgram, "u_texture"), 0); // sampler2D

    // 頂点データ
    float vertices[] = {
        // x, y, u, v
        -1.0f,  1.0f,  0.0f, 1.0f,
         1.0f,  1.0f,  1.0f, 1.0f,
         1.0f, -1.0f,  1.0f, 0.0f,
        -1.0f, -1.0f,  0.0f, 0.0f
    };

    unsigned int indices[] = {
        0, 1, 2,
        2, 3, 0
    };

    // VAO/VBO/EBO初期化
    GLuint 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, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // UV属性
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // テクスチャ読み込み
    int width, height, nrChannels;
    unsigned char *data = stbi_load("../texture.png", &width, &height, &nrChannels, 0);
    if (!data) {
        fprintf(stderr, "Failed to load texture\n");
        return -1;
    }

    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    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);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    GLenum format = (nrChannels == 4) ? GL_RGBA : GL_RGB;

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

    // ループ
    while (!glfwWindowShouldClose(window)) {
        float timeValue = (float)glfwGetTime();
        
        glfwGetCursorPos(window, &mouseX, &mouseY);
        glfwGetWindowSize(window, &winW, &winH);
        mouseX = mouseX/winW;  //
        mouseY = mouseY/winH;  //

        glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shaderProgram);
        glUniform1f(timeLoc, timeValue);
        glUniform2f(mouseLoc, (float)mouseX, (float)mouseY);
        glUniform2f(resolutionLoc, (float)winW, (float)winH);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture);

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

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glDeleteProgram(shaderProgram);
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    glfwTerminate();
    return 0;
}

shader.vert

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

out vec2 TexCoord;

void main()
{
    gl_Position = vec4(aPos, 0.0, 1.0);
    TexCoord = aTexCoord;
}

shader.frag

#version 330 core
out vec4 fragColor;

uniform sampler2D u_texture;
uniform vec2 u_mouse;       // マウス座標(0.0〜1.0)
uniform vec2 u_resolution;
uniform float u_time;

// カメラのレイ生成
vec3 getCameraRay(vec2 fragCoord, vec3 ro, vec3 ta) {
    vec2 uv = (fragCoord - 0.5 * u_resolution) / u_resolution.y;

    vec3 f = normalize(ta - ro);
    vec3 r = normalize(cross(f, vec3(0.0, 1.0, 0.0)));
    vec3 u = cross(r, f);

    return normalize(uv.x * r + uv.y * u + f);
}

// トーラスSDF
vec2 sdTorus(vec3 p, vec2 t) {
    vec2 q = vec2(length(p.xz) - t.x, p.y);
    float d = length(q) - t.y;
    return vec2(d, 1.0); // object ID = 1
}

// トーラスの中心位置(マウスに連動)
vec3 getTorusCenter() {
    // マウスを [-1,+1] に変換しXYにマッピング(Z位置固定)
    return vec3(
        (u_mouse.x * 2.0 - 1.0) * 1.5,
        (1.0 - u_mouse.y * 2.0) * 1.5,
        0.0
    );
}

// シーンの距離関数
vec2 map(vec3 p) {
    vec3 center = getTorusCenter();

    // 回転のみ(ローカル空間での処理)
    float angle = u_time * 0.5;
    mat3 rotY = mat3(
        cos(angle), 0.0, -sin(angle),
        0.0,        1.0,  0.0,
        sin(angle), 0.0,  cos(angle)
    );

    vec3 localP = (p - center) * rotY; // ローカル空間変換
    return sdTorus(localP, vec2(0.6, 0.2));
}

// 法線計算
vec3 getNormal(vec3 p) {
    float e = 0.001;
    vec2 h = vec2(e, 0.0);
    float dx = map(p + h.xyy).x - map(p - h.xyy).x;
    float dy = map(p + h.yxy).x - map(p - h.yxy).x;
    float dz = map(p + h.yyx).x - map(p - h.yyx).x;
    return normalize(vec3(dx, dy, dz));
}

// トーラスUV(ローカル空間UV)
vec2 torusUV(vec3 worldPos) {
    float angle = u_time * 0.5;
    mat3 rotY = mat3(
        cos(angle), 0.0, -sin(angle),
        0.0,        1.0,  0.0,
        sin(angle), 0.0,  cos(angle)
    );

    vec3 center = getTorusCenter();
    //vec3 localP = (worldPos - center) * rotY;
    vec3 localP = (worldPos - center) ;
    float u = atan(localP.z, localP.x) / (2.0 * 3.14159265) + 0.5;
    float r = length(localP.xz);
    float v = atan(localP.y, r - 0.6) / (2.0 * 3.14159265) + 0.5;
    return vec2(u, v);
}

// レイマーチング
vec3 raymarch(vec3 ro, vec3 rd) {
    float t = 0.0;
    vec3 p;
    float id = -1.0;

    for (int i = 0; i < 128; i++) {
        p = ro + rd * t;
        vec2 d = map(p);
        if (d.x < 0.001) {
            id = d.y;
            break;
        }
        if (t > 10.0) break;
        t += d.x;
    }

    if (id == 1.0) {
        vec2 uv = torusUV(p);
        vec3 tex = texture(u_texture, uv).rgb;
        vec3 n = getNormal(p);
        vec3 lightDir = normalize(vec3(0.4, 0.6, 0.3));
        float diff = clamp(dot(n, lightDir), 0.0, 1.0);
        return tex * diff + tex * 0.1;
    }

    return vec3(0.0); // background
}

void main() {
    vec2 fragCoord = gl_FragCoord.xy;
    vec3 ro = vec3(0.0, 0.0, 3.0);
    vec3 ta = vec3(0.0, 0.0, 0.0);
    vec3 rd = getCameraRay(fragCoord, ro, ta);

    vec3 col = raymarch(ro, rd);
    fragColor = vec4(col, 1.0);
}

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_201_3texture

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

furcr@furcraea_built MINGW64 /c/glsl_sample/glsl_sample_201_3texture/build
$ cmake -G "MSYS Makefiles" ..
CMake Deprecation Warning at CMakeLists.txt:1 (cmake_minimum_required):
  Compatibility with CMake < 3.10 will be removed from a future version of
  CMake.

  Update the VERSION argument <min> value.  Or, use the <min>...<max> syntax
  to tell CMake that the project requires at least <min> but has been updated
  to work with policies introduced by <max> or earlier.


-- 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
-- Found OpenGL: opengl32
-- Configuring done (2.4s)
-- Generating done (0.0s)
-- Build files have been written to: C:/glsl_sample/glsl_sample_201_3texture/build

furcr@furcraea_built MINGW64 /c/glsl_sample/glsl_sample_201_3texture/build
$ make
[ 50%] Building C object CMakeFiles/glsl_sample.dir/main.c.obj
[100%] Linking C executable glsl_sample.exe
[100%] Built target glsl_sample

furcr@furcraea_built MINGW64 /c/glsl_sample/glsl_sample_201_3texture/build
$ ./glsl_sample

[UE5.1]Customノードが安定してきたので色々試した。

いろんな意味で成功はしなかったが、かなり成長した。

まず、こちらのサイトで

ここのサイトが唯一.ushファイルのincludeをうまくやっている。
// Copyright Epic Games, Inc. All Rights Reserved.

#include "KA_MatCustomNode.h"
#include "Modules/ModuleManager.h"

IMPLEMENT_PRIMARY_GAME_MODULE(FKA_MatCustomNode, KA_MatCustomNode, "KA_MatCustomNode" );

void FKA_MatCustomNode::StartupModule()
{
    FString ShaderDirectory = FPaths::Combine(FPaths::ProjectDir(), TEXT("Shader"));
    if (!AllShaderSourceDirectoryMappings().Contains("/Project"))
    {
        AddShaderSourceDirectoryMapping("/Project", ShaderDirectory);
    }
    FString EngineDirectory = FPaths::Combine(FPaths::EngineDir(), TEXT("Engine"));
    if (!AllShaderSourceDirectoryMappings().Contains("/Engine"))
    {
        AddShaderSourceDirectoryMapping("/Engine", EngineDirectory);
    }
}

void FKA_MatCustomNode::ShutdownModule()
{
}

/Project/ というパスを入力することでプロジェクトフォルダの/Shader/へのパスからインクルードできるようにしていたので

よくあるインクルードコードで

/Engine/というパスを入力する事で/Engine/のShaderをインクルードできるようにしてみた。↑のソースコード

ただ.ushからのインクルードは機能しないっぽい

別の話だが

https://zhuanlan.zhihu.com/p/100834351

で紹介されているコードは実際には動かなかったが動くようにした。

#pragma once
#include "CoreMinimal.h"
#include "HAL/IConsoleManager.h"
#include "RHI.h"
#include "ShaderParameters.h"
#include "Shader.h"
#include "HitProxies.h"
#include "RHIStaticStates.h"
#include "SceneManagement.h"
#include "Materials/Material.h"
#include "PostProcess/SceneRenderTargets.h"
#include "DBufferTextures.h"
#include "LightMapRendering.h"
#include "VelocityRendering.h"
#include "MeshMaterialShaderType.h"
#include "MeshMaterialShader.h"
#include "ShaderBaseClasses.h"
#include "FogRendering.h"
#include "TranslucentLighting.h"
#include "PlanarReflectionRendering.h"
#include "UnrealEngine.h"
#include "ReflectionEnvironment.h"
#include "Strata/Strata.h"
#include "OIT/OITParameters.h"
#include "VirtualShadowMaps/VirtualShadowMapArray.h"
#include "VolumetricCloudRendering.h"
#include "Nanite/NaniteMaterials.h"

/**
 * Scene renderer that implements a deferred shading pipeline and associated features.
 */
class FDeferredShadingSceneRenderer : public FSceneRenderer
{
public:

	void RenderMyMeshPass(FRHICommandListImmediate& RHICmdList, const TArrayView<const FViewInfo*> PassViews);
	EDepthDrawingMode EarlyZPassMode;

}

#include "RHICommandList.h"
#include "Shader.h"
#include "RHIStaticStates.h"


#include "MyGS.h"
//My VertexShader
class FMyGS_VS : public FGlobalShader
{
	DECLARE_SHADER_TYPE(FMyGS_VS, Global);

public:

	FMyGS_VS() {}
	FMyGS_VS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FGlobalShader(Initializer)
	{

	}

	static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
	{

	}

	static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
	{
		return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
	}

	static bool ShouldCache(EShaderPlatform Platform)
	{
		return true;
	}

	virtual bool Serialize(FArchive& Ar) override
	{
		bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
		//Ar << ;
		return bShaderHasOutdatedParameters;
	}
	void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View)
	{
		FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, GetVertexShader(), View.ViewUniformBuffer);
	}
};

IMPLEMENT_SHADER_TYPE(, FMyGS_VS, TEXT("/Engine/Private/MyGS/MyGS.usf"), TEXT("MainVS"), SF_Vertex);


//My PixleShader
class FMyGS_PS : public FGlobalShader
{
	DECLARE_SHADER_TYPE(FMyGS_PS, Global);

public:

	FMyGS_PS() {}
	FMyGS_PS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FGlobalShader(Initializer)
	{

	}

	static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
	{

	}

	static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
	{
		return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
	}

	static bool ShouldCache(EShaderPlatform Platform)
	{
		return true;
	}

	virtual bool Serialize(FArchive& Ar) override
	{
		bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
		//Ar << ;
		return bShaderHasOutdatedParameters;
	}
	void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View)
	{
		FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, GetVertexShader(), View.ViewUniformBuffer);
	}
};

IMPLEMENT_SHADER_TYPE(, FMyGS_PS, TEXT("/Engine/Private/MyGS/MyGS.usf"), TEXT("MainPS"), SF_Pixel);

//My Geomertry shader
class FMyGS_GS : public FGlobalShader
{
	DECLARE_SHADER_TYPE(FMyGS_GS, Global);

public:

	FMyGS_GS() {}
	FMyGS_GS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FGlobalShader(Initializer)
	{

	}

	static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
	{

	}

	static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
	{
		return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
	}

	static bool ShouldCache(EShaderPlatform Platform)
	{
		return true;
	}

	virtual bool Serialize(FArchive& Ar) override
	{
		bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
		//Ar << ;
		return bShaderHasOutdatedParameters;
	}

	void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View)
	{
		FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, GetGeometryShader(), View.ViewUniformBuffer);
	}
};

IMPLEMENT_SHADER_TYPE(, FMyGS_GS, TEXT("/Engine/Private/MyGS/MyGS.usf"), TEXT("MainGS"), SF_Geometry);



class FDebugPane
{
public:

	FDebugPane();
	~FDebugPane();
	void FillRawData();
	void EmptyRawData();
	void Init();

	TArray<FVector> VerBuffer;
	TArray<uint16> InBuffer;

	uint32 Stride;

	bool Initialized;

	uint32 VertexCount;
	uint32 PrimitiveCount;

	FVertexBufferRHIRef VertexBufferRHI;
	FIndexBufferRHIRef IndexBufferRHI;

};
FDebugPane DebugMesh;

void FDeferredShadingSceneRenderer::RenderMyMeshPass(FRHICommandListImmediate& RHICmdList, const TArrayView<const FViewInfo*> PassViews)
{
	check(RHICmdList.IsOutsideRenderPass());

	TShaderMap<FGlobalShaderType>* ShaderMap = GetGlobalShaderMap(FeatureLevel);

	FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
	SceneContext.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthRead_StencilWrite, true);

	FGraphicsPipelineStateInitializer PSOInit;
	RHICmdList.ApplyCachedRenderTargets(PSOInit);

	PSOInit.RasterizerState = TStaticRasterizerState<FM_Wireframe, CM_None, false, false>::GetRHI();
	PSOInit.BlendState = TStaticBlendState<>::GetRHI();
	PSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_GreaterEqual>::GetRHI();
	PSOInit.PrimitiveType = EPrimitiveType::PT_TriangleList;
	PSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector3();

	TShaderMapRef<FMyGS_VS> Vs(ShaderMap);
	TShaderMapRef<FMyGS_PS> Ps(ShaderMap);
	TShaderMapRef<FMyGS_GS> Gs(ShaderMap);
	PSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*Vs);
	PSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*Ps);
	PSOInit.BoundShaderState.GeometryShaderRHI = GETSAFERHISHADER_GEOMETRY(*Gs);

	SetGraphicsPipelineState(RHICmdList, PSOInit);

	for (int i = 0; i < PassViews.Num(); ++i)
	{
		const FViewInfo* View = PassViews[i];

		if (DebugMesh.Initialized == false)
		{
			DebugMesh.Init();
		}
		RHICmdList.SetViewport(View->ViewRect.Min.X, View->ViewRect.Min.Y, 0.0f, View->ViewRect.Max.X, View->ViewRect.Max.Y, 1.0f);
		Gs->SetParameters(RHICmdList, *View);
		//Vs->SetParameters(RHICmdList, *View);

		RHICmdList.SetStreamSource(0, DebugMesh.VertexBufferRHI, 0);
		RHICmdList.DrawIndexedPrimitive(DebugMesh.IndexBufferRHI, PT_TriangleList, 0, DebugMesh.VertexCount, 0, DebugMesh.PrimitiveCount, 1);
	}
	SceneContext.FinishRenderingSceneColor(RHICmdList);
}

void FDebugPane::FillRawData()
{
	VerBuffer = {
		FVector(0.0f, 0.0f, 0.0f),
		FVector(100.0f, 0.0f, 0.0f),
		FVector(100.0f, 100.0f, 0.0f),
		FVector(0.0f, 100.0f, 0.0f)
	};

	InBuffer = {
		0, 1, 2,
		0, 2, 3
	};
}

FDebugPane::FDebugPane()
{
	Initialized = false;
}

FDebugPane::~FDebugPane()
{
	VertexBufferRHI.SafeRelease();
	IndexBufferRHI.SafeRelease();
}

void FDebugPane::EmptyRawData()
{
	VerBuffer.Empty();
	InBuffer.Empty();
}

void FDebugPane::Init()
{
	FillRawData();

	VertexCount = static_cast<uint32>(VerBuffer.Num());
	PrimitiveCount = static_cast<uint32>(InBuffer.Num() / 3);

	//GPU Vertex Buffer
	{
		TStaticMeshVertexData<FVector> VertexData(false);
		Stride = VertexData.GetStride();

		VertexData.ResizeBuffer(VerBuffer.Num());

		uint8* Data = VertexData.GetDataPointer();
		const uint8* InData = (const uint8*)&(VerBuffer[0]);
		FMemory::Memcpy(Data, InData, Stride * VerBuffer.Num());

		FResourceArrayInterface* ResourceArray = VertexData.GetResourceArray();
		FRHIResourceCreateInfo CreateInfo(ResourceArray);
		VertexBufferRHI = RHICreateVertexBuffer(ResourceArray->GetResourceDataSize(), BUF_Static, CreateInfo);
	}

	{
		TResourceArray<uint16, INDEXBUFFER_ALIGNMENT> IndexBuffer;
		IndexBuffer.AddUninitialized(InBuffer.Num());
		FMemory::Memcpy(IndexBuffer.GetData(), (void*)(&(InBuffer[0])), InBuffer.Num() * sizeof(uint16));

		// Create index buffer. Fill buffer with initial data upon creation
		FRHIResourceCreateInfo CreateInfo(&IndexBuffer);
		IndexBufferRHI = RHICreateIndexBuffer(sizeof(uint16), IndexBuffer.GetResourceDataSize(), BUF_Static, CreateInfo);
	}

	EmptyRawData();

	Initialized = true;
}

これでコンパイルは通る

また、別の話だが

これを移植しようとして

https://www.shadertoy.com/view/XsfGWN

コンパイルは通せた。

ちゃんと動かない。

const static float4 MyFloat = float4(1.0,0.0,0.0,1.0);

//const float uvScale = 1.0;
const float uvScale = 1.0;
//const float colorUvScale = 0.1;
const float colorUvScale = 1.0;
const float furDepth = 0.2;
const int furLayers = 64;
const float rayStep = 0.00625;
const float furThreshold = 0.4;
const float shininess = 50.0;
float iTime;

Texture2D<float4> Tex0;
Texture2D<float4> Tex1;
sampler Tex0Sampler;
sampler Tex1Sampler;

float2 UV;

//float3 blur = Texture2DSample(Tex0, Tex0Sampler, UV).rgb;

//bool intersectSphere(float3 ro, float3 rd, float r, out float t)
bool intersectSphere(float3 ro, float3 rd, float r,float t)
{
    //float t;
    float b = dot(-ro, rd);
	float det = b*b - dot(ro, ro) + r*r;
	if (det < 0.0) return false;
	det = sqrt(det);
	t = b - det;
	return t > 0.0;
}

float3 rotateX(float3 p, float a)
{
    float sa = sin(a);
    float ca = cos(a);
    return float3(p.x, ca*p.y - sa*p.z, sa*p.y + ca*p.z);
}
float3 rotateY(float3 p, float a)
{
    float sa = sin(a);
    float ca = cos(a);
    return float3(ca*p.x + sa*p.z, p.y, -sa*p.x + ca*p.z);
}

float2 cartesianToSpherical(float3 p)
{		
	float r = length(p);

	float t = (r - (1.0 - furDepth)) / furDepth;	
	p = rotateX(p.zyx, -cos(iTime*1.5)*t*t*0.4).zyx;	// curl

	p /= r;	
	float2 uv = float2(atan2(p.y, p.x), acos(p.z));

	//uv.x += cos(iTime*1.5)*t*t*0.4;	// curl
	//uv.y += sin(iTime*1.7)*t*t*0.2;
	uv.y -= t*t*0.1;	// curl down
	return uv;
}


//float furDensity(float3 pos, out float2 uv,Texture2D<float4> Tex0A,sampler Tex0ASampler)
float furDensity(float3 pos,float2 uv,Texture2D<float4> Tex0A,sampler Tex0ASampler,float2 UV0)
{
	uv = cartesianToSpherical(pos.xzy);	
	//float3 tex = Texture2DSample(Tex0,Tex0Sampler,uv*uvScale);
	float3 tex = Texture2DSample(Tex0A,Tex0ASampler,uv*uvScale);

	// thin out hair
	float density = smoothstep(furThreshold, 1.0, tex.x);
	
	float r = length(pos);
	float t = (r - (1.0 - furDepth)) / furDepth;
	
	// fade out along length
	float len = tex.y;
	density *= smoothstep(len, len-0.2, t);

	return density;	
}


// calculate normal from density
float3 furNormal(float3 pos, float density,Texture2D<float4> Tex0A,sampler Tex0ASampler,float2 UV0)
{
    float eps = 0.01;
    float3 n;
	float2 uv;
    n.x = furDensity( float3(pos.x+eps, pos.y, pos.z), uv ,Tex0A,Tex0ASampler,UV0) - density;
    n.y = furDensity( float3(pos.x, pos.y+eps, pos.z), uv ,Tex0A,Tex0ASampler,UV0) - density;
    n.z = furDensity( float3(pos.x, pos.y, pos.z+eps), uv ,Tex0A,Tex0ASampler,UV0) - density;
    return normalize(n);
}


//float3 furShade(Texture2D<float4> Tex1A,sampler Tex1ASampler,Texture2D<float4> Tex0A,sampler Tex0ASampler,float2 UV0)
float3 furShade(float3 pos, float2 uv, float3 ro, float density,Texture2D<float4> Tex1A,sampler Tex1ASampler,Texture2D<float4> Tex0A,sampler Tex0ASampler,float2 UV0)
{
    /*
    float2 iResolution = float2(2048,2048);
    float2 fragCoord = float2(640,360);
    
    float2 uv = fragCoord.xy / iResolution.xy;
	uv = uv*2.0-1.0;
	uv.x *= iResolution.x / iResolution.y;
    //uv =UV;
    
    float3 ro = float3(0.0, 0.0, 2.5);
	float3 rd = normalize(float3(uv, -2.0));
    float t2=1.0;
    float3 pos = ro + rd*t2;
    float density = furDensity(pos, uv,Tex0A,Tex0ASampler,UV0);
    */
    //----------------------------------------------------
	// lighting
	const float3 L = float3(0, 1, 0);
	float3 V = normalize(ro - pos);
	float3 H = normalize(V + L);

	float3 N = -furNormal(pos, density,Tex0A,Tex0ASampler,UV0);
	//float diff = max(0.0, dot(N, L));
	float diff = max(0.0, dot(N, L)*0.5+0.5);
	float spec = pow(max(0.0, dot(N, H)), shininess);
	
	// base color
	//float3 color = Texture2DSample(Tex1,Tex1Sampler, uv*colorUvScale).xyz;
	//float3 color = Texture2DSample(Tex1A,Tex1ASampler, UV0*colorUvScale).xyz;
	float3 color = Texture2DSample(Tex1A,Tex1ASampler, UV0*1.5).xyz;
    
	// darken with depth
	float r = length(pos);
	float t = (r - (1.0 - furDepth)) / furDepth;
	t = clamp(t, 0.0, 1.0);
	float i = t*0.5+0.5;
		
	//return color*diff*i + float3(spec*i,spec*i,spec*i);
    return color;
}	

float GetRandomNumber(float2 texCoord, int Seed)
{
    return frac(sin(dot(texCoord.xy, float2(12.9898, 78.233)) + Seed) * 43758.5453);
}

//float4 scene(float3 ro,float3 rd)
float4 scene(Texture2D<float4> Tex1A,sampler Tex1ASampler,Texture2D<float4> Tex0A,sampler Tex0ASampler,float2 UV0)
{
    float2 iResolution = float2(2048,2048);
    float2 fragCoord = float2(640,360);
    
    float2 uv = fragCoord.xy / iResolution.xy;
	uv = uv*2.0-1.0;
	uv.x *= iResolution.x / iResolution.y;
    uv=UV;
    float3 ro = float3(0.0, 0.0, 2.5);
	float3 rd = normalize(float3(uv, -2.0));
    
	//-------------------------------------------
	float3 p = float3(0.0,0.0,0.0);
	//const float r = 1.0;
	const float r = 1.1;
	float t=1.0;				  
	bool hit = intersectSphere(ro - p, rd, r, t);
	
	float4 c = float4(0.0,0.0,0.0,0.0);
    float4 sampleCol= float4(0.0,0.0,0.0,0.0);
    
    float rayStepA = furDepth*2.0 / float(furLayers);
    //float2 uv;
    float density;
    //float2 uv =float2(0.5,0.5);
	if (hit) {
		float3 pos = ro + rd*t;

		// ray-march into volume
		//for(int i=0; i<furLayers; i++) {
        for(int i=0; i<91; i++) {

			sampleCol.a = furDensity(pos, uv,Tex0A,Tex0ASampler,UV0)+0.5;
			//sampleCol.a = furDensity(pos, UV,Tex0A,Tex0ASampler,UV0)+0.5;
			//sampleCol.a = GetRandomNumber(UV,  5);
			//sampleCol.a = Texture2DSample(Tex0A,Tex0ASampler,UV*uvScale).y;
            
			//sampleCol.a = 1.0;
            density = sampleCol.a;
			if (sampleCol.a > 0.0) {
                sampleCol.rgb = furShade( pos,  uv,  ro, density, Tex1A, Tex1ASampler, Tex0A, Tex0ASampler, UV0);
                //sampleCol.rgb = furShade( pos,  UV,  ro, density, Tex1A, Tex1ASampler, Tex0A, Tex0ASampler, UV0);

				// pre-multiply alpha
				sampleCol.rgb *= sampleCol.a;
				c = c + sampleCol*(1.0 - c.a);
				if (c.a > 0.95) break;
			}
			
			pos += rd*rayStepA;
		}

	}
	
	return c;
	//return sampleCol;
}

/*
//float4 mainImage( out float4 fragColor, in float2 fragCoord )
//float4 mainImage(float2 fragCoord )
float4 mainImage( )
{
    //-----------------------------------------
    float2 iResolution = float2(256,256);
    float2 fragCoord = float2(256,256);
    float3 iMouse = float3(128,128,128);

	float2 uv = fragCoord.xy / iResolution.xy;
	uv = uv*2.0-1.0;
	uv.x *= iResolution.x / iResolution.y;
	
	float3 ro = float3(0.0, 0.0, 2.5);
	float3 rd = normalize(float3(uv, -2.0));
	
	float2 mouse = iMouse.xy / iResolution.xy;
	float roty = 0.0;
	float rotx = 0.0;
	if (iMouse.z > 0.0) {
		rotx = (mouse.y-0.5)*3.0;
		roty = -(mouse.x-0.5)*6.0;
	} else {
		roty = sin(iTime*1.5);
	}
	
    ro = rotateX(ro, rotx);	
    ro = rotateY(ro, roty);	
    rd = rotateX(rd, rotx);
    rd = rotateY(rd, roty);
	//--------------------------------------------------
    
    float2 iResolution = float2(256,256);
    float2 fragCoord = float2(256,256);
    
    float2 uv = fragCoord.xy / iResolution.xy;
	uv = uv*2.0-1.0;
	uv.x *= iResolution.x / iResolution.y;
    
    float3 ro = float3(0.0, 0.0, 2.5);
	float3 rd = normalize(float3(uv, -2.0));
    
	//fragColor = scene(ro, rd);
    //return fragColor;
    return scene(ro, rd);
}
*/

//float4 MyFunction(float2 UV,float iTime,Texture2D<float4> Tex0,Texture2D<float4> Tex1,sampler Tex0Sampler,sampler Tex1Sampler)
float4 MyFunction()

{
	return float4(0.0,1.0,0.0,1.0);
}

プロジェクトのダウンロード

https://drive.google.com/file/d/1RZ5TCEDluJOAzsGnDZp6nwCpN8u2we2U/view?usp=sharing

#UE4 #UE4Study 半径変更可能なRingをHLSLで描く #Shader #HLSL

Code : return MyFunction(texCoord,resolution,R);

OutputType: Float4

Inputs : texCoord,resolution,R,B

IncludeFilePath:/Project/Ring.usf

// ring
float centerR= length(p);//その座標の中心からの距離  中心が1 まわり0
float gradationOffset=R-centerR; //グラデーションをずらす。
float ring= abs(gradationOffset); //中心から距離が 0.5 となる場所ほど値を小さく
float t = B/ring;//見た目が天使の輪に見えるように係数をかける
//Ring.usf

//return MyFunction(texCoord,resolution,R,B);
float4 MyFunction(float2 texCoord,float2 resolution,float R,float B)
{
    // グラデーションのcenterをずらす
	float2 p = (texCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
	
    // ring
    float centerR= length(p);//その座標の中心からの距離  中心が1 まわり0
    float gradationOffset=R-centerR; //グラデーションをずらす。
    float ring= abs(gradationOffset); //中心から距離が 0.5 となる場所ほど値を小さく
    float t = B/ring;//見た目が天使の輪に見えるように係数をかける

    return float4(t,t,t, 1.0);;
}

参考

https://wgld.org/d/glsl/g004.html

#UE4 #UE4Study CostomノードのHLSLで円を描く三平方の定理で円を色分け

三平方の定理で円を色分け

Code: return MyFunction(texCoord,resolution,R,A,B);

OutputType:Float4

Inputs: texCoord,resolution,R,A,B

Input File Paths: /Project/Circle.usf

pow(V,2.0)でVの2乗って意味

https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-pow

つかわないでみた。

float R2=p.x*p.x+p.y*p.y;//三平方の定理


//Circle.usf

//return MyFunction(texCoord,resolution,R,A,B);
float4 MyFunction(float2 texCoord,float2 resolution,float R,float4 A,float4 B)
{
	
	float2 p = (texCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
	//return float3(p.x,p.y,1.0);
	
    //float R=0.5;

    //float4 c = float4(1.0,1.0,1.0,1.0);// baseColor
    float4 c =A;// baseColor
    float R2=p.x*p.x+p.y*p.y;//三平方の定理
    //if(pow(p.x,2.0) + pow(p.y,2.0) <= R){
    if(R2 <= R){
       // c = float4(0.0,0.0,0.0,0.0); //circleColor
        c = B;//circleColor
    }
    return c;
}

参考

UE4 Shader MaterialのCustomノードが進化してincludeFilePathでのファイル参照ができるようになっていた件

失敗1、2020年になってCustomノードが安定してきたみたいで

constで宣言しておくとそのままMyFloat使える

Codeにreturn MyFloat;で使える。

CodeにMyreturn MyFunction();で関数を呼び出せる。

const static float3 MyFloat = float3(1.0,0.0,0.0);

float3 MyFunction()
{
	return float3(0.0,1.0,0.0);
}

TestOutput1 = float3(0,0,1);
return 0.0;

Additional Output :TestOutput1

OutputType CMOT Float1

コンパイルされて自動生成されたHLSLコードの中身は

エラーコードで出てくるこれは

/Engine/Generated/Material.ush

マテリアルエディタのメニュー「ウインドウ>シェーダーコード>HLSL コード」を選択。

すると HLSL コードのウインドウが開き、コンパイルされた全マテリアルの内容が HLSL で表示される。

このプロジェクトの作り方は

【UE4】USF(Unreal Shader File) をすぐに始める環境設定 Project編さん

でのShaderフォルダの読み込み設定が必要だった。。50個ぐらいエラーがでるので見ない方がいいかも

今回はプロジェクト名は:Shader_MatCustomにしたよ

プロジェクト設定でCPP

Shader_MatCustom.h

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"

#include "Modules/ModuleManager.h"

class FShader_MatCustom : public IModuleInterface
{
public:
    virtual void StartupModule() override;
    virtual void ShutdownModule() override;


};

Shader_MatCustom.cpp

// Copyright Epic Games, Inc. All Rights Reserved.

#include "Shader_MatCustom.h"
#include "Modules/ModuleManager.h"

IMPLEMENT_PRIMARY_GAME_MODULE( FShader_MatCustom, Shader_MatCustom, "Shader_MatCustom" );//3つの書き換え


void FShader_MatCustom::StartupModule()
{
    FString ShaderDirectory = FPaths::Combine(FPaths::ProjectDir(), TEXT("Shader"));
    if (!AllShaderSourceDirectoryMappings().Contains("/Project"))
    {
        AddShaderSourceDirectoryMapping("/Project", ShaderDirectory);
    }

}

void FShader_MatCustom::ShutdownModule()
{
}

Shader_MatCustom.Build.cs

// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class Shader_MatCustom : ModuleRules  // ←クラス名リネーム
{
	public Shader_MatCustom(ReadOnlyTargetRules Target) : base(Target)  // ←クラス名リネーム
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[] {  //改行して展開した。
			"Core",
			"CoreUObject",
			"Engine",
			"InputCore",
			"RenderCore",  // ←追記
			"RHI"         // ←あとで必要になるので追記(パス追加に関係ない)
		});

		PrivateDependencyModuleNames.AddRange(new string[] {  });



		// Uncomment if you are using Slate UI
		// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
		
		// Uncomment if you are using online features
		// PrivateDependencyModuleNames.Add("OnlineSubsystem");

		// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
	}
}

VSでビルドをしてコンパイル

Shaderフォルダ作成

マテリアル作成

CustomNode作成

MyShader.usf作成

IncludeFilePathに/Project/MyShader.usf

MyShader.usf

const static float3 MyFloat = float3(1.0,0.0,0.0);

float3 MyFunction()
{
	return float3(0.0,1.0,0.0);
}

やっとうまくいったので

C++サンプルプロジェクトは丸ごとだ。.slnも入ってるよ

https://drive.google.com/file/d/1-ClY_v2cudLARAkMmAfPGrAnFndNnWIX/view?usp=sharing

参照

キンアジさんのところで見つけてしまった。