Compositor: Redesign Sun Beams node
This patch redesigns the Sun Beams node. The old implementation produces unexpected results with an arbitrary alpha channel, due to the use of a step count normalization instead of a weighted normalization. The quality is also questionable due to the use of nearest neighbour interpolation as well as a low resolution integration. This patches redesign the node to be a simple line integration towards the source, limited by the maximum ray length. The sampling resolution covers the entire path of the integration and the image is sampled using bilinear filtering, producing smoother results. No alpha is introduced. Pull Request: https://projects.blender.org/blender/blender/pulls/116787
This commit is contained in:
@@ -2,35 +2,50 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
|
||||
#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 input_size = vec2(texture_size(input_tx));
|
||||
|
||||
vec2 coordinates = (vec2(texel) + vec2(0.5)) / vec2(input_size);
|
||||
/* The number of steps is the distance in pixels from the source to the current texel. With at
|
||||
* least a single step and at most the user specified maximum ray length, which is proportional
|
||||
* to the diagonal pixel count. */
|
||||
float unbounded_steps = max(1.0, distance(vec2(texel), source * input_size));
|
||||
int max_steps = int(max_ray_length * length(input_size));
|
||||
int steps = min(max_steps, int(unbounded_steps));
|
||||
|
||||
/* We integrate from the current pixel to the source pixel, so compute the start coordinates and
|
||||
* step vector in the direction to source. Notice that the step vector is still computed from the
|
||||
* unbounded steps, such that the total integration length becomes limited by the bounded steps,
|
||||
* and thus by the maximum ray length. */
|
||||
vec2 coordinates = (vec2(texel) + vec2(0.5)) / 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(vec2(input_size)) * integration_length;
|
||||
int steps = max(1, int(integration_length_in_pixels));
|
||||
vec2 step_vector = (direction_to_source * integration_length) / steps;
|
||||
vec2 step_vector = vector_to_source / unbounded_steps;
|
||||
|
||||
float accumulated_weight = 0.0;
|
||||
vec4 accumulated_color = vec4(0.0);
|
||||
for (int i = 0; i < steps; i++) {
|
||||
for (int i = 0; i <= steps; i++) {
|
||||
vec2 position = coordinates + i * step_vector;
|
||||
|
||||
/* We are already past the image boundaries, and any future steps are also past the image
|
||||
* boundaries, so break. */
|
||||
if (any(lessThan(position, vec2(0.0))) || any(greaterThan(position, vec2(1.0)))) {
|
||||
break;
|
||||
}
|
||||
|
||||
vec4 sample_color = texture(input_tx, position);
|
||||
|
||||
/* 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;
|
||||
* quadratic falloff. Also weight by the alpha to give more significance to opaque pixels. */
|
||||
float weight = (square(1.0 - i / float(steps))) * sample_color.a;
|
||||
|
||||
accumulated_weight += weight;
|
||||
accumulated_color += sample_color * weight;
|
||||
}
|
||||
|
||||
imageStore(output_img, texel, accumulated_color / steps);
|
||||
accumulated_color /= accumulated_weight != 0.0 ? accumulated_weight : 1.0;
|
||||
imageStore(output_img, texel, accumulated_color);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user