diff --git a/scripts/startup/bl_ui/node_add_menu_compositor.py b/scripts/startup/bl_ui/node_add_menu_compositor.py index 2d51dfbcb63..269597f4936 100644 --- a/scripts/startup/bl_ui/node_add_menu_compositor.py +++ b/scripts/startup/bl_ui/node_add_menu_compositor.py @@ -27,6 +27,7 @@ class NODE_MT_category_compositor_input(Menu): node_add_menu.add_node_type(layout, "CompositorNodeMovieClip") node_add_menu.add_node_type(layout, "CompositorNodeTexture") node_add_menu.add_node_type(layout, "CompositorNodeImageInfo") + node_add_menu.add_node_type(layout, "CompositorNodeImageCoordinates") if is_group: layout.separator() diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 98af4cb4056..ee820d341b9 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 77 +#define BLENDER_FILE_SUBVERSION 78 /* 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 diff --git a/source/blender/blenloader/intern/versioning_450.cc b/source/blender/blenloader/intern/versioning_450.cc index 7257dbb349a..0658d9ecbcc 100644 --- a/source/blender/blenloader/intern/versioning_450.cc +++ b/source/blender/blenloader/intern/versioning_450.cc @@ -3976,6 +3976,80 @@ static void do_version_color_balance_node_options_to_inputs_animation(bNodeTree }); } +/* The Coordinates outputs were moved into their own Texture Coordinate node. If used, add a + * Texture Coordinates node and use it instead. */ +static void do_version_replace_image_info_node_coordinates(bNodeTree *node_tree) +{ + LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) { + if (!STREQ(node->idname, "CompositorNodeImageInfo")) { + continue; + } + + bNodeLink *input_link = nullptr; + bNodeLink *output_texture_link = nullptr; + bNodeLink *output_pixel_link = nullptr; + LISTBASE_FOREACH (bNodeLink *, link, &node_tree->links) { + if (link->tonode == node) { + input_link = link; + } + + if (link->fromnode == node && + blender::StringRef(link->fromsock->identifier) == "Texture Coordinates") + { + output_texture_link = link; + } + + if (link->fromnode == node && + blender::StringRef(link->fromsock->identifier) == "Pixel Coordinates") + { + output_pixel_link = link; + } + } + + if (!output_texture_link && !output_pixel_link) { + continue; + } + + bNode *image_coordinates_node = blender::bke::node_add_node( + nullptr, *node_tree, "CompositorNodeImageCoordinates"); + image_coordinates_node->parent = node->parent; + image_coordinates_node->location[0] = node->location[0]; + image_coordinates_node->location[1] = node->location[1] - node->height - 10.0f; + + if (input_link) { + bNodeSocket *image_input = blender::bke::node_find_socket( + *image_coordinates_node, SOCK_IN, "Image"); + version_node_add_link(*node_tree, + *input_link->fromnode, + *input_link->fromsock, + *image_coordinates_node, + *image_input); + } + + if (output_texture_link) { + bNodeSocket *uniform_output = blender::bke::node_find_socket( + *image_coordinates_node, SOCK_OUT, "Uniform"); + version_node_add_link(*node_tree, + *image_coordinates_node, + *uniform_output, + *output_texture_link->tonode, + *output_texture_link->tosock); + blender::bke::node_remove_link(node_tree, *output_texture_link); + } + + if (output_pixel_link) { + bNodeSocket *pixel_output = blender::bke::node_find_socket( + *image_coordinates_node, SOCK_OUT, "Pixel"); + version_node_add_link(*node_tree, + *image_coordinates_node, + *pixel_output, + *output_pixel_link->tonode, + *output_pixel_link->tosock); + blender::bke::node_remove_link(node_tree, *output_pixel_link); + } + } +} + void do_versions_after_linking_450(FileData * /*fd*/, Main *bmain) { if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 8)) { @@ -5737,6 +5811,15 @@ void blo_do_versions_450(FileData * /*fd*/, Library * /*lib*/, Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 78)) { + FOREACH_NODETREE_BEGIN (bmain, node_tree, id) { + if (node_tree->type == NTREE_COMPOSIT) { + do_version_replace_image_info_node_coordinates(node_tree); + } + } + FOREACH_NODETREE_END; + } + /* Always run this versioning (keep at the bottom of the function). Meshes are written with the * legacy format which always needs to be converted to the new format on file load. To be moved * to a subversion check in 5.0. */ diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 5365a01c3b6..2eaaf4733bb 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -106,14 +106,13 @@ set(SRC cached_resources/intern/deriche_gaussian_coefficients.cc cached_resources/intern/distortion_grid.cc cached_resources/intern/fog_glow_kernel.cc + cached_resources/intern/image_coordinates.cc cached_resources/intern/keying_screen.cc cached_resources/intern/morphological_distance_feather_weights.cc cached_resources/intern/ocio_color_space_conversion_shader.cc - cached_resources/intern/pixel_coordinates.cc cached_resources/intern/smaa_precomputed_textures.cc cached_resources/intern/symmetric_blur_weights.cc cached_resources/intern/symmetric_separable_blur_weights.cc - cached_resources/intern/texture_coordinates.cc cached_resources/intern/van_vliet_gaussian_coefficients.cc cached_resources/COM_bokeh_kernel.hh @@ -125,14 +124,13 @@ set(SRC cached_resources/COM_deriche_gaussian_coefficients.hh cached_resources/COM_distortion_grid.hh cached_resources/COM_fog_glow_kernel.hh + cached_resources/COM_image_coordinates.hh cached_resources/COM_keying_screen.hh cached_resources/COM_morphological_distance_feather_weights.hh cached_resources/COM_ocio_color_space_conversion_shader.hh - cached_resources/COM_pixel_coordinates.hh cached_resources/COM_smaa_precomputed_textures.hh cached_resources/COM_symmetric_blur_weights.hh cached_resources/COM_symmetric_separable_blur_weights.hh - cached_resources/COM_texture_coordinates.hh cached_resources/COM_van_vliet_gaussian_coefficients.hh derived_resources/intern/denoised_auxiliary_pass.cc @@ -205,6 +203,9 @@ set(GLSL_SRC shaders/compositor_glare_write_highlights_output.glsl shaders/compositor_horizontal_lens_distortion.glsl shaders/compositor_id_mask.glsl + shaders/compositor_image_coordinates_normalized.glsl + shaders/compositor_image_coordinates_pixel.glsl + shaders/compositor_image_coordinates_uniform.glsl shaders/compositor_image_crop.glsl shaders/compositor_inpaint_compute_boundary.glsl shaders/compositor_inpaint_compute_region.glsl @@ -231,7 +232,6 @@ set(GLSL_SRC shaders/compositor_movie_distortion.glsl shaders/compositor_normalize.glsl shaders/compositor_parallel_reduction.glsl - shaders/compositor_pixel_coordinates.glsl shaders/compositor_pixelate.glsl shaders/compositor_plane_deform_anisotropic.glsl shaders/compositor_plane_deform_mask.glsl @@ -256,7 +256,6 @@ set(GLSL_SRC shaders/compositor_symmetric_blur_variable_size.glsl shaders/compositor_symmetric_separable_blur.glsl shaders/compositor_symmetric_separable_blur_variable_size.glsl - shaders/compositor_texture_coordinates.glsl shaders/compositor_tone_map_photoreceptor.glsl shaders/compositor_tone_map_simple.glsl shaders/compositor_translate_wrapped.glsl diff --git a/source/blender/compositor/COM_static_cache_manager.hh b/source/blender/compositor/COM_static_cache_manager.hh index f0f64a2a25f..833a9b92c73 100644 --- a/source/blender/compositor/COM_static_cache_manager.hh +++ b/source/blender/compositor/COM_static_cache_manager.hh @@ -12,14 +12,13 @@ #include "COM_deriche_gaussian_coefficients.hh" #include "COM_distortion_grid.hh" #include "COM_fog_glow_kernel.hh" +#include "COM_image_coordinates.hh" #include "COM_keying_screen.hh" #include "COM_morphological_distance_feather_weights.hh" #include "COM_ocio_color_space_conversion_shader.hh" -#include "COM_pixel_coordinates.hh" #include "COM_smaa_precomputed_textures.hh" #include "COM_symmetric_blur_weights.hh" #include "COM_symmetric_separable_blur_weights.hh" -#include "COM_texture_coordinates.hh" #include "COM_van_vliet_gaussian_coefficients.hh" namespace blender::compositor { @@ -65,8 +64,7 @@ class StaticCacheManager { DericheGaussianCoefficientsContainer deriche_gaussian_coefficients; VanVlietGaussianCoefficientsContainer van_vliet_gaussian_coefficients; FogGlowKernelContainer fog_glow_kernels; - TextureCoordinatesContainer texture_coordinates; - PixelCoordinatesContainer pixel_coordinates; + ImageCoordinatesContainer image_coordinates; private: /* The cache manager should skip the next reset. See the skip_next_reset() method for more diff --git a/source/blender/compositor/cached_resources/COM_pixel_coordinates.hh b/source/blender/compositor/cached_resources/COM_image_coordinates.hh similarity index 54% rename from source/blender/compositor/cached_resources/COM_pixel_coordinates.hh rename to source/blender/compositor/cached_resources/COM_image_coordinates.hh index 6d4322f56e2..7c2ee38ffed 100644 --- a/source/blender/compositor/cached_resources/COM_pixel_coordinates.hh +++ b/source/blender/compositor/cached_resources/COM_image_coordinates.hh @@ -17,55 +17,61 @@ namespace blender::compositor { class Context; +enum class CoordinatesType : uint8_t { + Uniform, + Normalized, + Pixel, +}; + /* ------------------------------------------------------------------------------------------------ - * Pixel Coordinates Key. + * Image Coordinates Key. */ -class PixelCoordinatesKey { +class ImageCoordinatesKey { public: int2 size; + CoordinatesType type; - PixelCoordinatesKey(const int2 &size); + ImageCoordinatesKey(const int2 &size, const CoordinatesType type); uint64_t hash() const; }; -bool operator==(const PixelCoordinatesKey &a, const PixelCoordinatesKey &b); +bool operator==(const ImageCoordinatesKey &a, const ImageCoordinatesKey &b); /* ------------------------------------------------------------------------------------------------- - * Pixel Coordinates. + * Image Coordinates. * - * A cached resource that computes and caches a result containing the pixel coordinates of an image - * with the given size. The coordinates represent the center of pixels, so they include half pixel - * offsets. */ -class PixelCoordinates : public CachedResource { + * A cached resource that computes and caches a result containing the coordinates of the pixels of + * an image with the given size. */ +class ImageCoordinates : public CachedResource { public: Result result; - PixelCoordinates(Context &context, const int2 &size); + ImageCoordinates(Context &context, const int2 &size, const CoordinatesType type); - ~PixelCoordinates(); + ~ImageCoordinates(); private: - void compute_gpu(Context &context); + void compute_gpu(Context &context, const CoordinatesType type); - void compute_cpu(); + void compute_cpu(const CoordinatesType type); }; /* ------------------------------------------------------------------------------------------------ - * Pixel Coordinates Container. + * Image Coordinates Container. */ -class PixelCoordinatesContainer : CachedResourceContainer { +class ImageCoordinatesContainer : CachedResourceContainer { private: - Map> map_; + Map> map_; public: void reset() override; - /* Check if there is an available PixelCoordinates cached resource with the given parameters in + /* Check if there is an available ImageCoordinates cached resource with the given parameters in * the container, if one exists, return it, otherwise, return a newly created one and add it to * the container. In both cases, tag the cached resource as needed to keep it cached for the next * evaluation. */ - Result &get(Context &context, const int2 &size); + Result &get(Context &context, const int2 &size, const CoordinatesType type); }; } // namespace blender::compositor diff --git a/source/blender/compositor/cached_resources/COM_texture_coordinates.hh b/source/blender/compositor/cached_resources/COM_texture_coordinates.hh deleted file mode 100644 index ffa9674750f..00000000000 --- a/source/blender/compositor/cached_resources/COM_texture_coordinates.hh +++ /dev/null @@ -1,72 +0,0 @@ -/* SPDX-FileCopyrightText: 2025 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -#include -#include - -#include "BLI_map.hh" -#include "BLI_math_vector_types.hh" - -#include "COM_cached_resource.hh" -#include "COM_result.hh" - -namespace blender::compositor { - -class Context; - -/* ------------------------------------------------------------------------------------------------ - * Texture Coordinates Key. - */ -class TextureCoordinatesKey { - public: - int2 size; - - TextureCoordinatesKey(const int2 &size); - - uint64_t hash() const; -}; - -bool operator==(const TextureCoordinatesKey &a, const TextureCoordinatesKey &b); - -/* ------------------------------------------------------------------------------------------------- - * Texture Coordinates. - * - * A cached resource that computes and caches a result containing the texture coordinates of an - * image with the given size. The texture coordinates are the zero centered pixel coordinates - * normalized along the greater dimension. Pixel coordinates represent the center of pixels, so - * they include half pixel offsets. */ -class TextureCoordinates : public CachedResource { - public: - Result result; - - TextureCoordinates(Context &context, const int2 &size); - - ~TextureCoordinates(); - - private: - void compute_gpu(Context &context); - - void compute_cpu(); -}; - -/* ------------------------------------------------------------------------------------------------ - * Texture Coordinates Container. - */ -class TextureCoordinatesContainer : CachedResourceContainer { - private: - Map> map_; - - public: - void reset() override; - - /* Check if there is an available TextureCoordinates cached resource with the given parameters in - * the container, if one exists, return it, otherwise, return a newly created one and add it to - * the container. In both cases, tag the cached resource as needed to keep it cached for the next - * evaluation. */ - Result &get(Context &context, const int2 &size); -}; - -} // namespace blender::compositor diff --git a/source/blender/compositor/cached_resources/intern/image_coordinates.cc b/source/blender/compositor/cached_resources/intern/image_coordinates.cc new file mode 100644 index 00000000000..f261c2b599a --- /dev/null +++ b/source/blender/compositor/cached_resources/intern/image_coordinates.cc @@ -0,0 +1,149 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include +#include + +#include "BLI_assert.h" +#include "BLI_hash.hh" +#include "BLI_math_vector_types.hh" + +#include "GPU_shader.hh" + +#include "COM_context.hh" +#include "COM_image_coordinates.hh" +#include "COM_result.hh" +#include "COM_utilities.hh" + +namespace blender::compositor { + +/* -------------------------------------------------------------------- + * Image Coordinates Key. + */ + +ImageCoordinatesKey::ImageCoordinatesKey(const int2 &size, const CoordinatesType type) + : size(size), type(type) +{ +} + +uint64_t ImageCoordinatesKey::hash() const +{ + return get_default_hash(this->size, this->type); +} + +bool operator==(const ImageCoordinatesKey &a, const ImageCoordinatesKey &b) +{ + return a.size == b.size && a.type == b.type; +} + +/* -------------------------------------------------------------------- + * Image Coordinates. + */ + +ImageCoordinates::ImageCoordinates(Context &context, const int2 &size, const CoordinatesType type) + : result(context.create_result(ResultType::Float3)) +{ + this->result.allocate_texture(Domain(size), false); + + if (context.use_gpu()) { + this->compute_gpu(context, type); + } + else { + this->compute_cpu(type); + } +} + +ImageCoordinates::~ImageCoordinates() +{ + this->result.release(); +} + +static const char *get_shader_name(const CoordinatesType type) +{ + switch (type) { + case CoordinatesType::Uniform: + return "compositor_image_coordinates_uniform"; + case CoordinatesType::Normalized: + return "compositor_image_coordinates_normalized"; + case CoordinatesType::Pixel: + return "compositor_image_coordinates_pixel"; + } + + BLI_assert_unreachable(); + return ""; +} + +void ImageCoordinates::compute_gpu(Context &context, const CoordinatesType type) +{ + GPUShader *shader = context.get_shader(get_shader_name(type)); + GPU_shader_bind(shader); + + this->result.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, this->result.domain().size); + + this->result.unbind_as_image(); + GPU_shader_unbind(); +} + +void ImageCoordinates::compute_cpu(const CoordinatesType type) +{ + switch (type) { + case CoordinatesType::Uniform: { + const int2 size = this->result.domain().size; + const int max_size = math::max(size.x, size.y); + parallel_for(size, [&](const int2 texel) { + float2 centered_coordinates = (float2(texel) + 0.5f) - float2(size) / 2.0f; + float2 normalized_coordinates = (centered_coordinates / max_size) * 2.0f; + this->result.store_pixel(texel, float3(normalized_coordinates, 0.0f)); + }); + break; + } + case CoordinatesType::Normalized: { + const int2 size = this->result.domain().size; + parallel_for(size, [&](const int2 texel) { + float2 normalized_coordinates = (float2(texel) + 0.5f) / float2(size); + this->result.store_pixel(texel, float3(normalized_coordinates, 0.0f)); + }); + break; + } + case CoordinatesType::Pixel: { + parallel_for(this->result.domain().size, [&](const int2 texel) { + this->result.store_pixel(texel, float3(float2(texel), 0.0f)); + }); + break; + } + } +} + +/* -------------------------------------------------------------------- + * Image Coordinates Container. + */ + +void ImageCoordinatesContainer::reset() +{ + /* First, delete all resources that are no longer needed. */ + map_.remove_if([](auto item) { return !item.value->needed; }); + + /* Second, reset the needed status of the remaining resources to false to ready them to track + * their needed status for the next evaluation. */ + for (auto &value : map_.values()) { + value->needed = false; + } +} + +Result &ImageCoordinatesContainer::get(Context &context, + const int2 &size, + const CoordinatesType type) +{ + const ImageCoordinatesKey key(size, type); + + auto &pixel_coordinates = *map_.lookup_or_add_cb( + key, [&]() { return std::make_unique(context, size, type); }); + + pixel_coordinates.needed = true; + return pixel_coordinates.result; +} + +} // namespace blender::compositor diff --git a/source/blender/compositor/cached_resources/intern/pixel_coordinates.cc b/source/blender/compositor/cached_resources/intern/pixel_coordinates.cc deleted file mode 100644 index 72676a5bd8c..00000000000 --- a/source/blender/compositor/cached_resources/intern/pixel_coordinates.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* SPDX-FileCopyrightText: 2025 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include -#include - -#include "BLI_hash.hh" -#include "BLI_math_vector_types.hh" - -#include "GPU_shader.hh" - -#include "COM_context.hh" -#include "COM_pixel_coordinates.hh" -#include "COM_result.hh" -#include "COM_utilities.hh" - -namespace blender::compositor { - -/* -------------------------------------------------------------------- - * Pixel Coordinates Key. - */ - -PixelCoordinatesKey::PixelCoordinatesKey(const int2 &size) : size(size) {} - -uint64_t PixelCoordinatesKey::hash() const -{ - return get_default_hash(size); -} - -bool operator==(const PixelCoordinatesKey &a, const PixelCoordinatesKey &b) -{ - return a.size == b.size; -} - -/* -------------------------------------------------------------------- - * Pixel Coordinates. - */ - -PixelCoordinates::PixelCoordinates(Context &context, const int2 &size) - : result(context.create_result(ResultType::Float3)) -{ - this->result.allocate_texture(Domain(size), false); - - if (context.use_gpu()) { - this->compute_gpu(context); - } - else { - this->compute_cpu(); - } -} - -PixelCoordinates::~PixelCoordinates() -{ - this->result.release(); -} - -void PixelCoordinates::compute_gpu(Context &context) -{ - GPUShader *shader = context.get_shader("compositor_pixel_coordinates"); - GPU_shader_bind(shader); - - this->result.bind_as_image(shader, "output_img"); - - compute_dispatch_threads_at_least(shader, this->result.domain().size); - - this->result.unbind_as_image(); - GPU_shader_unbind(); -} - -void PixelCoordinates::compute_cpu() -{ - parallel_for(this->result.domain().size, [&](const int2 texel) { - this->result.store_pixel(texel, float3(float2(texel) + float2(0.5f), 0.0f)); - }); -} - -/* -------------------------------------------------------------------- - * Pixel Coordinates Container. - */ - -void PixelCoordinatesContainer::reset() -{ - /* First, delete all resources that are no longer needed. */ - map_.remove_if([](auto item) { return !item.value->needed; }); - - /* Second, reset the needed status of the remaining resources to false to ready them to track - * their needed status for the next evaluation. */ - for (auto &value : map_.values()) { - value->needed = false; - } -} - -Result &PixelCoordinatesContainer::get(Context &context, const int2 &size) -{ - const PixelCoordinatesKey key(size); - - auto &pixel_coordinates = *map_.lookup_or_add_cb( - key, [&]() { return std::make_unique(context, size); }); - - pixel_coordinates.needed = true; - return pixel_coordinates.result; -} - -} // namespace blender::compositor diff --git a/source/blender/compositor/cached_resources/intern/texture_coordinates.cc b/source/blender/compositor/cached_resources/intern/texture_coordinates.cc deleted file mode 100644 index dbc183af45d..00000000000 --- a/source/blender/compositor/cached_resources/intern/texture_coordinates.cc +++ /dev/null @@ -1,112 +0,0 @@ -/* SPDX-FileCopyrightText: 2025 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include -#include - -#include "BLI_hash.hh" -#include "BLI_math_base.hh" -#include "BLI_math_vector_types.hh" - -#include "GPU_shader.hh" - -#include "COM_context.hh" -#include "COM_result.hh" -#include "COM_texture_coordinates.hh" -#include "COM_utilities.hh" - -namespace blender::compositor { - -/* -------------------------------------------------------------------- - * Texture Coordinates Key. - */ - -TextureCoordinatesKey::TextureCoordinatesKey(const int2 &size) : size(size) {} - -uint64_t TextureCoordinatesKey::hash() const -{ - return get_default_hash(size); -} - -bool operator==(const TextureCoordinatesKey &a, const TextureCoordinatesKey &b) -{ - return a.size == b.size; -} - -/* -------------------------------------------------------------------- - * Texture Coordinates. - */ - -TextureCoordinates::TextureCoordinates(Context &context, const int2 &size) - : result(context.create_result(ResultType::Float3)) -{ - this->result.allocate_texture(Domain(size), false); - - if (context.use_gpu()) { - this->compute_gpu(context); - } - else { - this->compute_cpu(); - } -} - -TextureCoordinates::~TextureCoordinates() -{ - this->result.release(); -} - -void TextureCoordinates::compute_gpu(Context &context) -{ - GPUShader *shader = context.get_shader("compositor_texture_coordinates"); - GPU_shader_bind(shader); - - this->result.bind_as_image(shader, "output_img"); - - compute_dispatch_threads_at_least(shader, this->result.domain().size); - - this->result.unbind_as_image(); - GPU_shader_unbind(); -} - -void TextureCoordinates::compute_cpu() -{ - const int2 size = this->result.domain().size; - parallel_for(size, [&](const int2 texel) { - float2 centered_coordinates = (float2(texel) + 0.5f) - float2(size) / 2.0f; - - int max_size = math::max(size.x, size.y); - float2 normalized_coordinates = (centered_coordinates / max_size) * 2.0f; - - this->result.store_pixel(texel, float3(normalized_coordinates, 0.0f)); - }); -} - -/* -------------------------------------------------------------------- - * Texture Coordinates Container. - */ - -void TextureCoordinatesContainer::reset() -{ - /* First, delete all resources that are no longer needed. */ - map_.remove_if([](auto item) { return !item.value->needed; }); - - /* Second, reset the needed status of the remaining resources to false to ready them to track - * their needed status for the next evaluation. */ - for (auto &value : map_.values()) { - value->needed = false; - } -} - -Result &TextureCoordinatesContainer::get(Context &context, const int2 &size) -{ - const TextureCoordinatesKey key(size); - - auto &texture_coordinates = *map_.lookup_or_add_cb( - key, [&]() { return std::make_unique(context, size); }); - - texture_coordinates.needed = true; - return texture_coordinates.result; -} - -} // namespace blender::compositor diff --git a/source/blender/compositor/intern/implicit_input_operation.cc b/source/blender/compositor/intern/implicit_input_operation.cc index 3267c7b893d..d3cd2cc2112 100644 --- a/source/blender/compositor/intern/implicit_input_operation.cc +++ b/source/blender/compositor/intern/implicit_input_operation.cc @@ -44,8 +44,8 @@ void ImplicitInputOperation::execute() break; case ImplicitInput::TextureCoordinates: const int2 size = this->context().get_compositing_region_size(); - result.wrap_external( - this->context().cache_manager().texture_coordinates.get(this->context(), size)); + result.wrap_external(this->context().cache_manager().image_coordinates.get( + this->context(), size, CoordinatesType::Uniform)); } } diff --git a/source/blender/compositor/intern/static_cache_manager.cc b/source/blender/compositor/intern/static_cache_manager.cc index 1528ca5c78a..32fc712dabf 100644 --- a/source/blender/compositor/intern/static_cache_manager.cc +++ b/source/blender/compositor/intern/static_cache_manager.cc @@ -28,8 +28,7 @@ void StaticCacheManager::reset() deriche_gaussian_coefficients.reset(); van_vliet_gaussian_coefficients.reset(); fog_glow_kernels.reset(); - texture_coordinates.reset(); - pixel_coordinates.reset(); + image_coordinates.reset(); } void StaticCacheManager::skip_next_reset() diff --git a/source/blender/compositor/shaders/compositor_image_coordinates_normalized.glsl b/source/blender/compositor/shaders/compositor_image_coordinates_normalized.glsl new file mode 100644 index 00000000000..50fe7c14e47 --- /dev/null +++ b/source/blender/compositor/shaders/compositor_image_coordinates_normalized.glsl @@ -0,0 +1,13 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +void main() +{ + const int2 texel = int2(gl_GlobalInvocationID.xy); + + const int2 size = imageSize(output_img); + const float2 normalized_coordinates = (float2(texel) + 0.5f) / float2(size); + + imageStore(output_img, texel, float4(normalized_coordinates, float2(0.0f))); +} diff --git a/source/blender/compositor/shaders/compositor_image_coordinates_pixel.glsl b/source/blender/compositor/shaders/compositor_image_coordinates_pixel.glsl new file mode 100644 index 00000000000..c86891092f9 --- /dev/null +++ b/source/blender/compositor/shaders/compositor_image_coordinates_pixel.glsl @@ -0,0 +1,10 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +void main() +{ + const int2 texel = int2(gl_GlobalInvocationID.xy); + + imageStore(output_img, texel, float4(float2(texel), float2(0.0f))); +} diff --git a/source/blender/compositor/shaders/compositor_image_coordinates_uniform.glsl b/source/blender/compositor/shaders/compositor_image_coordinates_uniform.glsl new file mode 100644 index 00000000000..73e3e8b7c05 --- /dev/null +++ b/source/blender/compositor/shaders/compositor_image_coordinates_uniform.glsl @@ -0,0 +1,16 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +void main() +{ + const int2 texel = int2(gl_GlobalInvocationID.xy); + + const int2 size = imageSize(output_img); + const float2 centered_coordinates = (float2(texel) + 0.5f) - float2(size) / 2.0f; + + const int max_size = max(size.x, size.y); + const float2 normalized_coordinates = (centered_coordinates / max_size) * 2.0f; + + imageStore(output_img, texel, float4(normalized_coordinates, float2(0.0f))); +} diff --git a/source/blender/compositor/shaders/compositor_pixel_coordinates.glsl b/source/blender/compositor/shaders/compositor_pixel_coordinates.glsl deleted file mode 100644 index b09dfe97a80..00000000000 --- a/source/blender/compositor/shaders/compositor_pixel_coordinates.glsl +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-FileCopyrightText: 2025 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -void main() -{ - int2 texel = int2(gl_GlobalInvocationID.xy); - - imageStore(output_img, texel, float4(float2(texel) + float2(0.5f), float2(0.0f))); -} diff --git a/source/blender/compositor/shaders/compositor_texture_coordinates.glsl b/source/blender/compositor/shaders/compositor_texture_coordinates.glsl deleted file mode 100644 index bf9a4f48aad..00000000000 --- a/source/blender/compositor/shaders/compositor_texture_coordinates.glsl +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-FileCopyrightText: 2025 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -void main() -{ - int2 texel = int2(gl_GlobalInvocationID.xy); - - int2 size = imageSize(output_img); - float2 centered_coordinates = (float2(texel) + 0.5f) - float2(size) / 2.0f; - - int max_size = max(size.x, size.y); - float2 normalized_coordinates = (centered_coordinates / max_size) * 2.0f; - - imageStore(output_img, texel, float4(normalized_coordinates, float2(0.0f))); -} diff --git a/source/blender/compositor/shaders/infos/compositor_image_coordinates_info.hh b/source/blender/compositor/shaders/infos/compositor_image_coordinates_info.hh new file mode 100644 index 00000000000..ba3ef4027b9 --- /dev/null +++ b/source/blender/compositor/shaders/infos/compositor_image_coordinates_info.hh @@ -0,0 +1,26 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(compositor_image_coordinates_uniform) +LOCAL_GROUP_SIZE(16, 16) +IMAGE(0, GPU_RGBA16F, write, image2D, output_img) +COMPUTE_SOURCE("compositor_image_coordinates_uniform.glsl") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + +GPU_SHADER_CREATE_INFO(compositor_image_coordinates_normalized) +LOCAL_GROUP_SIZE(16, 16) +IMAGE(0, GPU_RGBA16F, write, image2D, output_img) +COMPUTE_SOURCE("compositor_image_coordinates_normalized.glsl") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + +GPU_SHADER_CREATE_INFO(compositor_image_coordinates_pixel) +LOCAL_GROUP_SIZE(16, 16) +IMAGE(0, GPU_RGBA16F, write, image2D, output_img) +COMPUTE_SOURCE("compositor_image_coordinates_pixel.glsl") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() diff --git a/source/blender/compositor/shaders/infos/compositor_pixel_coordinates_info.hh b/source/blender/compositor/shaders/infos/compositor_pixel_coordinates_info.hh deleted file mode 100644 index 70beb277cac..00000000000 --- a/source/blender/compositor/shaders/infos/compositor_pixel_coordinates_info.hh +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-FileCopyrightText: 2025 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "gpu_shader_create_info.hh" - -GPU_SHADER_CREATE_INFO(compositor_pixel_coordinates) -LOCAL_GROUP_SIZE(16, 16) -IMAGE(0, GPU_RGBA16F, write, image2D, output_img) -COMPUTE_SOURCE("compositor_pixel_coordinates.glsl") -DO_STATIC_COMPILATION() -GPU_SHADER_CREATE_END() diff --git a/source/blender/compositor/shaders/infos/compositor_texture_coordinates_info.hh b/source/blender/compositor/shaders/infos/compositor_texture_coordinates_info.hh deleted file mode 100644 index 94a8a16a44e..00000000000 --- a/source/blender/compositor/shaders/infos/compositor_texture_coordinates_info.hh +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-FileCopyrightText: 2025 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "gpu_shader_create_info.hh" - -GPU_SHADER_CREATE_INFO(compositor_texture_coordinates) -LOCAL_GROUP_SIZE(16, 16) -IMAGE(0, GPU_RGBA16F, write, image2D, output_img) -COMPUTE_SOURCE("compositor_texture_coordinates.glsl") -DO_STATIC_COMPILATION() -GPU_SHADER_CREATE_END() diff --git a/source/blender/gpu/intern/gpu_shader_create_info_list.hh b/source/blender/gpu/intern/gpu_shader_create_info_list.hh index 3e24ae7e2e5..6ebcb0aa9d5 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info_list.hh +++ b/source/blender/gpu/intern/gpu_shader_create_info_list.hh @@ -73,6 +73,7 @@ #include "compositor_gamma_correct_info.hh" #include "compositor_glare_info.hh" #include "compositor_id_mask_info.hh" +#include "compositor_image_coordinates_info.hh" #include "compositor_image_crop_info.hh" #include "compositor_inpaint_info.hh" #include "compositor_jump_flooding_info.hh" @@ -90,7 +91,6 @@ #include "compositor_movie_distortion_info.hh" #include "compositor_normalize_info.hh" #include "compositor_parallel_reduction_info.hh" -#include "compositor_pixel_coordinates_info.hh" #include "compositor_pixelate_info.hh" #include "compositor_plane_deform_info.hh" #include "compositor_premultiply_alpha_info.hh" @@ -105,7 +105,6 @@ #include "compositor_symmetric_blur_variable_size_info.hh" #include "compositor_symmetric_separable_blur_info.hh" #include "compositor_symmetric_separable_blur_variable_size_info.hh" -#include "compositor_texture_coordinates_info.hh" #include "compositor_tone_map_photoreceptor_info.hh" #include "compositor_tone_map_simple_info.hh" #include "compositor_translate_wrapped_info.hh" diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index 1c75b3b2b98..e3f230168f1 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -13838,6 +13838,7 @@ static void rna_def_nodes(BlenderRNA *brna) define("CompositorNode", "CompositorNodeHueSat"); define("CompositorNode", "CompositorNodeIDMask", def_cmp_id_mask); define("CompositorNode", "CompositorNodeImage", def_cmp_image); + define("CompositorNode", "CompositorNodeImageCoordinates"); define("CompositorNode", "CompositorNodeImageInfo"); define("CompositorNode", "CompositorNodeInpaint", def_cmp_inpaint); define("CompositorNode", "CompositorNodeInvert", def_cmp_invert); diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt index a926a4ff12f..f292e30414f 100644 --- a/source/blender/nodes/composite/CMakeLists.txt +++ b/source/blender/nodes/composite/CMakeLists.txt @@ -63,6 +63,7 @@ set(SRC nodes/node_composite_huecorrect.cc nodes/node_composite_id_mask.cc nodes/node_composite_image.cc + nodes/node_composite_image_coordinates.cc nodes/node_composite_image_info.cc nodes/node_composite_inpaint.cc nodes/node_composite_invert.cc diff --git a/source/blender/nodes/composite/nodes/node_composite_image_coordinates.cc b/source/blender/nodes/composite/nodes/node_composite_image_coordinates.cc new file mode 100644 index 00000000000..0588820eec8 --- /dev/null +++ b/source/blender/nodes/composite/nodes/node_composite_image_coordinates.cc @@ -0,0 +1,91 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "COM_node_operation.hh" + +#include "node_composite_util.hh" + +namespace blender::nodes::node_composite_image_coordinates_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input("Image").hide_value().compositor_realization_mode( + CompositorInputRealizationMode::None); + + b.add_output("Uniform").description( + "Zero centered coordinates normalizes along the larger dimension for uniform scaling"); + b.add_output("Normalized") + .description("Normalized coordinates with half pixel offsets"); + b.add_output("Pixel").description("Integer pixel coordinates"); +} + +using namespace blender::compositor; + +class ImageCoordinatesOperation : public NodeOperation { + public: + ImageCoordinatesOperation(Context &context, DNode node) : NodeOperation(context, node) + { + InputDescriptor &image_descriptor = this->get_input_descriptor("Image"); + image_descriptor.skip_type_conversion = true; + } + + void execute() override + { + const Result &input = this->get_input("Image"); + Result &uniform_coordinates_result = this->get_result("Uniform"); + Result &normalized_coordinates_result = this->get_result("Normalized"); + Result &pixel_coordinates_result = this->get_result("Pixel"); + if (input.is_single_value()) { + uniform_coordinates_result.allocate_invalid(); + normalized_coordinates_result.allocate_invalid(); + pixel_coordinates_result.allocate_invalid(); + return; + } + + const Domain domain = input.domain(); + + if (uniform_coordinates_result.should_compute()) { + const Result &uniform_coordinates = this->context().cache_manager().image_coordinates.get( + this->context(), domain.size, CoordinatesType::Uniform); + uniform_coordinates_result.wrap_external(uniform_coordinates); + uniform_coordinates_result.transform(domain.transformation); + } + + if (normalized_coordinates_result.should_compute()) { + const Result &normalized_coordinates = this->context().cache_manager().image_coordinates.get( + this->context(), domain.size, CoordinatesType::Normalized); + normalized_coordinates_result.wrap_external(normalized_coordinates); + normalized_coordinates_result.transform(domain.transformation); + } + + if (pixel_coordinates_result.should_compute()) { + const Result &pixel_coordinates = this->context().cache_manager().image_coordinates.get( + this->context(), domain.size, CoordinatesType::Pixel); + pixel_coordinates_result.wrap_external(pixel_coordinates); + pixel_coordinates_result.transform(domain.transformation); + } + } +}; + +static NodeOperation *get_compositor_operation(Context &context, DNode node) +{ + return new ImageCoordinatesOperation(context, node); +} + +static void register_node() +{ + static blender::bke::bNodeType ntype; + + cmp_node_type_base(&ntype, "CompositorNodeImageCoordinates"); + ntype.ui_name = "Image Coordinates"; + ntype.ui_description = "Returns the coordinates of the pixels of an image"; + ntype.nclass = NODE_CLASS_INPUT; + ntype.declare = node_declare; + ntype.get_compositor_operation = get_compositor_operation; + + blender::bke::node_register_type(ntype); +} +NOD_REGISTER_NODE(register_node) + +} // namespace blender::nodes::node_composite_image_coordinates_cc diff --git a/source/blender/nodes/composite/nodes/node_composite_image_info.cc b/source/blender/nodes/composite/nodes/node_composite_image_info.cc index 7683c7f6ba3..806d6e9da66 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image_info.cc +++ b/source/blender/nodes/composite/nodes/node_composite_image_info.cc @@ -6,9 +6,6 @@ #include "BLI_math_matrix.hh" #include "BLI_math_vector_types.hh" -#include "UI_interface.hh" -#include "UI_resources.hh" - #include "COM_node_operation.hh" #include "node_composite_util.hh" @@ -17,11 +14,9 @@ namespace blender::nodes::node_composite_image_info_cc { static void node_declare(NodeDeclarationBuilder &b) { - b.add_input("Image").compositor_domain_priority(0).compositor_realization_mode( + b.add_input("Image").compositor_realization_mode( CompositorInputRealizationMode::None); - b.add_output("Texture Coordinates"); - b.add_output("Pixel Coordinates"); b.add_output("Resolution"); b.add_output("Location"); b.add_output("Rotation"); @@ -48,22 +43,6 @@ class ImageInfoOperation : public NodeOperation { const Domain domain = input.domain(); - Result &texture_coordinates_result = this->get_result("Texture Coordinates"); - if (texture_coordinates_result.should_compute()) { - const Result &texture_coordinates = this->context().cache_manager().texture_coordinates.get( - this->context(), domain.size); - texture_coordinates_result.wrap_external(texture_coordinates); - texture_coordinates_result.transform(domain.transformation); - } - - Result &pixel_coordinates_result = this->get_result("Pixel Coordinates"); - if (pixel_coordinates_result.should_compute()) { - const Result &pixel_coordinates = this->context().cache_manager().pixel_coordinates.get( - this->context(), domain.size); - pixel_coordinates_result.wrap_external(pixel_coordinates); - pixel_coordinates_result.transform(domain.transformation); - } - Result &resolution_result = this->get_result("Resolution"); if (resolution_result.should_compute()) { resolution_result.allocate_single_value(); @@ -95,16 +74,6 @@ class ImageInfoOperation : public NodeOperation { void execute_invalid() { - Result &texture_coordinates_result = this->get_result("Texture Coordinates"); - if (texture_coordinates_result.should_compute()) { - texture_coordinates_result.allocate_invalid(); - } - - Result &pixel_coordinates_result = this->get_result("Pixel Coordinates"); - if (pixel_coordinates_result.should_compute()) { - pixel_coordinates_result.allocate_invalid(); - } - Result &resolution_result = this->get_result("Resolution"); if (resolution_result.should_compute()) { resolution_result.allocate_invalid();