diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index c11c7585203..2695dafb55a 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 87 +#define BLENDER_FILE_SUBVERSION 88 /* 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_500.cc b/source/blender/blenloader/intern/versioning_500.cc index dae9a5977c5..a01503d7fb0 100644 --- a/source/blender/blenloader/intern/versioning_500.cc +++ b/source/blender/blenloader/intern/versioning_500.cc @@ -2281,6 +2281,91 @@ static void version_dynamic_viewer_node_items(bNodeTree &ntree) } } +static void do_version_displace_node_remove_xy_scale(bNodeTree &node_tree, bNode &node) +{ + blender::bke::node_tree_set_type(node_tree); + + bNodeSocket *displacement_input = blender::bke::node_find_socket(node, SOCK_IN, "Displacement"); + bNodeSocket *x_scale_input = blender::bke::node_find_socket(node, SOCK_IN, "X Scale"); + bNodeSocket *y_scale_input = blender::bke::node_find_socket(node, SOCK_IN, "Y Scale"); + + /* Find the link going into the inputs of the node. */ + bNodeLink *displacement_link = nullptr; + bNodeLink *x_scale_link = nullptr; + bNodeLink *y_scale_link = nullptr; + LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) { + if (link->tosock == displacement_input) { + displacement_link = link; + } + if (link->tosock == x_scale_input) { + x_scale_link = link; + } + if (link->tosock == y_scale_input) { + y_scale_link = link; + } + } + + bNode *multiply_node = blender::bke::node_add_node(nullptr, node_tree, "ShaderNodeVectorMath"); + multiply_node->parent = node.parent; + multiply_node->location[0] = node.location[0] - node.width - 20.0f; + multiply_node->location[1] = node.location[1]; + multiply_node->custom1 = NODE_VECTOR_MATH_MULTIPLY; + + bNodeSocket *multiply_a_input = blender::bke::node_find_socket( + *multiply_node, SOCK_IN, "Vector"); + bNodeSocket *multiply_b_input = blender::bke::node_find_socket( + *multiply_node, SOCK_IN, "Vector_001"); + bNodeSocket *multiply_output = blender::bke::node_find_socket( + *multiply_node, SOCK_OUT, "Vector"); + + copy_v2_v2(multiply_a_input->default_value_typed()->value, + displacement_input->default_value_typed()->value); + if (displacement_link) { + version_node_add_link(node_tree, + *displacement_link->fromnode, + *displacement_link->fromsock, + *multiply_node, + *multiply_a_input); + blender::bke::node_remove_link(&node_tree, *displacement_link); + } + + version_node_add_link(node_tree, *multiply_node, *multiply_output, node, *displacement_input); + + bNode *combine_node = blender::bke::node_add_node(nullptr, node_tree, "ShaderNodeCombineXYZ"); + combine_node->parent = node.parent; + combine_node->location[0] = multiply_node->location[0] - multiply_node->width - 20.0f; + combine_node->location[1] = multiply_node->location[1]; + + bNodeSocket *combine_x_input = blender::bke::node_find_socket(*combine_node, SOCK_IN, "X"); + bNodeSocket *combine_y_input = blender::bke::node_find_socket(*combine_node, SOCK_IN, "Y"); + bNodeSocket *combine_output = blender::bke::node_find_socket(*combine_node, SOCK_OUT, "Vector"); + + version_node_add_link( + node_tree, *combine_node, *combine_output, *multiply_node, *multiply_b_input); + + combine_x_input->default_value_typed()->value = + x_scale_input->default_value_typed()->value; + if (x_scale_link) { + version_node_add_link(node_tree, + *x_scale_link->fromnode, + *x_scale_link->fromsock, + *combine_node, + *combine_x_input); + blender::bke::node_remove_link(&node_tree, *x_scale_link); + } + + combine_y_input->default_value_typed()->value = + y_scale_input->default_value_typed()->value; + if (y_scale_link) { + version_node_add_link(node_tree, + *y_scale_link->fromnode, + *y_scale_link->fromsock, + *combine_node, + *combine_y_input); + blender::bke::node_remove_link(&node_tree, *y_scale_link); + } +} + void do_versions_after_linking_500(FileData *fd, Main *bmain) { if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 9)) { @@ -3414,6 +3499,21 @@ void blo_do_versions_500(FileData *fd, Library * /*lib*/, Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 88)) { + FOREACH_NODETREE_BEGIN (bmain, node_tree, id) { + if (node_tree->type != NTREE_COMPOSIT) { + continue; + } + version_node_input_socket_name(node_tree, CMP_NODE_DISPLACE, "Vector", "Displacement"); + LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) { + if (node->type_legacy == CMP_NODE_DISPLACE) { + do_version_displace_node_remove_xy_scale(*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. diff --git a/source/blender/compositor/COM_result.hh b/source/blender/compositor/COM_result.hh index feee4ee640b..c6a985b76a5 100644 --- a/source/blender/compositor/COM_result.hh +++ b/source/blender/compositor/COM_result.hh @@ -688,11 +688,8 @@ BLI_INLINE_METHOD float4 Result::sample(const float2 &coordinates, extension_mode_x, extension_mode_y); break; - /* The anisotropic sampling requires separate handling with EWA. */ - case Interpolation::Anisotropic: - BLI_assert_unreachable(); - break; case Interpolation::Bicubic: + case Interpolation::Anisotropic: math::interpolate_cubic_bspline_wrapmode_fl(buffer, pixel_value, size.x, diff --git a/source/blender/compositor/shaders/compositor_displace.glsl b/source/blender/compositor/shaders/compositor_displace.glsl index 1a252cb46cc..3a714f9be00 100644 --- a/source/blender/compositor/shaders/compositor_displace.glsl +++ b/source/blender/compositor/shaders/compositor_displace.glsl @@ -16,8 +16,7 @@ void main() /* Note that the input displacement is in pixel space, so divide by the input size to transform * it into the normalized sampler space. */ - float2 scale = float2(texture_load(x_scale_tx, texel).x, texture_load(y_scale_tx, texel).x); - float2 displacement = texture_load(displacement_tx, texel).xy * scale / float2(input_size); + float2 displacement = texture_load(displacement_tx, texel).xy / float2(input_size); float2 displaced_coordinates = coordinates - displacement; imageStore(output_img, texel, SAMPLER_FUNCTION(input_tx, displaced_coordinates)); diff --git a/source/blender/compositor/shaders/compositor_displace_anisotropic.glsl b/source/blender/compositor/shaders/compositor_displace_anisotropic.glsl index b3bd9f8c9e7..f59592e7989 100644 --- a/source/blender/compositor/shaders/compositor_displace_anisotropic.glsl +++ b/source/blender/compositor/shaders/compositor_displace_anisotropic.glsl @@ -20,8 +20,7 @@ void main() /* Note that the input displacement is in pixel space, so divide by the input size to transform * it into the normalized sampler space. */ - float2 scale = float2(texture_load(x_scale_tx, texel).x, texture_load(y_scale_tx, texel).x); - float2 displacement = texture_load(displacement_tx, texel).xy * scale / float2(input_size); + float2 displacement = texture_load(displacement_tx, texel).xy / float2(input_size); float2 displaced_coordinates = coordinates - displacement; /* Store the displaced coordinates into the shared table and issue a barrier to later compute the diff --git a/source/blender/compositor/shaders/infos/compositor_displace_info.hh b/source/blender/compositor/shaders/infos/compositor_displace_info.hh index e7ded4ed916..c0326abcfac 100644 --- a/source/blender/compositor/shaders/infos/compositor_displace_info.hh +++ b/source/blender/compositor/shaders/infos/compositor_displace_info.hh @@ -8,8 +8,6 @@ GPU_SHADER_CREATE_INFO(compositor_displace_shared) LOCAL_GROUP_SIZE(16, 16) SAMPLER(0, sampler2D, input_tx) SAMPLER(1, sampler2D, displacement_tx) -SAMPLER(2, sampler2D, x_scale_tx) -SAMPLER(3, sampler2D, y_scale_tx) IMAGE(0, SFLOAT_16_16_16_16, write, image2D, output_img) GPU_SHADER_CREATE_END() diff --git a/source/blender/nodes/composite/nodes/node_composite_displace.cc b/source/blender/nodes/composite/nodes/node_composite_displace.cc index c14b45597c0..2722d3286e4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_displace.cc +++ b/source/blender/nodes/composite/nodes/node_composite_displace.cc @@ -2,13 +2,9 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -/** \file - * \ingroup cmpnodes - */ - #include "MEM_guardedalloc.h" -#include "BLI_assert.h" +#include "BLI_math_matrix.hh" #include "BLI_math_vector.hh" #include "BLI_math_vector_types.hh" #include "BLI_utildefines.h" @@ -39,22 +35,9 @@ static void cmp_node_displace_declare(NodeDeclarationBuilder &b) b.add_input("Image") .default_value({1.0f, 1.0f, 1.0f, 1.0f}) .structure_type(StructureType::Dynamic); - b.add_input("Vector") + b.add_input("Displacement") .dimensions(2) - .default_value({1.0f, 1.0f}) - .min(0.0f) - .max(1.0f) - .subtype(PROP_TRANSLATION) - .structure_type(StructureType::Dynamic); - b.add_input("X Scale") - .default_value(0.0f) - .min(-1000.0f) - .max(1000.0f) - .structure_type(StructureType::Dynamic); - b.add_input("Y Scale") - .default_value(0.0f) - .min(-1000.0f) - .max(1000.0f) + .default_value({0.0f, 0.0f}) .structure_type(StructureType::Dynamic); PanelDeclarationBuilder &sampling_panel = b.add_panel("Sampling").default_closed(true); @@ -87,13 +70,23 @@ class DisplaceOperation : public NodeOperation { void execute() override { - if (this->is_identity()) { - const Result &input = this->get_input("Image"); - Result &output = this->get_result("Image"); + const Result &input = this->get_input("Image"); + Result &output = this->get_result("Image"); + if (input.is_single_value()) { output.share_data(input); return; } + const Result &displacement = this->get_input("Displacement"); + if (displacement.is_single_value()) { + output.share_data(input); + output.transform(math::from_location(displacement.get_single_value())); + output.get_realization_options().interpolation = this->get_interpolation(); + output.get_realization_options().extension_x = this->get_extension_mode_x(); + output.get_realization_options().extension_y = this->get_extension_mode_y(); + return; + } + if (this->context().use_gpu()) { this->execute_gpu(); } @@ -105,12 +98,10 @@ class DisplaceOperation : public NodeOperation { void execute_gpu() { const Interpolation interpolation = this->get_interpolation(); - const ExtensionMode extension_x = this->get_extension_mode_x(); - const ExtensionMode extension_y = this->get_extension_mode_y(); - gpu::Shader *shader = context().get_shader(this->get_shader_name(interpolation)); + gpu::Shader *shader = this->context().get_shader(this->get_shader_name(interpolation)); GPU_shader_bind(shader); - const Result &input_image = get_input("Image"); + const Result &input_image = this->get_input("Image"); if (interpolation == Interpolation::Anisotropic) { GPU_texture_anisotropic_filter(input_image, true); GPU_texture_mipmap_mode(input_image, true, true); @@ -120,61 +111,49 @@ class DisplaceOperation : public NodeOperation { interpolation, Interpolation::Bilinear, Interpolation::Bicubic); GPU_texture_filter_mode(input_image, use_bilinear); } + + const ExtensionMode extension_x = this->get_extension_mode_x(); + const ExtensionMode extension_y = this->get_extension_mode_y(); GPU_texture_extend_mode_x(input_image, map_extension_mode_to_extend_mode(extension_x)); GPU_texture_extend_mode_y(input_image, map_extension_mode_to_extend_mode(extension_y)); input_image.bind_as_texture(shader, "input_tx"); - const Result &input_displacement = get_input("Vector"); - input_displacement.bind_as_texture(shader, "displacement_tx"); - const Result &input_x_scale = get_input("X Scale"); - input_x_scale.bind_as_texture(shader, "x_scale_tx"); - const Result &input_y_scale = get_input("Y Scale"); - input_y_scale.bind_as_texture(shader, "y_scale_tx"); + const Result &displacement = this->get_input("Displacement"); + displacement.bind_as_texture(shader, "displacement_tx"); - const Domain domain = compute_domain(); - Result &output_image = get_result("Image"); + const Domain domain = this->compute_domain(); + Result &output_image = this->get_result("Image"); output_image.allocate_texture(domain); output_image.bind_as_image(shader, "output_img"); compute_dispatch_threads_at_least(shader, domain.size); input_image.unbind_as_texture(); - input_displacement.unbind_as_texture(); - input_x_scale.unbind_as_texture(); - input_y_scale.unbind_as_texture(); + displacement.unbind_as_texture(); output_image.unbind_as_image(); GPU_shader_unbind(); } void execute_cpu() { - const Result &image = get_input("Image"); - const Result &input_displacement = get_input("Vector"); - const Result &x_scale = get_input("X Scale"); - const Result &y_scale = get_input("Y Scale"); + const Result &image = this->get_input("Image"); + const Result &displacement = this->get_input("Displacement"); const Interpolation interpolation = this->get_interpolation(); const ExtensionMode extension_x = this->get_extension_mode_x(); const ExtensionMode extension_y = this->get_extension_mode_y(); - const Domain domain = compute_domain(); - Result &output = get_result("Image"); + const Domain domain = this->compute_domain(); + Result &output = this->get_result("Image"); output.allocate_texture(domain); const int2 size = domain.size; if (interpolation == Interpolation::Anisotropic) { - this->compute_anisotropic(size, image, output, input_displacement, x_scale, y_scale); + this->compute_anisotropic(size, image, output, displacement); } else { - this->compute_interpolation(interpolation, - size, - image, - output, - input_displacement, - x_scale, - y_scale, - extension_x, - extension_y); + this->compute_interpolation( + interpolation, size, image, output, displacement, extension_x, extension_y); } } @@ -182,15 +161,12 @@ class DisplaceOperation : public NodeOperation { const int2 &size, const Result &image, Result &output, - const Result &input_displacement, - const Result &x_scale, - const Result &y_scale, + const Result &displacement, const ExtensionMode &extension_mode_x, const ExtensionMode &extension_mode_y) const { parallel_for(size, [&](const int2 base_texel) { - const float2 coordinates = compute_coordinates( - base_texel, size, input_displacement, x_scale, y_scale); + const float2 coordinates = this->compute_coordinates(base_texel, size, displacement); output.store_pixel( base_texel, image.sample(coordinates, interpolation, extension_mode_x, extension_mode_y)); @@ -207,18 +183,8 @@ class DisplaceOperation : public NodeOperation { void compute_anisotropic(const int2 &size, const Result &image, Result &output, - const Result &input_displacement, - const Result &x_scale, - const Result &y_scale) const + const Result &displacement) const { - auto compute_anisotropic_pixel = [&](const int2 &texel, - const float2 &coordinates, - const float2 &x_gradient, - const float2 &y_gradient) { - /* Sample the input using the displaced coordinates passing in the computed gradients in - * order to utilize the anisotropic filtering capabilities of the sampler. */ - output.store_pixel(texel, image.sample_ewa_zero(coordinates, x_gradient, y_gradient)); - }; parallel_for(math::divide_ceil(size, int2(2)), [&](const int2 base_texel) { /* Compute each of the pixels in the 2x2 block, making sure to exempt out of bounds right * and upper pixels. */ @@ -230,14 +196,14 @@ class DisplaceOperation : public NodeOperation { const int2 upper_left_texel = int2(x, y + 1); const int2 upper_right_texel = int2(x + 1, y + 1); - const float2 lower_left_coordinates = compute_coordinates( - lower_left_texel, size, input_displacement, x_scale, y_scale); - const float2 lower_right_coordinates = compute_coordinates( - lower_right_texel, size, input_displacement, x_scale, y_scale); - const float2 upper_left_coordinates = compute_coordinates( - upper_left_texel, size, input_displacement, x_scale, y_scale); - const float2 upper_right_coordinates = compute_coordinates( - upper_right_texel, size, input_displacement, x_scale, y_scale); + const float2 lower_left_coordinates = this->compute_coordinates( + lower_left_texel, size, displacement); + const float2 lower_right_coordinates = this->compute_coordinates( + lower_right_texel, size, displacement); + const float2 upper_left_coordinates = this->compute_coordinates( + upper_left_texel, size, displacement); + const float2 upper_right_coordinates = this->compute_coordinates( + upper_right_texel, size, displacement); /* Compute the partial derivatives using finite difference. Divide by the input size since * sample_ewa_zero assumes derivatives with respect to texel coordinates. */ @@ -247,6 +213,14 @@ class DisplaceOperation : public NodeOperation { const float2 upper_x_gradient = (upper_right_coordinates - upper_left_coordinates) / size.x; /* Computes one of the 2x2 pixels given its texel location, coordinates, and gradients. */ + auto compute_anisotropic_pixel = [&](const int2 &texel, + const float2 &coordinates, + const float2 &x_gradient, + const float2 &y_gradient) { + /* Sample the input using the displaced coordinates passing in the computed gradients in + * order to utilize the anisotropic filtering capabilities of the sampler. */ + output.store_pixel(texel, image.sample_ewa_zero(coordinates, x_gradient, y_gradient)); + }; compute_anisotropic_pixel( lower_left_texel, lower_left_coordinates, lower_x_gradient, left_y_gradient); @@ -265,23 +239,12 @@ class DisplaceOperation : public NodeOperation { }); } - float2 compute_coordinates(const int2 &texel, - const int2 &size, - const Result &input_displacement, - const Result &x_scale, - const Result &y_scale) const + float2 compute_coordinates(const int2 &texel, const int2 &size, const Result &displacement) const { - /* Add 0.5 to evaluate the sampler at the center of the pixel and divide by the image - * size to get the coordinates into the sampler's expected [0, 1] range. */ - float2 coordinates = (float2(texel) + float2(0.5f)) / float2(size); - /* Note that the input displacement is in pixel space, so divide by the input size to * transform it into the normalized sampler space. */ - float2 scale = float2(x_scale.load_pixel_extended(texel), - y_scale.load_pixel_extended(texel)); - float2 displacement = input_displacement.load_pixel_extended(texel) * scale / - float2(size); - return coordinates - displacement; + const float2 coordinates = (float2(texel) + float2(0.5f)) / float2(size); + return coordinates - displacement.load_pixel_extended(texel) / float2(size); } const char *get_shader_name(const Interpolation &interpolation) const @@ -354,31 +317,6 @@ class DisplaceOperation : public NodeOperation { return ExtensionMode::Clip; } - - bool is_identity() - { - const Result &input_image = get_input("Image"); - if (input_image.is_single_value()) { - return true; - } - - const Result &input_displacement = get_input("Vector"); - if (input_displacement.is_single_value() && - math::is_zero(input_displacement.get_single_value())) - { - return true; - } - - const Result &input_x_scale = get_input("X Scale"); - const Result &input_y_scale = get_input("Y Scale"); - if (input_x_scale.is_single_value() && input_x_scale.get_single_value() == 0.0f && - input_y_scale.is_single_value() && input_y_scale.get_single_value() == 0.0f) - { - return true; - } - - return false; - } }; static NodeOperation *get_compositor_operation(Context &context, DNode node) diff --git a/tests/files/render/denoise/cycles_renders/denoise_passes.png b/tests/files/render/denoise/cycles_renders/denoise_passes.png index d28104a6d05..c22a5956a18 100644 --- a/tests/files/render/denoise/cycles_renders/denoise_passes.png +++ b/tests/files/render/denoise/cycles_renders/denoise_passes.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f33286b1d76fc742c2ea8e1599284cafd7368e8af40d480a554bc268bed15344 -size 7849 +oid sha256:11a35efe1fde356429ff5844010ff149e2f1559de4d272d260af3752dda12d4e +size 9489