summaryrefslogtreecommitdiff
path: root/advanced_lighting/8.deferred_shading
diff options
context:
space:
mode:
Diffstat (limited to 'advanced_lighting/8.deferred_shading')
-rwxr-xr-xadvanced_lighting/8.deferred_shading/build5
-rw-r--r--advanced_lighting/8.deferred_shading/deferred.c274
-rw-r--r--advanced_lighting/8.deferred_shading/shaders/deferred.frag46
-rw-r--r--advanced_lighting/8.deferred_shading/shaders/gbuffer.frag23
-rw-r--r--advanced_lighting/8.deferred_shading/shaders/gbuffer.vert24
-rw-r--r--advanced_lighting/8.deferred_shading/shaders/light.frag11
-rw-r--r--advanced_lighting/8.deferred_shading/shaders/light.vert12
-rw-r--r--advanced_lighting/8.deferred_shading/shaders/screen.frag14
-rw-r--r--advanced_lighting/8.deferred_shading/shaders/screen.vert16
-rw-r--r--advanced_lighting/8.deferred_shading/shaders/specular.frag14
10 files changed, 439 insertions, 0 deletions
diff --git a/advanced_lighting/8.deferred_shading/build b/advanced_lighting/8.deferred_shading/build
new file mode 100755
index 0000000..fc81382
--- /dev/null
+++ b/advanced_lighting/8.deferred_shading/build
@@ -0,0 +1,5 @@
+#!/bin/sh
+. ../../config
+TARGET='deferred'
+set -x
+gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS
diff --git a/advanced_lighting/8.deferred_shading/deferred.c b/advanced_lighting/8.deferred_shading/deferred.c
new file mode 100644
index 0000000..d411b41
--- /dev/null
+++ b/advanced_lighting/8.deferred_shading/deferred.c
@@ -0,0 +1,274 @@
+#include "GL/glew.h"
+#include "GLFW/glfw3.h"
+
+#include "pwyazh.h"
+#include "pwyazh_GL.h"
+
+#include "common.h"
+
+#define LIGHT_COUNT 200
+#define CUBE_COUNT 1000
+
+int main(void)
+{
+ /* NOTE(pryazha): 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, "deferred", 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);
+
+ /* NOTE(pryazha): Program init */
+ State state = {0};
+ state.arena = arena_alloc(Kilobytes(256));
+ state.input.first_mouse = 1;
+ state.camera = (Camera){ v3f(0.0f, 2.0f, 5.0f), 90.0f, 0.1f, 100.0f, 0.0f, 0.0f };
+
+ /* NOTE(pryazha): Textures */
+ U32 woood_texture = load_texture("../../data/textures/wood.png");
+
+ /* NOTE(pryazha): Meshes */
+ Mesh *quad = mesh_gen_quad(state.arena);
+ Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj");
+
+ /* NOTE(pryazha): Framebuffers */
+ U32 gbuffer;
+ glGenFramebuffers(1, &gbuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, gbuffer);
+
+ // position color buffer
+ 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);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gpositions, 0);
+ // normal
+ 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);
+ // color + specular
+ U32 gcolor_specular;
+ glGenTextures(1, &gcolor_specular);
+ glBindTexture(GL_TEXTURE_2D, gcolor_specular);
+ 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, gcolor_specular, 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");
+
+ /* NOTE(pryazha): Shaders */
+ U32 shader_gbuffer = load_shader("shaders/gbuffer.vert", "shaders/gbuffer.frag");
+ U32 shader_screen = load_shader("shaders/screen.vert", "shaders/screen.frag");
+ U32 shader_specular = load_shader("shaders/screen.vert", "shaders/specular.frag");
+ U32 shader_deferred = load_shader("shaders/screen.vert", "shaders/deferred.frag");
+ U32 shader_light = load_shader("shaders/light.vert", "shaders/light.frag");
+
+ glUseProgram(shader_deferred);
+ shader_set_1i(shader_deferred, "positions", 0);
+ shader_set_1i(shader_deferred, "normals", 1);
+ shader_set_1i(shader_deferred, "color_specular", 2);
+ glUseProgram(0);
+
+ V3F cube_positions[CUBE_COUNT];
+ S32 cols = 30;
+ F32 spacing = 3.0f;
+ for (S32 i = 0; i < CUBE_COUNT; i++) {
+ S32 col = i % cols;
+ S32 row = i / cols;
+ cube_positions[i] = v3f(col * spacing, 0.0f, row * spacing);
+ }
+
+ light_t lights[LIGHT_COUNT];
+#if 0
+ V3F origin = {50.0f, 3.0f, 50.0f};
+ F32 da = 2.0f*pi_F32/LIGHT_COUNT;
+ F32 a = 0.0f;
+ F32 radius = 20.0f;
+ for (S32 i = 0; i < LIGHT_COUNT; i++, a += da) {
+ lights[i].position = v3f_add(v3f(f32_sin(a) * radius, 0.0f, f32_cos(a) * radius), origin);
+ F32 r = (F32)(rand() % 100) / 100.0f;
+ F32 g = (F32)(rand() % 100) / 100.0f;
+ F32 b = (F32)(rand() % 100) / 100.0f;
+ lights[i].color = v3f(r, g, b);
+ }
+#else
+ V3F origin = {0.0f, 3.0f, 0.0f};
+ cols = 30;
+ spacing = 3.0f;
+ for (S32 i = 0; i < LIGHT_COUNT; i++) {
+ S32 col = i % cols;
+ S32 row = i / cols;
+ lights[i].position = v3f_add(v3f(col * spacing, 0.0f, row * spacing), origin);
+ F32 r = (F32)(rand() % 100) / 100.0f;
+ F32 g = (F32)(rand() % 100) / 100.0f;
+ F32 b = (F32)(rand() % 100) / 100.0f;
+ lights[i].color = v3f(r, g, b);
+ }
+#endif
+
+ S32 show_gbuffer = 0;
+
+ F64 last_time = glfwGetTime();
+ while (!glfwWindowShouldClose(window)) {
+ F64 time = glfwGetTime();
+ state.dt = time - last_time;
+ last_time = time;
+
+ input_update_last_state(&state.input);
+
+ glfwPollEvents();
+ glfwGetFramebufferSize(window, &width, &height);
+ process_glfw_keyboard(window, &state.input);
+ process_glfw_mouse_pos(window, &state.input);
+
+ if (key_first_press(state.input.exit))
+ glfwSetWindowShouldClose(window, GLFW_TRUE);
+
+ F32 speed = 2.0f;
+ V3F dv = get_dv_camera_first_person(&state.input, &state.camera, speed, state.dt);
+ state.camera_dp = v3f_add(state.camera_dp, dv);
+ state.camera_dp = v3f_scalef(state.camera_dp, 0.8f);
+ state.camera.pos = v3f_add(state.camera.pos, state.camera_dp);
+
+ F32 sensitivity = 0.1f;
+ state.input.mouse_offset = v2f_scalef(state.input.mouse_offset, sensitivity);
+ state.camera.yaw += state.input.mouse_offset.x;
+ state.camera.pitch += state.input.mouse_offset.y;
+ if (state.camera.pitch > 89.0f)
+ state.camera.pitch = 89.0f;
+ if (state.camera.pitch < -89.0f)
+ state.camera.pitch = -89.0f;
+
+ /* NOTE(pryazha): Update */
+ for (S32 i = 0; i < LIGHT_COUNT; i++)
+ lights[i].position.y = origin.y + f32_sin(glfwGetTime() + i);
+
+ if (key_first_press(state.input.jump)) {
+ show_gbuffer = !show_gbuffer;
+ }
+
+ /* NOTE(pryazha): Render */
+ F32 ar = (F32)width/(F32)height;
+ MAT4 projection = camera_persp(state.camera, ar);
+ MAT4 view = get_view_matrix(&state.camera);
+
+ 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);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, woood_texture);
+
+ for (S32 i = 0; i < CUBE_COUNT; i++) {
+ MAT4 model = mat4_make_translate(cube_positions[i]);
+ shader_set_mat4fv(shader_gbuffer, "model", model);
+ mesh_draw(cube);
+ }
+
+ glUseProgram(0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if (show_gbuffer) {
+ glDisable(GL_DEPTH_TEST);
+ glUseProgram(shader_screen);
+ MAT4 model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f));
+ model = mat4_translate(model, v3f(-0.5f, 0.5f, 0.0f));
+ shader_set_mat4fv(shader_screen, "model", model);
+ glBindTexture(GL_TEXTURE_2D, gpositions);
+ mesh_draw(quad);
+
+ model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f));
+ model = mat4_translate(model, v3f(0.5f, 0.5f, 0.0f));
+ shader_set_mat4fv(shader_screen, "model", model);
+ glBindTexture(GL_TEXTURE_2D, gnormals);
+ mesh_draw(quad);
+
+ model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f));
+ model = mat4_translate(model, v3f(-0.5f, -0.5f, 0.0f));
+ shader_set_mat4fv(shader_screen, "model", model);
+ glBindTexture(GL_TEXTURE_2D, gcolor_specular);
+ mesh_draw(quad);
+ glUseProgram(0);
+
+ glUseProgram(shader_specular);
+ model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f));
+ model = mat4_translate(model, v3f(0.5f, -0.5f, 0.0f));
+ shader_set_mat4fv(shader_specular, "model", model);
+ glBindTexture(GL_TEXTURE_2D, gcolor_specular);
+ mesh_draw(quad);
+ glUseProgram(0);
+ glEnable(GL_DEPTH_TEST);
+ } else {
+ 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, gcolor_specular);
+ shader_set_3fv(shader_deferred, "view_position", state.camera.pos);
+ for (S32 i = 0; i < LIGHT_COUNT; i++) {
+ char light_string[512];
+ snprintf(light_string, 512, "lights[%d].position", i);
+ shader_set_3fv(shader_deferred, light_string, lights[i].position);
+ snprintf(light_string, 512, "lights[%d].color", i);
+ shader_set_3fv(shader_deferred, light_string, lights[i].color);
+ }
+ MAT4 model = mat4_identity();
+ shader_set_mat4fv(shader_deferred, "model", model);
+ mesh_draw(quad);
+ glUseProgram(0);
+ glEnable(GL_DEPTH_TEST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, gbuffer);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
+ GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ glUseProgram(shader_light);
+ shader_set_mat4fv(shader_light, "projection", projection);
+ shader_set_mat4fv(shader_light, "view", view);
+ for (S32 i = 0; i < LIGHT_COUNT; i++) {
+ shader_set_3fv(shader_light, "light_color", lights[i].color);
+ model = mat4_make_scale(v3f(0.2f, 0.2f, 0.2f));
+ model = mat4_translate(model, lights[i].position);
+ shader_set_mat4fv(shader_light, "model", model);
+ mesh_draw(cube);
+ }
+ glUseProgram(0);
+ }
+
+ glfwSwapBuffers(window);
+ }
+
+ return 0;
+}
diff --git a/advanced_lighting/8.deferred_shading/shaders/deferred.frag b/advanced_lighting/8.deferred_shading/shaders/deferred.frag
new file mode 100644
index 0000000..56e5f58
--- /dev/null
+++ b/advanced_lighting/8.deferred_shading/shaders/deferred.frag
@@ -0,0 +1,46 @@
+#version 330 core
+
+in vert_t {
+ vec2 tex_coords;
+} vert;
+
+out vec4 frag_color;
+
+uniform sampler2D positions;
+uniform sampler2D normals;
+uniform sampler2D color_specular;
+
+uniform vec3 view_position;
+
+struct light_t {
+ vec3 position;
+ vec3 color;
+};
+
+const int light_count = 200;
+uniform light_t lights[light_count];
+
+const float linear = 0.7f;
+const float quadratic = 1.8f;
+
+void main()
+{
+ vec3 position = texture(positions, vert.tex_coords).rgb;
+ vec3 normal = texture(normals, vert.tex_coords).rgb;
+ vec3 color = texture(color_specular, vert.tex_coords).rgb;
+ float specular = texture(color_specular, vert.tex_coords).a;
+
+ vec3 ambient = 0.1 * color;
+ vec3 view_dir = normalize(view_position - position);
+ vec3 result = ambient;
+ for (int i = 0; i < light_count; i++) {
+ vec3 light_dir = normalize(lights[i].position - position);
+ vec3 diffuse = max(dot(normal, light_dir), 0.0) * color * lights[i].color;
+ float distance = length(lights[i].position - position);
+ float attenuation = 1.0 / (1.0 + linear * distance + quadratic * distance * distance);
+ vec3 halfway_dir = normalize(view_dir + light_dir);
+ vec3 specular = pow(max(dot(halfway_dir, normal), 0.0), 32.0) * vec3(0.5);
+ result += (diffuse + specular) * attenuation;
+ }
+ frag_color = vec4(result, 1.0);
+}
diff --git a/advanced_lighting/8.deferred_shading/shaders/gbuffer.frag b/advanced_lighting/8.deferred_shading/shaders/gbuffer.frag
new file mode 100644
index 0000000..5f82c0b
--- /dev/null
+++ b/advanced_lighting/8.deferred_shading/shaders/gbuffer.frag
@@ -0,0 +1,23 @@
+#version 330 core
+
+in vert_t {
+ vec3 position;
+ vec3 normal;
+ vec2 tex_coords;
+} vert;
+
+layout (location = 0) out vec3 position;
+layout (location = 1) out vec3 normal;
+layout (location = 2) out vec4 color_specular;
+
+uniform sampler2D texture_diffuse;
+
+void main()
+{
+ position = vert.position;
+ normal = vert.normal;
+ color_specular.rgb = texture(texture_diffuse, vert.tex_coords).rgb;
+ // TODO(pryazha): add specular texture
+ // color_specular.a = texture(texture_specular, vert.tex_coords).r;
+ color_specular.a = 1;
+}
diff --git a/advanced_lighting/8.deferred_shading/shaders/gbuffer.vert b/advanced_lighting/8.deferred_shading/shaders/gbuffer.vert
new file mode 100644
index 0000000..1e825c8
--- /dev/null
+++ b/advanced_lighting/8.deferred_shading/shaders/gbuffer.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()
+{
+ vert.position = vec3(model * vec4(position, 1.0));
+ mat3 matrix_normal = transpose(inverse(mat3(model)));
+ vert.normal = matrix_normal * normal;
+ vert.tex_coords = tex_coords;
+ gl_Position = projection * view * model * vec4(position, 1.0);
+}
diff --git a/advanced_lighting/8.deferred_shading/shaders/light.frag b/advanced_lighting/8.deferred_shading/shaders/light.frag
new file mode 100644
index 0000000..e654b0e
--- /dev/null
+++ b/advanced_lighting/8.deferred_shading/shaders/light.frag
@@ -0,0 +1,11 @@
+#version 330 core
+
+out vec4 frag_color;
+
+uniform vec3 light_color;
+
+void main()
+{
+ frag_color = vec4(light_color, 1.0);
+}
+
diff --git a/advanced_lighting/8.deferred_shading/shaders/light.vert b/advanced_lighting/8.deferred_shading/shaders/light.vert
new file mode 100644
index 0000000..03ac7e2
--- /dev/null
+++ b/advanced_lighting/8.deferred_shading/shaders/light.vert
@@ -0,0 +1,12 @@
+#version 330 core
+
+layout(location = 0) in vec3 position;
+
+uniform mat4 projection;
+uniform mat4 view;
+uniform mat4 model;
+
+void main()
+{
+ gl_Position = projection * view * model * vec4(position, 1.0);
+}
diff --git a/advanced_lighting/8.deferred_shading/shaders/screen.frag b/advanced_lighting/8.deferred_shading/shaders/screen.frag
new file mode 100644
index 0000000..3ae592d
--- /dev/null
+++ b/advanced_lighting/8.deferred_shading/shaders/screen.frag
@@ -0,0 +1,14 @@
+#version 330 core
+
+in vert_t {
+ vec2 tex_coords;
+} vert;
+
+out vec4 frag_color;
+
+uniform sampler2D colorbuffer;
+
+void main()
+{
+ frag_color = vec4(texture(colorbuffer, vert.tex_coords).rgb, 1.0);
+}
diff --git a/advanced_lighting/8.deferred_shading/shaders/screen.vert b/advanced_lighting/8.deferred_shading/shaders/screen.vert
new file mode 100644
index 0000000..335635b
--- /dev/null
+++ b/advanced_lighting/8.deferred_shading/shaders/screen.vert
@@ -0,0 +1,16 @@
+#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()
+{
+ vert.tex_coords = tex_coords;
+ gl_Position = model * vec4(position, 1.0);
+}
diff --git a/advanced_lighting/8.deferred_shading/shaders/specular.frag b/advanced_lighting/8.deferred_shading/shaders/specular.frag
new file mode 100644
index 0000000..e6ea10e
--- /dev/null
+++ b/advanced_lighting/8.deferred_shading/shaders/specular.frag
@@ -0,0 +1,14 @@
+#version 330 core
+
+in vert_t {
+ vec2 tex_coords;
+} vert;
+
+out vec4 frag_color;
+
+uniform sampler2D colorbuffer;
+
+void main()
+{
+ frag_color = vec4(vec3(texture(colorbuffer, vert.tex_coords).a), 1.0);
+}