Compositor: Removing Sun Beams node

This patch removes the Sun Beams node since it is now part of the
Glare node. It is versioned using a Glare node of Sun Beams type.

Pull Request: https://projects.blender.org/blender/blender/pulls/144110
This commit is contained in:
Mohamed Hassan
2025-08-12 19:53:54 +02:00
committed by Omar Emara
parent 69cf5e1ad7
commit ce7759bae6
14 changed files with 100 additions and 217 deletions

View File

@@ -150,7 +150,6 @@ class NODE_MT_category_compositor_filter(Menu):
node_add_menu.add_node_type(layout, "CompositorNodeKuwahara")
node_add_menu.add_node_type(layout, "CompositorNodePixelate")
node_add_menu.add_node_type(layout, "CompositorNodePosterize")
node_add_menu.add_node_type(layout, "CompositorNodeSunBeams")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)

View File

@@ -27,7 +27,7 @@
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 56
#define BLENDER_FILE_SUBVERSION 57
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@@ -228,7 +228,7 @@
#define CMP_NODE_GLARE 301
#define CMP_NODE_TONEMAP 302
#define CMP_NODE_LENSDIST 303
#define CMP_NODE_SUNBEAMS 304
#define CMP_NODE_SUNBEAMS_DEPRECATED 304
#define CMP_NODE_COLORCORRECTION 312
#define CMP_NODE_MASK_BOX 313

View File

