From a11bca4ce2d78573a2fd42bc600515970b91df26 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Thu, 1 Oct 2020 20:17:46 -0700 Subject: [PATCH] Add half z matrix projection functions --- src/game/bootloader.cpp | 6 +-- src/game/states/play-state.cpp | 2 +- src/math/matrix-functions.hpp | 59 +++++++++++++++++++++++-- src/renderer/passes/material-pass.cpp | 16 +++++-- src/renderer/passes/material-pass.hpp | 2 + src/renderer/passes/shadow-map-pass.cpp | 9 +++- src/scene/camera.cpp | 5 ++- 7 files changed, 85 insertions(+), 14 deletions(-) diff --git a/src/game/bootloader.cpp b/src/game/bootloader.cpp index b4ec105..813e140 100644 --- a/src/game/bootloader.cpp +++ b/src/game/bootloader.cpp @@ -454,7 +454,7 @@ void setup_rendering(game_context* ctx) ctx->framebuffer_hdr_color->set_wrapping(texture_wrapping::clamp, texture_wrapping::clamp); ctx->framebuffer_hdr_color->set_filters(texture_min_filter::linear, texture_mag_filter::linear); ctx->framebuffer_hdr_color->set_max_anisotropy(0.0f); - ctx->framebuffer_hdr_depth = new texture_2d(viewport_dimensions[0], viewport_dimensions[1], pixel_type::uint_32, pixel_format::ds); + ctx->framebuffer_hdr_depth = new texture_2d(viewport_dimensions[0], viewport_dimensions[1], pixel_type::float_32, pixel_format::ds); ctx->framebuffer_hdr_depth->set_wrapping(texture_wrapping::clamp, texture_wrapping::clamp); ctx->framebuffer_hdr_depth->set_filters(texture_min_filter::linear, texture_mag_filter::linear); ctx->framebuffer_hdr_depth->set_max_anisotropy(0.0f); @@ -1179,7 +1179,7 @@ void setup_controls(game_context* ctx) ( [ctx, time_scale]() { - ctx->weather_system->set_time_scale(time_scale * 50.0f); + ctx->weather_system->set_time_scale(time_scale * 500.0f); } ); ctx->control_system->get_fast_forward_control()->set_deactivated_callback @@ -1193,7 +1193,7 @@ void setup_controls(game_context* ctx) ( [ctx, time_scale]() { - ctx->weather_system->set_time_scale(time_scale * -50.0f); + ctx->weather_system->set_time_scale(time_scale * -500.0f); } ); ctx->control_system->get_rewind_control()->set_deactivated_callback diff --git a/src/game/states/play-state.cpp b/src/game/states/play-state.cpp index efdb6f5..f3118a5 100644 --- a/src/game/states/play-state.cpp +++ b/src/game/states/play-state.cpp @@ -91,7 +91,7 @@ void play_state_enter(game_context* ctx) sky_pass->set_sky_model(ctx->resource_manager->load("sky-dome.mdl")); ctx->weather_system->set_coordinates(ctx->biome->coordinates); - ctx->weather_system->set_time(2020, 10, 1, 6, 0, 0, -7.0); + ctx->weather_system->set_time(2020, 6, 1, 5, 0, 0, -7.0); ctx->weather_system->set_sky_palette(ctx->biome->sky_palette); ctx->weather_system->set_sun_palette(ctx->biome->sun_palette); ctx->weather_system->set_ambient_palette(ctx->biome->ambient_palette); diff --git a/src/math/matrix-functions.hpp b/src/math/matrix-functions.hpp index de1c265..1c8dc3a 100644 --- a/src/math/matrix-functions.hpp +++ b/src/math/matrix-functions.hpp @@ -166,7 +166,7 @@ template vector mul(const matrix& m, const vector& v); /** - * Creates an orthographic projection matrix. + * Creates an orthographic projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively. * * @param left Signed distance to the left clipping plane. * @param right Signed distance to the right clipping plane. @@ -179,6 +179,20 @@ vector mul(const matrix& m, const vector& v); template matrix ortho(T left, T right, T bottom, T top, T z_near, T z_far); +/** + * Creates an orthographic projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively. + * + * @param left Signed distance to the left clipping plane. + * @param right Signed distance to the right clipping plane. + * @param bottom Signed distance to the bottom clipping plane. + * @param top Signed distance to the top clipping plane. + * @param z_near Signed distance to the near clipping plane. + * @param z_far Signed distance to the far clipping plane. + * @return Orthographic projection matrix. + */ +template +matrix ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far); + /** * Calculates the outer product of a pair of vectors. * @@ -197,7 +211,7 @@ template matrix outer_product(const vector& c, const vector r); /** - * Creates a perspective projection matrix. + * Creates a perspective projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively. * * @param vertical_fov Vertical field of view angle, in radians. * @param aspect_ratio Aspect ratio which determines the horizontal field of view. @@ -208,6 +222,18 @@ matrix outer_product(const vector& c, const vector r); template matrix perspective(T vertical_fov, T aspect_ratio, T z_near, T z_far); +/** + * Creates a perspective projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively. + * + * @param vertical_fov Vertical field of view angle, in radians. + * @param aspect_ratio Aspect ratio which determines the horizontal field of view. + * @param z_near Distance to the near clipping plane. + * @param z_far Distance to the far clipping plane. + * @return Perspective projection matrix. + */ +template +matrix perspective_half_z(T vertical_fov, T aspect_ratio, T z_near, T z_far); + /** * Resizes a matrix. Any new elements will be set to `1` if in the diagonal, and `0` otherwise. * @@ -579,6 +605,18 @@ matrix ortho(T left, T right, T bottom, T top, T z_near, T z_far) }}; } +template +matrix ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far) +{ + return + {{ + {T(2) / (right - left), T(0), T(0), T(0)}, + {T(0), T(2) / (top - bottom), T(0), T(0)}, + {T(0), T(0), T(-1) / (z_far - z_near), T(0)}, + {-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -z_near / (z_far - z_near), T(1)} + }}; +} + template matrix outer_product(const vector& c, const vector& r) { @@ -622,11 +660,26 @@ matrix perspective(T vertical_fov, T aspect_ratio, T z_near, T z_far) {{ {f / aspect_ratio, T(0), T(0), T(0)}, {T(0), f, T(0), T(0)}, - {T(0), T(0), (z_far + z_near) / (z_near - z_far), T(-1)}, + {T(0), T(0), (z_near + z_far) / (z_near - z_far), T(-1)}, {T(0), T(0), (T(2) * z_near * z_far) / (z_near - z_far), T(0)} }}; } +template +matrix perspective_half_z(T vertical_fov, T aspect_ratio, T z_near, T z_far) +{ + T half_fov = vertical_fov * T(0.5); + T f = std::cos(half_fov) / std::sin(half_fov); + + return + {{ + {f / aspect_ratio, T(0), T(0), T(0)}, + {T(0), f, T(0), T(0)}, + {T(0), T(0), z_far / (z_near - z_far), T(-1)}, + {T(0), T(0), -(z_far * z_near) / (z_far - z_near), T(0)} + }}; +} + template matrix resize(const matrix& m) { diff --git a/src/renderer/passes/material-pass.cpp b/src/renderer/passes/material-pass.cpp index d6f393c..fa77c30 100644 --- a/src/renderer/passes/material-pass.cpp +++ b/src/renderer/passes/material-pass.cpp @@ -113,6 +113,9 @@ void material_pass::render(render_context* context) const glCullFace(GL_BACK); glDisable(GL_STENCIL_TEST); glStencilMask(0x00); + + // For half-z buffer + glDepthRange(-1.0f, 1.0f); auto viewport = framebuffer->get_dimensions(); rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport)); @@ -128,9 +131,10 @@ void material_pass::render(render_context* context) const float4x4 model; float4x4 model_view; float3x3 normal_model_view; - - - + float2 clip_depth; + clip_depth[0] = context->camera->get_clip_near_tween().interpolate(context->alpha); + clip_depth[1] = context->camera->get_clip_far_tween().interpolate(context->alpha); + float log_depth_coef = 2.0f / std::log2(clip_depth[1] + 1.0f); int active_material_flags = 0; @@ -488,6 +492,10 @@ void material_pass::render(render_context* context) const parameters->model_view_projection->upload(model_view_projection); if (parameters->normal_model_view) parameters->normal_model_view->upload(normal_model_view); + if (parameters->clip_depth) + parameters->clip_depth->upload(clip_depth); + if (parameters->log_depth_coef) + parameters->log_depth_coef->upload(log_depth_coef); // Draw geometry if (operation.instance_count) @@ -533,6 +541,8 @@ const material_pass::parameter_set* material_pass::load_parameter_set(const shad parameters->view_projection = program->get_input("view_projection"); parameters->model_view_projection = program->get_input("model_view_projection"); parameters->normal_model_view = program->get_input("normal_model_view"); + parameters->clip_depth = program->get_input("clip_depth"); + parameters->log_depth_coef = program->get_input("log_depth_coef"); parameters->ambient_light_count = program->get_input("ambient_light_count"); parameters->ambient_light_colors = program->get_input("ambient_light_colors"); parameters->point_light_count = program->get_input("point_light_count"); diff --git a/src/renderer/passes/material-pass.hpp b/src/renderer/passes/material-pass.hpp index 90a625f..c193f1f 100644 --- a/src/renderer/passes/material-pass.hpp +++ b/src/renderer/passes/material-pass.hpp @@ -77,6 +77,8 @@ private: const shader_input* view_projection; const shader_input* model_view_projection; const shader_input* normal_model_view; + const shader_input* clip_depth; + const shader_input* log_depth_coef; const shader_input* ambient_light_count; const shader_input* ambient_light_colors; diff --git a/src/renderer/passes/shadow-map-pass.cpp b/src/renderer/passes/shadow-map-pass.cpp index 82a02ea..e523181 100644 --- a/src/renderer/passes/shadow-map-pass.cpp +++ b/src/renderer/passes/shadow-map-pass.cpp @@ -107,6 +107,9 @@ void shadow_map_pass::render(render_context* context) const // Disable face culling glDisable(GL_CULL_FACE); + // For half-z buffer + //glDepthRange(-1.0f, 1.0f); + // Get camera const ::camera& camera = *context->camera; @@ -137,7 +140,7 @@ void shadow_map_pass::render(render_context* context) const float3 forward = light_transform.rotation * global_forward; float3 up = light_transform.rotation * global_up; float4x4 light_view = math::look_at(light_transform.translation, light_transform.translation + forward, up); - float4x4 light_projection = math::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); + float4x4 light_projection = math::ortho_half_z(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); float4x4 light_view_projection = light_projection * light_view; // Get the camera's view matrix @@ -161,7 +164,7 @@ void shadow_map_pass::render(render_context* context) const // Calculate projection matrix for view camera subfrustum const float subfrustum_near = split_distances[i]; const float subfrustum_far = split_distances[i + 1]; - float4x4 subfrustum_projection = math::perspective(camera.get_fov(), camera.get_aspect_ratio(), subfrustum_near, subfrustum_far); + float4x4 subfrustum_projection = math::perspective_half_z(camera.get_fov(), camera.get_aspect_ratio(), subfrustum_near, subfrustum_far); // Calculate view camera subfrustum view_frustum subfrustum(subfrustum_projection * camera_view); @@ -186,6 +189,7 @@ void shadow_map_pass::render(render_context* context) const scale.x = 2.0f / (cropping_bounds.max_point.x - cropping_bounds.min_point.x); scale.y = 2.0f / (cropping_bounds.max_point.y - cropping_bounds.min_point.y); scale.z = 1.0f / (cropping_bounds.max_point.z - cropping_bounds.min_point.z); + //scale.z = 2.0f / (cropping_bounds.max_point.z - cropping_bounds.min_point.z); // Quantize scale float scale_quantizer = 64.0f; @@ -197,6 +201,7 @@ void shadow_map_pass::render(render_context* context) const offset.x = (cropping_bounds.max_point.x + cropping_bounds.min_point.x) * scale.x * -0.5f; offset.y = (cropping_bounds.max_point.y + cropping_bounds.min_point.y) * scale.y * -0.5f; offset.z = -cropping_bounds.min_point.z * scale.z; + //offset.z = (cropping_bounds.max_point.z + cropping_bounds.min_point.z) * scale.z * -0.5f; // Quantize offset float half_shadow_map_resolution = static_cast(shadow_map_resolution) * 0.5f; diff --git a/src/scene/camera.cpp b/src/scene/camera.cpp index 8c6daf0..93c82d3 100644 --- a/src/scene/camera.cpp +++ b/src/scene/camera.cpp @@ -93,7 +93,8 @@ float3 camera::unproject(const float3& window, const float4& viewport) const float4 result; result[0] = ((window[0] - viewport[0]) / viewport[2]) * 2.0f - 1.0f; result[1] = ((window[1] - viewport[1]) / viewport[3]) * 2.0f - 1.0f; - result[2] = window[2] * 2.0f - 1.0f; + //result[2] = window[2] * 2.0f - 1.0f; z: [-1, 1] + result[2] = window[2]; // z: [0, 1] result[3] = 1.0f; result = math::inverse(view_projection[1]) * result; @@ -110,7 +111,7 @@ void camera::set_perspective(float fov, float aspect_ratio, float clip_near, flo this->clip_near[1] = clip_near; this->clip_far[1] = clip_far; - projection[1] = math::perspective(fov, aspect_ratio, clip_near, clip_far); + projection[1] = math::perspective_half_z(fov, aspect_ratio, clip_near, clip_far); // Recalculate view-projection matrix view_projection[1] = projection[1] * view[1];