13#if defined(WITH_FFTW3)
43#define MAX_GLARE_ITERATIONS 5
44#define MAX_GLARE_SIZE 9
53 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
54 .compositor_domain_priority(0);
60 NodeGlare *ndg = MEM_cnew<NodeGlare>(__func__);
80 uiItemL(layout,
RPT_(
"Disabled, built without FFTW"), ICON_ERROR);
142 if (
get_input(
"Image").is_single_value()) {
148 if (node_storage(
bnode()).
mix == -1.0f) {
157 switch (node_storage(
bnode()).type) {
200 return highlights_result;
209 if (node_storage(
bnode()).star_45) {
223 Result &vertical_pass_result = highlights_result;
243 horizontal_pass_result.
release();
245 return vertical_pass_result;
264 horizontal_pass_result.
bind_as_image(shader,
"horizontal_img");
272 return horizontal_pass_result;
281 Result &anti_diagonal_pass_result = highlights_result;
291 anti_diagonal_pass_result.
bind_as_image(shader,
"anti_diagonal_img");
300 diagonal_pass_result.
release();
302 return anti_diagonal_pass_result;
329 return diagonal_pass_result;
339 return size.x + size.y - 1;
368 accumulated_streaks_result.
bind_as_image(shader,
"accumulated_streaks_img",
true);
379 return accumulated_streaks_result;
401 for (
const int iteration : iterations_range) {
405 const float2 streak_vector = streak_direction * iteration_magnitude;
415 output_streak_result.
bind_as_image(shader,
"output_streak_img");
425 if (iteration != iterations_range.
last()) {
434 return output_streak_result;
456 const float angle = start_angle + (
float(streak_index) / number_of_streaks) * (
M_PI * 2.0f);
487 const float fade_factor = std::pow(node_storage(
bnode()).
fade, iteration_magnitude);
488 return float3(fade_factor, std::pow(fade_factor, 2.0f), std::pow(fade_factor, 3.0f));
499 return std::pow(4.0f, iteration);
504 return node_storage(
bnode()).angle_ofs;
509 return node_storage(
bnode()).streaks;
527 color_modulators.size(),
528 (
const float(*)[4])color_modulators.data());
541 Result &input_ghost_result = base_ghost_result;
543 for (
const int i : iterations_range) {
548 accumulated_ghosts_result.
bind_as_image(shader,
"accumulated_ghost_img",
true);
558 if (i != iterations_range.
last()) {
567 return accumulated_ghosts_result;
609 base_ghost_result.
bind_as_image(shader,
"combined_ghost_img");
621 return base_ghost_result;
634 std::array<float4, 4> color_modulators;
635 color_modulators[0] =
float4(1.0f);
636 color_modulators[1] =
float4(1.0f, color_modulation_factor, color_modulation_factor, 1.0f);
637 color_modulators[2] =
float4(color_modulation_factor, color_modulation_factor, 1.0f, 1.0f);
638 color_modulators[3] =
float4(color_modulation_factor, 1.0f, color_modulation_factor, 1.0f);
640 return color_modulators;
659 std::array<float, 4> scales;
660 for (
const int i :
IndexRange(scales.size())) {
662 const int global_i = iteration * 4 + i;
666 scales[i] = 2.1f * (1.0f - progression);
671 scales[i] = -0.99f / scales[i];
739 const int smaller_glare_dimension =
math::min(glare_size.x, glare_size.y);
740 const int chain_length =
int(std::log2(smaller_glare_dimension)) -
746 if (chain_length < 2) {
757 const IndexRange upsample_passes_range(chain_length - 1);
761 for (
const int i : upsample_passes_range) {
762 Result &input = downsample_chain[upsample_passes_range.
last() - i + 1];
764 input.bind_as_texture(shader,
"input_tx");
766 const Result &output = downsample_chain[upsample_passes_range.
last() - i];
767 output.bind_as_image(shader,
"output_img",
true);
771 input.unbind_as_texture();
772 output.unbind_as_image();
778 return downsample_chain[0];
790 Array<Result> downsample_chain(chain_length, downsampled_result);
795 downsample_chain[0] = highlights_result;
796 const IndexRange downsample_passes_range(chain_length - 1);
799 for (
const int i : downsample_passes_range) {
804 if (i == downsample_passes_range.
first()) {
805 shader =
context().
get_shader(
"compositor_glare_bloom_downsample_karis_average");
809 shader =
context().
get_shader(
"compositor_glare_bloom_downsample_simple_average");
813 const Result &input = downsample_chain[i];
815 input.bind_as_texture(shader,
"input_tx");
817 Result &output = downsample_chain[i + 1];
818 output.allocate_texture(input.domain().size / 2);
819 output.bind_as_image(shader,
"output_img");
823 input.unbind_as_texture();
824 output.unbind_as_image();
828 return downsample_chain;
843 return node_storage(
bnode()).size;
855#if defined(WITH_FFTW3)
863 const int needed_padding_amount = kernel_size / 2;
865 const int2 needed_spatial_size = image_size + needed_padding_amount;
872 const int2 frequency_size =
int2(spatial_size.x / 2 + 1, spatial_size.y);
875 const int channels_count = 3;
876 const int image_channels_count = 4;
877 const int64_t spatial_pixels_per_channel =
int64_t(spatial_size.x) * spatial_size.y;
878 const int64_t frequency_pixels_per_channel =
int64_t(frequency_size.x) * frequency_size.y;
879 const int64_t spatial_pixels_count = spatial_pixels_per_channel * channels_count;
880 const int64_t frequency_pixels_count = frequency_pixels_per_channel * channels_count;
882 float *image_spatial_domain = fftwf_alloc_real(spatial_pixels_count);
883 std::complex<float> *image_frequency_domain =
reinterpret_cast<std::complex<float> *
>(
884 fftwf_alloc_complex(frequency_pixels_count));
887 fftwf_plan forward_plan = fftwf_plan_dft_r2c_2d(
890 image_spatial_domain,
891 reinterpret_cast<fftwf_complex *
>(image_frequency_domain),
895 float *highlights_buffer =
static_cast<float *
>(
901 for (const int64_t y : sub_y_range) {
902 for (const int64_t x : IndexRange(spatial_size.x)) {
903 const bool is_inside_image = x < image_size.x && y < image_size.y;
904 for (const int64_t channel : IndexRange(channels_count)) {
905 const int64_t base_index = y * spatial_size.x + x;
906 const int64_t output_index = base_index + spatial_pixels_per_channel * channel;
907 if (is_inside_image) {
908 const int64_t image_index = (y * image_size.x + x) * image_channels_count + channel;
909 image_spatial_domain[output_index] = highlights_buffer[image_index];
912 image_spatial_domain[output_index] = 0.0f;
920 for (
const int64_t channel : sub_range) {
921 fftwf_execute_dft_r2c(forward_plan,
922 image_spatial_domain + spatial_pixels_per_channel * channel,
923 reinterpret_cast<fftwf_complex *
>(image_frequency_domain) +
924 frequency_pixels_per_channel * channel);
929 kernel_size, spatial_size);
936 const float normalization_scale =
float(spatial_size.x) * spatial_size.y *
939 for (const int64_t channel : IndexRange(channels_count)) {
940 for (const int64_t y : sub_y_range) {
941 for (const int64_t x : IndexRange(frequency_size.x)) {
942 const int64_t base_index = x + y * frequency_size.x;
943 const int64_t output_index = base_index + frequency_pixels_per_channel * channel;
944 const std::complex<float> kernel_value = fog_glow_kernel.frequencies()[base_index];
945 image_frequency_domain[output_index] *= kernel_value / normalization_scale;
952 fftwf_plan backward_plan = fftwf_plan_dft_c2r_2d(
955 reinterpret_cast<fftwf_complex *
>(image_frequency_domain),
956 image_spatial_domain,
960 for (
const int64_t channel : sub_range) {
961 fftwf_execute_dft_c2r(backward_plan,
962 reinterpret_cast<fftwf_complex *
>(image_frequency_domain) +
963 frequency_pixels_per_channel * channel,
964 image_spatial_domain + spatial_pixels_per_channel * channel);
972 for (const int64_t y : sub_y_range) {
973 for (const int64_t x : IndexRange(image_size.x)) {
974 for (const int64_t channel : IndexRange(channels_count)) {
975 const int64_t output_index = (x + y * image_size.x) * image_channels_count;
976 const int64_t base_index = x + y * spatial_size.x;
977 const int64_t input_index = base_index + spatial_pixels_per_channel * channel;
978 output[output_index + channel] = image_spatial_domain[input_index];
979 output[output_index + 3] = highlights_buffer[output_index + 3];
986 fftwf_destroy_plan(forward_plan);
987 fftwf_destroy_plan(backward_plan);
988 fftwf_free(image_spatial_domain);
989 fftwf_free(image_frequency_domain);
996 return fog_glow_result;
1005 return (1 << node_storage(bnode()).size) + 1;
1014 GPUShader *shader = context().get_shader(
"compositor_glare_mix");
1025 const Domain domain = compute_domain();
1026 Result &output_image = get_result(
"Image");
1048 return compute_domain().size / get_quality_factor();
1053 return node_storage(bnode()).iter;
1058 return node_storage(bnode()).colmod;
1074 return 1 << node_storage(bnode()).quality;
1092 ntype.
declare = file_ns::cmp_node_glare_declare;
1093 ntype.
draw_buttons = file_ns::node_composit_buts_glare;
1094 ntype.
initfunc = file_ns::node_composit_init_glare;
#define NODE_STORAGE_FUNCS(StorageT)
#define NODE_CLASS_OP_FILTER
#define BLI_assert_unreachable()
@ CMP_NODE_GLARE_SIMPLE_STAR
@ CMP_NODE_GLARE_FOG_GLOW
void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2])
void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3])
void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float(*val)[4])
void GPU_shader_bind(GPUShader *shader)
void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4])
void GPU_memory_barrier(eGPUBarrier barrier)
@ GPU_BARRIER_TEXTURE_UPDATE
void GPU_texture_clear(GPUTexture *texture, eGPUDataFormat data_format, const void *data)
void GPU_texture_copy(GPUTexture *dst, GPUTexture *src)
void * GPU_texture_read(GPUTexture *texture, eGPUDataFormat data_format, int mip_level)
void GPU_texture_extend_mode(GPUTexture *texture, GPUSamplerExtendMode extend_mode)
@ GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER
void GPU_texture_filter_mode(GPUTexture *texture, bool use_filter)
void GPU_texture_update(GPUTexture *texture, eGPUDataFormat data_format, const void *data)
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
struct GPUShader GPUShader
constexpr int64_t first() const
constexpr int64_t last(const int64_t n=0) const
constexpr IndexRange drop_front(int64_t n) const
float get_small_ghost_radius()
float get_ghost_color_modulation_factor()
float3 compute_streak_fade_factors(float iteration_magnitude)
int get_number_of_streaks()
Result execute_simple_star_axis_aligned(Result &highlights_result)
int compute_fog_glow_kernel_size()
float get_streaks_start_angle()
float compute_streak_attenuation_factor()
Result execute_simple_star_horizontal_pass(Result &highlights_result)
Result execute_highlights()
Result execute_simple_star(Result &highlights_result)
Result execute_fog_glow(Result &highlights_result)
std::array< float4, 4 > compute_ghost_color_modulators()
float get_color_modulation_factor()
Array< Result > compute_bloom_downsample_chain(Result &highlights_result, int chain_length)
float compute_streak_iteration_magnitude(int iteration)
Result execute_simple_star_diagonal(Result &highlights_result)
float compute_streak_color_modulator(int iteration)
Result execute_bloom(Result &highlights_result)
int compute_simple_star_diagonals_count()
Result execute_simple_star_diagonal_pass(Result &highlights_result)
Result execute_ghost(Result &highlights_result)
Result apply_streak_filter(Result &highlights_result, const float2 &streak_direction)
float get_big_ghost_radius()
Result compute_base_ghost(Result &highlights_result)
void execute_mix(Result &glare_result)
float2 compute_streak_direction(int streak_index)
Result execute_glare(Result &highlights_result)
Result execute_streaks(Result &highlights_result)
int compute_bloom_size_halving_count()
std::array< float, 4 > compute_ghost_scales(int iteration)
int get_number_of_iterations()
StaticCacheManager & cache_manager()
GPUShader * get_shader(const char *info_name, ResultPrecision precision)
Result create_result(ResultType type, ResultPrecision precision)
FogGlowKernel & get(int kernel_size, int2 spatial_size)
float normalization_factor() const
NodeOperation(Context &context, DNode node)
const bNode & bnode() const
Result & get_input(StringRef identifier) const
Result & get_result(StringRef identifier)
Context & context() const
void bind_as_image(GPUShader *shader, const char *image_name, bool read=false) const
void pass_through(Result &target)
void unbind_as_texture() const
const Domain & domain() const
void unbind_as_image() const
void allocate_texture(Domain domain, bool from_pool=true)
void bind_as_texture(GPUShader *shader, const char *texture_name) const
FogGlowKernelContainer fog_glow_kernels
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void MEM_freeN(void *vmemh)
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
void node_register_type(bNodeType *ntype)
int optimal_size_for_real_transform(int size)
T cos(const AngleRadianBase< T > &a)
T min(const T &a, const T &b)
T sin(const AngleRadianBase< T > &a)
static void cmp_node_glare_declare(NodeDeclarationBuilder &b)
static void node_composit_buts_glare(uiLayout *layout, bContext *, PointerRNA *ptr)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static void node_composit_init_glare(bNodeTree *, bNode *node)
void symmetric_separable_blur(Context &context, Result &input, Result &output, float2 radius, int filter_type=R_FILTER_GAUSS, bool extend_bounds=false, bool gamma_correct=false)
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
void register_node_type_cmp_glare()
#define MAX_GLARE_ITERATIONS
void cmp_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void node_free_standard_storage(bNode *node)
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
CCL_NAMESPACE_BEGIN ccl_device float fade(float t)
int RNA_enum_get(PointerRNA *ptr, const char *name)
NodeGetCompositorOperationFunction get_compositor_operation
void(* initfunc)(bNodeTree *ntree, bNode *node)
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeDeclareFunction declare
static pxr::UsdShadeInput get_input(const pxr::UsdShadeShader &usd_shader, const pxr::TfToken &input_name)