@@ -4606,7 +4606,7 @@ void do_versions_after_linking_450(FileData * /*fd*/, Main *bmain)
FOREACH_NODETREE_BEGIN (bmain, node_tree, id) {
if (node_tree->type == NTREE_COMPOSIT) {
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
if (node->type_legacy == CMP_NODE_SUNBEAMS) {
if (node->type_legacy == CMP_NODE_SUNBEAMS_DEPRECATED) {
do_version_sun_beams_node_options_to_inputs_animation(node_tree, node);
}
}
@@ -5637,7 +5637,7 @@ void blo_do_versions_450(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
FOREACH_NODETREE_BEGIN (bmain, node_tree, id) {
if (node_tree->type == NTREE_COMPOSIT) {
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
if (node->type_legacy == CMP_NODE_SUNBEAMS) {
if (node->type_legacy == CMP_NODE_SUNBEAMS_DEPRECATED) {
do_version_sun_beams_node_options_to_inputs(node_tree, node);
}
}

View File

@@ -1347,6 +1347,69 @@ static void do_version_convert_gp_jitter_values(Brush *brush)
}
}
/* The Sun beams node was removed and the Glare node should be used instead, so we need to
* make the replacement. */
static void do_version_sun_beams(bNodeTree &node_tree, bNode &node)
{
blender::bke::node_tree_set_type(node_tree);
bNodeSocket *old_image_input = blender::bke::node_find_socket(node, SOCK_IN, "Image");
bNodeSocket *old_source_input = blender::bke::node_find_socket(node, SOCK_IN, "Source");
bNodeSocket *old_length_input = blender::bke::node_find_socket(node, SOCK_IN, "Length");
bNodeSocket *old_image_output = blender::bke::node_find_socket(node, SOCK_OUT, "Image");
bNode *glare_node = blender::bke::node_add_node(nullptr, node_tree, "CompositorNodeGlare");
static_cast<NodeGlare *>(glare_node->storage)->type = CMP_NODE_GLARE_SUN_BEAMS;
static_cast<NodeGlare *>(glare_node->storage)->quality = 0;
glare_node->parent = node.parent;
glare_node->location[0] = node.location[0];
glare_node->location[1] = node.location[1];
bNodeSocket *image_input = blender::bke::node_find_socket(*glare_node, SOCK_IN, "Image");
bNodeSocket *threshold_input = blender::bke::node_find_socket(
*glare_node, SOCK_IN, "Highlights Threshold");
bNodeSocket *size_input = blender::bke::node_find_socket(*glare_node, SOCK_IN, "Size");
bNodeSocket *source_input = blender::bke::node_find_socket(*glare_node, SOCK_IN, "Sun Position");
bNodeSocket *glare_output = blender::bke::node_find_socket(*glare_node, SOCK_OUT, "Glare");
copy_v4_v4(image_input->default_value_typed<bNodeSocketValueRGBA>()->value,
old_image_input->default_value_typed<bNodeSocketValueRGBA>()->value);
threshold_input->default_value_typed<bNodeSocketValueFloat>()->value = 0.0f;
size_input->default_value_typed<bNodeSocketValueFloat>()->value =
old_length_input->default_value_typed<bNodeSocketValueFloat>()->value;
copy_v2_v2(source_input->default_value_typed<bNodeSocketValueVector>()->value,
old_source_input->default_value_typed<bNodeSocketValueVector>()->value);
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &node_tree.links) {
if (link->tosock == old_image_input) {
version_node_add_link(
node_tree, *link->fromnode, *link->fromsock, *glare_node, *image_input);
blender::bke::node_remove_link(&node_tree, *link);
continue;
}
if (link->tosock == old_source_input) {
version_node_add_link(
node_tree, *link->fromnode, *link->fromsock, *glare_node, *source_input);
blender::bke::node_remove_link(&node_tree, *link);
continue;
}
if (link->tosock == old_length_input) {
version_node_add_link(node_tree, *link->fromnode, *link->fromsock, *glare_node, *size_input);
blender::bke::node_remove_link(&node_tree, *link);
continue;
}
if (link->fromsock == old_image_output) {
version_node_add_link(node_tree, *link->tonode, *link->tosock, *glare_node, *glare_output);
blender::bke::node_remove_link(&node_tree, *link);
}
}
version_node_remove(node_tree, node);
}
/* The Composite node was removed and a Group Output node should be used instead, so we need to
* make the replacement. But first note that the Group Output node relies on the node tree
* interface, so we ensure a default interface with a single input and output. This is only for
@@ -1602,6 +1665,19 @@ void do_versions_after_linking_500(FileData *fd, Main *bmain)
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 57)) {
FOREACH_NODETREE_BEGIN (bmain, node_tree, id) {
if (node_tree->type == NTREE_COMPOSIT) {
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNode *, node, &node_tree->nodes) {
if (node->type_legacy == CMP_NODE_SUNBEAMS_DEPRECATED) {
do_version_sun_beams(*node_tree, *node);
}
}
}
}
FOREACH_NODETREE_END;
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
@@ -1970,8 +2046,8 @@ void blo_do_versions_500(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
}
}
/* ImageFormatData gained a new media type which we need to be set according to the existing
* imtype. */
/* ImageFormatData gained a new media type which we need to be set according to the
* existing imtype. */
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 42)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
update_format_media_type(&scene->r.im_format);
@@ -2215,8 +2291,8 @@ void blo_do_versions_500(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
* \note Keep this message at the bottom of the function.
*/
/* Keep this versioning always enabled at the bottom of the function; it can only be moved behind
* a subversion bump when the file format is changed. */
/* Keep this versioning always enabled at the bottom of the function; it can only be moved
* behind a subversion bump when the file format is changed. */
LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) {
bke::mesh_freestyle_marks_to_generic(*mesh);
}

View File

@@ -202,6 +202,7 @@ set(GLSL_SRC
shaders/compositor_glare_simple_star_vertical_pass.glsl
shaders/compositor_glare_streaks_accumulate.glsl
shaders/compositor_glare_streaks_filter.glsl
shaders/compositor_glare_sun_beams.glsl
shaders/compositor_glare_write_glare_output.glsl
shaders/compositor_glare_write_highlights_output.glsl
shaders/compositor_horizontal_lens_distortion.glsl
@@ -256,7 +257,6 @@ set(GLSL_SRC
shaders/compositor_summed_area_table_compute_complete_x_prologues.glsl
shaders/compositor_summed_area_table_compute_complete_y_prologues.glsl
shaders/compositor_summed_area_table_compute_incomplete_prologues.glsl
shaders/compositor_sun_beams.glsl
shaders/compositor_symmetric_blur.glsl
shaders/compositor_symmetric_blur_variable_size.glsl
shaders/compositor_symmetric_separable_blur.glsl

View File

@@ -168,3 +168,17 @@ IMAGE(0, SFLOAT_16_16_16_16, read_write, image2D, output_img)
COMPUTE_SOURCE("compositor_glare_bloom_upsample.glsl")
DO_STATIC_COMPILATION()
GPU_SHADER_CREATE_END()
/* -----
* Sun Beams
* ----- */
GPU_SHADER_CREATE_INFO(compositor_glare_sun_beams)
LOCAL_GROUP_SIZE(16, 16)
PUSH_CONSTANT(float2, source)
PUSH_CONSTANT(int, max_steps)
SAMPLER(0, sampler2D, input_tx)
IMAGE(0, SFLOAT_16_16_16_16, write, image2D, output_img)
COMPUTE_SOURCE("compositor_glare_sun_beams.glsl")
DO_STATIC_COMPILATION()
GPU_SHADER_CREATE_END()

View File

@@ -1,15 +0,0 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* 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(float2, source)
PUSH_CONSTANT(int, max_steps)
SAMPLER(0, sampler2D, input_tx)
IMAGE(0, SFLOAT_16_16_16_16, write, image2D, output_img)
COMPUTE_SOURCE("compositor_sun_beams.glsl")
DO_STATIC_COMPILATION()
GPU_SHADER_CREATE_END()

View File

@@ -102,7 +102,6 @@
#include "compositor_smaa_info.hh"
#include "compositor_split_info.hh"
#include "compositor_summed_area_table_info.hh"
#include "compositor_sun_beams_info.hh"
#include "compositor_symmetric_blur_info.hh"
#include "compositor_symmetric_blur_variable_size_info.hh"
#include "compositor_symmetric_separable_blur_info.hh"

View File

@@ -10592,7 +10592,6 @@ static void rna_def_nodes(BlenderRNA *brna)
define("CompositorNode", "CompositorNodeSetAlpha", def_cmp_set_alpha);
define("CompositorNode", "CompositorNodeSplit", def_cmp_split);
define("CompositorNode", "CompositorNodeStabilize", def_cmp_stabilize2d);
define("CompositorNode", "CompositorNodeSunBeams");
define("CompositorNode", "CompositorNodeSwitch");
define("CompositorNode", "CompositorNodeSwitchView");
define("CompositorNode", "CompositorNodeTime", def_time);

View File

@@ -95,7 +95,6 @@ set(SRC
nodes/node_composite_setalpha.cc
nodes/node_composite_split.cc
nodes/node_composite_stabilize2d.cc
nodes/node_composite_sunbeams.cc
nodes/node_composite_switch.cc
nodes/node_composite_switchview.cc
nodes/node_composite_tonemap.cc

View File

@@ -2247,7 +2247,7 @@ class GlareOperation : public NodeOperation {
Result execute_sun_beams_gpu(Result &highlights, const int max_steps)
{
gpu::Shader *shader = context().get_shader("compositor_sun_beams");
gpu::Shader *shader = context().get_shader("compositor_glare_sun_beams");
GPU_shader_bind(shader);
GPU_shader_uniform_2fv(shader, "source", this->get_sun_position());

View File

@@ -1,188 +0,0 @@
/* SPDX-FileCopyrightText: 2014 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup cmpnodes
*/
#include "BLI_math_base.hh"
#include "BLI_math_vector.hh"
#include "BLI_math_vector_types.hh"
#include "UI_resources.hh"
#include "GPU_shader.hh"
#include "COM_node_operation.hh"
#include "COM_utilities.hh"
#include "node_composite_util.hh"
namespace blender::nodes::node_composite_sunbeams_cc {
static void cmp_node_sunbeams_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>("Image")
.default_value({1.0f, 1.0f, 1.0f, 1.0f})
.structure_type(StructureType::Dynamic);
b.add_input<decl::Vector>("Source")
.subtype(PROP_FACTOR)
.dimensions(2)
.default_value({0.5f, 0.5f})
.min(0.0f)
.max(1.0f)
.description(
"The position of the source of the rays in normalized coordinates. 0 means lower left "
"corner and 1 means upper right corner");
b.add_input<decl::Float>("Length")
.subtype(PROP_FACTOR)
.min(0.0f)
.max(1.0f)
.default_value(0.2f)
.description(
"The length of rays relative to the size of the image. 0 means no rays and 1 means the "
"rays cover the full extent of the image");
b.add_output<decl::Color>("Image");
}
using namespace blender::compositor;
class SunBeamsOperation : public NodeOperation {
public:
using NodeOperation::NodeOperation;
void execute() override
{
const Result &input_image = this->get_input("Image");
const int2 input_size = input_image.domain().size;
const int max_steps = int(this->get_length() * math::length(input_size));
if (max_steps == 0) {
Result &output_image = this->get_result("Image");
output_image.share_data(input_image);
return;
}
if (this->context().use_gpu()) {
this->execute_gpu(max_steps);
}
else {
this->execute_cpu(max_steps);
}
}
void execute_gpu(const int max_steps)
{
gpu::Shader *shader = context().get_shader("compositor_sun_beams");
GPU_shader_bind(shader);
GPU_shader_uniform_2fv(shader, "source", this->get_source());
GPU_shader_uniform_1i(shader, "max_steps", max_steps);
Result &input_image = get_input("Image");
GPU_texture_filter_mode(input_image, true);
GPU_texture_extend_mode(input_image, GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
input_image.bind_as_texture(shader, "input_tx");
Result &output_image = get_result("Image");
const Domain domain = compute_domain();
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();
}
void execute_cpu(const int max_steps)
{
const float2 source = this->get_source();
Result &input = get_input("Image");
const Domain domain = compute_domain();
Result &output = get_result("Image");
output.allocate_texture(domain);
const int2 input_size = domain.size;
parallel_for(input_size, [&](const int2 texel) {
/* 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 = math::max(
1.0f, math::distance(float2(texel), source * float2(input_size)));
int steps = math::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. */
float2 coordinates = (float2(texel) + float2(0.5f)) / float2(input_size);
float2 vector_to_source = source - coordinates;
float2 step_vector = vector_to_source / unbounded_steps;
float accumulated_weight = 0.0f;
float4 accumulated_color = float4(0.0f);
for (int i = 0; i <= steps; i++) {
float2 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 (position.x < 0.0f || position.y < 0.0f || position.x > 1.0f || position.y > 1.0f) {
break;
}
float4 sample_color = input.sample_bilinear_zero(position);
/* Attenuate the contributions of pixels that are further away from the source using a
* quadratic falloff. */
float weight = math::square(1.0f - i / float(steps));
accumulated_weight += weight;
accumulated_color += sample_color * weight;
}
accumulated_color /= accumulated_weight != 0.0f ? accumulated_weight : 1.0f;
output.store_pixel(texel, accumulated_color);
});
}
float2 get_source()
{
return this->get_input("Source").get_single_value_default(float2(0.5f));
}
float get_length()
{
return math::clamp(this->get_input("Length").get_single_value_default(0.2f), 0.0f, 1.0f);
}
};
static NodeOperation *get_compositor_operation(Context &context, DNode node)
{
return new SunBeamsOperation(context, node);
}
} // namespace blender::nodes::node_composite_sunbeams_cc
static void register_node_type_cmp_sunbeams()
{
namespace file_ns = blender::nodes::node_composite_sunbeams_cc;
static blender::bke::bNodeType ntype;
cmp_node_type_base(&ntype, "CompositorNodeSunBeams", CMP_NODE_SUNBEAMS);
ntype.ui_name = "Sun Beams";
ntype.ui_description = "Create sun beams based on image brightness";
ntype.enum_name_legacy = "SUNBEAMS";
ntype.nclass = NODE_CLASS_OP_FILTER;
ntype.declare = file_ns::cmp_node_sunbeams_declare;
ntype.get_compositor_operation = file_ns::get_compositor_operation;
blender::bke::node_register_type(ntype);
}
NOD_REGISTER_NODE(register_node_type_cmp_sunbeams)