diff options
Diffstat (limited to 'advanced_lighting')
49 files changed, 1796 insertions, 325 deletions
diff --git a/advanced_lighting/1.blinn_phong/blinn_phong.c b/advanced_lighting/1.blinn_phong/blinn_phong.c index 404df05..3974243 100644 --- a/advanced_lighting/1.blinn_phong/blinn_phong.c +++ b/advanced_lighting/1.blinn_phong/blinn_phong.c @@ -28,6 +28,7 @@ int main(void) glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); glfwWindowHint(GLFW_SAMPLES, 4); window = glfwCreateWindow(width, height, "Blinn-Phong shading", 0, 0); if (!window) @@ -60,8 +61,8 @@ int main(void) Mesh *quad = mesh_init(arena, vertices, 6, indices, 6); Mesh *cube = mesh_load_obj(arena, "../../data/models/cube.obj"); - U32 blinn_phong_shader = create_shader_program("shaders/blinn_phong.vert", "shaders/blinn_phong.frag"); - U32 light_shader = create_shader_program("shaders/light.vert", "shaders/light.frag"); + U32 blinn_phong_shader = load_shader("shaders/blinn_phong.vert", "shaders/blinn_phong.frag"); + U32 light_shader = load_shader("shaders/light.vert", "shaders/light.frag"); texture = load_texture("../../data/textures/wood.png"); diff --git a/advanced_lighting/1.blinn_phong/build.sh b/advanced_lighting/1.blinn_phong/build index 41fb831..41fb831 100755 --- a/advanced_lighting/1.blinn_phong/build.sh +++ b/advanced_lighting/1.blinn_phong/build diff --git a/advanced_lighting/2.gamma_correction/build.sh b/advanced_lighting/2.gamma_correction/build index 2b65776..2b65776 100755 --- a/advanced_lighting/2.gamma_correction/build.sh +++ b/advanced_lighting/2.gamma_correction/build diff --git a/advanced_lighting/2.gamma_correction/gamma_correction.c b/advanced_lighting/2.gamma_correction/gamma_correction.c index a027722..65d1d58 100644 --- a/advanced_lighting/2.gamma_correction/gamma_correction.c +++ b/advanced_lighting/2.gamma_correction/gamma_correction.c @@ -77,8 +77,8 @@ int main(void) Mesh *quad = mesh_init(arena, vertices, 6, indices, 6); Mesh *cube = mesh_load_obj(arena, "../../data/models/cube.obj"); - U32 blinn_phong_shader = create_shader_program("shaders/blinn_phong.vert", "shaders/blinn_phong.frag"); - U32 light_shader = create_shader_program("shaders/light.vert", "shaders/light.frag"); + U32 blinn_phong_shader = load_shader("shaders/blinn_phong.vert", "shaders/blinn_phong.frag"); + U32 light_shader = load_shader("shaders/light.vert", "shaders/light.frag"); U32 texture = load_texture_gamma("../../data/textures/wood.png", 0); U32 texture_gamma_corrected = load_texture_gamma("../../data/textures/wood.png", 1); diff --git a/advanced_lighting/3.1.shadow_mapping/build.sh b/advanced_lighting/3.1.shadow_mapping/build index bba445d..bba445d 100755 --- a/advanced_lighting/3.1.shadow_mapping/build.sh +++ b/advanced_lighting/3.1.shadow_mapping/build diff --git a/advanced_lighting/3.1.shadow_mapping/shadow_mapping.c b/advanced_lighting/3.1.shadow_mapping/shadow_mapping.c index fd03ed9..f691035 100644 --- a/advanced_lighting/3.1.shadow_mapping/shadow_mapping.c +++ b/advanced_lighting/3.1.shadow_mapping/shadow_mapping.c @@ -117,14 +117,10 @@ int main(void) glBindVertexArray(0); /* NOTE(pryazha): Shaders */ - U32 debug_quad_shader = create_shader_program("shaders/debug_quad.vert", - "shaders/debug_quad.frag"); - U32 simple_depth_shader = create_shader_program("shaders/simple_depth.vert", - "shaders/simple_depth.frag"); - U32 shadow_shader = create_shader_program("shaders/shadow.vert", - "shaders/shadow.frag"); - U32 color_shader = create_shader_program("shaders/color.vert", - "shaders/color.frag"); + U32 debug_quad_shader = load_shader("shaders/debug_quad.vert", "shaders/debug_quad.frag"); + U32 simple_depth_shader = load_shader("shaders/simple_depth.vert", "shaders/simple_depth.frag"); + U32 shadow_shader = load_shader("shaders/shadow.vert", "shaders/shadow.frag"); + U32 color_shader = load_shader("shaders/color.vert", "shaders/color.frag"); glUseProgram(shadow_shader); shader_set_1i(shadow_shader, "diffuse_texture", 0); diff --git a/advanced_lighting/3.2.point_shadows/build.sh b/advanced_lighting/3.2.point_shadows/build index bf934b6..bf934b6 100755 --- a/advanced_lighting/3.2.point_shadows/build.sh +++ b/advanced_lighting/3.2.point_shadows/build diff --git a/advanced_lighting/3.2.point_shadows/point_shadows.c b/advanced_lighting/3.2.point_shadows/point_shadows.c index e622f6c..8989bff 100644 --- a/advanced_lighting/3.2.point_shadows/point_shadows.c +++ b/advanced_lighting/3.2.point_shadows/point_shadows.c @@ -8,254 +8,247 @@ void render_scene(U32 shader, Mesh *cube) { - MAT4 model; - - model = mat4_identity(); - model = mat4_make_scale(v3f(5.0f, 5.0f, 5.0f)); - shader_set_mat4fv(shader, "model", model); - glDisable(GL_CULL_FACE); - shader_set_1i(shader, "reverse_normals", 1); - mesh_draw(cube); - shader_set_1i(shader, "reverse_normals", 0); - glEnable(GL_CULL_FACE); - - model = mat4_identity(); - model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); - model = mat4_translate(model, v3f(0.0f, 1.5f, 0.0f)); - shader_set_mat4fv(shader, "model", model); - mesh_draw(cube); - - model = mat4_identity(); - model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); - model = mat4_translate(model, v3f(2.0f, 0.0f, 1.0f)); - shader_set_mat4fv(shader, "model", model); - mesh_draw(cube); - - model = mat4_identity(); - model = mat4_make_scale(v3f(0.25f, 0.25f, 0.25f)); - model = mat4_rotate_angles(model, v3f(60.0f, 0.0f, 0.0f)); - model = mat4_translate(model, v3f(-1.0f, 0.0f, 2.0f)); - shader_set_mat4fv(shader, "model", model); - mesh_draw(cube); + MAT4 model; + + model = mat4_identity(); + model = mat4_make_scale(v3f(5.0f, 5.0f, 5.0f)); + shader_set_mat4fv(shader, "model", model); + glDisable(GL_CULL_FACE); + shader_set_1i(shader, "reverse_normals", 1); + mesh_draw(cube); + shader_set_1i(shader, "reverse_normals", 0); + glEnable(GL_CULL_FACE); + + model = mat4_identity(); + model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); + model = mat4_translate(model, v3f(0.0f, 1.5f, 0.0f)); + shader_set_mat4fv(shader, "model", model); + mesh_draw(cube); + + model = mat4_identity(); + model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); + model = mat4_translate(model, v3f(2.0f, 0.0f, 1.0f)); + shader_set_mat4fv(shader, "model", model); + mesh_draw(cube); + + model = mat4_identity(); + model = mat4_make_scale(v3f(0.25f, 0.25f, 0.25f)); + model = mat4_rotate_angles(model, v3f(60.0f, 0.0f, 0.0f)); + model = mat4_translate(model, v3f(-1.0f, 0.0f, 2.0f)); + shader_set_mat4fv(shader, "model", model); + mesh_draw(cube); } int main(void) { - GLFWwindow *window; - Arena *arena; - State state; - Input input; - F64 time, last_time; - V3F light_pos; - MAT4 shadow_transforms[6]; - MAT4 proj, view; - S32 screen_width, screen_height; - - glfwSetErrorCallback(error_callback); - - if (glfwInit() == GLFW_FALSE) - return(1); - - screen_width = 800; - screen_height = 600; - - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_SAMPLES, 4); - window = glfwCreateWindow(screen_width, screen_height, "Point shadows", 0, 0); - if (!window) - goto error; - - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - - glfwMakeContextCurrent(window); - - if (glewInit() != GLEW_OK) - goto error; - - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - - /* NOTE(pryazha): Init */ - arena = arena_alloc(Megabytes(64)); - - state.camera = (Camera){ - .pos = v3f(0.0f, 1.0f, 3.0f), - .fovx = 100.0f, - .near = 0.1f, - .far = 100.0f, - .yaw = 0.0f, - .pitch = 0.0f - }; - V3F camera_dp = v3f_zero(); - /* light_pos = v3f(-2.0f, 4.0f, -2.0f); */ - light_pos = v3f_zero(); - - /* NOTE(pryazha): Meshes */ - Mesh *cube = mesh_load_obj(arena, "../../data/models/cube.obj"); - - F32 quad_vertices[] = { - -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, - -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, - -1.0f, 1.0f, 0.0f, 0.0f, 1.0f - }; - U32 quad_vao, vbo; - glGenVertexArrays(1, &quad_vao); - glBindVertexArray(quad_vao); - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(quad_vertices), quad_vertices, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(F32), (void *)0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(F32), (void *)(3*sizeof(F32))); - glBindVertexArray(0); - - /* NOTE(pryazha): Shaders */ - U32 depth_shader = create_shader_program_geom("shaders/depth.vert", - "shaders/depth.frag", - "shaders/depth.geom"); - U32 shadow_shader = create_shader_program("shaders/shadow.vert", - "shaders/shadow.frag"); - - glUseProgram(shadow_shader); - shader_set_1i(shadow_shader, "diffuse_texture", 0); - shader_set_1i(shadow_shader, "depth_cubemap", 1); - glUseProgram(0); - - U32 wood_texture = load_texture_gamma("../../data/textures/wood.png", 0); - - /* NOTE(pryazha): Depth framebuffer init */ - U32 depth_cubemap_fbo, depth_cubemap; - U32 shadow_width = 1024, shadow_height = 1024; - glGenFramebuffers(1, &depth_cubemap_fbo); - glGenTextures(1, &depth_cubemap); - glBindTexture(GL_TEXTURE_CUBE_MAP, depth_cubemap); - for (U32 cubemap_side = 0; cubemap_side < 6; ++cubemap_side) - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+cubemap_side, 0, GL_DEPTH_COMPONENT, - shadow_width, shadow_height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); - glBindFramebuffer(GL_FRAMEBUFFER, depth_cubemap_fbo); - glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_cubemap, 0); - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - fprintf(stderr, "[ERROR]: Failed to complete depth map framebuffer.\n"); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - last_time = glfwGetTime(); - - while (!glfwWindowShouldClose(window)) { - glfwPollEvents(); - - /* NOTE(pryazha): For now it's easier to write all of the logic in the main loop */ - /* NOTE(pryazha): Update */ - F32 x, y, z, angular_speed, radius; - - glfwGetFramebufferSize(window, &screen_width, &screen_height); - process_glfw_keyboard(window, &input); - process_glfw_mouse_pos(window, &input); - - if (key_first_press(input.exit)) - glfwSetWindowShouldClose(window, GLFW_TRUE); - - F32 speed = 4.0f; - V3F dv = get_dv_camera_first_person(&input, &state.camera, - speed, state.dt); - if (key_is_pressed(input.action_up)) - dv = v3f_scalef(dv, 3.0f); - camera_dp = v3f_add(camera_dp, dv); - camera_dp = v3f_scalef(camera_dp, 0.8f); - state.camera.pos = v3f_add(state.camera.pos, camera_dp); - - F32 sensitivity = 0.1f; - input.mouse_offset = v2f_scalef(input.mouse_offset, sensitivity); - state.camera.yaw += input.mouse_offset.x; - state.camera.pitch += 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; - - input_update_last_state(&input); - - angular_speed = 1.0f; - radius = 4.0f; - x = f32_sin(time*angular_speed)*radius; - y = f32_sin(time*angular_speed)*f32_sin(time*angular_speed)*radius; - z = f32_cos(time*angular_speed)*radius; - - light_pos = v3f(x, y, z); - - /* NOTE(pryazha): Render */ - - /* NOTE(pryazha): Render the depth cubemap */ - F32 fovx, aspect, near, far; - fovx = 90.0f; - aspect = (F32)shadow_width/(F32)shadow_height; - near = 1.0f; - far = 25.0f; - proj = perspective(fovx, aspect, near, far); - shadow_transforms[0] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f( 1.0f, 0.0f, 0.0f)), v3f(0.0f, -1.0f, 0.0f))); /* right */ - shadow_transforms[1] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f(-1.0f, 0.0f, 0.0f)), v3f(0.0f, -1.0f, 0.0f))); /* left */ - shadow_transforms[2] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f( 0.0f, 1.0f, 0.0f)), v3f(0.0f, 0.0f, 1.0f))); /* top */ - shadow_transforms[3] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f( 0.0f, -1.0f, 0.0f)), v3f(0.0f, 0.0f, -1.0f))); /* bottom */ - shadow_transforms[4] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f( 0.0f, 0.0f, 1.0f)), v3f(0.0f, -1.0f, 0.0f))); /* near */ - shadow_transforms[5] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f( 0.0f, 0.0f, -1.0f)), v3f(0.0f, -1.0f, 0.0f))); /* far */ - glViewport(0, 0, shadow_width, shadow_height); - glBindFramebuffer(GL_FRAMEBUFFER, depth_cubemap_fbo); - glClear(GL_DEPTH_BUFFER_BIT); - glUseProgram(depth_shader); - shader_set_1f(depth_shader, "far", far); - shader_set_3fv(depth_shader, "light_pos", light_pos); - for (U32 i = 0; i < 6; ++i) { - char uniform_name[256]; - snprintf(uniform_name, 256, "shadow_transforms[%d]", i); - shader_set_mat4fv(depth_shader, uniform_name, shadow_transforms[i]); - } - render_scene(depth_shader, cube); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - /* NOTE(pryazha): Render the scene as normal */ - glViewport(0, 0, screen_width, screen_height); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glUseProgram(shadow_shader); - - aspect = (F32)screen_width/(F32)screen_height; - proj = perspective(state.camera.fovx, aspect, state.camera.near, state.camera.far); - view = get_view_matrix(&state.camera); - - shader_set_mat4fv(shadow_shader, "proj", proj); - shader_set_mat4fv(shadow_shader, "view", view); - shader_set_3fv(shadow_shader, "light_pos", light_pos); - shader_set_3fv(shadow_shader, "view_pos", state.camera.pos); - shader_set_1f(shadow_shader, "far", far); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, wood_texture); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_CUBE_MAP, depth_cubemap); - render_scene(shadow_shader, cube); - - glfwSwapBuffers(window); - - time = glfwGetTime(); - state.dt = time-last_time; - last_time = time; - } - - glfwTerminate(); - return(0); + Input input; + F64 time, last_time; + V3F light_pos; + MAT4 shadow_transforms[6]; + MAT4 proj, view; + + glfwSetErrorCallback(error_callback); + + if (glfwInit() == GLFW_FALSE) + return(1); + + S32 screen_width = 800; + S32 screen_height = 600; + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_SAMPLES, 4); + GLFWwindow *window = glfwCreateWindow(screen_width, screen_height, "Point shadows", 0, 0); + if (!window) + goto error; + + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + glfwMakeContextCurrent(window); + + if (glewInit() != GLEW_OK) + goto error; + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + /* NOTE(pryazha): Init */ + Arena *arena = arena_alloc(Megabytes(64)); + + State state = {0}; + state.camera = (Camera){ + .pos = v3f(0.0f, 1.0f, 3.0f), + .fovx = 100.0f, + .near = 0.1f, + .far = 100.0f, + .yaw = 0.0f, + .pitch = 0.0f + }; + V3F camera_dp = v3f_zero(); + light_pos = v3f_zero(); + + /* NOTE(pryazha): Meshes */ + Mesh *cube = mesh_load_obj(arena, "../../data/models/cube.obj"); + + F32 quad_vertices[] = { + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f + }; + U32 quad_vao, vbo; + glGenVertexArrays(1, &quad_vao); + glBindVertexArray(quad_vao); + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(quad_vertices), quad_vertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(F32), (void *)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(F32), (void *)(3*sizeof(F32))); + glBindVertexArray(0); + + /* NOTE(pryazha): Shaders */ + U32 depth_shader = load_shader_geom("shaders/depth.vert", "shaders/depth.frag", "shaders/depth.geom"); + U32 shadow_shader = load_shader("shaders/shadow.vert", "shaders/shadow.frag"); + + glUseProgram(shadow_shader); + shader_set_1i(shadow_shader, "diffuse_texture", 0); + shader_set_1i(shadow_shader, "depth_cubemap", 1); + glUseProgram(0); + + U32 wood_texture = load_texture_gamma("../../data/textures/wood.png", 0); + + /* NOTE(pryazha): Depth framebuffer init */ + U32 depth_cubemap_fbo, depth_cubemap; + U32 shadow_width = 1024, shadow_height = 1024; + glGenFramebuffers(1, &depth_cubemap_fbo); + glGenTextures(1, &depth_cubemap); + glBindTexture(GL_TEXTURE_CUBE_MAP, depth_cubemap); + for (U32 cubemap_side = 0; cubemap_side < 6; ++cubemap_side) + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+cubemap_side, 0, GL_DEPTH_COMPONENT, + shadow_width, shadow_height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); + glBindFramebuffer(GL_FRAMEBUFFER, depth_cubemap_fbo); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_cubemap, 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + fprintf(stderr, "[ERROR]: Failed to complete depth map framebuffer.\n"); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + last_time = glfwGetTime(); + + while (!glfwWindowShouldClose(window)) { + glfwPollEvents(); + + /* NOTE(pryazha): For now it's easier to write all of the logic in the main loop */ + /* NOTE(pryazha): Update */ + F32 x, y, z, angular_speed, radius; + + glfwGetFramebufferSize(window, &screen_width, &screen_height); + process_glfw_keyboard(window, &input); + process_glfw_mouse_pos(window, &input); + + if (key_first_press(input.exit)) + glfwSetWindowShouldClose(window, GLFW_TRUE); + + F32 speed = 4.0f; + V3F dv = get_dv_camera_first_person(&input, &state.camera, + speed, state.dt); + if (key_is_pressed(input.action_up)) + dv = v3f_scalef(dv, 3.0f); + camera_dp = v3f_add(camera_dp, dv); + camera_dp = v3f_scalef(camera_dp, 0.8f); + state.camera.pos = v3f_add(state.camera.pos, camera_dp); + + F32 sensitivity = 0.1f; + input.mouse_offset = v2f_scalef(input.mouse_offset, sensitivity); + state.camera.yaw += input.mouse_offset.x; + state.camera.pitch += 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; + + input_update_last_state(&input); + + angular_speed = 1.0f; + radius = 4.0f; + x = f32_sin(time*angular_speed)*radius; + y = f32_sin(time*angular_speed)*f32_sin(time*angular_speed)*radius; + z = f32_cos(time*angular_speed)*radius; + + light_pos = v3f(x, y, z); + + /* NOTE(pryazha): Render */ + + /* NOTE(pryazha): Render the depth cubemap */ + F32 fovx, aspect, near, far; + fovx = 90.0f; + aspect = (F32)shadow_width/(F32)shadow_height; + near = 1.0f; + far = 25.0f; + proj = perspective(fovx, aspect, near, far); + shadow_transforms[0] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f( 1.0f, 0.0f, 0.0f)), v3f(0.0f, -1.0f, 0.0f))); /* right */ + shadow_transforms[1] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f(-1.0f, 0.0f, 0.0f)), v3f(0.0f, -1.0f, 0.0f))); /* left */ + shadow_transforms[2] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f( 0.0f, 1.0f, 0.0f)), v3f(0.0f, 0.0f, 1.0f))); /* top */ + shadow_transforms[3] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f( 0.0f, -1.0f, 0.0f)), v3f(0.0f, 0.0f, -1.0f))); /* bottom */ + shadow_transforms[4] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f( 0.0f, 0.0f, 1.0f)), v3f(0.0f, -1.0f, 0.0f))); /* near */ + shadow_transforms[5] = mat4_mul(proj, look_at(light_pos, v3f_add(light_pos, v3f( 0.0f, 0.0f, -1.0f)), v3f(0.0f, -1.0f, 0.0f))); /* far */ + glViewport(0, 0, shadow_width, shadow_height); + glBindFramebuffer(GL_FRAMEBUFFER, depth_cubemap_fbo); + glClear(GL_DEPTH_BUFFER_BIT); + glUseProgram(depth_shader); + shader_set_1f(depth_shader, "far", far); + shader_set_3fv(depth_shader, "light_pos", light_pos); + for (U32 i = 0; i < 6; ++i) { + char uniform_name[256]; + snprintf(uniform_name, 256, "shadow_transforms[%d]", i); + shader_set_mat4fv(depth_shader, uniform_name, shadow_transforms[i]); + } + render_scene(depth_shader, cube); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + /* NOTE(pryazha): Render the scene as normal */ + glViewport(0, 0, screen_width, screen_height); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glUseProgram(shadow_shader); + + aspect = (F32)screen_width/(F32)screen_height; + proj = perspective(state.camera.fovx, aspect, state.camera.near, state.camera.far); + view = get_view_matrix(&state.camera); + + shader_set_mat4fv(shadow_shader, "proj", proj); + shader_set_mat4fv(shadow_shader, "view", view); + shader_set_3fv(shadow_shader, "light_pos", light_pos); + shader_set_3fv(shadow_shader, "view_pos", state.camera.pos); + shader_set_1f(shadow_shader, "far", far); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, wood_texture); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_CUBE_MAP, depth_cubemap); + render_scene(shadow_shader, cube); + + glfwSwapBuffers(window); + + time = glfwGetTime(); + state.dt = time-last_time; + last_time = time; + } + + glfwTerminate(); + return(0); error: - glfwTerminate(); - return(1); + glfwTerminate(); + return(1); } diff --git a/advanced_lighting/4.normal_mapping/build.sh b/advanced_lighting/4.normal_mapping/build index 4209fd0..4209fd0 100755 --- a/advanced_lighting/4.normal_mapping/build.sh +++ b/advanced_lighting/4.normal_mapping/build diff --git a/advanced_lighting/4.normal_mapping/normal_mapping.c b/advanced_lighting/4.normal_mapping/normal_mapping.c index 980f4a0..5051cb7 100644 --- a/advanced_lighting/4.normal_mapping/normal_mapping.c +++ b/advanced_lighting/4.normal_mapping/normal_mapping.c @@ -130,13 +130,9 @@ int main(void) glBindVertexArray(0); /* NOTE(pryazha): Shaders */ - U32 normal_map_shader = create_shader_program("shaders/normal_map.vert", - "shaders/normal_map.frag"); - U32 normals_debug_shader = create_shader_program_geom("shaders/normals_debug.vert", - "shaders/normals_debug.frag", - "shaders/normals_debug.geom"); - U32 color_shader = create_shader_program("shaders/color.vert", - "shaders/color.frag"); + U32 normal_map_shader = load_shader("shaders/normal_map.vert", "shaders/normal_map.frag"); + U32 normals_debug_shader = load_shader_geom("shaders/normals_debug.vert", "shaders/normals_debug.frag", "shaders/normals_debug.geom"); + U32 color_shader = load_shader("shaders/color.vert", "shaders/color.frag"); glUseProgram(normal_map_shader); shader_set_1i(normal_map_shader, "diffuse_texture", 0); diff --git a/advanced_lighting/5.parallax_mapping/build.sh b/advanced_lighting/5.parallax_mapping/build index e36f110..e36f110 100755 --- a/advanced_lighting/5.parallax_mapping/build.sh +++ b/advanced_lighting/5.parallax_mapping/build diff --git a/advanced_lighting/5.parallax_mapping/parallax_mapping.c b/advanced_lighting/5.parallax_mapping/parallax_mapping.c index 35859d2..e877926 100644 --- a/advanced_lighting/5.parallax_mapping/parallax_mapping.c +++ b/advanced_lighting/5.parallax_mapping/parallax_mapping.c @@ -142,10 +142,8 @@ int main(void) depth_texture = load_texture("../../data/textures/bricks2_disp.jpg"); /* NOTE(pryazha): Shaders */ - parallax_shader = create_shader_program("shaders/parallax.vert", "shaders/parallax.frag"); - normals_debug_shader = create_shader_program_geom("shaders/normals_debug.vert", - "shaders/normals_debug.frag", - "shaders/normals_debug.geom"); + parallax_shader = load_shader("shaders/parallax.vert", "shaders/parallax.frag"); + normals_debug_shader = load_shader_geom("shaders/normals_debug.vert", "shaders/normals_debug.frag", "shaders/normals_debug.geom"); glUseProgram(parallax_shader); shader_set_1i(parallax_shader, "diffuse_texture", 0); diff --git a/advanced_lighting/6.hdr/build.sh b/advanced_lighting/6.hdr/build index 3957e1d..3957e1d 100755 --- a/advanced_lighting/6.hdr/build.sh +++ b/advanced_lighting/6.hdr/build diff --git a/advanced_lighting/6.hdr/hdr.c b/advanced_lighting/6.hdr/hdr.c index 911f9da..655ab06 100644 --- a/advanced_lighting/6.hdr/hdr.c +++ b/advanced_lighting/6.hdr/hdr.c @@ -10,39 +10,8 @@ int main(void) { - S32 width, height; - - GLFWwindow *window; - F64 time, last_time; - - State state = {0}; - - U32 wooodtex; - - Mesh *quad, - *cube, - *tubecube; - - U32 blinn_shader, - hdr_shader, - light_shader, - normals_debug_shader; - - U32 hdrfbo, - hdrcolorbuf, - hdrrbo; - - S32 i; - - F32 a, da, r; - V3F lpos[LCOUNT]; - - F32 exposure; - - S32 show_normals, show_lights; - - width = 800; - height = 600; + S32 width = 800; + S32 height = 600; /* NOTE(pryazha): GLFW init */ glfwSetErrorCallback(error_callback); @@ -53,7 +22,7 @@ int main(void) glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - window = glfwCreateWindow(width, height, "HDR", 0, 0); + GLFWwindow *window = glfwCreateWindow(width, height, "HDR", 0, 0); if (!window) goto error; @@ -67,46 +36,49 @@ int main(void) 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, 0.0f, 3.0f), 90.0f, 0.1f, 100.0f, 0.0f, 0.0f }; state.camera_dp = v3f_zero(); - da = 2.0f*pi_F32/LCOUNT; - for (i = 0, a = 0.0f, r = 2.0f; i < LCOUNT; i++, a += da) + F32 da = 2.0f*pi_F32/LCOUNT; + F32 a = 0.0f; + F32 r = 2.0f; + V3F lpos[LCOUNT]; + for (S32 i = 0; i < LCOUNT; i++, a += da) lpos[i] = v3f(f32_sin(a)*r, 0.0f, f32_cos(a)*r); - exposure = 1.0f; + F32 exposure = 1.0f; - show_normals = 0; - show_lights = 1; + S32 show_normals = 0; + S32 show_lights = 1; /* NOTE(pryazha): Textures */ - wooodtex = load_texture_gamma("../../data/textures/wood.png", 1); + U32 wooodtex = load_texture_gamma("../../data/textures/wood.png", 1); /* NOTE(pryazha): Meshes */ - quad = mesh_gen_quad(state.arena); - cube = mesh_load_obj(state.arena, "../../data/models/cube.obj"); - tubecube = mesh_load_obj(state.arena, "../../data/models/tube_with_cube.obj"); + Mesh *quad = mesh_gen_quad(state.arena); + Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj"); + Mesh *tubecube = mesh_load_obj(state.arena, "../../data/models/tube_with_cube.obj"); /* NOTE(pryazha): Shaders */ - blinn_shader = create_shader_program("shaders/blinn.vert", "shaders/blinn.frag"); - hdr_shader = create_shader_program("shaders/hdr.vert", "shaders/hdr.frag"); - light_shader = create_shader_program("shaders/light.vert", "shaders/light.frag"); - normals_debug_shader = create_shader_program_geom("shaders/normals_debug.vert", - "shaders/normals_debug.frag", - "shaders/normals_debug.geom"); + U32 blinn_shader = load_shader("shaders/blinn.vert", "shaders/blinn.frag"); + U32 hdr_shader = load_shader("shaders/hdr.vert", "shaders/hdr.frag"); + U32 light_shader = load_shader("shaders/light.vert", "shaders/light.frag"); + U32 normals_debug_shader = load_shader_geom("shaders/normals_debug.vert", "shaders/normals_debug.frag", "shaders/normals_debug.geom"); /* NOTE(pryazha): Create HDR framebuffer, color buffer texture and * renderbuffer */ + U32 hdrfbo, hdrcolorbuf; glGenFramebuffers(1, &hdrfbo); glGenTextures(1, &hdrcolorbuf); glBindTexture(GL_TEXTURE_2D, hdrcolorbuf); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, 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); + + U32 hdrrbo; glGenRenderbuffers(1, &hdrrbo); glBindRenderbuffer(GL_RENDERBUFFER, hdrrbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); @@ -121,7 +93,7 @@ int main(void) glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); - last_time = glfwGetTime(); + F64 last_time = glfwGetTime(); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); @@ -161,7 +133,9 @@ int main(void) if (key_is_pressed(state.input.action_up)) exposure += 0.01f; - for (i = 0; i < LCOUNT; i++) + printf("exposure = %f\n", exposure); + + for (S32 i = 0; i < LCOUNT; i++) lpos[i].y = f32_sin(glfwGetTime()+i); /* NOTE(pryazha): Render */ @@ -188,7 +162,7 @@ int main(void) shader_set_mat4fv(blinn_shader, "view", view); shader_set_mat4fv(blinn_shader, "model", model); shader_set_1i(blinn_shader, "lcount", LCOUNT); - for (i = 0; i < LCOUNT; i++) { + for (S32 i = 0; i < LCOUNT; i++) { snprintf(lstr, 1024, "lpos[%d]", i); shader_set_3fv(blinn_shader, lstr, lpos[i]); } @@ -204,7 +178,7 @@ int main(void) glUseProgram(light_shader); shader_set_mat4fv(light_shader, "proj", proj); shader_set_mat4fv(light_shader, "view", view); - for (i = 0; i < LCOUNT; i++) { + for (S32 i = 0; i < LCOUNT; i++) { model = mat4_make_scale(v3f(0.2f, 0.2f, 0.2f)); model = mat4_translate(model, lpos[i]); shader_set_mat4fv(light_shader, "model", model); @@ -236,7 +210,7 @@ int main(void) glfwSwapBuffers(window); - time = glfwGetTime(); + F64 time = glfwGetTime(); state.dt = time-last_time; last_time = time; diff --git a/advanced_lighting/7.bloom/bloom.c b/advanced_lighting/7.bloom/bloom.c new file mode 100644 index 0000000..70adcfe --- /dev/null +++ b/advanced_lighting/7.bloom/bloom.c @@ -0,0 +1,287 @@ +#include "GL/glew.h" +#include "GLFW/glfw3.h" + +#include "pwyazh.h" +#include "pwyazh_GL.h" + +#include "common.h" + +#define LIGHT_COUNT 3 + +int main(void) +{ + S32 width = 1600; + S32 height = 900; + + /* 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); + GLFWwindow *window = glfwCreateWindow(width, height, "Bloom", 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, 0.0f, 3.0f), 90.0f, 0.1f, 100.0f, 0.0f, 0.0f }; + + V3F light_positions[LIGHT_COUNT]; + F32 da = 2.0f*pi_F32/LIGHT_COUNT; + F32 a = 0.0f; + F32 r = 2.0f; + for (S32 i = 0; i < LIGHT_COUNT; i++, a += da) + light_positions[i] = v3f(f32_sin(a)*r, 0.0f, f32_cos(a)*r); + + V3F light_colors[LIGHT_COUNT] = { + {5.0f, 5.0f, 5.0f}, + {10.0f, 0.0f, 0.0f}, + {0.0f, 5.0f, 0.0f}, + }; + + S32 bloom = 0; + F32 exposure = 1.0f; + + /* NOTE(pryazha): Textures */ + U32 woood_texture = load_texture_gamma("../../data/textures/wood.png", 1); + + /* NOTE(pryazha): Meshes */ + Mesh *quad = mesh_gen_quad(state.arena); + Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj"); + + /* NOTE(pryazha): Shaders */ + U32 shader = load_shader("shaders/bloom.vert", "shaders/bloom.frag"); + U32 shader_light = load_shader("shaders/bloom.vert", "shaders/light.frag"); + U32 shader_blur = load_shader("shaders/blur.vert", "shaders/blur.frag"); + U32 shader_test_blur = load_shader("shaders/test_blur.vert", "shaders/test_blur.frag"); + U32 shader_final = load_shader("shaders/final.vert", "shaders/final.frag"); + + glUseProgram(shader_final); + shader_set_1i(shader_final, "scene", 0); + shader_set_1i(shader_final, "blur", 1); + + /* NOTE(pryazha): Framebuffers */ + U32 hdrfbo; + glGenFramebuffers(1, &hdrfbo); + glBindFramebuffer(GL_FRAMEBUFFER, hdrfbo); + + U32 colorbuffers[2]; + glGenTextures(2, colorbuffers); + for (S32 i = 0; i < 2; ++i) { + glBindTexture(GL_TEXTURE_2D, colorbuffers[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, 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); + 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+i, GL_TEXTURE_2D, colorbuffers[i], 0); + } + + U32 hdrrbo; + glGenRenderbuffers(1, &hdrrbo); + glBindRenderbuffer(GL_RENDERBUFFER, hdrrbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdrrbo); + + U32 attachments[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; + glDrawBuffers(2, attachments); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + fprintf(stderr, "error: framebuffer not complete\n"); + + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + U32 pingpong_fbo[2]; + U32 pingpong_colorbuffers[2]; + glGenFramebuffers(2, pingpong_fbo); + glGenTextures(2, pingpong_colorbuffers); + for (S32 i = 0; i < 2; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, pingpong_fbo[i]); + glBindTexture(GL_TEXTURE_2D, pingpong_colorbuffers[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, 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); + 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, pingpong_colorbuffers[i], 0); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + fprintf(stderr, "error: framebuffer not complete\n"); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + U32 blur_fbo; + glGenFramebuffers(1, &blur_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, blur_fbo); + U32 blur_colorbuffer; + glGenTextures(1, &blur_colorbuffer); + glBindTexture(GL_TEXTURE_2D, blur_colorbuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, 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); + 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, blur_colorbuffer, 0); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + fprintf(stderr, "error: blur framebuffer not complete\n"); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + S32 myblur = 0; + + F64 last_time = glfwGetTime(); + while (!glfwWindowShouldClose(window)) { + 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 */ + if (key_is_pressed(state.input.action_down)) + exposure -= 0.01f; + if (key_is_pressed(state.input.action_up)) + exposure += 0.01f; + + if (key_first_press(state.input.jump)) + bloom = !bloom; + + if (key_first_press(state.input.action_left)) + myblur = !myblur; + + for (S32 i = 0; i < LIGHT_COUNT; i++) + light_positions[i].y = f32_sin(glfwGetTime()+i); + + /* NOTE(pryazha): Render */ + glClearColor(0.15f, 0.15f, 0.15f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + /* Render to HDR framebuffer */ + glBindFramebuffer(GL_FRAMEBUFFER, hdrfbo); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + F32 ar = (F32)width/(F32)height; + MAT4 projection = camera_persp(state.camera, ar); + MAT4 view = get_view_matrix(&state.camera); + + glUseProgram(shader); + shader_set_mat4fv(shader, "projection", projection); + shader_set_mat4fv(shader, "view", view); + for (S32 i = 0; i < LIGHT_COUNT; i++) { + char light_string[1024]; + snprintf(light_string, 1024, "lights[%d].position", i); + shader_set_3fv(shader, light_string, light_positions[i]); + snprintf(light_string, 1024, "lights[%d].color", i); + shader_set_3fv(shader, light_string, light_colors[i]); + } + shader_set_3fv(shader, "view_pos", state.camera.pos); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, woood_texture); + + MAT4 model = mat4_make_scale(v3f(10.0f, 0.25f, 10.0f)); + model = mat4_translate(model, v3f(0.0f, -2.0f, 0.0f)); + shader_set_mat4fv(shader, "model", model); + mesh_draw(cube); + + model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); + model = mat4_rotate_angles(model, v3f(30.0f, 45.0f, 0.0f)); + model = mat4_translate(model, v3f(-0.5f, -1.0f, -2.0f)); + shader_set_mat4fv(shader, "model", model); + mesh_draw(cube); + + model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); + model = mat4_rotate_angles(model, v3f(-30.0f, 45.0f, 90.0f)); + model = mat4_translate(model, v3f(0.75f, -1.5f, 1.0f)); + shader_set_mat4fv(shader, "model", model); + mesh_draw(cube); + + glBindTexture(GL_TEXTURE_2D, 0); + glUseProgram(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++) { + model = mat4_make_scale(v3f(0.2f, 0.2f, 0.2f)); + model = mat4_translate(model, light_positions[i]); + shader_set_mat4fv(shader_light, "model", model); + shader_set_3fv(shader_light, "light_color", light_colors[i]); + mesh_draw(cube); + } + glUseProgram(0); + + S32 horizontal = 1, first = 1, amount = 10; + glUseProgram(shader_blur); + for (S32 i = 0; i < amount; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, pingpong_fbo[horizontal]); + shader_set_1i(shader_blur, "horizontal", horizontal); + glBindTexture(GL_TEXTURE_2D, first ? colorbuffers[1] : pingpong_colorbuffers[!horizontal]); + mesh_draw(quad); + horizontal = !horizontal; + if (first) + first = 0; + } + glUseProgram(0); + + glBindFramebuffer(GL_FRAMEBUFFER, blur_fbo); + glUseProgram(shader_test_blur); + glActiveTexture(0); + glBindTexture(GL_TEXTURE_2D, colorbuffers[1]); + mesh_draw(quad); + glUseProgram(0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glUseProgram(shader_final); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, colorbuffers[0]); + glActiveTexture(GL_TEXTURE1); + if (myblur) { + glBindTexture(GL_TEXTURE_2D, blur_colorbuffer); + } else { + glBindTexture(GL_TEXTURE_2D, pingpong_colorbuffers[!horizontal]); + } + shader_set_1i(shader_final, "bloom", bloom); + shader_set_1f(shader_final, "exposure", exposure); + mesh_draw(quad); + + glfwSwapBuffers(window); + + F64 time = glfwGetTime(); + state.dt = time - last_time; + last_time = time; + + input_update_last_state(&state.input); + } + + return 0; +} diff --git a/advanced_lighting/7.bloom/build b/advanced_lighting/7.bloom/build new file mode 100755 index 0000000..99df29a --- /dev/null +++ b/advanced_lighting/7.bloom/build @@ -0,0 +1,5 @@ +#!/bin/sh +. ../../config +TARGET='bloom' +set -x +gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS diff --git a/advanced_lighting/7.bloom/shaders/bloom.frag b/advanced_lighting/7.bloom/shaders/bloom.frag new file mode 100644 index 0000000..88decf8 --- /dev/null +++ b/advanced_lighting/7.bloom/shaders/bloom.frag @@ -0,0 +1,45 @@ +#version 330 core + +in VS_OUT { + vec3 position; + vec3 normal; + vec2 tex_coords; +} vs_out; + +layout(location = 0) out vec4 frag_color; +layout(location = 1) out vec4 bright_color; + +struct light_t { + vec3 position; + vec3 color; +}; + +uniform light_t lights[3]; +uniform sampler2D diffuse_texture; +uniform vec3 view_pos; + +const int light_count = 3; + +void main(void) +{ + vec3 color = texture(diffuse_texture, vs_out.tex_coords).rgb; + vec3 ambient = 0.01 * color; + vec3 lighting = vec3(0.0); + vec3 view_dir = normalize(view_pos - vs_out.position); + for (int i = 0; i < light_count; i++) { + vec3 light_dir = normalize(lights[i].position - vs_out.position); + float diff = max(dot(light_dir, vs_out.normal), 0.0); + vec3 result = lights[i].color * diff * color; + float distance = length(vs_out.position - lights[i].position); + result *= 1.0 / (distance * distance); + lighting += result; + } + vec3 result = ambient + lighting; + float brightness = dot(result, vec3(0.2126, 0.7152, 0.0722)); + if (brightness > 1.0) { + bright_color = vec4(result, 1.0); + } else { + bright_color = vec4(0.0, 0.0, 0.0, 1.0); + } + frag_color = vec4(result, 1.0); +} diff --git a/advanced_lighting/7.bloom/shaders/bloom.vert b/advanced_lighting/7.bloom/shaders/bloom.vert new file mode 100644 index 0000000..0c9dc02 --- /dev/null +++ b/advanced_lighting/7.bloom/shaders/bloom.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 VS_OUT { + vec3 position; + vec3 normal; + vec2 tex_coords; +} vs_out; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main() +{ + vs_out.position = vec3(model * vec4(position, 1.0)); + mat3 normal_matrix = transpose(inverse(mat3(model))); + vs_out.normal = normalize(normal_matrix * normal); + vs_out.tex_coords = tex_coords; + gl_Position = projection * view * model * vec4(position, 1.0); +} diff --git a/advanced_lighting/7.bloom/shaders/blur.frag b/advanced_lighting/7.bloom/shaders/blur.frag new file mode 100644 index 0000000..67b7e43 --- /dev/null +++ b/advanced_lighting/7.bloom/shaders/blur.frag @@ -0,0 +1,29 @@ +#version 330 core + +in VS_OUT { + vec2 tex_coords; +} vs_out; + +out vec4 frag_color; + +uniform sampler2D image; +uniform bool horizontal; +uniform float weights[5] = float[](0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162); + +void main(void) +{ + vec2 tex_offset = 1.0 / textureSize(image, 0); + vec3 result = texture(image, vs_out.tex_coords).rgb * weights[0]; + if (horizontal) { + for (int i = 1; i < 5; i++) { + result += texture(image, vs_out.tex_coords + vec2(tex_offset.x * i, 0.0)).rgb * weights[i]; + result += texture(image, vs_out.tex_coords - vec2(tex_offset.x * i, 0.0)).rgb * weights[i]; + } + } else { + for (int i = 1; i < 5; i++) { + result += texture(image, vs_out.tex_coords + vec2(0.0, tex_offset.y * i)).rgb * weights[i]; + result += texture(image, vs_out.tex_coords - vec2(0.0, tex_offset.y * i)).rgb * weights[i]; + } + } + frag_color = vec4(result, 1.0); +} diff --git a/advanced_lighting/7.bloom/shaders/blur.vert b/advanced_lighting/7.bloom/shaders/blur.vert new file mode 100644 index 0000000..e4ced24 --- /dev/null +++ b/advanced_lighting/7.bloom/shaders/blur.vert @@ -0,0 +1,14 @@ +#version 330 core + +layout (location = 0) in vec3 position; +layout (location = 2) in vec2 tex_coords; + +out VS_OUT { + vec2 tex_coords; +} vs_out; + +void main(void) +{ + vs_out.tex_coords = tex_coords; + gl_Position = vec4(position, 1.0); +} diff --git a/advanced_lighting/7.bloom/shaders/final.frag b/advanced_lighting/7.bloom/shaders/final.frag new file mode 100644 index 0000000..fe9f5d7 --- /dev/null +++ b/advanced_lighting/7.bloom/shaders/final.frag @@ -0,0 +1,25 @@ +#version 330 core + +in VS_OUT { + vec2 tex_coords; +} vs_out; + +out vec4 frag_color; + +uniform sampler2D scene; +uniform sampler2D blur; +uniform bool bloom; +uniform float exposure; + +void main() +{ + const float gamma = 2.2; + vec3 scene_color = texture(scene, vs_out.tex_coords).rgb; + vec3 blur_color = texture(blur, vs_out.tex_coords).rgb; + if (bloom) { + scene_color += blur_color; + } + vec3 result = vec3(1.0) - exp(-scene_color * exposure); + result = pow(result, vec3(1.0 / gamma)); + frag_color = vec4(result, 1.0); +} diff --git a/advanced_lighting/7.bloom/shaders/final.vert b/advanced_lighting/7.bloom/shaders/final.vert new file mode 100644 index 0000000..f6a4e38 --- /dev/null +++ b/advanced_lighting/7.bloom/shaders/final.vert @@ -0,0 +1,14 @@ +#version 330 core + +layout (location = 0) in vec3 position; +layout (location = 2) in vec2 tex_coords; + +out VS_OUT { + vec2 tex_coords; +} vs_out; + +void main() +{ + vs_out.tex_coords = tex_coords; + gl_Position = vec4(position, 1.0); +} diff --git a/advanced_lighting/7.bloom/shaders/light.frag b/advanced_lighting/7.bloom/shaders/light.frag new file mode 100644 index 0000000..72a2874 --- /dev/null +++ b/advanced_lighting/7.bloom/shaders/light.frag @@ -0,0 +1,22 @@ +#version 330 core + +in VS_OUT { + vec3 position; + vec3 normal; + vec2 tex_coords; +} vs_out; + +layout(location = 0) out vec4 frag_color; +layout(location = 1) out vec4 bright_color; + +uniform vec3 light_color; + +void main() +{ + frag_color = vec4(light_color, 1.0); + float brightness = dot(vec3(frag_color), vec3(0.2126, 0.7152, 0.0722)); + if (brightness > 1.0) + bright_color = vec4(vec3(frag_color), 1.0); + else + bright_color = vec4(0.0, 0.0, 0.0, 1.0); +} diff --git a/advanced_lighting/7.bloom/shaders/test_blur.frag b/advanced_lighting/7.bloom/shaders/test_blur.frag new file mode 100644 index 0000000..8d7ee9a --- /dev/null +++ b/advanced_lighting/7.bloom/shaders/test_blur.frag @@ -0,0 +1,28 @@ +#version 330 core + +in vert_t { + vec2 tex_coords; +} vert; + +out vec4 frag_color; + +uniform sampler2D colorbuffer; + +uniform float weights[5] = float[](0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162); + +void main() +{ + vec2 texture_offset = 1.0 / textureSize(colorbuffer, 0); + vec3 result = texture(colorbuffer, vert.tex_coords).rgb * weights[0]; + for (int x = 1; x < weights.length(); x++) { + vec2 offset = vec2(texture_offset.x * x, 0.0f); + result += texture(colorbuffer, vert.tex_coords + offset).rgb * weights[x]; + result += texture(colorbuffer, vert.tex_coords - offset).rgb * weights[x]; + } + for (int y = 1; y < weights.length(); y++) { + vec2 offset = vec2(0.0f, texture_offset.y * y); + result += texture(colorbuffer, vert.tex_coords + offset).rgb * weights[y]; + result += texture(colorbuffer, vert.tex_coords - offset).rgb * weights[y]; + } + frag_color = vec4(result, 1.0); +} diff --git a/advanced_lighting/7.bloom/shaders/test_blur.vert b/advanced_lighting/7.bloom/shaders/test_blur.vert new file mode 100644 index 0000000..eed3be3 --- /dev/null +++ b/advanced_lighting/7.bloom/shaders/test_blur.vert @@ -0,0 +1,14 @@ +#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/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); +} diff --git a/advanced_lighting/9.ssao/build b/advanced_lighting/9.ssao/build new file mode 100755 index 0000000..dc6929a --- /dev/null +++ b/advanced_lighting/9.ssao/build @@ -0,0 +1,5 @@ +#!/bin/sh +. ../../config +TARGET='ssao' +set -x +gcc -o $TARGET $CFLAGS $INCLUDE $LFLAGS $TARGET.c $LIBS diff --git a/advanced_lighting/9.ssao/deferred.frag b/advanced_lighting/9.ssao/deferred.frag new file mode 100644 index 0000000..5a3cc33 --- /dev/null +++ b/advanced_lighting/9.ssao/deferred.frag @@ -0,0 +1,44 @@ +#version 330 core + +in vert_t { + vec2 tex_coords; +} vert; + +out vec4 frag_color; + +uniform sampler2D positions; +uniform sampler2D normals; +uniform sampler2D albedo; +uniform sampler2D ssao; + +uniform vec3 view_position; + +struct light_t { + vec3 position; + vec3 color; +}; + +uniform light_t light; + +const float linear = 0.7f; +const float quadratic = 1.8f; + +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; + float occlusion = texture(ssao, vert.tex_coords).r; + + vec3 ambient = 0.1 * color * occlusion; + vec3 result = ambient; + vec3 view_dir = normalize(-position); + vec3 light_dir = normalize(light.position - position); + vec3 diffuse = max(dot(normal, light_dir), 0.0) * color * light.color; + vec3 halfway_dir = normalize(view_dir + light_dir); + vec3 specular = pow(max(dot(halfway_dir, normal), 0.0), 16.0) * vec3(0.5); + float distance = length(light.position - position); + float attenuation = 1.0 / (1.0 + linear * distance + quadratic * distance * distance); + result += (diffuse + specular) * attenuation; + frag_color = vec4(result, 1.0); +} diff --git a/advanced_lighting/9.ssao/deferred.vert b/advanced_lighting/9.ssao/deferred.vert new file mode 100644 index 0000000..335635b --- /dev/null +++ b/advanced_lighting/9.ssao/deferred.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/9.ssao/gbuffer.frag b/advanced_lighting/9.ssao/gbuffer.frag new file mode 100644 index 0000000..7755107 --- /dev/null +++ b/advanced_lighting/9.ssao/gbuffer.frag @@ -0,0 +1,17 @@ +#version 330 core + +in vert_t { + vec3 position; + vec3 normal; +} vert; + +layout(location = 0) out vec3 position; +layout(location = 1) out vec3 normal; +layout(location = 2) out vec3 albedo; + +void main() +{ + position = vert.position; + normal = normalize(vert.normal); + albedo.rgb = vec3(0.95); +} diff --git a/advanced_lighting/9.ssao/gbuffer.vert b/advanced_lighting/9.ssao/gbuffer.vert new file mode 100644 index 0000000..81ab951 --- /dev/null +++ b/advanced_lighting/9.ssao/gbuffer.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() +{ + vert.position = vec3(view * model * vec4(position, 1.0)); + mat3 matrix_normal = transpose(inverse(mat3(view * model))); + vert.normal = matrix_normal * normal; + gl_Position = projection * view * model * vec4(position, 1.0); +} diff --git a/advanced_lighting/9.ssao/occlusion.frag b/advanced_lighting/9.ssao/occlusion.frag new file mode 100644 index 0000000..41a436b --- /dev/null +++ b/advanced_lighting/9.ssao/occlusion.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).r), 1.0); +} diff --git a/advanced_lighting/9.ssao/screen.frag b/advanced_lighting/9.ssao/screen.frag new file mode 100644 index 0000000..3ae592d --- /dev/null +++ b/advanced_lighting/9.ssao/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/9.ssao/screen.vert b/advanced_lighting/9.ssao/screen.vert new file mode 100644 index 0000000..335635b --- /dev/null +++ b/advanced_lighting/9.ssao/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/9.ssao/ssao b/advanced_lighting/9.ssao/ssao Binary files differnew file mode 100755 index 0000000..72a9677 --- /dev/null +++ b/advanced_lighting/9.ssao/ssao diff --git a/advanced_lighting/9.ssao/ssao.c b/advanced_lighting/9.ssao/ssao.c new file mode 100644 index 0000000..3cfca03 --- /dev/null +++ b/advanced_lighting/9.ssao/ssao.c @@ -0,0 +1,331 @@ +#include "GL/glew.h" +#include "GLFW/glfw3.h" + +#include "pwyazh.h" +#include "pwyazh_GL.h" + +#include "xoshiro128plus.c" + +#include "common.h" + +#include "assert.h" + +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; +} diff --git a/advanced_lighting/9.ssao/ssao.frag b/advanced_lighting/9.ssao/ssao.frag new file mode 100644 index 0000000..e4d04b1 --- /dev/null +++ b/advanced_lighting/9.ssao/ssao.frag @@ -0,0 +1,45 @@ +#version 330 core + +in vert_t { + vec2 tex_coords; +} vert; + +out float frag_color; + +uniform sampler2D positions; +uniform sampler2D normals; +uniform sampler2D noise; + +uniform vec3 samples[64]; +uniform mat4 projection; + +const vec2 noise_scale = vec2(1600.0 / 4.0, 900.0 / 4.0) + +void main() +{ + vec3 position = texture(positions, vert.tex_coords).rgb; + vec3 normal = texture(normals, vert.tex_coords).rgb; + vec3 random = texture(noise, vert.tex_coords * noise_scale).rgb; + + vec3 tangent = normalize(random - normal * dot(random, normal)); + vec3 bitangent = cross(normal, tangent); + mat3 TBN = mat3(tangent, bitangent, normal); + + int nsamples = 64; + float radius = 0.5; + float bias = 0.025; + float occlusion = 0.0; + for (int i = 0; i < nsamples; i++) { + vec3 sample = TBN * samples[i]; + sample = position + sample * radius; + vec4 offset = vec4(sample, 1.0); + offset = projection * offset; + 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; + } + occlusion = 1.0 - (occlusion / nsamples); + frag_color = occlusion; +} diff --git a/advanced_lighting/9.ssao/ssao.vert b/advanced_lighting/9.ssao/ssao.vert new file mode 100644 index 0000000..3ce6fb2 --- /dev/null +++ b/advanced_lighting/9.ssao/ssao.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/9.ssao/xoshiro128plus.c b/advanced_lighting/9.ssao/xoshiro128plus.c new file mode 100644 index 0000000..b55c63b --- /dev/null +++ b/advanced_lighting/9.ssao/xoshiro128plus.c @@ -0,0 +1,28 @@ +#include <stdint.h> + +/* --- xoshiro128+ --- */ +static inline uint32_t rotl(const uint32_t x, int k) { + return (x << k) | (x >> (32 - k)); +} + +uint32_t next(uint32_t *s) { + const uint32_t result = s[0] + s[3]; + const uint32_t t = s[1] << 9; + s[2] ^= s[0]; + s[3] ^= s[1]; + s[1] ^= s[2]; + s[0] ^= s[3]; + s[2] ^= t; + s[3] = rotl(s[3], 11); + return result; +} +/* --- /xoshiro128+ --- */ + +float int_to_float(uint32_t random) { + union { uint32_t u32; float f; } u = { .u32 = random >> 9 | 0x3f800000 }; + return u.f - 1.0; +} + +float nextf(uint32_t* s) { + return int_to_float(next(s)); +} diff --git a/advanced_lighting/build.sh b/advanced_lighting/build index 4829c7d..1168d91 100755 --- a/advanced_lighting/build.sh +++ b/advanced_lighting/build @@ -1,9 +1,9 @@ #!/bin/sh targets=$(ls) for target in $targets ; do - if [ $target != 'build.sh' ] ; then + if [ $target != 'build' ] ; then cd $target - ./build.sh + ./build cd .. fi done |