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


