diff options
Diffstat (limited to 'advanced_lighting/8.deferred_shading')
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); +} |