summaryrefslogtreecommitdiff
path: root/advanced_lighting/9.ssao
diff options
context:
space:
mode:
authorpryazha <pryadeiniv@mail.ru>2025-07-15 16:15:26 +0500
committerpryazha <pryadeiniv@mail.ru>2025-07-15 16:15:26 +0500
commit6f9ab1f55fd54beab7f0999a69b80ef92fe63722 (patch)
treed75178447d4b81d60c06fa223fe9b7c193a25a51 /advanced_lighting/9.ssao
parent9d944f26d359e4bc1ffd8e44350b0df9f0935b18 (diff)
finish ssao
Diffstat (limited to 'advanced_lighting/9.ssao')
-rw-r--r--advanced_lighting/9.ssao/blur.frag22
-rwxr-xr-xadvanced_lighting/9.ssao/build.sh (renamed from advanced_lighting/9.ssao/build)0
-rw-r--r--advanced_lighting/9.ssao/deferred.frag4
-rw-r--r--advanced_lighting/9.ssao/gbuffer.frag4
-rwxr-xr-xadvanced_lighting/9.ssao/ssaobin1291232 -> 399776 bytes
-rw-r--r--advanced_lighting/9.ssao/ssao.c649
-rw-r--r--advanced_lighting/9.ssao/ssao.frag6
-rw-r--r--advanced_lighting/9.ssao/ssao.vert4
8 files changed, 363 insertions, 326 deletions
diff --git a/advanced_lighting/9.ssao/blur.frag b/advanced_lighting/9.ssao/blur.frag
new file mode 100644
index 0000000..dea23e8
--- /dev/null
+++ b/advanced_lighting/9.ssao/blur.frag
@@ -0,0 +1,22 @@
+#version 330 core
+
+in vert_t {
+ vec2 tex_coords;
+} vert;
+
+out float frag_color;
+
+uniform sampler2D ssao;
+
+void main()
+{
+ vec2 texel_size = 1.0 / vec2(textureSize(ssao, 0));
+ float result = 0.0;
+ for (int x = -2; x < 2; x++) {
+ for (int y = -2; y < 2; y++) {
+ vec2 offset = vec2(float(x), float(y)) * texel_size;
+ result += texture(ssao, vert.tex_coords + offset).r;
+ }
+ }
+ frag_color = result / (4.0 * 4.0);
+}
diff --git a/advanced_lighting/9.ssao/build b/advanced_lighting/9.ssao/build.sh
index dc6929a..dc6929a 100755
--- a/advanced_lighting/9.ssao/build
+++ b/advanced_lighting/9.ssao/build.sh
diff --git a/advanced_lighting/9.ssao/deferred.frag b/advanced_lighting/9.ssao/deferred.frag
index 5a3cc33..3e9f740 100644
--- a/advanced_lighting/9.ssao/deferred.frag
+++ b/advanced_lighting/9.ssao/deferred.frag
@@ -8,7 +8,7 @@ out vec4 frag_color;
uniform sampler2D positions;
uniform sampler2D normals;
-uniform sampler2D albedo;
+uniform sampler2D colors;
uniform sampler2D ssao;
uniform vec3 view_position;
@@ -27,7 +27,7 @@ void main()
{
vec3 position = texture(positions, vert.tex_coords).xyz;
vec3 normal = texture(normals, vert.tex_coords).xyz;
- vec3 color = texture(albedo, vert.tex_coords).rgb;
+ vec3 color = texture(colors, vert.tex_coords).rgb;
float occlusion = texture(ssao, vert.tex_coords).r;
vec3 ambient = 0.1 * color * occlusion;
diff --git a/advanced_lighting/9.ssao/gbuffer.frag b/advanced_lighting/9.ssao/gbuffer.frag
index 7755107..fd90740 100644
--- a/advanced_lighting/9.ssao/gbuffer.frag
+++ b/advanced_lighting/9.ssao/gbuffer.frag
@@ -7,11 +7,11 @@ in vert_t {
layout(location = 0) out vec3 position;
layout(location = 1) out vec3 normal;
-layout(location = 2) out vec3 albedo;
+layout(location = 2) out vec3 color;
void main()
{
position = vert.position;
normal = normalize(vert.normal);
- albedo.rgb = vec3(0.95);
+ color.rgb = vec3(0.95);
}
diff --git a/advanced_lighting/9.ssao/ssao b/advanced_lighting/9.ssao/ssao
index 72a9677..2d72697 100755
--- a/advanced_lighting/9.ssao/ssao
+++ b/advanced_lighting/9.ssao/ssao
Binary files differ
diff --git a/advanced_lighting/9.ssao/ssao.c b/advanced_lighting/9.ssao/ssao.c
index 3cfca03..5c592f7 100644
--- a/advanced_lighting/9.ssao/ssao.c
+++ b/advanced_lighting/9.ssao/ssao.c
@@ -12,320 +12,337 @@
int main(void)
{
- // glfw init
- glfwSetErrorCallback(error_callback);
- if (glfwInit() == GLFW_FALSE)
- return 1;
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
- glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
- S32 width = 1600;
- S32 height = 900;
- GLFWwindow *window = glfwCreateWindow(width, height, "ssao", 0, 0);
- if (!window)
- return 1;
- glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
- glfwMakeContextCurrent(window);
- if (glewInit() != GLEW_OK)
- return 1;
- glEnable(GL_DEPTH_TEST);
-
- // program init
- Arena *arena = arena_alloc(Kilobytes(256));
- Input input = input_init();
- Camera camera = {
- .pos = v3f(0.0f, 2.0f, 5.0f),
- .fovx = 90.0f,
- .near = 0.1f,
- .far = 100.0f,
- .yaw = 0.0f,
- .pitch = 0.0f
- };
- V3F camera_dp = {0};
- light_t light = {{2.0f, 2.0f, 2.0f}, {5.0f, 5.0f, 10.0f}};
-
- // meshes
- Mesh *quad = mesh_gen_quad(arena);
- Mesh *cube = mesh_load_obj(arena, "../../data/models/cube.obj");
-
- // framebuffers
- U32 gbuffer;
- glGenFramebuffers(1, &gbuffer);
- glBindFramebuffer(GL_FRAMEBUFFER, gbuffer);
-
- U32 gpositions;
- glGenTextures(1, &gpositions);
- glBindTexture(GL_TEXTURE_2D, gpositions);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gpositions, 0);
-
- U32 gnormals;
- glGenTextures(1, &gnormals);
- glBindTexture(GL_TEXTURE_2D, gnormals);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gnormals, 0);
-
- U32 galbedo;
- glGenTextures(1, &galbedo);
- glBindTexture(GL_TEXTURE_2D, galbedo);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, galbedo, 0);
- U32 attachments[3] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
- glDrawBuffers(3, attachments);
-
- U32 rbo;
- glGenRenderbuffers(1, &rbo);
- glBindRenderbuffer(GL_RENDERBUFFER, rbo);
- glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
-
- if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
- fprintf(stderr, "error: gbuffer not complete\n");
- fprintf(stdout, "info: gbuffer complete\n");
-
- // shaders
- U32 shader_gbuffer = load_shader("gbuffer.vert", "gbuffer.frag");
- U32 shader_ssao = load_shader("ssao.vert", "ssao.frag");
- U32 shader_deferred = load_shader("deferred.vert", "deferred.frag");
- U32 shader_screen = load_shader("screen.vert", "screen.frag");
- U32 shader_occlusion = load_shader("screen.vert", "occlusion.frag");
-
- glUseProgram(shader_ssao);
- shader_set_1i(shader_ssao, "positions", 0);
- shader_set_1i(shader_ssao, "normals", 1);
- shader_set_1i(shader_ssao, "noise", 2);
- glUseProgram(shader_deferred);
- shader_set_1i(shader_deferred, "positions", 0);
- shader_set_1i(shader_deferred, "normals", 1);
- shader_set_1i(shader_deferred, "albedo", 2);
- shader_set_1i(shader_deferred, "ssao", 3);
- glUseProgram(0);
-
- S32 show_gbuffer = 0;
-
- S32 nsamples = 64;
- V3F *samples = malloc(nsamples * sizeof(V3F));
- S32 file = open("/dev/urandom", O_RDONLY);
- if (file < 0) {
- perror("error:");
- return 1;
- }
- U32 seed[4];
- if (read(file, seed, sizeof(seed)) < 0) {
- perror("error");
- return 1;
- }
- for (S32 i = 0; i < nsamples; i++) {
- V3F sample = {
- nextf(seed) * 2.0f - 1.0f,
- nextf(seed) * 2.0f - 1.0f,
- nextf(seed)
- };
- sample = v3f_norm(sample);
- float scale = (F32)i / 64.0f;
- scale = lerp(0.1f, 1.0f, scale * scale);
- sample = v3f_scalef(sample, scale);
- samples[i] = sample;
- assert(-1.0f < sample.x && sample.x < 1.0f);
- assert(-1.0f < sample.y && sample.y < 1.0f);
- assert(0.0f < sample.z && sample.z < 1.0f);
- // printf("color:\t%f\t%f\t%f\n", sample.x, sample.y, sample.z);
- }
- V3F noise[16];
- for (S32 i = 0; i < 16; i++) {
- noise[i] = (V3F){
- nextf(seed) * 2.0f - 1.0f,
- nextf(seed) * 2.0f - 1.0f,
- 0.0f,
- };
- }
- close(file);
-
- U32 noise_texture;
- glGenTextures(1, &noise_texture);
- glBindTexture(GL_TEXTURE_2D, noise_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 4, 4, 0, GL_RGB, GL_FLOAT, noise);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glBindTexture(GL_TEXTURE_2D, 0);
-
- U32 ssao_fbo;
- glGenFramebuffers(1, &ssao_fbo);
- glBindFramebuffer(GL_FRAMEBUFFER, ssao_fbo);
- U32 ssao_colorbuffer;
- glGenTextures(1, &ssao_colorbuffer);
- glBindTexture(GL_TEXTURE_2D, ssao_colorbuffer);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_FLOAT, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssao_colorbuffer, 0);
- glBindTexture(GL_TEXTURE_2D, 0);
-
- F64 last_time = glfwGetTime();
- while (!glfwWindowShouldClose(window)) {
- F64 time = glfwGetTime();
- F32 dt = time - last_time;
- last_time = time;
-
- input_update_last_state(&input);
-
- glfwPollEvents();
- glfwGetFramebufferSize(window, &width, &height);
- process_glfw_keyboard(window, &input);
- process_glfw_mouse_pos(window, &input);
-
- if (key_first_press(input.exit))
- glfwSetWindowShouldClose(window, GLFW_TRUE);
-
- F32 speed = 2.0f;
- V3F dv = get_dv_camera_first_person(&input, &camera, speed, dt);
- camera_dp = v3f_add(camera_dp, dv);
- camera_dp = v3f_scalef(camera_dp, 0.8f);
- camera.pos = v3f_add(camera.pos, camera_dp);
-
- F32 sensitivity = 0.1f;
- input.mouse_offset = v2f_scalef(input.mouse_offset, sensitivity);
- camera.yaw += input.mouse_offset.x;
- camera.pitch += input.mouse_offset.y;
- if (camera.pitch > 89.0f)
- camera.pitch = 89.0f;
- if (camera.pitch < -89.0f)
- camera.pitch = -89.0f;
-
- // update
- if (key_first_press(input.jump))
- show_gbuffer = !show_gbuffer;
-
- // render
- F32 ar = (F32)width / (F32)height;
- MAT4 projection = camera_persp(camera, ar);
- MAT4 view = get_view_matrix(&camera);
-
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- // render stuff into gbuffer
- glBindFramebuffer(GL_FRAMEBUFFER, gbuffer);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- glUseProgram(shader_gbuffer);
-
- shader_set_mat4fv(shader_gbuffer, "projection", projection);
- shader_set_mat4fv(shader_gbuffer, "view", view);
-
- shader_set_mat4fv(shader_gbuffer, "model", mat4_identity());
- mesh_draw(cube);
-
- MAT4 model = mat4_make_scale(v3f(10.0f, 0.2f, 10.0f));
- model = mat4_translate(model, v3f(0.0f, -1.25f, 0.0f));
- shader_set_mat4fv(shader_gbuffer, "model", model);
- mesh_draw(cube);
-
- glUseProgram(0);
-
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
- // render ssao texture
- glBindFramebuffer(GL_FRAMEBUFFER, ssao_fbo);
- glClear(GL_COLOR_BUFFER_BIT);
-
- glUseProgram(shader_ssao);
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, gpositions);
-
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, gnormals);
-
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_2D, noise_texture);
-
- for (S32 i = 0; i < nsamples; i++) {
-
- char str[512] = {0};
- snprintf(str, 512, "samples[%d]", i);
- shader_set_3fv(shader_ssao, str, samples[i]);
- }
- shader_set_mat4fv(shader_ssao, "projection", projection);
-
- mesh_draw(quad);
-
- glUseProgram(0);
-
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
- if (show_gbuffer) {
- MAT4 scale = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f));
- MAT4 leftup = mat4_translate(scale, v3f(-0.5f, 0.5f, 0.0f));
- MAT4 rightup = mat4_translate(scale, v3f(0.5f, 0.5f, 0.0f));
- MAT4 leftdown = mat4_translate(scale, v3f(-0.5f, -0.5f, 0.0f));
- MAT4 rightdown = mat4_translate(scale, v3f(0.5f, -0.5f, 0.0f));
-
- glDisable(GL_DEPTH_TEST);
-
- glUseProgram(shader_screen);
- shader_set_mat4fv(shader_screen, "model", leftup);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, gpositions);
- mesh_draw(quad);
-
- shader_set_mat4fv(shader_screen, "model", rightup);
- glBindTexture(GL_TEXTURE_2D, gnormals);
- mesh_draw(quad);
-
- shader_set_mat4fv(shader_screen, "model", leftdown);
- glBindTexture(GL_TEXTURE_2D, galbedo);
- mesh_draw(quad);
- glUseProgram(0);
-
- glUseProgram(shader_occlusion);
- shader_set_mat4fv(shader_occlusion, "model", rightdown);
- glBindTexture(GL_TEXTURE_2D, ssao_colorbuffer);
- mesh_draw(quad);
- glUseProgram(0);
-
- glEnable(GL_DEPTH_TEST);
- } else {
- // render scene lighting
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- glUseProgram(shader_deferred);
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, gpositions);
-
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, gnormals);
-
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_2D, galbedo);
-
- glActiveTexture(GL_TEXTURE3);
- glBindTexture(GL_TEXTURE_2D, ssao_colorbuffer);
-
- V4F light_pos_v4 = v4f(light.position.x, light.position.y, light.position.z, 1.0f);
- V4F light_view_pos = mat4_v4f_mul(view, light_pos_v4);
- shader_set_3fv(shader_deferred, "light.position", v3f_from_v4f(light_view_pos));
- shader_set_3fv(shader_deferred, "light.color", light.color);
- shader_set_mat4fv(shader_deferred, "model", mat4_identity());
-
- mesh_draw(quad);
-
- glUseProgram(0);
- }
-
- glfwSwapBuffers(window);
- }
-
- return 0;
+ // glfw init
+ glfwSetErrorCallback(error_callback);
+ if (glfwInit() == GLFW_FALSE)
+ return 1;
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+ glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
+ S32 width = 1600;
+ S32 height = 900;
+ GLFWwindow *window = glfwCreateWindow(width, height, "ssao", 0, 0);
+ if (!window)
+ return 1;
+ glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+ glfwMakeContextCurrent(window);
+ if (glewInit() != GLEW_OK)
+ return 1;
+ glEnable(GL_DEPTH_TEST);
+
+ // program init
+ Arena *arena = arena_alloc(Kilobytes(256));
+ Input input = input_init();
+ Camera camera = {
+ .pos = v3f(0.0f, 2.0f, 5.0f),
+ .fovx = 90.0f,
+ .near = 0.1f,
+ .far = 100.0f,
+ .yaw = 0.0f,
+ .pitch = 0.0f
+ };
+ light_t light = {{2.0f, 2.0f, 2.0f}, {10.0f, 10.0f, 15.0f}};
+
+ // meshes
+ Mesh *quad = mesh_gen_quad(arena);
+ Mesh *cube = mesh_load_obj(arena, "../../data/models/cube.obj");
+
+ // shaders
+ U32 shader_gbuffer = load_shader("gbuffer.vert", "gbuffer.frag");
+ U32 shader_ssao = load_shader("ssao.vert", "ssao.frag");
+ U32 shader_ssao_blur = load_shader("ssao.vert", "blur.frag");
+ U32 shader_deferred = load_shader("deferred.vert", "deferred.frag");
+ U32 shader_screen = load_shader("screen.vert", "screen.frag");
+ U32 shader_occlusion = load_shader("screen.vert", "occlusion.frag");
+
+ glUseProgram(shader_ssao);
+ shader_set_1i(shader_ssao, "positions", 0);
+ shader_set_1i(shader_ssao, "normals", 1);
+ shader_set_1i(shader_ssao, "noise", 2);
+ glUseProgram(shader_deferred);
+ shader_set_1i(shader_deferred, "positions", 0);
+ shader_set_1i(shader_deferred, "normals", 1);
+ shader_set_1i(shader_deferred, "colors", 2);
+ shader_set_1i(shader_deferred, "ssao", 3);
+ glUseProgram(shader_ssao_blur);
+ shader_set_1i(shader_ssao_blur, "ssao", 0);
+ glUseProgram(0);
+
+ // framebuffers
+ U32 gbuffer;
+ glGenFramebuffers(1, &gbuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, gbuffer);
+
+ U32 gpositions, gnormals, gcolors, rbo;
+
+ glGenTextures(1, &gpositions);
+ glBindTexture(GL_TEXTURE_2D, gpositions);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gpositions, 0);
+
+ glGenTextures(1, &gnormals);
+ glBindTexture(GL_TEXTURE_2D, gnormals);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gnormals, 0);
+
+ glGenTextures(1, &gcolors);
+ glBindTexture(GL_TEXTURE_2D, gcolors);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gcolors, 0);
+
+ U32 attachments[3] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
+ glDrawBuffers(3, attachments);
+
+ glGenRenderbuffers(1, &rbo);
+ glBindRenderbuffer(GL_RENDERBUFFER, rbo);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
+
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ fprintf(stderr, "error: gbuffer not complete\n");
+ fprintf(stdout, "info: gbuffer complete\n");
+
+ S32 show_gbuffer = 0;
+
+ S32 nsamples = 64;
+ V3F *samples = malloc(nsamples * sizeof(V3F));
+ S32 file = open("/dev/urandom", O_RDONLY);
+ if (file < 0) {
+ perror("error:");
+ return 1;
+ }
+ U32 seed[4];
+ if (read(file, seed, sizeof(seed)) < 0) {
+ perror("error");
+ return 1;
+ }
+ close(file);
+ for (S32 i = 0; i < nsamples; i++) {
+ V3F sample = {
+ nextf(seed) * 2.0f - 1.0f,
+ nextf(seed) * 2.0f - 1.0f,
+ nextf(seed)
+ };
+ sample = v3f_norm(sample);
+ float scale = (F32)i / 64.0f;
+ scale = lerp(0.1f, 1.0f, scale * scale);
+ sample = v3f_scalef(sample, scale);
+ samples[i] = sample;
+ assert(-1.0f < sample.x && sample.x < 1.0f);
+ assert(-1.0f < sample.y && sample.y < 1.0f);
+ assert(0.0f < sample.z && sample.z < 1.0f);
+ // printf("color:\t%f\t%f\t%f\n", sample.x, sample.y, sample.z);
+ }
+ V3F noise[16];
+ for (S32 i = 0; i < 16; i++) {
+ noise[i] = (V3F){
+ nextf(seed) * 2.0f - 1.0f,
+ nextf(seed) * 2.0f - 1.0f,
+ 0.0f,
+ };
+ }
+
+ U32 noise_texture;
+ glGenTextures(1, &noise_texture);
+ glBindTexture(GL_TEXTURE_2D, noise_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 4, 4, 0, GL_RGB, GL_FLOAT, noise);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ U32 ssao_fbo;
+ glGenFramebuffers(1, &ssao_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, ssao_fbo);
+ U32 ssao_colorbuffer;
+ glGenTextures(1, &ssao_colorbuffer);
+ glBindTexture(GL_TEXTURE_2D, ssao_colorbuffer);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_FLOAT, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssao_colorbuffer, 0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ U32 ssao_blur_fbo, ssao_blur_colorbuffer;
+ glGenFramebuffers(1, &ssao_blur_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, ssao_blur_fbo);
+ glGenTextures(1, &ssao_blur_colorbuffer);
+ glBindTexture(GL_TEXTURE_2D, ssao_blur_colorbuffer);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_FLOAT, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssao_blur_colorbuffer, 0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ F64 last_time = glfwGetTime();
+ while (!glfwWindowShouldClose(window)) {
+ F64 time = glfwGetTime();
+ F32 dt = time - last_time;
+ last_time = time;
+
+ input_update_last_state(&input);
+
+ glfwPollEvents();
+ glfwGetFramebufferSize(window, &width, &height);
+ process_glfw_keyboard(window, &input);
+ process_glfw_mouse_pos(window, &input);
+
+ if (key_first_press(input.exit))
+ glfwSetWindowShouldClose(window, GLFW_TRUE);
+
+ F32 speed = 2.0f;
+ V3F dv = get_dv_camera_first_person(&input, &camera, speed, dt);
+ V3F camera_dp = v3f_add(camera_dp, dv);
+ camera_dp = v3f_scalef(camera_dp, 0.8f);
+ camera.pos = v3f_add(camera.pos, camera_dp);
+
+ F32 sensitivity = 0.1f;
+ input.mouse_offset = v2f_scalef(input.mouse_offset, sensitivity);
+ camera.yaw += input.mouse_offset.x;
+ camera.pitch += input.mouse_offset.y;
+ if (camera.pitch > 89.0f)
+ camera.pitch = 89.0f;
+ if (camera.pitch < -89.0f)
+ camera.pitch = -89.0f;
+
+ // update
+ if (key_first_press(input.jump))
+ show_gbuffer = !show_gbuffer;
+
+ F32 radius = 3.0f;
+ light.position = v3f(cos(time) * radius, light.position.y, -sin(time) * radius);
+
+ // render
+ F32 ar = (F32)width / (F32)height;
+ MAT4 projection = camera_persp(camera, ar);
+ MAT4 view = get_view_matrix(&camera);
+
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // render stuff into gbuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, gbuffer);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glUseProgram(shader_gbuffer);
+ shader_set_mat4fv(shader_gbuffer, "projection", projection);
+ shader_set_mat4fv(shader_gbuffer, "view", view);
+ shader_set_mat4fv(shader_gbuffer, "model", mat4_identity());
+ mesh_draw(cube);
+ MAT4 model = mat4_make_scale(v3f(10.0f, 0.2f, 10.0f));
+ model = mat4_translate(model, v3f(0.0f, -1.25f, 0.0f));
+ shader_set_mat4fv(shader_gbuffer, "model", model);
+ mesh_draw(cube);
+ glUseProgram(0);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // render ssao texture
+ glBindFramebuffer(GL_FRAMEBUFFER, ssao_fbo);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glUseProgram(shader_ssao);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, gpositions);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, gnormals);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, noise_texture);
+
+ for (S32 i = 0; i < nsamples; i++) {
+ char str[512] = {0};
+ snprintf(str, 512, "samples[%d]", i);
+ shader_set_3fv(shader_ssao, str, samples[i]);
+ }
+ shader_set_mat4fv(shader_ssao, "projection", projection);
+ mesh_draw(quad);
+
+ glUseProgram(0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, ssao_blur_fbo);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glUseProgram(shader_ssao_blur);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, ssao_colorbuffer);
+ mesh_draw(quad);
+ glUseProgram(0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ if (show_gbuffer) {
+ MAT4 scale = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f));
+ MAT4 leftup = mat4_translate(scale, v3f(-0.5f, 0.5f, 0.0f));
+ MAT4 rightup = mat4_translate(scale, v3f(0.5f, 0.5f, 0.0f));
+ MAT4 leftdown = mat4_translate(scale, v3f(-0.5f, -0.5f, 0.0f));
+ MAT4 rightdown = mat4_translate(scale, v3f(0.5f, -0.5f, 0.0f));
+
+ glDisable(GL_DEPTH_TEST);
+
+ glUseProgram(shader_screen);
+ shader_set_mat4fv(shader_screen, "model", leftup);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, gpositions);
+ mesh_draw(quad);
+
+ shader_set_mat4fv(shader_screen, "model", rightup);
+ glBindTexture(GL_TEXTURE_2D, gnormals);
+ mesh_draw(quad);
+
+ shader_set_mat4fv(shader_screen, "model", leftdown);
+ glBindTexture(GL_TEXTURE_2D, gcolors);
+ mesh_draw(quad);
+ glUseProgram(0);
+
+ glUseProgram(shader_occlusion);
+ shader_set_mat4fv(shader_occlusion, "model", rightdown);
+ glBindTexture(GL_TEXTURE_2D, ssao_blur_colorbuffer);
+ mesh_draw(quad);
+ glUseProgram(0);
+
+ glEnable(GL_DEPTH_TEST);
+ } else {
+ // render scene lighting
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glUseProgram(shader_deferred);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, gpositions);
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, gnormals);
+
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, gcolors);
+
+ glActiveTexture(GL_TEXTURE3);
+ glBindTexture(GL_TEXTURE_2D, ssao_blur_colorbuffer);
+
+ V4F light_pos_v4 = v4f(light.position.x, light.position.y, light.position.z, 1.0f);
+ V4F light_view_pos = mat4_v4f_mul(view, light_pos_v4);
+ shader_set_3fv(shader_deferred, "light.position", v3f_from_v4f(light_view_pos));
+ shader_set_3fv(shader_deferred, "light.color", light.color);
+ shader_set_mat4fv(shader_deferred, "model", mat4_identity());
+
+ mesh_draw(quad);
+
+ glUseProgram(0);
+ }
+
+ glfwSwapBuffers(window);
+ }
+
+ return 0;
}
diff --git a/advanced_lighting/9.ssao/ssao.frag b/advanced_lighting/9.ssao/ssao.frag
index e4d04b1..dd03754 100644
--- a/advanced_lighting/9.ssao/ssao.frag
+++ b/advanced_lighting/9.ssao/ssao.frag
@@ -13,7 +13,7 @@ uniform sampler2D noise;
uniform vec3 samples[64];
uniform mat4 projection;
-const vec2 noise_scale = vec2(1600.0 / 4.0, 900.0 / 4.0)
+const vec2 noise_scale = vec2(1600.0 / 4.0, 900.0 / 4.0);
void main()
{
@@ -37,8 +37,8 @@ void main()
offset.xyz /= offset.w;
offset.xyz = offset.xyz * 0.5 + 0.5;
float depth = texture(positions, offset.xy).z;
- // float range_check = smoothstep(0.0, 1.0, radius / abs(position.z - depth));
- occlusion += (depth >= sample.z + bias ? 1.0 : 0.0); // * range_check;
+ float range_check = smoothstep(0.0, 1.0, radius / abs(position.z - depth));
+ occlusion += (depth >= sample.z + bias ? 1.0 : 0.0) * range_check;
}
occlusion = 1.0 - (occlusion / nsamples);
frag_color = occlusion;
diff --git a/advanced_lighting/9.ssao/ssao.vert b/advanced_lighting/9.ssao/ssao.vert
index 3ce6fb2..eed3be3 100644
--- a/advanced_lighting/9.ssao/ssao.vert
+++ b/advanced_lighting/9.ssao/ssao.vert
@@ -7,10 +7,8 @@ out vert_t {
vec2 tex_coords;
} vert;
-uniform mat4 model;
-
void main()
{
vert.tex_coords = tex_coords;
- gl_Position = model * vec4(position, 1.0);
+ gl_Position = vec4(position, 1.0);
}