From 11aa762b1173079c14e6bdbd8cdc6a3f46fa9aa0 Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Wed, 7 Jun 2023 19:36:44 +0300 Subject: [PATCH] Realtime Compositor: Implement Sun Beams node This patch implements the Sun Beams node for the realtime compositor. The implementation is not identical to the existing CPU implementation, but is very close. The new implementation is a higher quality one and resolves some of the artefacts in the existing implementation. This is achieved by doing a simple line integration toward the source pixel, while having a number of integration steps that is invariant of the angle to the source. --- .../realtime_compositor/CMakeLists.txt | 2 ++ .../shaders/compositor_sun_beams.glsl | 32 +++++++++++++++++ .../infos/compositor_sun_beams_info.hh | 14 ++++++++ .../nodes/node_composite_sunbeams.cc | 34 ++++++++++++++++--- 4 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 source/blender/compositor/realtime_compositor/shaders/compositor_sun_beams.glsl create mode 100644 source/blender/compositor/realtime_compositor/shaders/infos/compositor_sun_beams_info.hh diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt index c2227545e8f..1d4840109b8 100644 --- a/source/blender/compositor/realtime_compositor/CMakeLists.txt +++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt @@ -145,6 +145,7 @@ set(GLSL_SRC shaders/compositor_smaa_edge_detection.glsl shaders/compositor_smaa_neighborhood_blending.glsl shaders/compositor_split_viewer.glsl + shaders/compositor_sun_beams.glsl shaders/compositor_symmetric_blur.glsl shaders/compositor_symmetric_blur_variable_size.glsl shaders/compositor_symmetric_separable_blur.glsl @@ -244,6 +245,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/infos/compositor_screen_lens_distortion_info.hh shaders/infos/compositor_smaa_info.hh shaders/infos/compositor_split_viewer_info.hh + shaders/infos/compositor_sun_beams_info.hh shaders/infos/compositor_symmetric_blur_info.hh shaders/infos/compositor_symmetric_blur_variable_size_info.hh shaders/infos/compositor_symmetric_separable_blur_info.hh diff --git a/source/blender/compositor/realtime_compositor/shaders/compositor_sun_beams.glsl b/source/blender/compositor/realtime_compositor/shaders/compositor_sun_beams.glsl new file mode 100644 index 00000000000..6b884b8f96b --- /dev/null +++ b/source/blender/compositor/realtime_compositor/shaders/compositor_sun_beams.glsl @@ -0,0 +1,32 @@ +#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) + +void main() +{ + ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + ivec2 input_size = texture_size(input_tx); + + vec2 coordinates = (vec2(texel) + vec2(0.5)) / vec2(input_size); + + vec2 vector_to_source = source - coordinates; + float distance_to_source = length(vector_to_source); + vec2 direction_to_source = vector_to_source / distance_to_source; + + /* We integrate from the current pixel to the source pixel, but up until the user specified + * maximum ray length. The number of integration steps is roughly equivalent to the number of + * pixels along the integration path. Assume a minimum number of steps of 1 to avoid zero + * division handling and return source pixels as is. */ + float integration_length = min(distance_to_source, max_ray_length); + float integration_length_in_pixels = length(input_size) * integration_length; + int steps = max(1, int(integration_length_in_pixels)); + vec2 step_vector = (direction_to_source * integration_length) / steps; + + vec4 accumulated_color = vec4(0.0); + for (int i = 0; i < steps; i++) { + /* Attenuate the contributions of pixels that are further away from the source using a + * quadratic falloff. */ + float weight = pow(1.0f - i / integration_length_in_pixels, 2.0); + accumulated_color += texture(input_tx, coordinates + i * step_vector) * weight; + } + + imageStore(output_img, texel, accumulated_color / steps); +} diff --git a/source/blender/compositor/realtime_compositor/shaders/infos/compositor_sun_beams_info.hh b/source/blender/compositor/realtime_compositor/shaders/infos/compositor_sun_beams_info.hh new file mode 100644 index 00000000000..44af0fd0940 --- /dev/null +++ b/source/blender/compositor/realtime_compositor/shaders/infos/compositor_sun_beams_info.hh @@ -0,0 +1,14 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_sun_beams) + .local_group_size(16, 16) + .push_constant(Type::VEC2, "source") + .push_constant(Type::FLOAT, "max_ray_length") + .sampler(0, ImageType::FLOAT_2D, "input_tx") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img") + .compute_source("compositor_sun_beams.glsl") + .do_static_compilation(true); diff --git a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc index 51e62ad14f9..287a41c0363 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc @@ -9,15 +9,22 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_shader.h" + #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" namespace blender::nodes::node_composite_sunbeams_cc { +NODE_STORAGE_FUNCS(NodeSunBeams) + static void cmp_node_sunbeams_declare(NodeDeclarationBuilder &b) { - b.add_input("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input("Image") + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); b.add_output("Image"); } @@ -49,8 +56,27 @@ class SunBeamsOperation : public NodeOperation { void execute() override { - get_input("Image").pass_through(get_result("Image")); - context().set_info_message("Viewport compositor setup not fully supported"); + GPUShader *shader = shader_manager().get("compositor_sun_beams"); + GPU_shader_bind(shader); + + GPU_shader_uniform_2fv(shader, "source", node_storage(bnode()).source); + GPU_shader_uniform_1f(shader, "max_ray_length", node_storage(bnode()).ray_length); + + const Result &input_image = get_input("Image"); + GPU_texture_filter_mode(input_image.texture(), true); + GPU_texture_extend_mode(input_image.texture(), GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER); + input_image.bind_as_texture(shader, "input_tx"); + + const Domain domain = compute_domain(); + Result &output_image = get_result("Image"); + output_image.allocate_texture(domain); + output_image.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + GPU_shader_unbind(); + output_image.unbind_as_image(); + input_image.unbind_as_texture(); } }; @@ -74,8 +100,6 @@ void register_node_type_cmp_sunbeams() node_type_storage( &ntype, "NodeSunBeams", node_free_standard_storage, node_copy_standard_storage); ntype.get_compositor_operation = file_ns::get_compositor_operation; - ntype.realtime_compositor_unsupported_message = N_( - "Node not supported in the Viewport compositor"); nodeRegisterType(&ntype); } -- 2.30.2