From 2e64d3c5d6eb1eb04168d39d5eb5f2d89af1a8b0 Mon Sep 17 00:00:00 2001 From: pryazha Date: Sat, 2 Aug 2025 13:21:42 +0500 Subject: debug chapter --- debug/build.sh | 7 + debug/debug | Bin 0 -> 396728 bytes debug/debug.c | 62 +++++ debug/shader.frag | 12 + debug/shader.vert | 13 + libs/common.h | 127 ++++++++- pbr/1.1.lighting/build.sh | 5 - pbr/1.1.lighting/default.frag | 15 - pbr/1.1.lighting/default.vert | 17 -- pbr/1.1.lighting/hdr.frag | 18 -- pbr/1.1.lighting/hdr.vert | 17 -- pbr/1.1.lighting/lighting | Bin 401936 -> 0 bytes pbr/1.1.lighting/lighting.c | 157 ----------- pbr/1.1.lighting/pbr.frag | 105 ------- pbr/1.1.lighting/pbr.vert | 21 -- pbr/1.2.textured/build.sh | 5 - pbr/1.2.textured/hdr.frag | 18 -- pbr/1.2.textured/hdr.vert | 17 -- pbr/1.2.textured/pbr.frag | 126 --------- pbr/1.2.textured/pbr.vert | 24 -- pbr/1.2.textured/textured | Bin 397880 -> 0 bytes pbr/1.2.textured/textured.c | 151 ---------- .../background.frag | 17 -- .../background.vert | 19 -- pbr/2.1.1.ibl_irradiance_conversion/build.sh | 5 - pbr/2.1.1.ibl_irradiance_conversion/cubemap.frag | 25 -- pbr/2.1.1.ibl_irradiance_conversion/cubemap.vert | 17 -- pbr/2.1.1.ibl_irradiance_conversion/hdr.frag | 18 -- pbr/2.1.1.ibl_irradiance_conversion/hdr.vert | 17 -- .../ibl_irradiance_conversion | Bin 402568 -> 0 bytes .../ibl_irradiance_conversion.c | 193 ------------- pbr/2.1.1.ibl_irradiance_conversion/pbr.frag | 105 ------- pbr/2.1.1.ibl_irradiance_conversion/pbr.vert | 21 -- pbr/2.1.2.ibl_irradiance/background.frag | 17 -- pbr/2.1.2.ibl_irradiance/background.vert | 19 -- pbr/2.1.2.ibl_irradiance/build.sh | 5 - pbr/2.1.2.ibl_irradiance/convolution.frag | 33 --- pbr/2.1.2.ibl_irradiance/convolution.vert | 17 -- pbr/2.1.2.ibl_irradiance/cubemap.frag | 25 -- pbr/2.1.2.ibl_irradiance/cubemap.vert | 17 -- pbr/2.1.2.ibl_irradiance/hdr.frag | 18 -- pbr/2.1.2.ibl_irradiance/hdr.vert | 17 -- pbr/2.1.2.ibl_irradiance/ibl_irradiance | Bin 402768 -> 0 bytes pbr/2.1.2.ibl_irradiance/ibl_irradiance.c | 230 --------------- pbr/2.1.2.ibl_irradiance/pbr.frag | 114 -------- pbr/2.1.2.ibl_irradiance/pbr.vert | 21 -- pbr/ibl_irradiance/background.frag | 17 ++ pbr/ibl_irradiance/background.vert | 19 ++ pbr/ibl_irradiance/build.sh | 5 + pbr/ibl_irradiance/convolution.frag | 33 +++ pbr/ibl_irradiance/convolution.vert | 17 ++ pbr/ibl_irradiance/cubemap.frag | 25 ++ pbr/ibl_irradiance/cubemap.vert | 17 ++ pbr/ibl_irradiance/hdr.frag | 18 ++ pbr/ibl_irradiance/hdr.vert | 17 ++ pbr/ibl_irradiance/ibl_irradiance | Bin 0 -> 402760 bytes pbr/ibl_irradiance/ibl_irradiance.c | 228 +++++++++++++++ pbr/ibl_irradiance/pbr.frag | 114 ++++++++ pbr/ibl_irradiance/pbr.vert | 21 ++ pbr/ibl_irradiance_conversion/background.frag | 17 ++ pbr/ibl_irradiance_conversion/background.vert | 19 ++ pbr/ibl_irradiance_conversion/build.sh | 5 + pbr/ibl_irradiance_conversion/cubemap.frag | 25 ++ pbr/ibl_irradiance_conversion/cubemap.vert | 17 ++ pbr/ibl_irradiance_conversion/hdr.frag | 18 ++ pbr/ibl_irradiance_conversion/hdr.vert | 17 ++ .../ibl_irradiance_conversion | Bin 0 -> 402568 bytes .../ibl_irradiance_conversion.c | 193 +++++++++++++ pbr/ibl_irradiance_conversion/pbr.frag | 105 +++++++ pbr/ibl_irradiance_conversion/pbr.vert | 21 ++ pbr/ibl_specular/background.frag | 17 ++ pbr/ibl_specular/background.vert | 19 ++ pbr/ibl_specular/brdf.frag | 98 +++++++ pbr/ibl_specular/brdf.vert | 13 + pbr/ibl_specular/build.sh | 5 + pbr/ibl_specular/convolution.frag | 33 +++ pbr/ibl_specular/convolution.vert | 17 ++ pbr/ibl_specular/cubemap.frag | 25 ++ pbr/ibl_specular/cubemap.vert | 17 ++ pbr/ibl_specular/hdr.frag | 18 ++ pbr/ibl_specular/hdr.vert | 17 ++ pbr/ibl_specular/ibl_specular | Bin 0 -> 407864 bytes pbr/ibl_specular/ibl_specular.c | 307 +++++++++++++++++++++ pbr/ibl_specular/pbr.frag | 131 +++++++++ pbr/ibl_specular/pbr.vert | 21 ++ pbr/ibl_specular/prefilter.frag | 91 ++++++ pbr/ibl_specular/prefilter.vert | 17 ++ pbr/lighting/build.sh | 5 + pbr/lighting/default.frag | 15 + pbr/lighting/default.vert | 17 ++ pbr/lighting/hdr.frag | 18 ++ pbr/lighting/hdr.vert | 17 ++ pbr/lighting/lighting | Bin 0 -> 401936 bytes pbr/lighting/lighting.c | 157 +++++++++++ pbr/lighting/pbr.frag | 105 +++++++ pbr/lighting/pbr.vert | 21 ++ pbr/textured/build.sh | 5 + pbr/textured/hdr.frag | 18 ++ pbr/textured/hdr.vert | 17 ++ pbr/textured/pbr.frag | 126 +++++++++ pbr/textured/pbr.vert | 24 ++ pbr/textured/textured | Bin 0 -> 397880 bytes pbr/textured/textured.c | 151 ++++++++++ 103 files changed, 2729 insertions(+), 1668 deletions(-) create mode 100755 debug/build.sh create mode 100755 debug/debug create mode 100644 debug/debug.c create mode 100644 debug/shader.frag create mode 100644 debug/shader.vert delete mode 100755 pbr/1.1.lighting/build.sh delete mode 100644 pbr/1.1.lighting/default.frag delete mode 100644 pbr/1.1.lighting/default.vert delete mode 100644 pbr/1.1.lighting/hdr.frag delete mode 100644 pbr/1.1.lighting/hdr.vert delete mode 100755 pbr/1.1.lighting/lighting delete mode 100644 pbr/1.1.lighting/lighting.c delete mode 100644 pbr/1.1.lighting/pbr.frag delete mode 100644 pbr/1.1.lighting/pbr.vert delete mode 100755 pbr/1.2.textured/build.sh delete mode 100644 pbr/1.2.textured/hdr.frag delete mode 100644 pbr/1.2.textured/hdr.vert delete mode 100644 pbr/1.2.textured/pbr.frag delete mode 100644 pbr/1.2.textured/pbr.vert delete mode 100755 pbr/1.2.textured/textured delete mode 100644 pbr/1.2.textured/textured.c delete mode 100644 pbr/2.1.1.ibl_irradiance_conversion/background.frag delete mode 100644 pbr/2.1.1.ibl_irradiance_conversion/background.vert delete mode 100755 pbr/2.1.1.ibl_irradiance_conversion/build.sh delete mode 100644 pbr/2.1.1.ibl_irradiance_conversion/cubemap.frag delete mode 100644 pbr/2.1.1.ibl_irradiance_conversion/cubemap.vert delete mode 100644 pbr/2.1.1.ibl_irradiance_conversion/hdr.frag delete mode 100644 pbr/2.1.1.ibl_irradiance_conversion/hdr.vert delete mode 100755 pbr/2.1.1.ibl_irradiance_conversion/ibl_irradiance_conversion delete mode 100644 pbr/2.1.1.ibl_irradiance_conversion/ibl_irradiance_conversion.c delete mode 100644 pbr/2.1.1.ibl_irradiance_conversion/pbr.frag delete mode 100644 pbr/2.1.1.ibl_irradiance_conversion/pbr.vert delete mode 100644 pbr/2.1.2.ibl_irradiance/background.frag delete mode 100644 pbr/2.1.2.ibl_irradiance/background.vert delete mode 100755 pbr/2.1.2.ibl_irradiance/build.sh delete mode 100644 pbr/2.1.2.ibl_irradiance/convolution.frag delete mode 100644 pbr/2.1.2.ibl_irradiance/convolution.vert delete mode 100644 pbr/2.1.2.ibl_irradiance/cubemap.frag delete mode 100644 pbr/2.1.2.ibl_irradiance/cubemap.vert delete mode 100644 pbr/2.1.2.ibl_irradiance/hdr.frag delete mode 100644 pbr/2.1.2.ibl_irradiance/hdr.vert delete mode 100755 pbr/2.1.2.ibl_irradiance/ibl_irradiance delete mode 100644 pbr/2.1.2.ibl_irradiance/ibl_irradiance.c delete mode 100644 pbr/2.1.2.ibl_irradiance/pbr.frag delete mode 100644 pbr/2.1.2.ibl_irradiance/pbr.vert create mode 100644 pbr/ibl_irradiance/background.frag create mode 100644 pbr/ibl_irradiance/background.vert create mode 100755 pbr/ibl_irradiance/build.sh create mode 100644 pbr/ibl_irradiance/convolution.frag create mode 100644 pbr/ibl_irradiance/convolution.vert create mode 100644 pbr/ibl_irradiance/cubemap.frag create mode 100644 pbr/ibl_irradiance/cubemap.vert create mode 100644 pbr/ibl_irradiance/hdr.frag create mode 100644 pbr/ibl_irradiance/hdr.vert create mode 100755 pbr/ibl_irradiance/ibl_irradiance create mode 100644 pbr/ibl_irradiance/ibl_irradiance.c create mode 100644 pbr/ibl_irradiance/pbr.frag create mode 100644 pbr/ibl_irradiance/pbr.vert create mode 100644 pbr/ibl_irradiance_conversion/background.frag create mode 100644 pbr/ibl_irradiance_conversion/background.vert create mode 100755 pbr/ibl_irradiance_conversion/build.sh create mode 100644 pbr/ibl_irradiance_conversion/cubemap.frag create mode 100644 pbr/ibl_irradiance_conversion/cubemap.vert create mode 100644 pbr/ibl_irradiance_conversion/hdr.frag create mode 100644 pbr/ibl_irradiance_conversion/hdr.vert create mode 100755 pbr/ibl_irradiance_conversion/ibl_irradiance_conversion create mode 100644 pbr/ibl_irradiance_conversion/ibl_irradiance_conversion.c create mode 100644 pbr/ibl_irradiance_conversion/pbr.frag create mode 100644 pbr/ibl_irradiance_conversion/pbr.vert create mode 100644 pbr/ibl_specular/background.frag create mode 100644 pbr/ibl_specular/background.vert create mode 100644 pbr/ibl_specular/brdf.frag create mode 100644 pbr/ibl_specular/brdf.vert create mode 100755 pbr/ibl_specular/build.sh create mode 100644 pbr/ibl_specular/convolution.frag create mode 100644 pbr/ibl_specular/convolution.vert create mode 100644 pbr/ibl_specular/cubemap.frag create mode 100644 pbr/ibl_specular/cubemap.vert create mode 100644 pbr/ibl_specular/hdr.frag create mode 100644 pbr/ibl_specular/hdr.vert create mode 100755 pbr/ibl_specular/ibl_specular create mode 100644 pbr/ibl_specular/ibl_specular.c create mode 100644 pbr/ibl_specular/pbr.frag create mode 100644 pbr/ibl_specular/pbr.vert create mode 100644 pbr/ibl_specular/prefilter.frag create mode 100644 pbr/ibl_specular/prefilter.vert create mode 100755 pbr/lighting/build.sh create mode 100644 pbr/lighting/default.frag create mode 100644 pbr/lighting/default.vert create mode 100644 pbr/lighting/hdr.frag create mode 100644 pbr/lighting/hdr.vert create mode 100755 pbr/lighting/lighting create mode 100644 pbr/lighting/lighting.c create mode 100644 pbr/lighting/pbr.frag create mode 100644 pbr/lighting/pbr.vert create mode 100755 pbr/textured/build.sh create mode 100644 pbr/textured/hdr.frag create mode 100644 pbr/textured/hdr.vert create mode 100644 pbr/textured/pbr.frag create mode 100644 pbr/textured/pbr.vert create mode 100755 pbr/textured/textured create mode 100644 pbr/textured/textured.c diff --git a/debug/build.sh b/debug/build.sh new file mode 100755 index 0000000..40da223 --- /dev/null +++ b/debug/build.sh @@ -0,0 +1,7 @@ +#!/bin/sh +include='-I../libs -I../libs/pwyazh' +cflags="-g -Wall -Wextra -Wno-unused-parameter $include" +libs='-lm -lGL -lGLEW -lglfw' +target='debug' +set -x +gcc -o $target $cflags $target.c $libs diff --git a/debug/debug b/debug/debug new file mode 100755 index 0000000..d516f24 Binary files /dev/null and b/debug/debug differ diff --git a/debug/debug.c b/debug/debug.c new file mode 100644 index 0000000..8cddc16 --- /dev/null +++ b/debug/debug.c @@ -0,0 +1,62 @@ +#include +#include + +#include "common.h" + +int main(void) +{ + state_t state = init_state(1600, 800, 1); + init_glfw(&state); + init_gl(); + + F32 vertices[] = { + -0.5f, -0.5f, + 0.0f, 0.5f, + 0.5f, -0.5f + }; + U32 indices[] = { + 0, 1, 2 + }; + U32 vao = 0, vbo = 0, ebo = 0; + glGenVertexArrays(1, &vao); + glGenBuffers(1, &ebo); + glGenBuffers(1, &vbo); + 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); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(F32), 0); + glBindVertexArray(0); + + add_shader("shader.vert", "shader.frag", 0); + U32 shader = find_shader("shader"); + glUseProgram(shader); + + glClearColor(0.16f, 0.16f, 0.16f, 1.0f); + glBindVertexArray(vao); + + V2F offset = v2f(0.0f, 0.0f); + F32 time = 0.0f; + + while (!glfwWindowShouldClose(state.window)) { + handle_glfw_events(state.window, &state.input); + F32 dt = lock_framerate(60); + + /* update */ + offset.x += 0.5f * dt; + + /* render */ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glUniform2fv(glGetUniformLocation(shader, "offset"), 1, (F32 *)&offset); + glUniform1f(glGetUniformLocation(shader, "time"), time); + glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0); + + glfwSwapBuffers(state.window); + + time += dt; + } + + return 0; +} diff --git a/debug/shader.frag b/debug/shader.frag new file mode 100644 index 0000000..fd25c5f --- /dev/null +++ b/debug/shader.frag @@ -0,0 +1,12 @@ +#version 330 core + +in vec2 pos; + +out vec4 frag_color; + +uniform float time; + +void main() +{ + frag_color = vec4(sin(2.0 * time) * pos.x + 0.5, cos(2.0 * time) * pos.y + 0.5, 0.5, 1.0); +} diff --git a/debug/shader.vert b/debug/shader.vert new file mode 100644 index 0000000..e37e212 --- /dev/null +++ b/debug/shader.vert @@ -0,0 +1,13 @@ +#version 330 core + +layout(location = 0) in vec2 apos; + +out vec2 pos; + +uniform vec2 offset; + +void main() +{ + pos = apos; + gl_Position = vec4(apos + offset, 0.0, 1.0); +} diff --git a/libs/common.h b/libs/common.h index 72b44e7..08e753a 100644 --- a/libs/common.h +++ b/libs/common.h @@ -181,6 +181,7 @@ typedef struct { GLFWwindow *window; S32 width; S32 height; + S32 debug; } state_t; Input input_init() @@ -190,7 +191,7 @@ Input input_init() return(input); } -state_t init_state(S32 width, S32 height) +state_t init_state(S32 width, S32 height, S32 debug) { state_t state = { .arena = arena_alloc(Megabytes(64)), @@ -204,7 +205,8 @@ state_t init_state(S32 width, S32 height) .pitch = 0.0f }, .width = width, - .height = height + .height = height, + .debug = debug }; return state; } @@ -664,6 +666,8 @@ void init_glfw(state_t *state) { glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + if (state->debug) + glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); glfwWindowHint(GLFW_POSITION_X, xpos + monitor_width / 2.0f - state->width / 2.0f); @@ -680,10 +684,91 @@ void init_glfw(state_t *state) { glfwSwapInterval(0); } +void gl_debug_output(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) +{ + /* ignore these non-significant error codes */ + if(id == 131169 || id == 131185 || id == 131218 || id == 131204) + return; + info("debug message (%d): %s", id, message); + switch (source) { + case GL_DEBUG_SOURCE_API: + info("source: api"); + break; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: + info("source: window system"); + break; + case GL_DEBUG_SOURCE_SHADER_COMPILER: + info("source: shader compiler"); + break; + case GL_DEBUG_SOURCE_THIRD_PARTY: + info("source: third party"); + break; + case GL_DEBUG_SOURCE_APPLICATION: + info("source: application"); + break; + case GL_DEBUG_SOURCE_OTHER: + info("source: other"); + break; + } + switch (type) { + case GL_DEBUG_TYPE_ERROR: + info("type: error"); + break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + info("type: deprecated behaviour"); + break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + info("type: undefined behaviour"); + break; + case GL_DEBUG_TYPE_PORTABILITY: + info("type: portability"); + break; + case GL_DEBUG_TYPE_PERFORMANCE: + info("type: performance"); + break; + case GL_DEBUG_TYPE_MARKER: + info("type: marker"); + break; + case GL_DEBUG_TYPE_PUSH_GROUP: + info("type: push group"); + break; + case GL_DEBUG_TYPE_POP_GROUP: + info("type: pop group"); + break; + case GL_DEBUG_TYPE_OTHER: + info("type: other"); + break; + } + switch (severity) { + case GL_DEBUG_SEVERITY_HIGH: + info("severity: high"); + break; + case GL_DEBUG_SEVERITY_MEDIUM: + info("severity: medium"); + break; + case GL_DEBUG_SEVERITY_LOW: + info("severity: low"); + break; + case GL_DEBUG_SEVERITY_NOTIFICATION: + info("severity: notification"); + break; + } + putc('\n', stdout); +} + void init_gl(void) { if (glewInit() != GLEW_OK) die("failed to initialize glew"); + int flags; + glGetIntegerv(GL_CONTEXT_FLAGS, &flags); + if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) { + info("debug context initialized successfully"); + glEnable(GL_DEBUG_OUTPUT); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + glDebugMessageCallback(gl_debug_output, 0); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); + } glEnable(GL_DEPTH_TEST); } @@ -1056,4 +1141,42 @@ F32 lerp(F32 a, F32 b, F32 f) return a + f * (b - a); } +U32 check_gl_errors_(const char *file, int line) +{ + U32 code; + while ((code = glGetError()) != GL_NO_ERROR) { + char *error; + switch (code) { + case GL_INVALID_ENUM: + error = "invalid enum"; + break; + case GL_INVALID_VALUE: + error = "invalid value"; + break; + case GL_INVALID_OPERATION: + error = "invalid operation"; + break; + case GL_STACK_OVERFLOW: + error = "stack overflow"; + break; + case GL_STACK_UNDERFLOW: + error = "stack underflow"; + break; + case GL_OUT_OF_MEMORY: + error = "out of memory"; + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + error = "invalid framebuffer operation"; + break; + default: + error = "undefined error"; + break; + } + info("%s:%d: %s", file, line, error); + } + return code; +} + +#define check_gl_errors() check_gl_errors_(__FILE__, __LINE__) + #endif /* COMMON_H */ diff --git a/pbr/1.1.lighting/build.sh b/pbr/1.1.lighting/build.sh deleted file mode 100755 index 2cd71b7..0000000 --- a/pbr/1.1.lighting/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -. ../../config -TARGET='lighting' -set -x -gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS diff --git a/pbr/1.1.lighting/default.frag b/pbr/1.1.lighting/default.frag deleted file mode 100644 index 9351a1b..0000000 --- a/pbr/1.1.lighting/default.frag +++ /dev/null @@ -1,15 +0,0 @@ -#version 330 core - -in vert_t { - vec2 tex_coords; -} vert; - -out vec4 frag_color; - -uniform sampler2D colorbuffer; - -void main(void) -{ - vec3 color = vec3(texture(colorbuffer, vert.tex_coords)); - frag_color = vec4(color, 1.0); -} diff --git a/pbr/1.1.lighting/default.vert b/pbr/1.1.lighting/default.vert deleted file mode 100644 index 1b953d7..0000000 --- a/pbr/1.1.lighting/default.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; -layout(location = 2) in vec2 tex_coords; - -out vert_t { - vec2 tex_coords; -} vert; - -uniform mat4 model; - -void main(void) -{ - gl_Position = model * vec4(position, 1.0); - - vert.tex_coords = tex_coords; -} diff --git a/pbr/1.1.lighting/hdr.frag b/pbr/1.1.lighting/hdr.frag deleted file mode 100644 index 01650ae..0000000 --- a/pbr/1.1.lighting/hdr.frag +++ /dev/null @@ -1,18 +0,0 @@ -#version 330 core - -in vert_t { - vec2 tex_coords; -} vert; - -out vec4 frag_color; - -uniform sampler2D colorbuffer; - -void main(void) -{ - const float gamma = 2.2; - vec3 color = vec3(texture(colorbuffer, vert.tex_coords)); - color /= color + vec3(1.0); - color = pow(color, vec3(1.0 / gamma)); - frag_color = vec4(color, 1.0); -} diff --git a/pbr/1.1.lighting/hdr.vert b/pbr/1.1.lighting/hdr.vert deleted file mode 100644 index 1b953d7..0000000 --- a/pbr/1.1.lighting/hdr.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; -layout(location = 2) in vec2 tex_coords; - -out vert_t { - vec2 tex_coords; -} vert; - -uniform mat4 model; - -void main(void) -{ - gl_Position = model * vec4(position, 1.0); - - vert.tex_coords = tex_coords; -} diff --git a/pbr/1.1.lighting/lighting b/pbr/1.1.lighting/lighting deleted file mode 100755 index a68bd2b..0000000 Binary files a/pbr/1.1.lighting/lighting and /dev/null differ diff --git a/pbr/1.1.lighting/lighting.c b/pbr/1.1.lighting/lighting.c deleted file mode 100644 index d2a941d..0000000 --- a/pbr/1.1.lighting/lighting.c +++ /dev/null @@ -1,157 +0,0 @@ -#include "GL/glew.h" -#include "GLFW/glfw3.h" -#include "common.h" - -int main(void) -{ - state_t state = init_state(1600, 800); - - init_glfw(&state); - init_gl(); - - /* meshes */ - Mesh *sphere = mesh_load_obj(state.arena, "../../data/models/sphere.obj"); - Mesh *quad = mesh_gen_quad(state.arena); - - /* shaders */ - add_shader("default.vert", "default.frag", 0); - add_shader("pbr.vert", "pbr.frag", 0); - add_shader("hdr.vert", "hdr.frag", 0); - - light_t lights[4] = { - {{-6.0f, 0.0f, 7.0f}, {300.0f, 300.0f, 300.0f}}, - {{-4.0f, 0.0f, 6.0f}, {300.0f, 300.0f, 300.0f}}, - {{ 1.0f, 0.0f, 5.0f}, {300.0f, 300.0f, 300.0f}}, - {{ 3.0f, 0.0f, 8.0f}, {300.0f, 300.0f, 300.0f}}, - }; - - /* framebuffers */ - U32 hdr_fbo, hdr_colorbuffer, hdr_rbo; - glGenFramebuffers(1, &hdr_fbo); - glGenTextures(1, &hdr_colorbuffer); - glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, state.width, state.height, 0, GL_RGBA, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glGenRenderbuffers(1, &hdr_rbo); - glBindRenderbuffer(GL_RENDERBUFFER, hdr_rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, state.width, state.height); - glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdr_colorbuffer, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdr_rbo); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - die("failed to create framebuffer"); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - F32 time = 0; - - S32 show_gamma = 0; - - while (!glfwWindowShouldClose(state.window)) { - handle_glfw_events(state.window, &state.input); - F32 dt = lock_framerate(60); - fps_info(dt, 10); - - /* update */ - update_camera_first_person(&state.camera, &state.input, dt, 2.0f); - F32 limit = 4.0f; - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) - lights[i].position.y = sinf(time + i) * limit; - time += dt; - - if (key_first_press(state.input.jump)) - show_gamma = 1 - show_gamma; - - /* render */ - F32 ar = 0; - if (show_gamma) { - ar = (F32)state.width / 2.0f / (F32)state.height; - } else { - ar = (F32)state.width / (F32)state.height; - } - MAT4 projection = camera_persp(state.camera, ar); - MAT4 view = get_view_matrix(&state.camera); - - glClearColor(0.16f, 0.16f, 0.16f, 1.0f); - - glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - U32 shader = find_shader("pbr"); - if (!shader) die("wha"); - glUseProgram(shader); - shader_set_mat4fv(shader, "projection", projection); - shader_set_mat4fv(shader, "view", view); - shader_set_3fv(shader, "camera", state.camera.pos); - shader_set_3fv(shader, "color", v3f(0.04, 0.04, 0.04)); - shader_set_1f(shader, "ao", 1.0f); - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { - char str[512]; - snprintf(str, 512, "lights[%d].position", i); - shader_set_3fv(shader, str, lights[i].position); - snprintf(str, 512, "lights[%d].color", i); - shader_set_3fv(shader, str, lights[i].color); - } - S32 rows = 7; - S32 cols = 7; - F32 offset = 3.0f; - for (S32 row = 0; row < rows; row++) { - shader_set_1f(shader, "metallic", (F32)row / (F32)rows); - for (S32 col = 0; col < cols; col++) { - shader_set_1f(shader, "roughness", clamp(0.05f, (F32)col / (F32)cols, 1.0f)); - V3F pos = {(col - cols / 2.0f) * offset, (row - rows / 2.0f) * offset, 0.0f}; - MAT4 model = mat4_make_translate(pos); - shader_set_mat4fv(shader, "model", model); - mesh_draw(sphere); - } - } - - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { - MAT4 model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); - model = mat4_translate(model, lights[i].position); - shader_set_mat4fv(shader, "model", model); - mesh_draw(sphere); - } - - glUseProgram(0); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - if (show_gamma) { - shader = find_shader("default"); - if (!shader) die("!"); - glUseProgram(shader); - glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); - MAT4 model = mat4_make_scale(v3f(0.5f, 1.0f, 1.0f)); - model = mat4_translate(model, v3f(-0.5f, 0.0f, 0.0f)); - shader_set_mat4fv(shader, "model", model); - mesh_draw(quad); - glUseProgram(0); - - shader = find_shader("hdr"); - if (!shader) die("!"); - glUseProgram(shader); - glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); - model = mat4_make_scale(v3f(0.5f, 1.0f, 1.0f)); - model = mat4_translate(model, v3f(0.5f, 0.0f, 0.0f)); - shader_set_mat4fv(shader, "model", model); - mesh_draw(quad); - glUseProgram(0); - } else { - shader = find_shader("hdr"); - if (!shader) die("!"); - glUseProgram(shader); - glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); - shader_set_mat4fv(shader, "model", mat4_identity()); - mesh_draw(quad); - glUseProgram(0); - } - - glfwSwapBuffers(state.window); - } - - return 0; -} diff --git a/pbr/1.1.lighting/pbr.frag b/pbr/1.1.lighting/pbr.frag deleted file mode 100644 index db9edea..0000000 --- a/pbr/1.1.lighting/pbr.frag +++ /dev/null @@ -1,105 +0,0 @@ -#version 330 core - -in vert_t { - vec3 position; - vec3 normal; -} vert; - -out vec4 frag_color; - -uniform vec3 camera; - -uniform vec3 color; -uniform float metallic; -uniform float roughness; -uniform float ao; - -struct light_t { - vec3 position; - vec3 color; -}; - -const int light_count = 4; -uniform light_t lights[light_count]; - -const float PI = 3.14159265358; - -vec3 fresnel_shlick(float costheta, vec3 f0) -{ - return f0 + (1.0 - f0) * pow(1.0 - costheta, 5.0); -} - -float distribution_ggx(vec3 n, vec3 h, float roughness) -{ - float a = roughness * roughness; - float a2 = a * a; - float ndoth = max(dot(n, h), 0.0); - float ndoth2 = ndoth * ndoth; - - float num = a2; - float denom = (ndoth2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; - - return num / denom; -} - -float geometry_shlick_ggx(float ndotv, float roughness) -{ - float r = roughness + 1.0; - float k = r * r / 8.0; - - float num = ndotv; - float denom = ndotv * (1.0 - k) + k; - - return num / denom; -} - -float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) -{ - float ndotv = max(dot(n, v), 0.0); - float ndotl = max(dot(n, l), 0.0); - float ggx2 = geometry_shlick_ggx(ndotv, roughness); - float ggx1 = geometry_shlick_ggx(ndotl, roughness); - - return ggx1 * ggx2; -} - -void main(void) -{ - vec3 n = vert.normal; - vec3 v = normalize(camera - vert.position); - - vec3 lo = vec3(0.0); - for (int i = 0; i < light_count; i++) { - vec3 l = normalize(lights[i].position - vert.position); - vec3 h = normalize(v + l); - float ndotv = max(dot(n, v), 0.0); - float ndotl = max(dot(n, l), 0.0); - - float distance = length(lights[i].position - vert.position); - float attenuation = 1.0 / (distance * distance); - - vec3 radiance = lights[i].color * attenuation; - - vec3 f0 = vec3(0.04); - f0 = mix(f0, color, metallic); - vec3 f = fresnel_shlick(max(dot(h, v), 0.0), f0); - - float ndf = distribution_ggx(n, h, roughness); - float g = geometry_smith(n, v, l, roughness); - - vec3 numerator = ndf * g * f; - float denominator = 4.0 * ndotv * ndotl; - vec3 specular = numerator / max(denominator, 0.001); - - vec3 ks = f; - vec3 kd = vec3(1.0) - ks; - - kd *= 1.0 - metallic; - - lo += (kd * color / PI + specular) * radiance * ndotl; - } - - vec3 ambient = vec3(0.03) * color * ao; - frag_color = vec4(ambient + lo, 1.0); -} diff --git a/pbr/1.1.lighting/pbr.vert b/pbr/1.1.lighting/pbr.vert deleted file mode 100644 index e6e3800..0000000 --- a/pbr/1.1.lighting/pbr.vert +++ /dev/null @@ -1,21 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; -layout(location = 1) in vec3 normal; - -out vert_t { - vec3 position; - vec3 normal; -} vert; - -uniform mat4 projection; -uniform mat4 view; -uniform mat4 model; - -void main(void) -{ - gl_Position = projection * view * model * vec4(position, 1.0); - - vert.position = vec3(model * vec4(position, 1.0)); - vert.normal = normalize(mat3(transpose(inverse(model))) * normal); -} diff --git a/pbr/1.2.textured/build.sh b/pbr/1.2.textured/build.sh deleted file mode 100755 index 5c5427f..0000000 --- a/pbr/1.2.textured/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -. ../../config -TARGET='textured' -set -x -gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS diff --git a/pbr/1.2.textured/hdr.frag b/pbr/1.2.textured/hdr.frag deleted file mode 100644 index 01650ae..0000000 --- a/pbr/1.2.textured/hdr.frag +++ /dev/null @@ -1,18 +0,0 @@ -#version 330 core - -in vert_t { - vec2 tex_coords; -} vert; - -out vec4 frag_color; - -uniform sampler2D colorbuffer; - -void main(void) -{ - const float gamma = 2.2; - vec3 color = vec3(texture(colorbuffer, vert.tex_coords)); - color /= color + vec3(1.0); - color = pow(color, vec3(1.0 / gamma)); - frag_color = vec4(color, 1.0); -} diff --git a/pbr/1.2.textured/hdr.vert b/pbr/1.2.textured/hdr.vert deleted file mode 100644 index 1b953d7..0000000 --- a/pbr/1.2.textured/hdr.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; -layout(location = 2) in vec2 tex_coords; - -out vert_t { - vec2 tex_coords; -} vert; - -uniform mat4 model; - -void main(void) -{ - gl_Position = model * vec4(position, 1.0); - - vert.tex_coords = tex_coords; -} diff --git a/pbr/1.2.textured/pbr.frag b/pbr/1.2.textured/pbr.frag deleted file mode 100644 index f0aaeca..0000000 --- a/pbr/1.2.textured/pbr.frag +++ /dev/null @@ -1,126 +0,0 @@ -#version 330 core - -in vert_t { - vec3 position; - vec3 normal; - vec2 tex_coords; -} vert; - -out vec4 frag_color; - -uniform vec3 camera; - -uniform sampler2D color_map; -uniform sampler2D normal_map; -uniform sampler2D metallic_map; -uniform sampler2D roughness_map; -uniform sampler2D ao_map; - -struct light_t { - vec3 position; - vec3 color; -}; - -const int light_count = 4; -uniform light_t lights[light_count]; - -const float PI = 3.14159265358; - -vec3 get_normal_from_map() -{ - vec3 tangent = texture(normal_map, vert.tex_coords).xyz * 2.0 - 1.0; - vec3 q1 = dFdx(vert.position); - vec3 q2 = dFdy(vert.position); - vec2 st1 = dFdx(vert.tex_coords); - vec2 st2 = dFdy(vert.tex_coords); - vec3 n = normalize(vert.normal); - vec3 t = normalize(q1*st2.t - q2*st1.t); - vec3 b = -normalize(cross(n, t)); - mat3 tbn = mat3(t, b, n); - return normalize(tbn * tangent); -} - -vec3 fresnel_shlick(float costheta, vec3 f0) -{ - return f0 + (1.0 - f0) * pow(1.0 - costheta, 5.0); -} - -float distribution_ggx(vec3 n, vec3 h, float roughness) -{ - float a = roughness * roughness; - float a2 = a * a; - float ndoth = max(dot(n, h), 0.0); - float ndoth2 = ndoth * ndoth; - - float num = a2; - float denom = (ndoth2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; - - return num / denom; -} - -float geometry_shlick_ggx(float ndotv, float roughness) -{ - float r = roughness + 1.0; - float k = r * r / 8.0; - - float num = ndotv; - float denom = ndotv * (1.0 - k) + k; - - return num / denom; -} - -float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) -{ - float ndotv = max(dot(n, v), 0.0); - float ndotl = max(dot(n, l), 0.0); - float ggx2 = geometry_shlick_ggx(ndotv, roughness); - float ggx1 = geometry_shlick_ggx(ndotl, roughness); - - return ggx1 * ggx2; -} - -void main(void) -{ - vec3 color = pow(texture(color_map, vert.tex_coords).rgb, vec3(2.2)); - float metallic = texture(metallic_map, vert.tex_coords).r; - float roughness = texture(roughness_map, vert.tex_coords).r; - float ao = texture(ao_map, vert.tex_coords).r; - - vec3 n = get_normal_from_map(); - vec3 v = normalize(camera - vert.position); - - vec3 lo = vec3(0.0); - for (int i = 0; i < light_count; i++) { - vec3 l = normalize(lights[i].position - vert.position); - vec3 h = normalize(v + l); - float ndotv = max(dot(n, v), 0.0); - float ndotl = max(dot(n, l), 0.0); - - float distance = length(lights[i].position - vert.position); - float attenuation = 1.0 / (distance * distance); - - vec3 radiance = lights[i].color * attenuation; - - vec3 f0 = vec3(0.04); - f0 = mix(f0, color, metallic); - vec3 f = fresnel_shlick(max(dot(h, v), 0.0), f0); - - float ndf = distribution_ggx(n, h, roughness); - float g = geometry_smith(n, v, l, roughness); - - vec3 numerator = ndf * g * f; - float denominator = 4.0 * ndotv * ndotl; - vec3 specular = numerator / max(denominator, 0.001); - - vec3 ks = f; - vec3 kd = vec3(1.0) - ks; - - kd *= 1.0 - metallic; - - lo += (kd * color / PI + specular) * radiance * ndotl; - } - - vec3 ambient = vec3(0.03) * color * ao; - frag_color = vec4(ambient + lo, 1.0); -} diff --git a/pbr/1.2.textured/pbr.vert b/pbr/1.2.textured/pbr.vert deleted file mode 100644 index 0ff1bdb..0000000 --- a/pbr/1.2.textured/pbr.vert +++ /dev/null @@ -1,24 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; -layout(location = 1) in vec3 normal; -layout(location = 2) in vec2 tex_coords; - -out vert_t { - vec3 position; - vec3 normal; - vec2 tex_coords; -} vert; - -uniform mat4 projection; -uniform mat4 view; -uniform mat4 model; - -void main(void) -{ - gl_Position = projection * view * model * vec4(position, 1.0); - - vert.position = vec3(model * vec4(position, 1.0)); - vert.normal = normalize(mat3(transpose(inverse(model))) * normal); - vert.tex_coords = tex_coords; -} diff --git a/pbr/1.2.textured/textured b/pbr/1.2.textured/textured deleted file mode 100755 index e339406..0000000 Binary files a/pbr/1.2.textured/textured and /dev/null differ diff --git a/pbr/1.2.textured/textured.c b/pbr/1.2.textured/textured.c deleted file mode 100644 index e8ed096..0000000 --- a/pbr/1.2.textured/textured.c +++ /dev/null @@ -1,151 +0,0 @@ -#include "GL/glew.h" -#include "GLFW/glfw3.h" -#include "common.h" - -int main(void) -{ - state_t state = init_state(1600, 800); - - init_glfw(&state); - init_gl(); - - /* meshes */ - Mesh *sphere = mesh_load_obj(state.arena, "../../data/models/sphere.obj"); - Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj"); - Mesh *quad = mesh_gen_quad(state.arena); - - /* shaders */ - add_shader("pbr.vert", "pbr.frag", 0); - add_shader("hdr.vert", "hdr.frag", 0); - - U32 shader = find_shader("pbr"); - if (!shader) - die("not again"); - glUseProgram(shader); - shader_set_1i(shader, "color_map", 0); - shader_set_1i(shader, "normal_map", 1); - shader_set_1i(shader, "metallic_map", 2); - shader_set_1i(shader, "roughness_map", 3); - shader_set_1i(shader, "ao_map", 4); - glUseProgram(0); - - light_t lights[4] = { - {{-6.0f, 0.0f, 7.0f}, {300.0f, 300.0f, 300.0f}}, - {{-4.0f, 0.0f, 6.0f}, {300.0f, 300.0f, 300.0f}}, - {{ 1.0f, 0.0f, 5.0f}, {300.0f, 300.0f, 300.0f}}, - {{ 3.0f, 0.0f, 8.0f}, {300.0f, 300.0f, 300.0f}}, - }; - - /* textures */ - U32 color_map = load_texture("../../data/textures/pbr/albedo.png"); - U32 normal_map = load_texture("../../data/textures/pbr/normal.png"); - U32 metallic_map = load_texture("../../data/textures/pbr/metallic.png"); - U32 roughness_map = load_texture("../../data/textures/pbr/roughness.png"); - U32 ao_map = load_texture("../../data/textures/pbr/ao.png"); - - /* framebuffers */ - U32 hdr_fbo, hdr_colorbuffer, hdr_rbo; - glGenFramebuffers(1, &hdr_fbo); - glGenTextures(1, &hdr_colorbuffer); - glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, state.width, state.height, 0, GL_RGBA, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glGenRenderbuffers(1, &hdr_rbo); - glBindRenderbuffer(GL_RENDERBUFFER, hdr_rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, state.width, state.height); - glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdr_colorbuffer, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdr_rbo); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - die("failed to create framebuffer"); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - F32 time = 0; - - while (!glfwWindowShouldClose(state.window)) { - handle_glfw_events(state.window, &state.input); - F32 dt = lock_framerate(60); - fps_info(dt, 10); - - /* update */ - update_camera_first_person(&state.camera, &state.input, dt, 2.0f); - F32 limit = 4.0f; - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) - lights[i].position.y = sinf(2.0f * time + i) * limit; - time += dt; - - /* render */ - F32 ar = (F32)state.width / (F32)state.height; - MAT4 projection = camera_persp(state.camera, ar); - MAT4 view = get_view_matrix(&state.camera); - - glClearColor(0.16f, 0.16f, 0.16f, 1.0f); - - glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - shader = find_shader("pbr"); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, color_map); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, normal_map); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, metallic_map); - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, roughness_map); - glActiveTexture(GL_TEXTURE4); - glBindTexture(GL_TEXTURE_2D, ao_map); - - if (!shader) die("wha"); - glUseProgram(shader); - shader_set_mat4fv(shader, "projection", projection); - shader_set_mat4fv(shader, "view", view); - shader_set_3fv(shader, "camera", state.camera.pos); - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { - char str[512]; - snprintf(str, 512, "lights[%d].position", i); - shader_set_3fv(shader, str, lights[i].position); - snprintf(str, 512, "lights[%d].color", i); - shader_set_3fv(shader, str, lights[i].color); - } - S32 rows = 7; - S32 cols = 7; - F32 offset = 3.0f; - for (S32 row = 0; row < rows; row++) { - for (S32 col = 0; col < cols; col++) { - V3F pos = {(col - cols / 2.0f) * offset, (row - rows / 2.0f) * offset, 0.0f}; - MAT4 model = mat4_make_translate(pos); - shader_set_mat4fv(shader, "model", model); - mesh_draw(cube); - } - } - - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { - MAT4 model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); - model = mat4_translate(model, lights[i].position); - shader_set_mat4fv(shader, "model", model); - mesh_draw(sphere); - } - - glUseProgram(0); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - shader = find_shader("hdr"); - if (!shader) die("!"); - glUseProgram(shader); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); - shader_set_mat4fv(shader, "model", mat4_identity()); - mesh_draw(quad); - glUseProgram(0); - - glfwSwapBuffers(state.window); - } - - return 0; -} diff --git a/pbr/2.1.1.ibl_irradiance_conversion/background.frag b/pbr/2.1.1.ibl_irradiance_conversion/background.frag deleted file mode 100644 index e3891eb..0000000 --- a/pbr/2.1.1.ibl_irradiance_conversion/background.frag +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 core - -in vert_t { - vec3 position; -} vert; - -out vec4 frag_color; - -uniform samplerCube cubemap; - -void main(void) -{ - vec3 color = texture(cubemap, vert.position).rgb; - color /= color + vec3(1.0); - color = pow(color, vec3(1.0 / 2.2)); - frag_color = vec4(color, 1.0); -} diff --git a/pbr/2.1.1.ibl_irradiance_conversion/background.vert b/pbr/2.1.1.ibl_irradiance_conversion/background.vert deleted file mode 100644 index 25b9778..0000000 --- a/pbr/2.1.1.ibl_irradiance_conversion/background.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; - -out vert_t { - vec3 position; -} vert; - -uniform mat4 projection; -uniform mat4 view; - -void main(void) -{ - vert.position = position; - - mat4 rotate_view = mat4(mat3(view)); - vec4 clip_position = projection * rotate_view * vec4(position, 1.0); - gl_Position = clip_position.xyww; -} diff --git a/pbr/2.1.1.ibl_irradiance_conversion/build.sh b/pbr/2.1.1.ibl_irradiance_conversion/build.sh deleted file mode 100755 index 834030a..0000000 --- a/pbr/2.1.1.ibl_irradiance_conversion/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -. ../../config -TARGET='ibl_irradiance_conversion' -set -x -gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS diff --git a/pbr/2.1.1.ibl_irradiance_conversion/cubemap.frag b/pbr/2.1.1.ibl_irradiance_conversion/cubemap.frag deleted file mode 100644 index 349347a..0000000 --- a/pbr/2.1.1.ibl_irradiance_conversion/cubemap.frag +++ /dev/null @@ -1,25 +0,0 @@ -#version 330 core - -in vert_t { - vec3 position; -} vert; - -out vec4 frag_color; - -uniform sampler2D map; - -const vec2 inv_atan = vec2(0.1591, 0.3183); -vec2 sample_spherical_map(vec3 v) -{ - vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); - uv *= inv_atan; - uv += 0.5; - return uv; -} - -void main(void) -{ - vec2 uv = sample_spherical_map(normalize(vert.position)); - vec3 color = texture(map, uv).rgb; - frag_color = vec4(color, 1.0); -} diff --git a/pbr/2.1.1.ibl_irradiance_conversion/cubemap.vert b/pbr/2.1.1.ibl_irradiance_conversion/cubemap.vert deleted file mode 100644 index 8f8862e..0000000 --- a/pbr/2.1.1.ibl_irradiance_conversion/cubemap.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; - -out vert_t { - vec3 position; -} vert; - -uniform mat4 projection; -uniform mat4 view; - -void main(void) -{ - gl_Position = projection * view * vec4(position, 1.0); - - vert.position = position; -} diff --git a/pbr/2.1.1.ibl_irradiance_conversion/hdr.frag b/pbr/2.1.1.ibl_irradiance_conversion/hdr.frag deleted file mode 100644 index 01650ae..0000000 --- a/pbr/2.1.1.ibl_irradiance_conversion/hdr.frag +++ /dev/null @@ -1,18 +0,0 @@ -#version 330 core - -in vert_t { - vec2 tex_coords; -} vert; - -out vec4 frag_color; - -uniform sampler2D colorbuffer; - -void main(void) -{ - const float gamma = 2.2; - vec3 color = vec3(texture(colorbuffer, vert.tex_coords)); - color /= color + vec3(1.0); - color = pow(color, vec3(1.0 / gamma)); - frag_color = vec4(color, 1.0); -} diff --git a/pbr/2.1.1.ibl_irradiance_conversion/hdr.vert b/pbr/2.1.1.ibl_irradiance_conversion/hdr.vert deleted file mode 100644 index 1b953d7..0000000 --- a/pbr/2.1.1.ibl_irradiance_conversion/hdr.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; -layout(location = 2) in vec2 tex_coords; - -out vert_t { - vec2 tex_coords; -} vert; - -uniform mat4 model; - -void main(void) -{ - gl_Position = model * vec4(position, 1.0); - - vert.tex_coords = tex_coords; -} diff --git a/pbr/2.1.1.ibl_irradiance_conversion/ibl_irradiance_conversion b/pbr/2.1.1.ibl_irradiance_conversion/ibl_irradiance_conversion deleted file mode 100755 index cc43012..0000000 Binary files a/pbr/2.1.1.ibl_irradiance_conversion/ibl_irradiance_conversion and /dev/null differ diff --git a/pbr/2.1.1.ibl_irradiance_conversion/ibl_irradiance_conversion.c b/pbr/2.1.1.ibl_irradiance_conversion/ibl_irradiance_conversion.c deleted file mode 100644 index 0ffbe7c..0000000 --- a/pbr/2.1.1.ibl_irradiance_conversion/ibl_irradiance_conversion.c +++ /dev/null @@ -1,193 +0,0 @@ -#include "GL/glew.h" -#include "GLFW/glfw3.h" -#include "common.h" - -int main(void) -{ - state_t state = init_state(1600, 800); - - init_glfw(&state); - init_gl(); - glDepthFunc(GL_LEQUAL); - - /* meshes */ - Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj"); - Mesh *quad = mesh_gen_quad(state.arena); - - /* shaders */ - add_shader("pbr.vert", "pbr.frag", 0); - add_shader("hdr.vert", "hdr.frag", 0); - add_shader("cubemap.vert", "cubemap.frag", 0); - add_shader("background.vert", "background.frag", 0); - - light_t lights[4] = { - {{-10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, - {{-5.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, - {{ 5.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, - {{ 10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, - }; - - /* textures */ - U32 hdr_texture = load_hdr_texture("../../data/textures/loigerwiesen.hdr"); - - /* framebuffers */ - U32 hdr_fbo, hdr_colorbuffer, hdr_rbo; - glGenFramebuffers(1, &hdr_fbo); - glGenTextures(1, &hdr_colorbuffer); - glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, state.width, state.height, 0, GL_RGBA, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glGenRenderbuffers(1, &hdr_rbo); - glBindRenderbuffer(GL_RENDERBUFFER, hdr_rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, state.width, state.height); - glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdr_colorbuffer, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdr_rbo); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - die("failed to create framebuffer"); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - U32 capture_fbo, capture_rbo; - glGenFramebuffers(1, &capture_fbo); - glGenRenderbuffers(1, &capture_rbo); - glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); - glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, capture_rbo); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - die("failed to create framebuffer"); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - U32 cubemap; - glGenTextures(1, &cubemap); - glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); - for (U32 i = 0; i < 6; i++) - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - MAT4 capture_projection = perspective(90.0f, 1.0f, 0.1f, 10.0f); - V3F capture_origin = {0}; - MAT4 capture_views[6] = { - look_at(capture_origin, v3f( 1.0f, 0.0f, 0.0f), v3f(0.0f, -1.0f, 0.0f)), - look_at(capture_origin, v3f(-1.0f, 0.0f, 0.0f), v3f(0.0f, -1.0f, 0.0f)), - look_at(capture_origin, v3f( 0.0f, 1.0f, 0.0f), v3f(0.0f, 0.0f, 1.0f)), - look_at(capture_origin, v3f( 0.0f, -1.0f, 0.0f), v3f(0.0f, 0.0f, -1.0f)), - look_at(capture_origin, v3f( 0.0f, 0.0f, 1.0f), v3f(0.0f, -1.0f, 0.0f)), - look_at(capture_origin, v3f( 0.0f, 0.0f, -1.0f), v3f(0.0f, -1.0f, 0.0f)), - }; - - glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); - U32 shader = find_shader("cubemap"); - if (!shader) die("waht"); - glUseProgram(shader); - shader_set_mat4fv(shader, "projection", capture_projection); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, hdr_texture); - - glViewport(0, 0, 512, 512); - for (U32 i = 0; i < 6; i++) { - shader_set_mat4fv(shader, "view", capture_views[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - mesh_draw(cube); - } - glUseProgram(0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glViewport(0, 0, state.width, state.height); - - F32 time = 0; - - while (!glfwWindowShouldClose(state.window)) { - handle_glfw_events(state.window, &state.input); - F32 dt = lock_framerate(60); - fps_info(dt, 10); - - /* update */ - update_camera_first_person(&state.camera, &state.input, dt, 2.0f); - F32 limit = 4.0f; - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) - lights[i].position.y = sinf(time + i) * limit; - time += dt; - - /* render */ - F32 ar = (F32)state.width / (F32)state.height; - MAT4 projection = camera_persp(state.camera, ar); - MAT4 view = get_view_matrix(&state.camera); - - glClearColor(0.16f, 0.16f, 0.16f, 1.0f); - - glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - shader = find_shader("pbr"); - if (!shader) die("wha"); - glUseProgram(shader); - shader_set_mat4fv(shader, "projection", projection); - shader_set_mat4fv(shader, "view", view); - shader_set_3fv(shader, "camera", state.camera.pos); - shader_set_3fv(shader, "color", v3f(0.04, 0.04, 0.04)); - shader_set_1f(shader, "ao", 1.0f); - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { - char str[512]; - snprintf(str, 512, "lights[%d].position", i); - shader_set_3fv(shader, str, lights[i].position); - snprintf(str, 512, "lights[%d].color", i); - shader_set_3fv(shader, str, lights[i].color); - } - S32 rows = 7; - S32 cols = 7; - F32 offset = 3.0f; - for (S32 row = 0; row < rows; row++) { - shader_set_1f(shader, "metallic", (F32)row / (F32)rows); - for (S32 col = 0; col < cols; col++) { - shader_set_1f(shader, "roughness", clamp(0.05f, (F32)col / (F32)cols, 1.0f)); - V3F pos = {(col - cols / 2.0f) * offset, (row - rows / 2.0f) * offset, 0.0f}; - MAT4 model = mat4_make_translate(pos); - shader_set_mat4fv(shader, "model", model); - mesh_draw(cube); - } - } - - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { - MAT4 model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); - model = mat4_translate(model, lights[i].position); - shader_set_mat4fv(shader, "model", model); - mesh_draw(cube); - } - - glUseProgram(0); - - shader = find_shader("background"); - glUseProgram(shader); - shader_set_mat4fv(shader, "projection", projection); - shader_set_mat4fv(shader, "view", view); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); - mesh_draw(cube); - glUseProgram(0); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - shader = find_shader("hdr"); - if (!shader) die("failed to find hdr shader!"); - glUseProgram(shader); - glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); - shader_set_mat4fv(shader, "model", mat4_identity()); - mesh_draw(quad); - glUseProgram(0); - - glfwSwapBuffers(state.window); - } - - return 0; -} diff --git a/pbr/2.1.1.ibl_irradiance_conversion/pbr.frag b/pbr/2.1.1.ibl_irradiance_conversion/pbr.frag deleted file mode 100644 index db9edea..0000000 --- a/pbr/2.1.1.ibl_irradiance_conversion/pbr.frag +++ /dev/null @@ -1,105 +0,0 @@ -#version 330 core - -in vert_t { - vec3 position; - vec3 normal; -} vert; - -out vec4 frag_color; - -uniform vec3 camera; - -uniform vec3 color; -uniform float metallic; -uniform float roughness; -uniform float ao; - -struct light_t { - vec3 position; - vec3 color; -}; - -const int light_count = 4; -uniform light_t lights[light_count]; - -const float PI = 3.14159265358; - -vec3 fresnel_shlick(float costheta, vec3 f0) -{ - return f0 + (1.0 - f0) * pow(1.0 - costheta, 5.0); -} - -float distribution_ggx(vec3 n, vec3 h, float roughness) -{ - float a = roughness * roughness; - float a2 = a * a; - float ndoth = max(dot(n, h), 0.0); - float ndoth2 = ndoth * ndoth; - - float num = a2; - float denom = (ndoth2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; - - return num / denom; -} - -float geometry_shlick_ggx(float ndotv, float roughness) -{ - float r = roughness + 1.0; - float k = r * r / 8.0; - - float num = ndotv; - float denom = ndotv * (1.0 - k) + k; - - return num / denom; -} - -float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) -{ - float ndotv = max(dot(n, v), 0.0); - float ndotl = max(dot(n, l), 0.0); - float ggx2 = geometry_shlick_ggx(ndotv, roughness); - float ggx1 = geometry_shlick_ggx(ndotl, roughness); - - return ggx1 * ggx2; -} - -void main(void) -{ - vec3 n = vert.normal; - vec3 v = normalize(camera - vert.position); - - vec3 lo = vec3(0.0); - for (int i = 0; i < light_count; i++) { - vec3 l = normalize(lights[i].position - vert.position); - vec3 h = normalize(v + l); - float ndotv = max(dot(n, v), 0.0); - float ndotl = max(dot(n, l), 0.0); - - float distance = length(lights[i].position - vert.position); - float attenuation = 1.0 / (distance * distance); - - vec3 radiance = lights[i].color * attenuation; - - vec3 f0 = vec3(0.04); - f0 = mix(f0, color, metallic); - vec3 f = fresnel_shlick(max(dot(h, v), 0.0), f0); - - float ndf = distribution_ggx(n, h, roughness); - float g = geometry_smith(n, v, l, roughness); - - vec3 numerator = ndf * g * f; - float denominator = 4.0 * ndotv * ndotl; - vec3 specular = numerator / max(denominator, 0.001); - - vec3 ks = f; - vec3 kd = vec3(1.0) - ks; - - kd *= 1.0 - metallic; - - lo += (kd * color / PI + specular) * radiance * ndotl; - } - - vec3 ambient = vec3(0.03) * color * ao; - frag_color = vec4(ambient + lo, 1.0); -} diff --git a/pbr/2.1.1.ibl_irradiance_conversion/pbr.vert b/pbr/2.1.1.ibl_irradiance_conversion/pbr.vert deleted file mode 100644 index e6e3800..0000000 --- a/pbr/2.1.1.ibl_irradiance_conversion/pbr.vert +++ /dev/null @@ -1,21 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; -layout(location = 1) in vec3 normal; - -out vert_t { - vec3 position; - vec3 normal; -} vert; - -uniform mat4 projection; -uniform mat4 view; -uniform mat4 model; - -void main(void) -{ - gl_Position = projection * view * model * vec4(position, 1.0); - - vert.position = vec3(model * vec4(position, 1.0)); - vert.normal = normalize(mat3(transpose(inverse(model))) * normal); -} diff --git a/pbr/2.1.2.ibl_irradiance/background.frag b/pbr/2.1.2.ibl_irradiance/background.frag deleted file mode 100644 index e3891eb..0000000 --- a/pbr/2.1.2.ibl_irradiance/background.frag +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 core - -in vert_t { - vec3 position; -} vert; - -out vec4 frag_color; - -uniform samplerCube cubemap; - -void main(void) -{ - vec3 color = texture(cubemap, vert.position).rgb; - color /= color + vec3(1.0); - color = pow(color, vec3(1.0 / 2.2)); - frag_color = vec4(color, 1.0); -} diff --git a/pbr/2.1.2.ibl_irradiance/background.vert b/pbr/2.1.2.ibl_irradiance/background.vert deleted file mode 100644 index 25b9778..0000000 --- a/pbr/2.1.2.ibl_irradiance/background.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; - -out vert_t { - vec3 position; -} vert; - -uniform mat4 projection; -uniform mat4 view; - -void main(void) -{ - vert.position = position; - - mat4 rotate_view = mat4(mat3(view)); - vec4 clip_position = projection * rotate_view * vec4(position, 1.0); - gl_Position = clip_position.xyww; -} diff --git a/pbr/2.1.2.ibl_irradiance/build.sh b/pbr/2.1.2.ibl_irradiance/build.sh deleted file mode 100755 index fdecd76..0000000 --- a/pbr/2.1.2.ibl_irradiance/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -. ../../config -TARGET='ibl_irradiance' -set -x -gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS diff --git a/pbr/2.1.2.ibl_irradiance/convolution.frag b/pbr/2.1.2.ibl_irradiance/convolution.frag deleted file mode 100644 index 69ce8af..0000000 --- a/pbr/2.1.2.ibl_irradiance/convolution.frag +++ /dev/null @@ -1,33 +0,0 @@ -#version 330 core - -in vert_t { - vec3 position; -} vert; - -out vec4 frag_color; - -uniform samplerCube cubemap; - -const float PI = 3.14159265359; - -void main(void) -{ - vec3 normal = normalize(vert.position); - vec3 up = vec3(0.0, 1.0, 0.0); - vec3 right = cross(up, normal); - up = cross(normal, right); - - vec3 irradiance = vec3(0.0); - float delta = 0.025; - int nsamples = 0; - for (float phi = 0.0; phi < 2.0 * PI; phi += delta) { - for (float theta = 0.0; theta < 0.5 * PI; theta += delta) { - vec3 tangent = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); - vec3 v = tangent.x * right + tangent.y * up + tangent.z * normal; - irradiance += texture(cubemap, v).rgb * cos(theta) * sin(theta); - nsamples++; - } - } - irradiance *= PI / nsamples; - frag_color = vec4(irradiance, 1.0); -} diff --git a/pbr/2.1.2.ibl_irradiance/convolution.vert b/pbr/2.1.2.ibl_irradiance/convolution.vert deleted file mode 100644 index 8f8862e..0000000 --- a/pbr/2.1.2.ibl_irradiance/convolution.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; - -out vert_t { - vec3 position; -} vert; - -uniform mat4 projection; -uniform mat4 view; - -void main(void) -{ - gl_Position = projection * view * vec4(position, 1.0); - - vert.position = position; -} diff --git a/pbr/2.1.2.ibl_irradiance/cubemap.frag b/pbr/2.1.2.ibl_irradiance/cubemap.frag deleted file mode 100644 index 349347a..0000000 --- a/pbr/2.1.2.ibl_irradiance/cubemap.frag +++ /dev/null @@ -1,25 +0,0 @@ -#version 330 core - -in vert_t { - vec3 position; -} vert; - -out vec4 frag_color; - -uniform sampler2D map; - -const vec2 inv_atan = vec2(0.1591, 0.3183); -vec2 sample_spherical_map(vec3 v) -{ - vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); - uv *= inv_atan; - uv += 0.5; - return uv; -} - -void main(void) -{ - vec2 uv = sample_spherical_map(normalize(vert.position)); - vec3 color = texture(map, uv).rgb; - frag_color = vec4(color, 1.0); -} diff --git a/pbr/2.1.2.ibl_irradiance/cubemap.vert b/pbr/2.1.2.ibl_irradiance/cubemap.vert deleted file mode 100644 index 8f8862e..0000000 --- a/pbr/2.1.2.ibl_irradiance/cubemap.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; - -out vert_t { - vec3 position; -} vert; - -uniform mat4 projection; -uniform mat4 view; - -void main(void) -{ - gl_Position = projection * view * vec4(position, 1.0); - - vert.position = position; -} diff --git a/pbr/2.1.2.ibl_irradiance/hdr.frag b/pbr/2.1.2.ibl_irradiance/hdr.frag deleted file mode 100644 index 01650ae..0000000 --- a/pbr/2.1.2.ibl_irradiance/hdr.frag +++ /dev/null @@ -1,18 +0,0 @@ -#version 330 core - -in vert_t { - vec2 tex_coords; -} vert; - -out vec4 frag_color; - -uniform sampler2D colorbuffer; - -void main(void) -{ - const float gamma = 2.2; - vec3 color = vec3(texture(colorbuffer, vert.tex_coords)); - color /= color + vec3(1.0); - color = pow(color, vec3(1.0 / gamma)); - frag_color = vec4(color, 1.0); -} diff --git a/pbr/2.1.2.ibl_irradiance/hdr.vert b/pbr/2.1.2.ibl_irradiance/hdr.vert deleted file mode 100644 index 1b953d7..0000000 --- a/pbr/2.1.2.ibl_irradiance/hdr.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; -layout(location = 2) in vec2 tex_coords; - -out vert_t { - vec2 tex_coords; -} vert; - -uniform mat4 model; - -void main(void) -{ - gl_Position = model * vec4(position, 1.0); - - vert.tex_coords = tex_coords; -} diff --git a/pbr/2.1.2.ibl_irradiance/ibl_irradiance b/pbr/2.1.2.ibl_irradiance/ibl_irradiance deleted file mode 100755 index 4561ae2..0000000 Binary files a/pbr/2.1.2.ibl_irradiance/ibl_irradiance and /dev/null differ diff --git a/pbr/2.1.2.ibl_irradiance/ibl_irradiance.c b/pbr/2.1.2.ibl_irradiance/ibl_irradiance.c deleted file mode 100644 index e6f1390..0000000 --- a/pbr/2.1.2.ibl_irradiance/ibl_irradiance.c +++ /dev/null @@ -1,230 +0,0 @@ -#include "GL/glew.h" -#include "GLFW/glfw3.h" -#include "common.h" - -int main(void) -{ - state_t state = init_state(1600, 800); - - init_glfw(&state); - init_gl(); - glDepthFunc(GL_LEQUAL); - - /* meshes */ - Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj"); - Mesh *sphere = mesh_load_obj(state.arena, "../../data/models/sphere.obj"); - Mesh *quad = mesh_gen_quad(state.arena); - - /* shaders */ - add_shader("pbr.vert", "pbr.frag", 0); - add_shader("hdr.vert", "hdr.frag", 0); - add_shader("cubemap.vert", "cubemap.frag", 0); - add_shader("background.vert", "background.frag", 0); - add_shader("convolution.vert", "convolution.frag", 0); - - light_t lights[4] = { - {{-10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, - {{-5.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, - {{ 5.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, - {{ 10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, - }; - - /* textures */ - U32 hdr_texture = load_hdr_texture("../../data/textures/loigerwiesen.hdr");; - - /* framebuffers */ - U32 hdr_fbo, hdr_colorbuffer, hdr_rbo; - glGenFramebuffers(1, &hdr_fbo); - glGenTextures(1, &hdr_colorbuffer); - glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, state.width, state.height, 0, GL_RGBA, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glGenRenderbuffers(1, &hdr_rbo); - glBindRenderbuffer(GL_RENDERBUFFER, hdr_rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, state.width, state.height); - glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdr_colorbuffer, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdr_rbo); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - die("failed to create framebuffer"); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - U32 capture_fbo, capture_rbo; - glGenFramebuffers(1, &capture_fbo); - glGenRenderbuffers(1, &capture_rbo); - glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); - glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, capture_rbo); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - die("failed to create framebuffer"); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - U32 cubemap; - glGenTextures(1, &cubemap); - glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); - for (U32 i = 0; i < 6; i++) - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - MAT4 capture_projection = perspective(90.0f, 1.0f, 0.1f, 10.0f); - V3F capture_origin = {0}; - MAT4 capture_views[6] = { - look_at(capture_origin, v3f( 1.0f, 0.0f, 0.0f), v3f(0.0f, -1.0f, 0.0f)), - look_at(capture_origin, v3f(-1.0f, 0.0f, 0.0f), v3f(0.0f, -1.0f, 0.0f)), - look_at(capture_origin, v3f( 0.0f, 1.0f, 0.0f), v3f(0.0f, 0.0f, 1.0f)), - look_at(capture_origin, v3f( 0.0f, -1.0f, 0.0f), v3f(0.0f, 0.0f, -1.0f)), - look_at(capture_origin, v3f( 0.0f, 0.0f, 1.0f), v3f(0.0f, -1.0f, 0.0f)), - look_at(capture_origin, v3f( 0.0f, 0.0f, -1.0f), v3f(0.0f, -1.0f, 0.0f)), - }; - - glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); - U32 shader = find_shader("cubemap"); - if (!shader) die("waht"); - glUseProgram(shader); - shader_set_mat4fv(shader, "projection", capture_projection); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, hdr_texture); - - glViewport(0, 0, 512, 512); - for (U32 i = 0; i < 6; i++) { - shader_set_mat4fv(shader, "view", capture_views[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - mesh_draw(cube); - } - glUseProgram(0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - U32 irradiance_map; - glGenTextures(1, &irradiance_map); - glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance_map); - for (U32 i = 0; i < 6; i++) - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 32, 32, 0, GL_RGB, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); - - glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); - glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); - shader = find_shader("convolution"); - glUseProgram(shader); - shader_set_mat4fv(shader, "projection", capture_projection); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); - glViewport(0, 0, 32, 32); - for (U32 i = 0; i < 6; i++) { - shader_set_mat4fv(shader, "view", capture_views[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradiance_map, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - mesh_draw(cube); - } - glUseProgram(0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glViewport(0, 0, state.width, state.height); - - F32 time = 0; - - while (!glfwWindowShouldClose(state.window)) { - handle_glfw_events(state.window, &state.input); - F32 dt = lock_framerate(60); - fps_info(dt, 10); - - /* update */ - update_camera_first_person(&state.camera, &state.input, dt, 2.0f); - F32 limit = 4.0f; - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) - lights[i].position.y = sinf(time + i) * limit; - time += dt; - - /* render */ - F32 ar = (F32)state.width / (F32)state.height; - MAT4 projection = camera_persp(state.camera, ar); - MAT4 view = get_view_matrix(&state.camera); - - glClearColor(0.16f, 0.16f, 0.16f, 1.0f); - - glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - shader = find_shader("pbr"); - glUseProgram(shader); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance_map); - shader_set_mat4fv(shader, "projection", projection); - shader_set_mat4fv(shader, "view", view); - shader_set_3fv(shader, "camera", state.camera.pos); - shader_set_3fv(shader, "color", v3f(0.04, 0.04, 0.04)); - shader_set_1f(shader, "ao", 1.0f); - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { - char str[512]; - snprintf(str, 512, "lights[%d].position", i); - shader_set_3fv(shader, str, lights[i].position); - snprintf(str, 512, "lights[%d].color", i); - shader_set_3fv(shader, str, lights[i].color); - } - S32 rows = 7; - S32 cols = 7; - F32 offset = 3.0f; - for (S32 row = 0; row < rows; row++) { - shader_set_1f(shader, "metallic", (F32)row / (F32)rows); - for (S32 col = 0; col < cols; col++) { - shader_set_1f(shader, "roughness", clamp(0.05f, (F32)col / (F32)cols, 1.0f)); - V3F pos = {(col - cols / 2.0f) * offset, (row - rows / 2.0f) * offset, 0.0f}; - MAT4 model = mat4_make_translate(pos); - shader_set_mat4fv(shader, "model", model); - mesh_draw(sphere); - } - } - - for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { - MAT4 model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); - model = mat4_translate(model, lights[i].position); - shader_set_mat4fv(shader, "model", model); - mesh_draw(sphere); - } - - glUseProgram(0); - - shader = find_shader("background"); - glUseProgram(shader); - shader_set_mat4fv(shader, "projection", projection); - shader_set_mat4fv(shader, "view", view); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance_map); - mesh_draw(cube); - glUseProgram(0); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - shader = find_shader("hdr"); - if (!shader) die("failed to find hdr shader!"); - glUseProgram(shader); - glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); - shader_set_mat4fv(shader, "model", mat4_identity()); - mesh_draw(quad); - glUseProgram(0); - - glfwSwapBuffers(state.window); - } - - return 0; -} diff --git a/pbr/2.1.2.ibl_irradiance/pbr.frag b/pbr/2.1.2.ibl_irradiance/pbr.frag deleted file mode 100644 index 88cf01d..0000000 --- a/pbr/2.1.2.ibl_irradiance/pbr.frag +++ /dev/null @@ -1,114 +0,0 @@ -#version 330 core - -in vert_t { - vec3 position; - vec3 normal; -} vert; - -out vec4 frag_color; - -uniform vec3 camera; - -uniform vec3 color; -uniform float metallic; -uniform float roughness; -uniform float ao; - -uniform samplerCube irradiance_map; - -struct light_t { - vec3 position; - vec3 color; -}; - -const int light_count = 4; -uniform light_t lights[light_count]; - -const float PI = 3.14159265358; - -vec3 fresnel_shlick(float costheta, vec3 f0) -{ - return f0 + (1.0 - f0) * pow(1.0 - costheta, 5.0); -} - -float distribution_ggx(vec3 n, vec3 h, float roughness) -{ - float a = roughness * roughness; - float a2 = a * a; - float ndoth = max(dot(n, h), 0.0); - float ndoth2 = ndoth * ndoth; - - float num = a2; - float denom = (ndoth2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; - - return num / denom; -} - -float geometry_shlick_ggx(float ndotv, float roughness) -{ - float r = roughness + 1.0; - float k = r * r / 8.0; - - float num = ndotv; - float denom = ndotv * (1.0 - k) + k; - - return num / denom; -} - -float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) -{ - float ndotv = max(dot(n, v), 0.0); - float ndotl = max(dot(n, l), 0.0); - float ggx2 = geometry_shlick_ggx(ndotv, roughness); - float ggx1 = geometry_shlick_ggx(ndotl, roughness); - - return ggx1 * ggx2; -} - -void main(void) -{ - vec3 n = vert.normal; - vec3 v = normalize(camera - vert.position); - - vec3 f0 = vec3(0.04); - f0 = mix(f0, color, metallic); - - vec3 lo = vec3(0.0); - for (int i = 0; i < light_count; i++) { - vec3 l = normalize(lights[i].position - vert.position); - vec3 h = normalize(v + l); - float ndotv = max(dot(n, v), 0.0); - float ndotl = max(dot(n, l), 0.0); - - float distance = length(lights[i].position - vert.position); - float attenuation = 1.0 / (distance * distance); - - vec3 radiance = lights[i].color * attenuation; - - vec3 f = fresnel_shlick(max(dot(h, v), 0.0), f0); - - float ndf = distribution_ggx(n, h, roughness); - float g = geometry_smith(n, v, l, roughness); - - vec3 numerator = ndf * g * f; - float denominator = 4.0 * ndotv * ndotl; - vec3 specular = numerator / max(denominator, 0.001); - - vec3 ks = f; - vec3 kd = vec3(1.0) - ks; - - kd *= 1.0 - metallic; - - lo += (kd * color / PI + specular) * radiance * ndotl; - } - - vec3 ks = fresnel_shlick(max(dot(n, v), 0.0), f0); - vec3 kd = 1.0 - ks; - kd *= 1.0 - metallic; - vec3 irradiance = texture(irradiance_map, n).rgb; - vec3 diffuse = irradiance * color; - vec3 ambient = kd * diffuse * ao; - - frag_color = vec4(ambient + lo, 1.0); -} diff --git a/pbr/2.1.2.ibl_irradiance/pbr.vert b/pbr/2.1.2.ibl_irradiance/pbr.vert deleted file mode 100644 index e6e3800..0000000 --- a/pbr/2.1.2.ibl_irradiance/pbr.vert +++ /dev/null @@ -1,21 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 position; -layout(location = 1) in vec3 normal; - -out vert_t { - vec3 position; - vec3 normal; -} vert; - -uniform mat4 projection; -uniform mat4 view; -uniform mat4 model; - -void main(void) -{ - gl_Position = projection * view * model * vec4(position, 1.0); - - vert.position = vec3(model * vec4(position, 1.0)); - vert.normal = normalize(mat3(transpose(inverse(model))) * normal); -} diff --git a/pbr/ibl_irradiance/background.frag b/pbr/ibl_irradiance/background.frag new file mode 100644 index 0000000..e3891eb --- /dev/null +++ b/pbr/ibl_irradiance/background.frag @@ -0,0 +1,17 @@ +#version 330 core + +in vert_t { + vec3 position; +} vert; + +out vec4 frag_color; + +uniform samplerCube cubemap; + +void main(void) +{ + vec3 color = texture(cubemap, vert.position).rgb; + color /= color + vec3(1.0); + color = pow(color, vec3(1.0 / 2.2)); + frag_color = vec4(color, 1.0); +} diff --git a/pbr/ibl_irradiance/background.vert b/pbr/ibl_irradiance/background.vert new file mode 100644 index 0000000..25b9778 --- /dev/null +++ b/pbr/ibl_irradiance/background.vert @@ -0,0 +1,19 @@ +#version 330 core + +layout(location = 0) in vec3 position; + +out vert_t { + vec3 position; +} vert; + +uniform mat4 projection; +uniform mat4 view; + +void main(void) +{ + vert.position = position; + + mat4 rotate_view = mat4(mat3(view)); + vec4 clip_position = projection * rotate_view * vec4(position, 1.0); + gl_Position = clip_position.xyww; +} diff --git a/pbr/ibl_irradiance/build.sh b/pbr/ibl_irradiance/build.sh new file mode 100755 index 0000000..fdecd76 --- /dev/null +++ b/pbr/ibl_irradiance/build.sh @@ -0,0 +1,5 @@ +#!/bin/sh +. ../../config +TARGET='ibl_irradiance' +set -x +gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS diff --git a/pbr/ibl_irradiance/convolution.frag b/pbr/ibl_irradiance/convolution.frag new file mode 100644 index 0000000..69ce8af --- /dev/null +++ b/pbr/ibl_irradiance/convolution.frag @@ -0,0 +1,33 @@ +#version 330 core + +in vert_t { + vec3 position; +} vert; + +out vec4 frag_color; + +uniform samplerCube cubemap; + +const float PI = 3.14159265359; + +void main(void) +{ + vec3 normal = normalize(vert.position); + vec3 up = vec3(0.0, 1.0, 0.0); + vec3 right = cross(up, normal); + up = cross(normal, right); + + vec3 irradiance = vec3(0.0); + float delta = 0.025; + int nsamples = 0; + for (float phi = 0.0; phi < 2.0 * PI; phi += delta) { + for (float theta = 0.0; theta < 0.5 * PI; theta += delta) { + vec3 tangent = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); + vec3 v = tangent.x * right + tangent.y * up + tangent.z * normal; + irradiance += texture(cubemap, v).rgb * cos(theta) * sin(theta); + nsamples++; + } + } + irradiance *= PI / nsamples; + frag_color = vec4(irradiance, 1.0); +} diff --git a/pbr/ibl_irradiance/convolution.vert b/pbr/ibl_irradiance/convolution.vert new file mode 100644 index 0000000..8f8862e --- /dev/null +++ b/pbr/ibl_irradiance/convolution.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; + +out vert_t { + vec3 position; +} vert; + +uniform mat4 projection; +uniform mat4 view; + +void main(void) +{ + gl_Position = projection * view * vec4(position, 1.0); + + vert.position = position; +} diff --git a/pbr/ibl_irradiance/cubemap.frag b/pbr/ibl_irradiance/cubemap.frag new file mode 100644 index 0000000..349347a --- /dev/null +++ b/pbr/ibl_irradiance/cubemap.frag @@ -0,0 +1,25 @@ +#version 330 core + +in vert_t { + vec3 position; +} vert; + +out vec4 frag_color; + +uniform sampler2D map; + +const vec2 inv_atan = vec2(0.1591, 0.3183); +vec2 sample_spherical_map(vec3 v) +{ + vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); + uv *= inv_atan; + uv += 0.5; + return uv; +} + +void main(void) +{ + vec2 uv = sample_spherical_map(normalize(vert.position)); + vec3 color = texture(map, uv).rgb; + frag_color = vec4(color, 1.0); +} diff --git a/pbr/ibl_irradiance/cubemap.vert b/pbr/ibl_irradiance/cubemap.vert new file mode 100644 index 0000000..8f8862e --- /dev/null +++ b/pbr/ibl_irradiance/cubemap.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; + +out vert_t { + vec3 position; +} vert; + +uniform mat4 projection; +uniform mat4 view; + +void main(void) +{ + gl_Position = projection * view * vec4(position, 1.0); + + vert.position = position; +} diff --git a/pbr/ibl_irradiance/hdr.frag b/pbr/ibl_irradiance/hdr.frag new file mode 100644 index 0000000..01650ae --- /dev/null +++ b/pbr/ibl_irradiance/hdr.frag @@ -0,0 +1,18 @@ +#version 330 core + +in vert_t { + vec2 tex_coords; +} vert; + +out vec4 frag_color; + +uniform sampler2D colorbuffer; + +void main(void) +{ + const float gamma = 2.2; + vec3 color = vec3(texture(colorbuffer, vert.tex_coords)); + color /= color + vec3(1.0); + color = pow(color, vec3(1.0 / gamma)); + frag_color = vec4(color, 1.0); +} diff --git a/pbr/ibl_irradiance/hdr.vert b/pbr/ibl_irradiance/hdr.vert new file mode 100644 index 0000000..1b953d7 --- /dev/null +++ b/pbr/ibl_irradiance/hdr.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 2) in vec2 tex_coords; + +out vert_t { + vec2 tex_coords; +} vert; + +uniform mat4 model; + +void main(void) +{ + gl_Position = model * vec4(position, 1.0); + + vert.tex_coords = tex_coords; +} diff --git a/pbr/ibl_irradiance/ibl_irradiance b/pbr/ibl_irradiance/ibl_irradiance new file mode 100755 index 0000000..aee47cb Binary files /dev/null and b/pbr/ibl_irradiance/ibl_irradiance differ diff --git a/pbr/ibl_irradiance/ibl_irradiance.c b/pbr/ibl_irradiance/ibl_irradiance.c new file mode 100644 index 0000000..921c60d --- /dev/null +++ b/pbr/ibl_irradiance/ibl_irradiance.c @@ -0,0 +1,228 @@ +#include "GL/glew.h" +#include "GLFW/glfw3.h" +#include "common.h" + +int main(void) +{ + state_t state = init_state(1600, 800); + + init_glfw(&state); + init_gl(); + glDepthFunc(GL_LEQUAL); + + /* meshes */ + Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj"); + Mesh *sphere = mesh_load_obj(state.arena, "../../data/models/sphere.obj"); + Mesh *quad = mesh_gen_quad(state.arena); + + /* shaders */ + add_shader("pbr.vert", "pbr.frag", 0); + add_shader("hdr.vert", "hdr.frag", 0); + add_shader("cubemap.vert", "cubemap.frag", 0); + add_shader("background.vert", "background.frag", 0); + add_shader("convolution.vert", "convolution.frag", 0); + + light_t lights[4] = { + {{-10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + {{-5.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + {{ 5.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + {{ 10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + }; + + /* textures */ + U32 hdr_texture = load_hdr_texture("../../data/textures/loigerwiesen.hdr");; + + /* framebuffers */ + U32 hdr_fbo, hdr_colorbuffer, hdr_rbo; + glGenFramebuffers(1, &hdr_fbo); + glGenTextures(1, &hdr_colorbuffer); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, state.width, state.height, 0, GL_RGBA, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glGenRenderbuffers(1, &hdr_rbo); + glBindRenderbuffer(GL_RENDERBUFFER, hdr_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, state.width, state.height); + glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdr_colorbuffer, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdr_rbo); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + die("failed to create framebuffer"); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + U32 capture_fbo, capture_rbo; + glGenFramebuffers(1, &capture_fbo); + glGenRenderbuffers(1, &capture_rbo); + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, capture_rbo); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + die("failed to create framebuffer"); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + U32 cubemap; + glGenTextures(1, &cubemap); + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); + for (U32 i = 0; i < 6; i++) + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + MAT4 capture_projection = perspective(90.0f, 1.0f, 0.1f, 10.0f); + V3F capture_origin = {0}; + MAT4 capture_views[6] = { + look_at(capture_origin, v3f( 1.0f, 0.0f, 0.0f), v3f(0.0f, -1.0f, 0.0f)), + look_at(capture_origin, v3f(-1.0f, 0.0f, 0.0f), v3f(0.0f, -1.0f, 0.0f)), + look_at(capture_origin, v3f( 0.0f, 1.0f, 0.0f), v3f(0.0f, 0.0f, 1.0f)), + look_at(capture_origin, v3f( 0.0f, -1.0f, 0.0f), v3f(0.0f, 0.0f, -1.0f)), + look_at(capture_origin, v3f( 0.0f, 0.0f, 1.0f), v3f(0.0f, -1.0f, 0.0f)), + look_at(capture_origin, v3f( 0.0f, 0.0f, -1.0f), v3f(0.0f, -1.0f, 0.0f)), + }; + + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + U32 shader = find_shader("cubemap"); + if (!shader) die("waht"); + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", capture_projection); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, hdr_texture); + + glViewport(0, 0, 512, 512); + for (U32 i = 0; i < 6; i++) { + shader_set_mat4fv(shader, "view", capture_views[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + mesh_draw(cube); + } + glUseProgram(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + U32 irradiance_map; + glGenTextures(1, &irradiance_map); + glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance_map); + for (U32 i = 0; i < 6; i++) + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 32, 32, 0, GL_RGB, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + shader = find_shader("convolution"); + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", capture_projection); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); + glViewport(0, 0, 32, 32); + for (U32 i = 0; i < 6; i++) { + shader_set_mat4fv(shader, "view", capture_views[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradiance_map, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + mesh_draw(cube); + } + glUseProgram(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glViewport(0, 0, state.width, state.height); + + F32 time = 0; + + while (!glfwWindowShouldClose(state.window)) { + handle_glfw_events(state.window, &state.input); + F32 dt = lock_framerate(60); + fps_info(dt, 10); + + /* update */ + update_camera_first_person(&state.camera, &state.input, dt, 2.0f); + F32 limit = 4.0f; + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) + lights[i].position.y = sinf(time + i) * limit; + time += dt; + + /* render */ + F32 ar = (F32)state.width / (F32)state.height; + MAT4 projection = camera_persp(state.camera, ar); + MAT4 view = get_view_matrix(&state.camera); + + glClearColor(0.16f, 0.16f, 0.16f, 1.0f); + + glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + shader = find_shader("pbr"); + glUseProgram(shader); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance_map); + shader_set_mat4fv(shader, "projection", projection); + shader_set_mat4fv(shader, "view", view); + shader_set_3fv(shader, "camera", state.camera.pos); + shader_set_3fv(shader, "color", v3f(0.04, 0.04, 0.04)); + shader_set_1f(shader, "ao", 1.0f); + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { + char str[512]; + snprintf(str, 512, "lights[%d].position", i); + shader_set_3fv(shader, str, lights[i].position); + snprintf(str, 512, "lights[%d].color", i); + shader_set_3fv(shader, str, lights[i].color); + } + S32 rows = 7; + S32 cols = 7; + F32 offset = 3.0f; + for (S32 row = 0; row < rows; row++) { + shader_set_1f(shader, "metallic", (F32)row / (F32)rows); + for (S32 col = 0; col < cols; col++) { + shader_set_1f(shader, "roughness", clamp(0.05f, (F32)col / (F32)cols, 1.0f)); + V3F pos = {(col - cols / 2.0f) * offset, (row - rows / 2.0f) * offset, 0.0f}; + MAT4 model = mat4_make_translate(pos); + shader_set_mat4fv(shader, "model", model); + mesh_draw(sphere); + } + } + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { + MAT4 model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); + model = mat4_translate(model, lights[i].position); + shader_set_mat4fv(shader, "model", model); + mesh_draw(sphere); + } + glUseProgram(0); + + shader = find_shader("background"); + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", projection); + shader_set_mat4fv(shader, "view", view); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); + mesh_draw(cube); + glUseProgram(0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + shader = find_shader("hdr"); + if (!shader) die("!"); + glUseProgram(shader); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + shader_set_mat4fv(shader, "model", mat4_identity()); + mesh_draw(quad); + glUseProgram(0); + + glfwSwapBuffers(state.window); + } + + return 0; +} diff --git a/pbr/ibl_irradiance/pbr.frag b/pbr/ibl_irradiance/pbr.frag new file mode 100644 index 0000000..88cf01d --- /dev/null +++ b/pbr/ibl_irradiance/pbr.frag @@ -0,0 +1,114 @@ +#version 330 core + +in vert_t { + vec3 position; + vec3 normal; +} vert; + +out vec4 frag_color; + +uniform vec3 camera; + +uniform vec3 color; +uniform float metallic; +uniform float roughness; +uniform float ao; + +uniform samplerCube irradiance_map; + +struct light_t { + vec3 position; + vec3 color; +}; + +const int light_count = 4; +uniform light_t lights[light_count]; + +const float PI = 3.14159265358; + +vec3 fresnel_shlick(float costheta, vec3 f0) +{ + return f0 + (1.0 - f0) * pow(1.0 - costheta, 5.0); +} + +float distribution_ggx(vec3 n, vec3 h, float roughness) +{ + float a = roughness * roughness; + float a2 = a * a; + float ndoth = max(dot(n, h), 0.0); + float ndoth2 = ndoth * ndoth; + + float num = a2; + float denom = (ndoth2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return num / denom; +} + +float geometry_shlick_ggx(float ndotv, float roughness) +{ + float r = roughness + 1.0; + float k = r * r / 8.0; + + float num = ndotv; + float denom = ndotv * (1.0 - k) + k; + + return num / denom; +} + +float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) +{ + float ndotv = max(dot(n, v), 0.0); + float ndotl = max(dot(n, l), 0.0); + float ggx2 = geometry_shlick_ggx(ndotv, roughness); + float ggx1 = geometry_shlick_ggx(ndotl, roughness); + + return ggx1 * ggx2; +} + +void main(void) +{ + vec3 n = vert.normal; + vec3 v = normalize(camera - vert.position); + + vec3 f0 = vec3(0.04); + f0 = mix(f0, color, metallic); + + vec3 lo = vec3(0.0); + for (int i = 0; i < light_count; i++) { + vec3 l = normalize(lights[i].position - vert.position); + vec3 h = normalize(v + l); + float ndotv = max(dot(n, v), 0.0); + float ndotl = max(dot(n, l), 0.0); + + float distance = length(lights[i].position - vert.position); + float attenuation = 1.0 / (distance * distance); + + vec3 radiance = lights[i].color * attenuation; + + vec3 f = fresnel_shlick(max(dot(h, v), 0.0), f0); + + float ndf = distribution_ggx(n, h, roughness); + float g = geometry_smith(n, v, l, roughness); + + vec3 numerator = ndf * g * f; + float denominator = 4.0 * ndotv * ndotl; + vec3 specular = numerator / max(denominator, 0.001); + + vec3 ks = f; + vec3 kd = vec3(1.0) - ks; + + kd *= 1.0 - metallic; + + lo += (kd * color / PI + specular) * radiance * ndotl; + } + + vec3 ks = fresnel_shlick(max(dot(n, v), 0.0), f0); + vec3 kd = 1.0 - ks; + kd *= 1.0 - metallic; + vec3 irradiance = texture(irradiance_map, n).rgb; + vec3 diffuse = irradiance * color; + vec3 ambient = kd * diffuse * ao; + + frag_color = vec4(ambient + lo, 1.0); +} diff --git a/pbr/ibl_irradiance/pbr.vert b/pbr/ibl_irradiance/pbr.vert new file mode 100644 index 0000000..e6e3800 --- /dev/null +++ b/pbr/ibl_irradiance/pbr.vert @@ -0,0 +1,21 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 1) in vec3 normal; + +out vert_t { + vec3 position; + vec3 normal; +} vert; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main(void) +{ + gl_Position = projection * view * model * vec4(position, 1.0); + + vert.position = vec3(model * vec4(position, 1.0)); + vert.normal = normalize(mat3(transpose(inverse(model))) * normal); +} diff --git a/pbr/ibl_irradiance_conversion/background.frag b/pbr/ibl_irradiance_conversion/background.frag new file mode 100644 index 0000000..e3891eb --- /dev/null +++ b/pbr/ibl_irradiance_conversion/background.frag @@ -0,0 +1,17 @@ +#version 330 core + +in vert_t { + vec3 position; +} vert; + +out vec4 frag_color; + +uniform samplerCube cubemap; + +void main(void) +{ + vec3 color = texture(cubemap, vert.position).rgb; + color /= color + vec3(1.0); + color = pow(color, vec3(1.0 / 2.2)); + frag_color = vec4(color, 1.0); +} diff --git a/pbr/ibl_irradiance_conversion/background.vert b/pbr/ibl_irradiance_conversion/background.vert new file mode 100644 index 0000000..25b9778 --- /dev/null +++ b/pbr/ibl_irradiance_conversion/background.vert @@ -0,0 +1,19 @@ +#version 330 core + +layout(location = 0) in vec3 position; + +out vert_t { + vec3 position; +} vert; + +uniform mat4 projection; +uniform mat4 view; + +void main(void) +{ + vert.position = position; + + mat4 rotate_view = mat4(mat3(view)); + vec4 clip_position = projection * rotate_view * vec4(position, 1.0); + gl_Position = clip_position.xyww; +} diff --git a/pbr/ibl_irradiance_conversion/build.sh b/pbr/ibl_irradiance_conversion/build.sh new file mode 100755 index 0000000..834030a --- /dev/null +++ b/pbr/ibl_irradiance_conversion/build.sh @@ -0,0 +1,5 @@ +#!/bin/sh +. ../../config +TARGET='ibl_irradiance_conversion' +set -x +gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS diff --git a/pbr/ibl_irradiance_conversion/cubemap.frag b/pbr/ibl_irradiance_conversion/cubemap.frag new file mode 100644 index 0000000..349347a --- /dev/null +++ b/pbr/ibl_irradiance_conversion/cubemap.frag @@ -0,0 +1,25 @@ +#version 330 core + +in vert_t { + vec3 position; +} vert; + +out vec4 frag_color; + +uniform sampler2D map; + +const vec2 inv_atan = vec2(0.1591, 0.3183); +vec2 sample_spherical_map(vec3 v) +{ + vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); + uv *= inv_atan; + uv += 0.5; + return uv; +} + +void main(void) +{ + vec2 uv = sample_spherical_map(normalize(vert.position)); + vec3 color = texture(map, uv).rgb; + frag_color = vec4(color, 1.0); +} diff --git a/pbr/ibl_irradiance_conversion/cubemap.vert b/pbr/ibl_irradiance_conversion/cubemap.vert new file mode 100644 index 0000000..8f8862e --- /dev/null +++ b/pbr/ibl_irradiance_conversion/cubemap.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; + +out vert_t { + vec3 position; +} vert; + +uniform mat4 projection; +uniform mat4 view; + +void main(void) +{ + gl_Position = projection * view * vec4(position, 1.0); + + vert.position = position; +} diff --git a/pbr/ibl_irradiance_conversion/hdr.frag b/pbr/ibl_irradiance_conversion/hdr.frag new file mode 100644 index 0000000..01650ae --- /dev/null +++ b/pbr/ibl_irradiance_conversion/hdr.frag @@ -0,0 +1,18 @@ +#version 330 core + +in vert_t { + vec2 tex_coords; +} vert; + +out vec4 frag_color; + +uniform sampler2D colorbuffer; + +void main(void) +{ + const float gamma = 2.2; + vec3 color = vec3(texture(colorbuffer, vert.tex_coords)); + color /= color + vec3(1.0); + color = pow(color, vec3(1.0 / gamma)); + frag_color = vec4(color, 1.0); +} diff --git a/pbr/ibl_irradiance_conversion/hdr.vert b/pbr/ibl_irradiance_conversion/hdr.vert new file mode 100644 index 0000000..1b953d7 --- /dev/null +++ b/pbr/ibl_irradiance_conversion/hdr.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 2) in vec2 tex_coords; + +out vert_t { + vec2 tex_coords; +} vert; + +uniform mat4 model; + +void main(void) +{ + gl_Position = model * vec4(position, 1.0); + + vert.tex_coords = tex_coords; +} diff --git a/pbr/ibl_irradiance_conversion/ibl_irradiance_conversion b/pbr/ibl_irradiance_conversion/ibl_irradiance_conversion new file mode 100755 index 0000000..cc43012 Binary files /dev/null and b/pbr/ibl_irradiance_conversion/ibl_irradiance_conversion differ diff --git a/pbr/ibl_irradiance_conversion/ibl_irradiance_conversion.c b/pbr/ibl_irradiance_conversion/ibl_irradiance_conversion.c new file mode 100644 index 0000000..0ffbe7c --- /dev/null +++ b/pbr/ibl_irradiance_conversion/ibl_irradiance_conversion.c @@ -0,0 +1,193 @@ +#include "GL/glew.h" +#include "GLFW/glfw3.h" +#include "common.h" + +int main(void) +{ + state_t state = init_state(1600, 800); + + init_glfw(&state); + init_gl(); + glDepthFunc(GL_LEQUAL); + + /* meshes */ + Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj"); + Mesh *quad = mesh_gen_quad(state.arena); + + /* shaders */ + add_shader("pbr.vert", "pbr.frag", 0); + add_shader("hdr.vert", "hdr.frag", 0); + add_shader("cubemap.vert", "cubemap.frag", 0); + add_shader("background.vert", "background.frag", 0); + + light_t lights[4] = { + {{-10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + {{-5.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + {{ 5.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + {{ 10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + }; + + /* textures */ + U32 hdr_texture = load_hdr_texture("../../data/textures/loigerwiesen.hdr"); + + /* framebuffers */ + U32 hdr_fbo, hdr_colorbuffer, hdr_rbo; + glGenFramebuffers(1, &hdr_fbo); + glGenTextures(1, &hdr_colorbuffer); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, state.width, state.height, 0, GL_RGBA, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glGenRenderbuffers(1, &hdr_rbo); + glBindRenderbuffer(GL_RENDERBUFFER, hdr_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, state.width, state.height); + glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdr_colorbuffer, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdr_rbo); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + die("failed to create framebuffer"); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + U32 capture_fbo, capture_rbo; + glGenFramebuffers(1, &capture_fbo); + glGenRenderbuffers(1, &capture_rbo); + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, capture_rbo); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + die("failed to create framebuffer"); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + U32 cubemap; + glGenTextures(1, &cubemap); + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); + for (U32 i = 0; i < 6; i++) + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + MAT4 capture_projection = perspective(90.0f, 1.0f, 0.1f, 10.0f); + V3F capture_origin = {0}; + MAT4 capture_views[6] = { + look_at(capture_origin, v3f( 1.0f, 0.0f, 0.0f), v3f(0.0f, -1.0f, 0.0f)), + look_at(capture_origin, v3f(-1.0f, 0.0f, 0.0f), v3f(0.0f, -1.0f, 0.0f)), + look_at(capture_origin, v3f( 0.0f, 1.0f, 0.0f), v3f(0.0f, 0.0f, 1.0f)), + look_at(capture_origin, v3f( 0.0f, -1.0f, 0.0f), v3f(0.0f, 0.0f, -1.0f)), + look_at(capture_origin, v3f( 0.0f, 0.0f, 1.0f), v3f(0.0f, -1.0f, 0.0f)), + look_at(capture_origin, v3f( 0.0f, 0.0f, -1.0f), v3f(0.0f, -1.0f, 0.0f)), + }; + + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + U32 shader = find_shader("cubemap"); + if (!shader) die("waht"); + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", capture_projection); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, hdr_texture); + + glViewport(0, 0, 512, 512); + for (U32 i = 0; i < 6; i++) { + shader_set_mat4fv(shader, "view", capture_views[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + mesh_draw(cube); + } + glUseProgram(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glViewport(0, 0, state.width, state.height); + + F32 time = 0; + + while (!glfwWindowShouldClose(state.window)) { + handle_glfw_events(state.window, &state.input); + F32 dt = lock_framerate(60); + fps_info(dt, 10); + + /* update */ + update_camera_first_person(&state.camera, &state.input, dt, 2.0f); + F32 limit = 4.0f; + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) + lights[i].position.y = sinf(time + i) * limit; + time += dt; + + /* render */ + F32 ar = (F32)state.width / (F32)state.height; + MAT4 projection = camera_persp(state.camera, ar); + MAT4 view = get_view_matrix(&state.camera); + + glClearColor(0.16f, 0.16f, 0.16f, 1.0f); + + glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + shader = find_shader("pbr"); + if (!shader) die("wha"); + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", projection); + shader_set_mat4fv(shader, "view", view); + shader_set_3fv(shader, "camera", state.camera.pos); + shader_set_3fv(shader, "color", v3f(0.04, 0.04, 0.04)); + shader_set_1f(shader, "ao", 1.0f); + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { + char str[512]; + snprintf(str, 512, "lights[%d].position", i); + shader_set_3fv(shader, str, lights[i].position); + snprintf(str, 512, "lights[%d].color", i); + shader_set_3fv(shader, str, lights[i].color); + } + S32 rows = 7; + S32 cols = 7; + F32 offset = 3.0f; + for (S32 row = 0; row < rows; row++) { + shader_set_1f(shader, "metallic", (F32)row / (F32)rows); + for (S32 col = 0; col < cols; col++) { + shader_set_1f(shader, "roughness", clamp(0.05f, (F32)col / (F32)cols, 1.0f)); + V3F pos = {(col - cols / 2.0f) * offset, (row - rows / 2.0f) * offset, 0.0f}; + MAT4 model = mat4_make_translate(pos); + shader_set_mat4fv(shader, "model", model); + mesh_draw(cube); + } + } + + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { + MAT4 model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); + model = mat4_translate(model, lights[i].position); + shader_set_mat4fv(shader, "model", model); + mesh_draw(cube); + } + + glUseProgram(0); + + shader = find_shader("background"); + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", projection); + shader_set_mat4fv(shader, "view", view); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); + mesh_draw(cube); + glUseProgram(0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + shader = find_shader("hdr"); + if (!shader) die("failed to find hdr shader!"); + glUseProgram(shader); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + shader_set_mat4fv(shader, "model", mat4_identity()); + mesh_draw(quad); + glUseProgram(0); + + glfwSwapBuffers(state.window); + } + + return 0; +} diff --git a/pbr/ibl_irradiance_conversion/pbr.frag b/pbr/ibl_irradiance_conversion/pbr.frag new file mode 100644 index 0000000..db9edea --- /dev/null +++ b/pbr/ibl_irradiance_conversion/pbr.frag @@ -0,0 +1,105 @@ +#version 330 core + +in vert_t { + vec3 position; + vec3 normal; +} vert; + +out vec4 frag_color; + +uniform vec3 camera; + +uniform vec3 color; +uniform float metallic; +uniform float roughness; +uniform float ao; + +struct light_t { + vec3 position; + vec3 color; +}; + +const int light_count = 4; +uniform light_t lights[light_count]; + +const float PI = 3.14159265358; + +vec3 fresnel_shlick(float costheta, vec3 f0) +{ + return f0 + (1.0 - f0) * pow(1.0 - costheta, 5.0); +} + +float distribution_ggx(vec3 n, vec3 h, float roughness) +{ + float a = roughness * roughness; + float a2 = a * a; + float ndoth = max(dot(n, h), 0.0); + float ndoth2 = ndoth * ndoth; + + float num = a2; + float denom = (ndoth2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return num / denom; +} + +float geometry_shlick_ggx(float ndotv, float roughness) +{ + float r = roughness + 1.0; + float k = r * r / 8.0; + + float num = ndotv; + float denom = ndotv * (1.0 - k) + k; + + return num / denom; +} + +float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) +{ + float ndotv = max(dot(n, v), 0.0); + float ndotl = max(dot(n, l), 0.0); + float ggx2 = geometry_shlick_ggx(ndotv, roughness); + float ggx1 = geometry_shlick_ggx(ndotl, roughness); + + return ggx1 * ggx2; +} + +void main(void) +{ + vec3 n = vert.normal; + vec3 v = normalize(camera - vert.position); + + vec3 lo = vec3(0.0); + for (int i = 0; i < light_count; i++) { + vec3 l = normalize(lights[i].position - vert.position); + vec3 h = normalize(v + l); + float ndotv = max(dot(n, v), 0.0); + float ndotl = max(dot(n, l), 0.0); + + float distance = length(lights[i].position - vert.position); + float attenuation = 1.0 / (distance * distance); + + vec3 radiance = lights[i].color * attenuation; + + vec3 f0 = vec3(0.04); + f0 = mix(f0, color, metallic); + vec3 f = fresnel_shlick(max(dot(h, v), 0.0), f0); + + float ndf = distribution_ggx(n, h, roughness); + float g = geometry_smith(n, v, l, roughness); + + vec3 numerator = ndf * g * f; + float denominator = 4.0 * ndotv * ndotl; + vec3 specular = numerator / max(denominator, 0.001); + + vec3 ks = f; + vec3 kd = vec3(1.0) - ks; + + kd *= 1.0 - metallic; + + lo += (kd * color / PI + specular) * radiance * ndotl; + } + + vec3 ambient = vec3(0.03) * color * ao; + frag_color = vec4(ambient + lo, 1.0); +} diff --git a/pbr/ibl_irradiance_conversion/pbr.vert b/pbr/ibl_irradiance_conversion/pbr.vert new file mode 100644 index 0000000..e6e3800 --- /dev/null +++ b/pbr/ibl_irradiance_conversion/pbr.vert @@ -0,0 +1,21 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 1) in vec3 normal; + +out vert_t { + vec3 position; + vec3 normal; +} vert; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main(void) +{ + gl_Position = projection * view * model * vec4(position, 1.0); + + vert.position = vec3(model * vec4(position, 1.0)); + vert.normal = normalize(mat3(transpose(inverse(model))) * normal); +} diff --git a/pbr/ibl_specular/background.frag b/pbr/ibl_specular/background.frag new file mode 100644 index 0000000..e3891eb --- /dev/null +++ b/pbr/ibl_specular/background.frag @@ -0,0 +1,17 @@ +#version 330 core + +in vert_t { + vec3 position; +} vert; + +out vec4 frag_color; + +uniform samplerCube cubemap; + +void main(void) +{ + vec3 color = texture(cubemap, vert.position).rgb; + color /= color + vec3(1.0); + color = pow(color, vec3(1.0 / 2.2)); + frag_color = vec4(color, 1.0); +} diff --git a/pbr/ibl_specular/background.vert b/pbr/ibl_specular/background.vert new file mode 100644 index 0000000..25b9778 --- /dev/null +++ b/pbr/ibl_specular/background.vert @@ -0,0 +1,19 @@ +#version 330 core + +layout(location = 0) in vec3 position; + +out vert_t { + vec3 position; +} vert; + +uniform mat4 projection; +uniform mat4 view; + +void main(void) +{ + vert.position = position; + + mat4 rotate_view = mat4(mat3(view)); + vec4 clip_position = projection * rotate_view * vec4(position, 1.0); + gl_Position = clip_position.xyww; +} diff --git a/pbr/ibl_specular/brdf.frag b/pbr/ibl_specular/brdf.frag new file mode 100644 index 0000000..6e7cf5b --- /dev/null +++ b/pbr/ibl_specular/brdf.frag @@ -0,0 +1,98 @@ +#version 330 core + +in vert_t { + vec2 tex_coords; +} vert; + +out vec2 frag_color; + +const float PI = 3.14159265359; + +float radical_inverse_vdc(uint bits) +{ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 hammersley(uint i, uint n) +{ + return vec2(float(i) / float(n), radical_inverse_vdc(i)); +} + +vec3 importance_sample_ggx(vec2 xi, vec3 n, float roughness) +{ + float a = roughness * roughness; + + float phi = 2.0 * PI * xi.x; + float cos_theta = sqrt((1.0 - xi.y) / (1.0 + (a * a - 1.0) * xi.y)); + float sin_theta = sqrt(1.0 - cos_theta * cos_theta); + + vec3 h; + h.x = cos(phi) * sin_theta; + h.y = sin(phi) * sin_theta; + h.z = cos_theta; + + vec3 up = abs(n.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangent = normalize(cross(up, n)); + vec3 bitangent = cross(n, tangent); + + vec3 samplevec = tangent * h.x + bitangent * h.y + n * h.z; + return normalize(samplevec); +} + +float geometry_schlick_ggx(float ndotv, float roughness) +{ + float a = roughness; + float k = (a * a) / 2.0; + float nom = ndotv; + float denom = ndotv * (1.0 - k) + k; + return nom / denom; +} + +float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) +{ + float ndotv = max(dot(n, v), 0.0); + float ndotl = max(dot(n, l), 0.0); + float ggx1 = geometry_schlick_ggx(ndotl, roughness); + float ggx2 = geometry_schlick_ggx(ndotv, roughness); + return ggx1 * ggx2; +} + +vec2 integrate_brdf(float ndotv, float roughness) +{ + vec3 v; + v.x = sqrt(1.0 - ndotv * ndotv); + v.y = 0.0; + v.z = ndotv; + float a = 0.0; + float b = 0.0; + vec3 n = vec3(0.0, 0.0, 1.0); + uint sample_count = 1024u; + for (uint i = 0u; i < sample_count; i++) { + vec2 xi = hammersley(i, sample_count); + vec3 h = importance_sample_ggx(xi, n, roughness); + vec3 l = normalize(2.0 * dot(v, h) * h - v); + float ndotl = max(l.z, 0.0); + float ndoth = max(h.z, 0.0); + float vdoth = max(dot(v, h), 0.0); + if (ndotl > 0.0) { + float g = geometry_smith(n, v, l, roughness); + float g_vis = (g * vdoth) / (ndoth * ndotv); + float fc = pow(1.0 - vdoth, 5.0); + a += (1.0 - fc) * g_vis; + b += fc * g_vis; + } + } + a /= float(sample_count); + b /= float(sample_count); + return vec2(a, b); +} + +void main() +{ + frag_color = integrate_brdf(vert.tex_coords.x, vert.tex_coords.y); +} diff --git a/pbr/ibl_specular/brdf.vert b/pbr/ibl_specular/brdf.vert new file mode 100644 index 0000000..fd86ecc --- /dev/null +++ b/pbr/ibl_specular/brdf.vert @@ -0,0 +1,13 @@ +#version 330 core +layout(location = 0) in vec3 position; +layout(location = 2) in vec2 tex_coords; + +out vert_t { + vec2 tex_coords; +} vert; + +void main() +{ + vert.tex_coords = tex_coords; + gl_Position = vec4(position, 1.0); +} diff --git a/pbr/ibl_specular/build.sh b/pbr/ibl_specular/build.sh new file mode 100755 index 0000000..5ed5193 --- /dev/null +++ b/pbr/ibl_specular/build.sh @@ -0,0 +1,5 @@ +#!/bin/bash +. ../../config +TARGET='ibl_specular' +set -x +gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS diff --git a/pbr/ibl_specular/convolution.frag b/pbr/ibl_specular/convolution.frag new file mode 100644 index 0000000..69ce8af --- /dev/null +++ b/pbr/ibl_specular/convolution.frag @@ -0,0 +1,33 @@ +#version 330 core + +in vert_t { + vec3 position; +} vert; + +out vec4 frag_color; + +uniform samplerCube cubemap; + +const float PI = 3.14159265359; + +void main(void) +{ + vec3 normal = normalize(vert.position); + vec3 up = vec3(0.0, 1.0, 0.0); + vec3 right = cross(up, normal); + up = cross(normal, right); + + vec3 irradiance = vec3(0.0); + float delta = 0.025; + int nsamples = 0; + for (float phi = 0.0; phi < 2.0 * PI; phi += delta) { + for (float theta = 0.0; theta < 0.5 * PI; theta += delta) { + vec3 tangent = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); + vec3 v = tangent.x * right + tangent.y * up + tangent.z * normal; + irradiance += texture(cubemap, v).rgb * cos(theta) * sin(theta); + nsamples++; + } + } + irradiance *= PI / nsamples; + frag_color = vec4(irradiance, 1.0); +} diff --git a/pbr/ibl_specular/convolution.vert b/pbr/ibl_specular/convolution.vert new file mode 100644 index 0000000..8f8862e --- /dev/null +++ b/pbr/ibl_specular/convolution.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; + +out vert_t { + vec3 position; +} vert; + +uniform mat4 projection; +uniform mat4 view; + +void main(void) +{ + gl_Position = projection * view * vec4(position, 1.0); + + vert.position = position; +} diff --git a/pbr/ibl_specular/cubemap.frag b/pbr/ibl_specular/cubemap.frag new file mode 100644 index 0000000..349347a --- /dev/null +++ b/pbr/ibl_specular/cubemap.frag @@ -0,0 +1,25 @@ +#version 330 core + +in vert_t { + vec3 position; +} vert; + +out vec4 frag_color; + +uniform sampler2D map; + +const vec2 inv_atan = vec2(0.1591, 0.3183); +vec2 sample_spherical_map(vec3 v) +{ + vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); + uv *= inv_atan; + uv += 0.5; + return uv; +} + +void main(void) +{ + vec2 uv = sample_spherical_map(normalize(vert.position)); + vec3 color = texture(map, uv).rgb; + frag_color = vec4(color, 1.0); +} diff --git a/pbr/ibl_specular/cubemap.vert b/pbr/ibl_specular/cubemap.vert new file mode 100644 index 0000000..8f8862e --- /dev/null +++ b/pbr/ibl_specular/cubemap.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; + +out vert_t { + vec3 position; +} vert; + +uniform mat4 projection; +uniform mat4 view; + +void main(void) +{ + gl_Position = projection * view * vec4(position, 1.0); + + vert.position = position; +} diff --git a/pbr/ibl_specular/hdr.frag b/pbr/ibl_specular/hdr.frag new file mode 100644 index 0000000..01650ae --- /dev/null +++ b/pbr/ibl_specular/hdr.frag @@ -0,0 +1,18 @@ +#version 330 core + +in vert_t { + vec2 tex_coords; +} vert; + +out vec4 frag_color; + +uniform sampler2D colorbuffer; + +void main(void) +{ + const float gamma = 2.2; + vec3 color = vec3(texture(colorbuffer, vert.tex_coords)); + color /= color + vec3(1.0); + color = pow(color, vec3(1.0 / gamma)); + frag_color = vec4(color, 1.0); +} diff --git a/pbr/ibl_specular/hdr.vert b/pbr/ibl_specular/hdr.vert new file mode 100644 index 0000000..1b953d7 --- /dev/null +++ b/pbr/ibl_specular/hdr.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 2) in vec2 tex_coords; + +out vert_t { + vec2 tex_coords; +} vert; + +uniform mat4 model; + +void main(void) +{ + gl_Position = model * vec4(position, 1.0); + + vert.tex_coords = tex_coords; +} diff --git a/pbr/ibl_specular/ibl_specular b/pbr/ibl_specular/ibl_specular new file mode 100755 index 0000000..e4466f5 Binary files /dev/null and b/pbr/ibl_specular/ibl_specular differ diff --git a/pbr/ibl_specular/ibl_specular.c b/pbr/ibl_specular/ibl_specular.c new file mode 100644 index 0000000..5692505 --- /dev/null +++ b/pbr/ibl_specular/ibl_specular.c @@ -0,0 +1,307 @@ +#include "GL/glew.h" +#include "GLFW/glfw3.h" +#include "common.h" + +int main(void) +{ + state_t state = init_state(1600, 800); + + init_glfw(&state); + init_gl(); + glDepthFunc(GL_LEQUAL); + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + + /* meshes */ + Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj"); + Mesh *sphere = mesh_load_obj(state.arena, "../../data/models/sphere.obj"); + Mesh *quad = mesh_gen_quad(state.arena); + + /* shaders */ + add_shader("pbr.vert", "pbr.frag", 0); + add_shader("hdr.vert", "hdr.frag", 0); + add_shader("cubemap.vert", "cubemap.frag", 0); + add_shader("background.vert", "background.frag", 0); + add_shader("convolution.vert", "convolution.frag", 0); + add_shader("prefilter.vert", "prefilter.frag", 0); + add_shader("brdf.vert", "brdf.frag", 0); + + U32 shader = find_shader("pbr"); + glUseProgram(shader); + shader_set_1i(shader, "irradiance_map", 0); + shader_set_1i(shader, "prefilter_map", 1); + shader_set_1i(shader, "brdf_lut", 2); + glUseProgram(0); + + light_t lights[4] = { + {{-10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + {{-5.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + {{ 5.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + {{ 10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}}, + }; + + /* textures */ + U32 textures[] = { + load_hdr_texture("../../data/textures/loigerwiesen.hdr"), + load_hdr_texture("../../data/textures/wells.hdr") + }; + U32 hdr_texture = 1; + + /* framebuffers */ + U32 hdr_fbo, hdr_colorbuffer, hdr_rbo; + glGenFramebuffers(1, &hdr_fbo); + glGenTextures(1, &hdr_colorbuffer); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, state.width, state.height, 0, GL_RGBA, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glGenRenderbuffers(1, &hdr_rbo); + glBindRenderbuffer(GL_RENDERBUFFER, hdr_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, state.width, state.height); + glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdr_colorbuffer, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdr_rbo); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + die("failed to create framebuffer"); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + U32 capture_fbo, capture_rbo; + glGenFramebuffers(1, &capture_fbo); + glGenRenderbuffers(1, &capture_rbo); + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, capture_rbo); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + die("failed to create framebuffer"); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + U32 cubemap; + glGenTextures(1, &cubemap); + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); + for (U32 i = 0; i < 6; i++) + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + MAT4 capture_projection = perspective(90.0f, 1.0f, 0.1f, 10.0f); + V3F capture_origin = {0}; + MAT4 capture_views[6] = { + look_at(capture_origin, v3f( 1.0f, 0.0f, 0.0f), v3f(0.0f, -1.0f, 0.0f)), + look_at(capture_origin, v3f(-1.0f, 0.0f, 0.0f), v3f(0.0f, -1.0f, 0.0f)), + look_at(capture_origin, v3f( 0.0f, 1.0f, 0.0f), v3f(0.0f, 0.0f, 1.0f)), + look_at(capture_origin, v3f( 0.0f, -1.0f, 0.0f), v3f(0.0f, 0.0f, -1.0f)), + look_at(capture_origin, v3f( 0.0f, 0.0f, 1.0f), v3f(0.0f, -1.0f, 0.0f)), + look_at(capture_origin, v3f( 0.0f, 0.0f, -1.0f), v3f(0.0f, -1.0f, 0.0f)), + }; + + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + shader = find_shader("cubemap"); + if (!shader) die("waht"); + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", capture_projection); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textures[hdr_texture]); + + glViewport(0, 0, 512, 512); + for (U32 i = 0; i < 6; i++) { + shader_set_mat4fv(shader, "view", capture_views[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + mesh_draw(cube); + } + glUseProgram(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + + U32 irradiance_map; + glGenTextures(1, &irradiance_map); + glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance_map); + for (U32 i = 0; i < 6; i++) + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 32, 32, 0, GL_RGB, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + shader = find_shader("convolution"); + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", capture_projection); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); + glViewport(0, 0, 32, 32); + for (U32 i = 0; i < 6; i++) { + shader_set_mat4fv(shader, "view", capture_views[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradiance_map, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + mesh_draw(cube); + } + glUseProgram(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + U32 prefilter_map; + glGenTextures(1, &prefilter_map); + glBindTexture(GL_TEXTURE_CUBE_MAP, prefilter_map); + for (U32 i = 0; i < 6; i++) + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 128, 128, 0, GL_RGB, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + + shader = find_shader("prefilter"); + glUseProgram(shader); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); + shader_set_mat4fv(shader, "projection", capture_projection); + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + U32 mipmap_levels = 5; + for (U32 mip = 0; mip < mipmap_levels; mip++) { + U32 width = 128 * pow(0.5, mip); + U32 height = width; + glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); + glViewport(0, 0, width, height); + float roughness = (float)mip / (float)(mipmap_levels - 1); + shader_set_1f(shader, "roughness", roughness); + for (U32 i = 0; i < 6; i++) { + shader_set_mat4fv(shader, "view", capture_views[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilter_map, mip); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + mesh_draw(cube); + } + } + glUseProgram(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + U32 brdf_lut_texture; + glGenTextures(1, &brdf_lut_texture); + glBindTexture(GL_TEXTURE_2D, brdf_lut_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, 512, 512, 0, GL_RG, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, brdf_lut_texture, 0); + glViewport(0, 0, 512, 512); + shader = find_shader("brdf"); + assert(shader); + glUseProgram(shader); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + mesh_draw(quad); + glUseProgram(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glViewport(0, 0, state.width, state.height); + + F32 time = 0; + + while (!glfwWindowShouldClose(state.window)) { + handle_glfw_events(state.window, &state.input); + F32 dt = lock_framerate(60); + fps_info(dt, 10); + + /* update */ + update_camera_first_person(&state.camera, &state.input, dt, 2.0f); + F32 limit = 4.0f; + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) + lights[i].position.y = sinf(time + i) * limit; + time += dt; + + /* render */ + F32 ar = (F32)state.width / (F32)state.height; + MAT4 projection = camera_persp(state.camera, ar); + MAT4 view = get_view_matrix(&state.camera); + + glClearColor(0.16f, 0.16f, 0.16f, 1.0f); + + glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + shader = find_shader("pbr"); + glUseProgram(shader); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance_map); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_CUBE_MAP, prefilter_map); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, brdf_lut_texture); + shader_set_mat4fv(shader, "projection", projection); + shader_set_mat4fv(shader, "view", view); + shader_set_3fv(shader, "camera", state.camera.pos); + shader_set_3fv(shader, "color", v3f(0.04, 0.04, 0.04)); + shader_set_1f(shader, "ao", 1.0f); + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { + char str[512]; + snprintf(str, 512, "lights[%d].position", i); + shader_set_3fv(shader, str, lights[i].position); + snprintf(str, 512, "lights[%d].color", i); + shader_set_3fv(shader, str, lights[i].color); + } + S32 rows = 7; + S32 cols = 7; + F32 offset = 3.0f; + for (S32 row = 0; row < rows; row++) { + shader_set_1f(shader, "metallic", (F32)row / (F32)rows); + for (S32 col = 0; col < cols; col++) { + shader_set_1f(shader, "roughness", clamp(0.05f, (F32)col / (F32)cols, 1.0f)); + V3F pos = {(col - cols / 2.0f) * offset, (row - rows / 2.0f) * offset, 0.0f}; + MAT4 model = mat4_make_translate(pos); + shader_set_mat4fv(shader, "model", model); + mesh_draw(cube); + } + } + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { + MAT4 model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); + model = mat4_translate(model, lights[i].position); + shader_set_mat4fv(shader, "model", model); + mesh_draw(sphere); + } + glUseProgram(0); + + shader = find_shader("background"); + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", projection); + shader_set_mat4fv(shader, "view", view); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); + mesh_draw(cube); + glUseProgram(0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + shader = find_shader("hdr"); + if (!shader) die("!"); + glUseProgram(shader); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + shader_set_mat4fv(shader, "model", mat4_identity()); + mesh_draw(quad); + glUseProgram(0); + + glfwSwapBuffers(state.window); + } + + return 0; +} diff --git a/pbr/ibl_specular/pbr.frag b/pbr/ibl_specular/pbr.frag new file mode 100644 index 0000000..3ed2018 --- /dev/null +++ b/pbr/ibl_specular/pbr.frag @@ -0,0 +1,131 @@ +#version 330 core + +in vert_t { + vec3 position; + vec3 normal; +} vert; + +out vec4 frag_color; + +uniform vec3 camera; + +uniform vec3 color; +uniform float metallic; +uniform float roughness; +uniform float ao; + +uniform samplerCube irradiance_map; +uniform samplerCube prefilter_map; +uniform sampler2D brdf_lut; + +struct light_t { + vec3 position; + vec3 color; +}; + +const int light_count = 4; +uniform light_t lights[light_count]; + +const float PI = 3.14159265358; + +vec3 fresnel_schlick(float costheta, vec3 f0) +{ + return f0 + (1.0 - f0) * pow(1.0 - costheta, 5.0); +} + +vec3 fresnel_schlick_roughness(float costheta, vec3 f0, float roughness) +{ + return f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(clamp(1.0 - costheta, 0.0, 1.0), 5.0); +} + +float distribution_ggx(vec3 n, vec3 h, float roughness) +{ + float a = roughness * roughness; + float a2 = a * a; + float ndoth = max(dot(n, h), 0.0); + float ndoth2 = ndoth * ndoth; + + float num = a2; + float denom = (ndoth2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return num / denom; +} + +float geometry_schlick_ggx(float ndotv, float roughness) +{ + float r = roughness + 1.0; + float k = r * r / 8.0; + + float num = ndotv; + float denom = ndotv * (1.0 - k) + k; + + return num / denom; +} + +float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) +{ + float ndotv = max(dot(n, v), 0.0); + float ndotl = max(dot(n, l), 0.0); + float ggx2 = geometry_schlick_ggx(ndotv, roughness); + float ggx1 = geometry_schlick_ggx(ndotl, roughness); + + return ggx1 * ggx2; +} + +void main(void) +{ + vec3 n = vert.normal; + vec3 v = normalize(camera - vert.position); + vec3 r = reflect(-v, n); + + vec3 f0 = vec3(0.04); + f0 = mix(f0, color, metallic); + + vec3 lo = vec3(0.0); + for (int i = 0; i < light_count; i++) { + vec3 l = normalize(lights[i].position - vert.position); + vec3 h = normalize(v + l); + float ndotv = max(dot(n, v), 0.0); + float ndotl = max(dot(n, l), 0.0); + + float distance = length(lights[i].position - vert.position); + float attenuation = 1.0 / (distance * distance); + + vec3 radiance = lights[i].color * attenuation; + + vec3 f = fresnel_schlick(max(dot(h, v), 0.0), f0); + + float ndf = distribution_ggx(n, h, roughness); + float g = geometry_smith(n, v, l, roughness); + + vec3 numerator = ndf * g * f; + float denominator = 4.0 * ndotv * ndotl; + vec3 specular = numerator / max(denominator, 0.001); + + vec3 ks = f; + vec3 kd = vec3(1.0) - ks; + + kd *= 1.0 - metallic; + + lo += (kd * color / PI + specular) * radiance * ndotl; + } + + vec3 f = fresnel_schlick_roughness(max(dot(n, v), 0.0), f0, roughness); + + vec3 ks = f; + vec3 kd = 1.0 - ks; + kd *= 1.0 - metallic; + + vec3 irradiance = texture(irradiance_map, n).rgb; + vec3 diffuse = irradiance * color; + + float max_reflection_lod = 4.0; + vec3 prefiltered = textureLod(prefilter_map, r, roughness * max_reflection_lod).rgb; + vec2 brdf = texture(brdf_lut, vec2(max(dot(n, v), 0.0), roughness)).rg; + vec3 specular = prefiltered * (f * brdf.x + brdf.y); + + vec3 ambient = (kd * diffuse + specular)* ao; + + frag_color = vec4(ambient + lo, 1.0); +} diff --git a/pbr/ibl_specular/pbr.vert b/pbr/ibl_specular/pbr.vert new file mode 100644 index 0000000..e6e3800 --- /dev/null +++ b/pbr/ibl_specular/pbr.vert @@ -0,0 +1,21 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 1) in vec3 normal; + +out vert_t { + vec3 position; + vec3 normal; +} vert; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main(void) +{ + gl_Position = projection * view * model * vec4(position, 1.0); + + vert.position = vec3(model * vec4(position, 1.0)); + vert.normal = normalize(mat3(transpose(inverse(model))) * normal); +} diff --git a/pbr/ibl_specular/prefilter.frag b/pbr/ibl_specular/prefilter.frag new file mode 100644 index 0000000..5359c58 --- /dev/null +++ b/pbr/ibl_specular/prefilter.frag @@ -0,0 +1,91 @@ +#version 330 core + +in vert_t { + vec3 position; +} vert; + +out vec4 frag_color; + +uniform samplerCube cubemap; +uniform float roughness; + +const float PI = 3.14159265359; + +float distribution_ggx(vec3 n, vec3 h, float roughness) +{ + float a = roughness * roughness; + float a2 = a * a; + float ndoth = max(dot(n, h), 0.0); + float ndoth2 = ndoth * ndoth; + float nom = a2; + float denom = (ndoth2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + return nom / denom; +} + +float radical_inverse_vdc(uint bits) +{ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 hammersley(uint i, uint n) +{ + return vec2(float(i) / float(n), radical_inverse_vdc(i)); +} + +vec3 importance_sample_ggx(vec2 xi, vec3 n, float roughness) +{ + float a = roughness * roughness; + + float phi = 2.0 * PI * xi.x; + float cos_theta = sqrt((1.0 - xi.y) / (1.0 + (a * a - 1.0) * xi.y)); + float sin_theta = sqrt(1.0 - cos_theta * cos_theta); + + vec3 h; + h.x = cos(phi) * sin_theta; + h.y = sin(phi) * sin_theta; + h.z = cos_theta; + + vec3 up = abs(n.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangent = normalize(cross(up, n)); + vec3 bitangent = cross(n, tangent); + + vec3 samplevec = tangent * h.x + bitangent * h.y + n * h.z; + return normalize(samplevec); +} + +void main(void) +{ + vec3 n = normalize(vert.position); + vec3 r = n; + vec3 v = r; + + uint count = 1024u; + float total = 0.0; + vec3 prefiltered = vec3(0.0); + for (uint i = 0u; i < count; i++) { + vec2 xi = hammersley(i, count); + vec3 h = importance_sample_ggx(xi, n, roughness); + vec3 l = normalize(2.0 * dot(v, h) * h - v); + float ndotl = max(dot(n, l), 0.0); + if (ndotl > 0.0) { + float d = distribution_ggx(n, h, roughness); + float ndoth = max(dot(n, h), 0.0); + float hdotv = max(dot(h, v), 0.0); + float pdf = d * ndoth / (4.0 * hdotv) + 0.0001; + float resolution = 512.0; + float sa_texel = 4.0 * PI / (6.0 * resolution * resolution); + float sa_sample = 1.0 / (float(count) * pdf + 0.0001); + float mip_level = roughness == 0.0 ? 0.0 : 0.5 * log2(sa_sample / sa_texel); + prefiltered += textureLod(cubemap, l, mip_level).rgb * ndotl; + total += ndotl; + } + } + prefiltered /= total; + frag_color = vec4(prefiltered, 1.0); +} diff --git a/pbr/ibl_specular/prefilter.vert b/pbr/ibl_specular/prefilter.vert new file mode 100644 index 0000000..8f8862e --- /dev/null +++ b/pbr/ibl_specular/prefilter.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; + +out vert_t { + vec3 position; +} vert; + +uniform mat4 projection; +uniform mat4 view; + +void main(void) +{ + gl_Position = projection * view * vec4(position, 1.0); + + vert.position = position; +} diff --git a/pbr/lighting/build.sh b/pbr/lighting/build.sh new file mode 100755 index 0000000..2cd71b7 --- /dev/null +++ b/pbr/lighting/build.sh @@ -0,0 +1,5 @@ +#!/bin/sh +. ../../config +TARGET='lighting' +set -x +gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS diff --git a/pbr/lighting/default.frag b/pbr/lighting/default.frag new file mode 100644 index 0000000..9351a1b --- /dev/null +++ b/pbr/lighting/default.frag @@ -0,0 +1,15 @@ +#version 330 core + +in vert_t { + vec2 tex_coords; +} vert; + +out vec4 frag_color; + +uniform sampler2D colorbuffer; + +void main(void) +{ + vec3 color = vec3(texture(colorbuffer, vert.tex_coords)); + frag_color = vec4(color, 1.0); +} diff --git a/pbr/lighting/default.vert b/pbr/lighting/default.vert new file mode 100644 index 0000000..1b953d7 --- /dev/null +++ b/pbr/lighting/default.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 2) in vec2 tex_coords; + +out vert_t { + vec2 tex_coords; +} vert; + +uniform mat4 model; + +void main(void) +{ + gl_Position = model * vec4(position, 1.0); + + vert.tex_coords = tex_coords; +} diff --git a/pbr/lighting/hdr.frag b/pbr/lighting/hdr.frag new file mode 100644 index 0000000..01650ae --- /dev/null +++ b/pbr/lighting/hdr.frag @@ -0,0 +1,18 @@ +#version 330 core + +in vert_t { + vec2 tex_coords; +} vert; + +out vec4 frag_color; + +uniform sampler2D colorbuffer; + +void main(void) +{ + const float gamma = 2.2; + vec3 color = vec3(texture(colorbuffer, vert.tex_coords)); + color /= color + vec3(1.0); + color = pow(color, vec3(1.0 / gamma)); + frag_color = vec4(color, 1.0); +} diff --git a/pbr/lighting/hdr.vert b/pbr/lighting/hdr.vert new file mode 100644 index 0000000..1b953d7 --- /dev/null +++ b/pbr/lighting/hdr.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 2) in vec2 tex_coords; + +out vert_t { + vec2 tex_coords; +} vert; + +uniform mat4 model; + +void main(void) +{ + gl_Position = model * vec4(position, 1.0); + + vert.tex_coords = tex_coords; +} diff --git a/pbr/lighting/lighting b/pbr/lighting/lighting new file mode 100755 index 0000000..a68bd2b Binary files /dev/null and b/pbr/lighting/lighting differ diff --git a/pbr/lighting/lighting.c b/pbr/lighting/lighting.c new file mode 100644 index 0000000..d2a941d --- /dev/null +++ b/pbr/lighting/lighting.c @@ -0,0 +1,157 @@ +#include "GL/glew.h" +#include "GLFW/glfw3.h" +#include "common.h" + +int main(void) +{ + state_t state = init_state(1600, 800); + + init_glfw(&state); + init_gl(); + + /* meshes */ + Mesh *sphere = mesh_load_obj(state.arena, "../../data/models/sphere.obj"); + Mesh *quad = mesh_gen_quad(state.arena); + + /* shaders */ + add_shader("default.vert", "default.frag", 0); + add_shader("pbr.vert", "pbr.frag", 0); + add_shader("hdr.vert", "hdr.frag", 0); + + light_t lights[4] = { + {{-6.0f, 0.0f, 7.0f}, {300.0f, 300.0f, 300.0f}}, + {{-4.0f, 0.0f, 6.0f}, {300.0f, 300.0f, 300.0f}}, + {{ 1.0f, 0.0f, 5.0f}, {300.0f, 300.0f, 300.0f}}, + {{ 3.0f, 0.0f, 8.0f}, {300.0f, 300.0f, 300.0f}}, + }; + + /* framebuffers */ + U32 hdr_fbo, hdr_colorbuffer, hdr_rbo; + glGenFramebuffers(1, &hdr_fbo); + glGenTextures(1, &hdr_colorbuffer); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, state.width, state.height, 0, GL_RGBA, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glGenRenderbuffers(1, &hdr_rbo); + glBindRenderbuffer(GL_RENDERBUFFER, hdr_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, state.width, state.height); + glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdr_colorbuffer, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdr_rbo); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + die("failed to create framebuffer"); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + F32 time = 0; + + S32 show_gamma = 0; + + while (!glfwWindowShouldClose(state.window)) { + handle_glfw_events(state.window, &state.input); + F32 dt = lock_framerate(60); + fps_info(dt, 10); + + /* update */ + update_camera_first_person(&state.camera, &state.input, dt, 2.0f); + F32 limit = 4.0f; + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) + lights[i].position.y = sinf(time + i) * limit; + time += dt; + + if (key_first_press(state.input.jump)) + show_gamma = 1 - show_gamma; + + /* render */ + F32 ar = 0; + if (show_gamma) { + ar = (F32)state.width / 2.0f / (F32)state.height; + } else { + ar = (F32)state.width / (F32)state.height; + } + MAT4 projection = camera_persp(state.camera, ar); + MAT4 view = get_view_matrix(&state.camera); + + glClearColor(0.16f, 0.16f, 0.16f, 1.0f); + + glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + U32 shader = find_shader("pbr"); + if (!shader) die("wha"); + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", projection); + shader_set_mat4fv(shader, "view", view); + shader_set_3fv(shader, "camera", state.camera.pos); + shader_set_3fv(shader, "color", v3f(0.04, 0.04, 0.04)); + shader_set_1f(shader, "ao", 1.0f); + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { + char str[512]; + snprintf(str, 512, "lights[%d].position", i); + shader_set_3fv(shader, str, lights[i].position); + snprintf(str, 512, "lights[%d].color", i); + shader_set_3fv(shader, str, lights[i].color); + } + S32 rows = 7; + S32 cols = 7; + F32 offset = 3.0f; + for (S32 row = 0; row < rows; row++) { + shader_set_1f(shader, "metallic", (F32)row / (F32)rows); + for (S32 col = 0; col < cols; col++) { + shader_set_1f(shader, "roughness", clamp(0.05f, (F32)col / (F32)cols, 1.0f)); + V3F pos = {(col - cols / 2.0f) * offset, (row - rows / 2.0f) * offset, 0.0f}; + MAT4 model = mat4_make_translate(pos); + shader_set_mat4fv(shader, "model", model); + mesh_draw(sphere); + } + } + + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { + MAT4 model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); + model = mat4_translate(model, lights[i].position); + shader_set_mat4fv(shader, "model", model); + mesh_draw(sphere); + } + + glUseProgram(0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (show_gamma) { + shader = find_shader("default"); + if (!shader) die("!"); + glUseProgram(shader); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + MAT4 model = mat4_make_scale(v3f(0.5f, 1.0f, 1.0f)); + model = mat4_translate(model, v3f(-0.5f, 0.0f, 0.0f)); + shader_set_mat4fv(shader, "model", model); + mesh_draw(quad); + glUseProgram(0); + + shader = find_shader("hdr"); + if (!shader) die("!"); + glUseProgram(shader); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + model = mat4_make_scale(v3f(0.5f, 1.0f, 1.0f)); + model = mat4_translate(model, v3f(0.5f, 0.0f, 0.0f)); + shader_set_mat4fv(shader, "model", model); + mesh_draw(quad); + glUseProgram(0); + } else { + shader = find_shader("hdr"); + if (!shader) die("!"); + glUseProgram(shader); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + shader_set_mat4fv(shader, "model", mat4_identity()); + mesh_draw(quad); + glUseProgram(0); + } + + glfwSwapBuffers(state.window); + } + + return 0; +} diff --git a/pbr/lighting/pbr.frag b/pbr/lighting/pbr.frag new file mode 100644 index 0000000..db9edea --- /dev/null +++ b/pbr/lighting/pbr.frag @@ -0,0 +1,105 @@ +#version 330 core + +in vert_t { + vec3 position; + vec3 normal; +} vert; + +out vec4 frag_color; + +uniform vec3 camera; + +uniform vec3 color; +uniform float metallic; +uniform float roughness; +uniform float ao; + +struct light_t { + vec3 position; + vec3 color; +}; + +const int light_count = 4; +uniform light_t lights[light_count]; + +const float PI = 3.14159265358; + +vec3 fresnel_shlick(float costheta, vec3 f0) +{ + return f0 + (1.0 - f0) * pow(1.0 - costheta, 5.0); +} + +float distribution_ggx(vec3 n, vec3 h, float roughness) +{ + float a = roughness * roughness; + float a2 = a * a; + float ndoth = max(dot(n, h), 0.0); + float ndoth2 = ndoth * ndoth; + + float num = a2; + float denom = (ndoth2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return num / denom; +} + +float geometry_shlick_ggx(float ndotv, float roughness) +{ + float r = roughness + 1.0; + float k = r * r / 8.0; + + float num = ndotv; + float denom = ndotv * (1.0 - k) + k; + + return num / denom; +} + +float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) +{ + float ndotv = max(dot(n, v), 0.0); + float ndotl = max(dot(n, l), 0.0); + float ggx2 = geometry_shlick_ggx(ndotv, roughness); + float ggx1 = geometry_shlick_ggx(ndotl, roughness); + + return ggx1 * ggx2; +} + +void main(void) +{ + vec3 n = vert.normal; + vec3 v = normalize(camera - vert.position); + + vec3 lo = vec3(0.0); + for (int i = 0; i < light_count; i++) { + vec3 l = normalize(lights[i].position - vert.position); + vec3 h = normalize(v + l); + float ndotv = max(dot(n, v), 0.0); + float ndotl = max(dot(n, l), 0.0); + + float distance = length(lights[i].position - vert.position); + float attenuation = 1.0 / (distance * distance); + + vec3 radiance = lights[i].color * attenuation; + + vec3 f0 = vec3(0.04); + f0 = mix(f0, color, metallic); + vec3 f = fresnel_shlick(max(dot(h, v), 0.0), f0); + + float ndf = distribution_ggx(n, h, roughness); + float g = geometry_smith(n, v, l, roughness); + + vec3 numerator = ndf * g * f; + float denominator = 4.0 * ndotv * ndotl; + vec3 specular = numerator / max(denominator, 0.001); + + vec3 ks = f; + vec3 kd = vec3(1.0) - ks; + + kd *= 1.0 - metallic; + + lo += (kd * color / PI + specular) * radiance * ndotl; + } + + vec3 ambient = vec3(0.03) * color * ao; + frag_color = vec4(ambient + lo, 1.0); +} diff --git a/pbr/lighting/pbr.vert b/pbr/lighting/pbr.vert new file mode 100644 index 0000000..e6e3800 --- /dev/null +++ b/pbr/lighting/pbr.vert @@ -0,0 +1,21 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 1) in vec3 normal; + +out vert_t { + vec3 position; + vec3 normal; +} vert; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main(void) +{ + gl_Position = projection * view * model * vec4(position, 1.0); + + vert.position = vec3(model * vec4(position, 1.0)); + vert.normal = normalize(mat3(transpose(inverse(model))) * normal); +} diff --git a/pbr/textured/build.sh b/pbr/textured/build.sh new file mode 100755 index 0000000..5c5427f --- /dev/null +++ b/pbr/textured/build.sh @@ -0,0 +1,5 @@ +#!/bin/sh +. ../../config +TARGET='textured' +set -x +gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS diff --git a/pbr/textured/hdr.frag b/pbr/textured/hdr.frag new file mode 100644 index 0000000..01650ae --- /dev/null +++ b/pbr/textured/hdr.frag @@ -0,0 +1,18 @@ +#version 330 core + +in vert_t { + vec2 tex_coords; +} vert; + +out vec4 frag_color; + +uniform sampler2D colorbuffer; + +void main(void) +{ + const float gamma = 2.2; + vec3 color = vec3(texture(colorbuffer, vert.tex_coords)); + color /= color + vec3(1.0); + color = pow(color, vec3(1.0 / gamma)); + frag_color = vec4(color, 1.0); +} diff --git a/pbr/textured/hdr.vert b/pbr/textured/hdr.vert new file mode 100644 index 0000000..1b953d7 --- /dev/null +++ b/pbr/textured/hdr.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 2) in vec2 tex_coords; + +out vert_t { + vec2 tex_coords; +} vert; + +uniform mat4 model; + +void main(void) +{ + gl_Position = model * vec4(position, 1.0); + + vert.tex_coords = tex_coords; +} diff --git a/pbr/textured/pbr.frag b/pbr/textured/pbr.frag new file mode 100644 index 0000000..f0aaeca --- /dev/null +++ b/pbr/textured/pbr.frag @@ -0,0 +1,126 @@ +#version 330 core + +in vert_t { + vec3 position; + vec3 normal; + vec2 tex_coords; +} vert; + +out vec4 frag_color; + +uniform vec3 camera; + +uniform sampler2D color_map; +uniform sampler2D normal_map; +uniform sampler2D metallic_map; +uniform sampler2D roughness_map; +uniform sampler2D ao_map; + +struct light_t { + vec3 position; + vec3 color; +}; + +const int light_count = 4; +uniform light_t lights[light_count]; + +const float PI = 3.14159265358; + +vec3 get_normal_from_map() +{ + vec3 tangent = texture(normal_map, vert.tex_coords).xyz * 2.0 - 1.0; + vec3 q1 = dFdx(vert.position); + vec3 q2 = dFdy(vert.position); + vec2 st1 = dFdx(vert.tex_coords); + vec2 st2 = dFdy(vert.tex_coords); + vec3 n = normalize(vert.normal); + vec3 t = normalize(q1*st2.t - q2*st1.t); + vec3 b = -normalize(cross(n, t)); + mat3 tbn = mat3(t, b, n); + return normalize(tbn * tangent); +} + +vec3 fresnel_shlick(float costheta, vec3 f0) +{ + return f0 + (1.0 - f0) * pow(1.0 - costheta, 5.0); +} + +float distribution_ggx(vec3 n, vec3 h, float roughness) +{ + float a = roughness * roughness; + float a2 = a * a; + float ndoth = max(dot(n, h), 0.0); + float ndoth2 = ndoth * ndoth; + + float num = a2; + float denom = (ndoth2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return num / denom; +} + +float geometry_shlick_ggx(float ndotv, float roughness) +{ + float r = roughness + 1.0; + float k = r * r / 8.0; + + float num = ndotv; + float denom = ndotv * (1.0 - k) + k; + + return num / denom; +} + +float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) +{ + float ndotv = max(dot(n, v), 0.0); + float ndotl = max(dot(n, l), 0.0); + float ggx2 = geometry_shlick_ggx(ndotv, roughness); + float ggx1 = geometry_shlick_ggx(ndotl, roughness); + + return ggx1 * ggx2; +} + +void main(void) +{ + vec3 color = pow(texture(color_map, vert.tex_coords).rgb, vec3(2.2)); + float metallic = texture(metallic_map, vert.tex_coords).r; + float roughness = texture(roughness_map, vert.tex_coords).r; + float ao = texture(ao_map, vert.tex_coords).r; + + vec3 n = get_normal_from_map(); + vec3 v = normalize(camera - vert.position); + + vec3 lo = vec3(0.0); + for (int i = 0; i < light_count; i++) { + vec3 l = normalize(lights[i].position - vert.position); + vec3 h = normalize(v + l); + float ndotv = max(dot(n, v), 0.0); + float ndotl = max(dot(n, l), 0.0); + + float distance = length(lights[i].position - vert.position); + float attenuation = 1.0 / (distance * distance); + + vec3 radiance = lights[i].color * attenuation; + + vec3 f0 = vec3(0.04); + f0 = mix(f0, color, metallic); + vec3 f = fresnel_shlick(max(dot(h, v), 0.0), f0); + + float ndf = distribution_ggx(n, h, roughness); + float g = geometry_smith(n, v, l, roughness); + + vec3 numerator = ndf * g * f; + float denominator = 4.0 * ndotv * ndotl; + vec3 specular = numerator / max(denominator, 0.001); + + vec3 ks = f; + vec3 kd = vec3(1.0) - ks; + + kd *= 1.0 - metallic; + + lo += (kd * color / PI + specular) * radiance * ndotl; + } + + vec3 ambient = vec3(0.03) * color * ao; + frag_color = vec4(ambient + lo, 1.0); +} diff --git a/pbr/textured/pbr.vert b/pbr/textured/pbr.vert new file mode 100644 index 0000000..0ff1bdb --- /dev/null +++ b/pbr/textured/pbr.vert @@ -0,0 +1,24 @@ +#version 330 core + +layout(location = 0) in vec3 position; +layout(location = 1) in vec3 normal; +layout(location = 2) in vec2 tex_coords; + +out vert_t { + vec3 position; + vec3 normal; + vec2 tex_coords; +} vert; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main(void) +{ + gl_Position = projection * view * model * vec4(position, 1.0); + + vert.position = vec3(model * vec4(position, 1.0)); + vert.normal = normalize(mat3(transpose(inverse(model))) * normal); + vert.tex_coords = tex_coords; +} diff --git a/pbr/textured/textured b/pbr/textured/textured new file mode 100755 index 0000000..e339406 Binary files /dev/null and b/pbr/textured/textured differ diff --git a/pbr/textured/textured.c b/pbr/textured/textured.c new file mode 100644 index 0000000..e8ed096 --- /dev/null +++ b/pbr/textured/textured.c @@ -0,0 +1,151 @@ +#include "GL/glew.h" +#include "GLFW/glfw3.h" +#include "common.h" + +int main(void) +{ + state_t state = init_state(1600, 800); + + init_glfw(&state); + init_gl(); + + /* meshes */ + Mesh *sphere = mesh_load_obj(state.arena, "../../data/models/sphere.obj"); + Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj"); + Mesh *quad = mesh_gen_quad(state.arena); + + /* shaders */ + add_shader("pbr.vert", "pbr.frag", 0); + add_shader("hdr.vert", "hdr.frag", 0); + + U32 shader = find_shader("pbr"); + if (!shader) + die("not again"); + glUseProgram(shader); + shader_set_1i(shader, "color_map", 0); + shader_set_1i(shader, "normal_map", 1); + shader_set_1i(shader, "metallic_map", 2); + shader_set_1i(shader, "roughness_map", 3); + shader_set_1i(shader, "ao_map", 4); + glUseProgram(0); + + light_t lights[4] = { + {{-6.0f, 0.0f, 7.0f}, {300.0f, 300.0f, 300.0f}}, + {{-4.0f, 0.0f, 6.0f}, {300.0f, 300.0f, 300.0f}}, + {{ 1.0f, 0.0f, 5.0f}, {300.0f, 300.0f, 300.0f}}, + {{ 3.0f, 0.0f, 8.0f}, {300.0f, 300.0f, 300.0f}}, + }; + + /* textures */ + U32 color_map = load_texture("../../data/textures/pbr/albedo.png"); + U32 normal_map = load_texture("../../data/textures/pbr/normal.png"); + U32 metallic_map = load_texture("../../data/textures/pbr/metallic.png"); + U32 roughness_map = load_texture("../../data/textures/pbr/roughness.png"); + U32 ao_map = load_texture("../../data/textures/pbr/ao.png"); + + /* framebuffers */ + U32 hdr_fbo, hdr_colorbuffer, hdr_rbo; + glGenFramebuffers(1, &hdr_fbo); + glGenTextures(1, &hdr_colorbuffer); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, state.width, state.height, 0, GL_RGBA, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glGenRenderbuffers(1, &hdr_rbo); + glBindRenderbuffer(GL_RENDERBUFFER, hdr_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, state.width, state.height); + glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdr_colorbuffer, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdr_rbo); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + die("failed to create framebuffer"); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + F32 time = 0; + + while (!glfwWindowShouldClose(state.window)) { + handle_glfw_events(state.window, &state.input); + F32 dt = lock_framerate(60); + fps_info(dt, 10); + + /* update */ + update_camera_first_person(&state.camera, &state.input, dt, 2.0f); + F32 limit = 4.0f; + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) + lights[i].position.y = sinf(2.0f * time + i) * limit; + time += dt; + + /* render */ + F32 ar = (F32)state.width / (F32)state.height; + MAT4 projection = camera_persp(state.camera, ar); + MAT4 view = get_view_matrix(&state.camera); + + glClearColor(0.16f, 0.16f, 0.16f, 1.0f); + + glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + shader = find_shader("pbr"); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, color_map); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, normal_map); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, metallic_map); + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, roughness_map); + glActiveTexture(GL_TEXTURE4); + glBindTexture(GL_TEXTURE_2D, ao_map); + + if (!shader) die("wha"); + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", projection); + shader_set_mat4fv(shader, "view", view); + shader_set_3fv(shader, "camera", state.camera.pos); + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { + char str[512]; + snprintf(str, 512, "lights[%d].position", i); + shader_set_3fv(shader, str, lights[i].position); + snprintf(str, 512, "lights[%d].color", i); + shader_set_3fv(shader, str, lights[i].color); + } + S32 rows = 7; + S32 cols = 7; + F32 offset = 3.0f; + for (S32 row = 0; row < rows; row++) { + for (S32 col = 0; col < cols; col++) { + V3F pos = {(col - cols / 2.0f) * offset, (row - rows / 2.0f) * offset, 0.0f}; + MAT4 model = mat4_make_translate(pos); + shader_set_mat4fv(shader, "model", model); + mesh_draw(cube); + } + } + + for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) { + MAT4 model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); + model = mat4_translate(model, lights[i].position); + shader_set_mat4fv(shader, "model", model); + mesh_draw(sphere); + } + + glUseProgram(0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + shader = find_shader("hdr"); + if (!shader) die("!"); + glUseProgram(shader); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer); + shader_set_mat4fv(shader, "model", mat4_identity()); + mesh_draw(quad); + glUseProgram(0); + + glfwSwapBuffers(state.window); + } + + return 0; +} -- cgit v1.2.3-70-g09d2