diff --git a/assets/shaders/block_f_shader.glsl b/assets/shaders/block_f_shader.glsl index 9e0d681..0e680c7 100644 --- a/assets/shaders/block_f_shader.glsl +++ b/assets/shaders/block_f_shader.glsl @@ -15,17 +15,117 @@ uniform vec3 sunlightDir; uniform bool shader_on; uniform int shadowMode; -const vec2 poissonDisk[8] = vec2[]( +uniform float lightSizeUV; +uniform float minRadius; +uniform float maxRadius; +const vec2 poissonDisk32[32] = vec2[]( + vec2(-0.975402, -0.071138), + vec2(-0.920347, -0.411420), + vec2(-0.883908, 0.217872), + vec2(-0.815442, -0.879125), + vec2(-0.775043, 0.543896), + vec2(-0.698126, -0.227570), + vec2(-0.682433, 0.801894), + vec2(-0.563905, 0.021517), + vec2(-0.443233, -0.975116), + vec2(-0.412231, 0.361307), + vec2(-0.264969, -0.418930), + vec2(-0.241888, 0.997065), + vec2(-0.094184, -0.929389), + vec2(-0.019101, 0.680997), + vec2( 0.143832, -0.141008), + vec2( 0.199841, 0.786414), + + vec2( 0.344959, 0.293878), + vec2( 0.443233, -0.475115), + vec2( 0.537430, -0.473734), + vec2( 0.589349, 0.569135), + vec2( 0.674281, -0.178897), + vec2( 0.791975, 0.190902), + vec2( 0.815442, 0.879125), + vec2( 0.896420, -0.613392), + vec2( 0.945586, -0.768907), + vec2( 0.974844, 0.756484), + vec2(-0.814100, 0.914376), + vec2(-0.382775, 0.276768), + vec2(-0.915886, 0.457714), + vec2( 0.537800, 0.912200), + vec2(-0.620000, -0.650000), + vec2( 0.120000, -0.780000) +); + +const vec2 poissonDisk16[16] = vec2[]( + vec2(-0.94201624, -0.39906216), vec2(0.94558609, -0.76890725), + vec2(-0.09418410, -0.92938870), vec2(0.34495938, 0.29387760), + vec2(-0.91588581, 0.45771432), vec2(-0.81544232, -0.87912464), + vec2(-0.38277543, 0.27676845), vec2(0.97484398, 0.75648379), + vec2(0.44323325, -0.97511554), vec2(0.53742981, -0.47373420), + vec2(-0.26496911, -0.41893023), vec2(0.79197514, 0.19090188), + vec2(-0.24188840, 0.99706507), vec2(-0.81409955, 0.91437590), + vec2(0.19984126, 0.78641367), vec2(0.14383161, -0.14100790) +); +const vec2 poissonDisk8[8] = vec2[]( vec2( 0.1440, 0.7659), vec2(-0.5761, 0.4479), vec2(-0.3220, -0.6058), vec2( 0.5693, -0.4048), vec2(-0.1276, 0.1657), vec2(-0.0649, -0.0165), vec2( 0.2773, -0.0305), vec2(-0.1134, -0.2122) ); - +uniform int samples; float random(vec3 seed) { return fract(sin(dot(seed, vec3(12.9898,78.233,45.5432))) * 43758.5453); } +float FindBlocker(vec2 uv, + float zReceiver, + vec2 texelSize, + float bias, + float lightSizeUV) +{ + float avgDepth = 0.0; + int blockers = 0; + + float searchRadius = lightSizeUV * 0.5; + + for(int i = 0; i < samples; i++) + { + vec2 offset; + if (samples == 32) { + offset = + poissonDisk32[i] + * searchRadius + * texelSize; + } else if (samples == 16) { + offset = + poissonDisk16[i] + * searchRadius + * texelSize; + } else if (samples == 8) { + offset = + poissonDisk8[i] + * searchRadius + * texelSize; + } else { + offset = + poissonDisk32[i] + * searchRadius + * texelSize; + } + float depth = + texture(shadowMap, uv + offset).r; + + if(depth < zReceiver - bias) + { + avgDepth += depth; + blockers++; + } + } + + if(blockers == 0) + return -1.0; + + return avgDepth / blockers; +} + float ShadowCalculation(vec4 fragPosLightSpace, vec3 norm, vec3 lightDir) { @@ -40,10 +140,12 @@ float ShadowCalculation(vec4 fragPosLightSpace, vec3 norm, vec3 lightDir) float currentDepth = projCoords.z; vec2 texelSize = 1.0 / vec2(textureSize(shadowMap, 0)); float shadow = 0.0; + float bias = - max( + clamp( + 0.001 * (1.0 - dot(norm, lightDir)), 0.0003, - 0.001 * (1.0 - dot(norm, lightDir)) + 0.003 ); if (shadowMode == 0) { @@ -51,13 +153,20 @@ float ShadowCalculation(vec4 fragPosLightSpace, vec3 norm, vec3 lightDir) float angle = random(seed) * 6.2831853;; // 2*PI float s = sin(angle), c = cos(angle); mat2 rot = mat2(c, -s, s, c); - - float radius = 0.7; - + //float radius = 0.7; + float radius = mix(1.0, 4.0, currentDepth); - const int samples = 8; for (int i = 0; i < samples; ++i) { - vec2 offset = rot * poissonDisk[i] * radius * texelSize; + vec2 offset; + if (samples == 32) { + offset = rot * poissonDisk32[i] * radius * texelSize; + } else if (samples == 16) { + offset = rot * poissonDisk16[i] * radius * texelSize; + } else if (samples == 8) { + offset = rot * poissonDisk8[i] * radius * texelSize; + } else { + offset = rot * poissonDisk32[i] * radius * texelSize; + } float pcfDepth = texture(shadowMap, projCoords.xy + offset).r; shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0); } @@ -80,6 +189,59 @@ float ShadowCalculation(vec4 fragPosLightSpace, vec3 norm, vec3 lightDir) currentDepth - bias > pcfDepth ? 1.0 : 0.0; + } else if (shadowMode == 3) { + float avgBlockerDepth = + FindBlocker( + projCoords.xy, + currentDepth, + texelSize, + bias, + lightSizeUV + ); + + if(avgBlockerDepth < 0.0) + { + return 0.0; + } + + vec3 seed = vert_pos * 37.0 + sin(vert_pos * 91.7) * 13.0; + float angle = random(seed) * 6.2831853;; // 2*PI + float s = sin(angle), c = cos(angle); + mat2 rot = mat2(c, -s, s, c); + /* + float penumbraRatio = (currentDepth - avgBlockerDepth); + float radius = clamp( + penumbraRatio * lightSizeUV, + minRadius, + maxRadius + ); + */ + float radius = + mix( + minRadius, + maxRadius, + smoothstep( + 0.0, + 0.05, + currentDepth - avgBlockerDepth + ) + ); + for (int i = 0; i < samples; ++i) { + vec2 offset; + if (samples == 32) { + offset = rot * poissonDisk32[i] * radius * texelSize; + } else if (samples == 16) { + offset = rot * poissonDisk16[i] * radius * texelSize; + } else if (samples == 8) { + offset = rot * poissonDisk8[i] * radius * texelSize; + } else { + offset = rot * poissonDisk32[i] * radius * texelSize; + } + float pcfDepth = texture(shadowMap, projCoords.xy + offset).r; + shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0); + } + shadow /= float(samples); + } else { float pcfDepth = texture(shadowMap, projCoords.xy).r; diff --git a/include/Cubed/dev_panel.hpp b/include/Cubed/dev_panel.hpp index 4b47e56..7993746 100644 --- a/include/Cubed/dev_panel.hpp +++ b/include/Cubed/dev_panel.hpp @@ -47,6 +47,7 @@ private: int m_pre_set_day_tick = 0; int m_pre_set_tick_speed = 1; bool m_tick_frezze = false; + int m_samples_idx = 1; void show_about_table_bar(); void show_biome_table_bar(); void show_time_table_bar(); diff --git a/include/Cubed/renderer.hpp b/include/Cubed/renderer.hpp index 935dd29..fcad3e6 100644 --- a/include/Cubed/renderer.hpp +++ b/include/Cubed/renderer.hpp @@ -34,6 +34,10 @@ public: bool& shader_on(); int& shadow_mode(); int& light_cull_face(); + int& light_size_uv(); + float& min_radius(); + float& max_radius(); + int& samples(); private: static constexpr glm::vec3 SUNLIGHT_COLOR{1.0f, 1.0f, 1.0f}; @@ -99,7 +103,11 @@ private: float m_blend_t = 1.0f; bool m_blend_initialized = false; static constexpr float BLEND_DURATION = 0.15f; + int m_light_size_uv = 20; + float m_min_radius = 2.0f; + float m_max_radius = 20.0f; + int m_samples = 16; /* 0 - quad vao 1 - sky vao diff --git a/src/dev_panel.cpp b/src/dev_panel.cpp index dc248a5..16ca3da 100644 --- a/src/dev_panel.cpp +++ b/src/dev_panel.cpp @@ -611,9 +611,10 @@ void DevPanel::show_items_tab_item() { void DevPanel::show_shader_tab_item() { - static const char* shader_mode[] = {"Rotated Poisson Disk PCF", - "3x3 Square Grid PCF", "PCF off"}; + static const char* shader_mode[] = { + "Rotated Poisson Disk PCF", "3x3 Square Grid PCF", "PCF off", "PCSS"}; static const char* cull_face_mode[] = {"Front", "Back"}; + static const char* samples[] = {"8", "16", "32"}; if (ImGui::BeginTabItem("shader")) { ImGui::Checkbox("Shader", &m_app.renderer().shader_on()); if (ImGui::SliderFloat("AmbientStrength", @@ -626,6 +627,25 @@ void DevPanel::show_shader_tab_item() { IM_ARRAYSIZE(shader_mode)); ImGui::Combo("LightCullFaceMode", &m_app.renderer().light_cull_face(), cull_face_mode, IM_ARRAYSIZE(cull_face_mode)); + if (ImGui::Combo("samples", &m_samples_idx, samples, + IM_ARRAYSIZE(samples))) { + if (m_samples_idx == 0) { + m_app.renderer().samples() = 8; + } else if (m_samples_idx == 1) { + m_app.renderer().samples() = 16; + } else if (m_samples_idx == 2) { + m_app.renderer().samples() = 32; + } else { + Logger::warn("Samples Index {} is invaild", m_samples_idx); + m_app.renderer().samples() = 16; + } + } + ImGui::SliderInt("LightSizeUV", &m_app.renderer().light_size_uv(), 0, + 800); + ImGui::SliderFloat("MinRaduis", &m_app.renderer().min_radius(), 0.0f, + 20.0f); + ImGui::SliderFloat("MaxRadius", &m_app.renderer().max_radius(), 0.0f, + 100.0f); ImGui::EndTabItem(); } } diff --git a/src/renderer.cpp b/src/renderer.cpp index 9ffdf72..51199c1 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -505,6 +505,7 @@ void Renderer::render_world() { glm::mat4 light_space_matrix; auto& m_render_snapshots = m_world.render_snapshots(); auto& camera_pos = m_camera.get_camera_pos(); + float texels_per_unit = 0.0f; if (m_shader_on) { const auto& depth_shader = get_shader("depth_shader"); depth_shader.use(); @@ -524,7 +525,7 @@ void Renderer::render_world() { : glm::vec3(0, 1, 0); glm::mat4 light_basis = glm::lookAt(glm::vec3(0.0f), shadow_sundir, up); - float texels_per_unit = DEPTH_MAP_SIZE / (half_extent * 2.0f); + texels_per_unit = DEPTH_MAP_SIZE / (half_extent * 2.0f); glm::vec3 ls_center = glm::vec3(light_basis * glm::vec4(center, 1.0f)); ls_center.x = std::round(ls_center.x * texels_per_unit) / texels_per_unit; @@ -633,6 +634,12 @@ void Renderer::render_world() { glm::value_ptr(light_dir_view)); glUniform1i(normal_block_shader.loc("shadowMode"), m_shadow_mode); glUniform1i(normal_block_shader.loc("shader_on"), m_shader_on); + glUniform1f(normal_block_shader.loc("texelsPerUnit"), texels_per_unit); + glUniform1f(normal_block_shader.loc("lightSizeUV"), + static_cast(m_light_size_uv)); + glUniform1f(normal_block_shader.loc("minRadius"), m_min_radius); + glUniform1f(normal_block_shader.loc("maxRadius"), m_max_radius); + glUniform1i(normal_block_shader.loc("samples"), m_samples); m_mvp_mat = m_p_mat * m_mv_mat; auto& m_planes = m_world.planes(); @@ -814,4 +821,8 @@ bool& Renderer::discard_transparent() { return m_discard_tranparent; } bool& Renderer::shader_on() { return m_shader_on; } int& Renderer::shadow_mode() { return m_shadow_mode; } int& Renderer::light_cull_face() { return m_light_cull_face; } +int& Renderer::light_size_uv() { return m_light_size_uv; } +float& Renderer::min_radius() { return m_min_radius; } +float& Renderer::max_radius() { return m_max_radius; } +int& Renderer::samples() { return m_samples; } } // namespace Cubed \ No newline at end of file