Fix #136939: Translation is ignored in some nodes
The compositor ignores translation in certain nodes like Corner Pin. Users find this unexpected as adjusting the translation of the input has no effect on the output. The only alternative logical thing to do if translation exists is to clip the image, which this patch do. This affects the following nodes: - File Output. - Map UV (Image input). - Corner Pin. - Plane Track Deform. - Bokeh Blur (Bokeh Kernel input). Pull Request: https://projects.blender.org/blender/blender/pulls/144049
This commit is contained in:
@@ -44,10 +44,14 @@ class RealizeOnDomainOperation : public SimpleOperation {
|
|||||||
/* Given a potentially transformed domain, compute a domain such that its rotation and scale
|
/* Given a potentially transformed domain, compute a domain such that its rotation and scale
|
||||||
* become identity and the size of the domain is increased/reduced to adapt to the new
|
* become identity and the size of the domain is increased/reduced to adapt to the new
|
||||||
* transformation. For instance, if the domain is rotated, the returned domain will have zero
|
* transformation. For instance, if the domain is rotated, the returned domain will have zero
|
||||||
* rotation but expanded size to account for the bounding box of the domain after rotation. The
|
* rotation but expanded size to account for the bounding box of the domain after rotation.
|
||||||
* size of the returned domain is bound and clipped by the maximum possible size to avoid
|
* Similarly, if the realize_translation argument is true, translation will be set to zero,
|
||||||
* allocations that surpass hardware limits. */
|
* though this will not affect the size of the domain in any way. The size of the returned domain
|
||||||
static Domain compute_realized_transformation_domain(Context &context, const Domain &domain);
|
* is bound and clipped by the maximum possible size to avoid allocations that surpass hardware
|
||||||
|
* limits. */
|
||||||
|
static Domain compute_realized_transformation_domain(Context &context,
|
||||||
|
const Domain &domain,
|
||||||
|
const bool realize_translation = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* The operation domain is just the target domain. */
|
/* The operation domain is just the target domain. */
|
||||||
|
|||||||
@@ -207,16 +207,19 @@ Domain RealizeOnDomainOperation::compute_domain()
|
|||||||
* realization shouldn't be needed. */
|
* realization shouldn't be needed. */
|
||||||
static constexpr float transformation_tolerance = 10e-6f;
|
static constexpr float transformation_tolerance = 10e-6f;
|
||||||
|
|
||||||
Domain RealizeOnDomainOperation::compute_realized_transformation_domain(Context &context,
|
Domain RealizeOnDomainOperation::compute_realized_transformation_domain(
|
||||||
const Domain &domain)
|
Context &context, const Domain &domain, const bool realize_translation)
|
||||||
{
|
{
|
||||||
const int2 size = domain.size;
|
const int2 size = domain.size;
|
||||||
|
|
||||||
/* If the domain is only infinitesimally rotated or scaled, return a domain with just the
|
/* If the domain is only infinitesimally rotated or scaled, return a domain with just the
|
||||||
* translation component. */
|
* translation component if not realizing translation. */
|
||||||
if (math::is_equal(
|
if (math::is_equal(
|
||||||
float2x2(domain.transformation), float2x2::identity(), transformation_tolerance))
|
float2x2(domain.transformation), float2x2::identity(), transformation_tolerance))
|
||||||
{
|
{
|
||||||
|
if (realize_translation) {
|
||||||
|
return Domain(size);
|
||||||
|
}
|
||||||
return Domain(size, math::from_location<float3x3>(domain.transformation.location()));
|
return Domain(size, math::from_location<float3x3>(domain.transformation.location()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +266,10 @@ Domain RealizeOnDomainOperation::compute_realized_transformation_domain(Context
|
|||||||
const int2 safe_size = math::clamp(new_size, int2(1), int2(max_size));
|
const int2 safe_size = math::clamp(new_size, int2(1), int2(max_size));
|
||||||
|
|
||||||
/* Create a domain from the new safe size and just the translation component of the
|
/* Create a domain from the new safe size and just the translation component of the
|
||||||
* transformation, */
|
* transformation if not realizing translation. */
|
||||||
|
if (realize_translation) {
|
||||||
|
return Domain(safe_size);
|
||||||
|
}
|
||||||
return Domain(safe_size, math::from_location<float3x3>(domain.transformation.location()));
|
return Domain(safe_size, math::from_location<float3x3>(domain.transformation.location()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,8 +301,11 @@ SimpleOperation *RealizeOnDomainOperation::construct_if_needed(
|
|||||||
InputRealizationMode::OperationDomain;
|
InputRealizationMode::OperationDomain;
|
||||||
const Domain target_domain = use_operation_domain ? operation_domain : input_result.domain();
|
const Domain target_domain = use_operation_domain ? operation_domain : input_result.domain();
|
||||||
|
|
||||||
|
const bool should_realize_translation = input_descriptor.realization_mode ==
|
||||||
|
InputRealizationMode::Transforms;
|
||||||
const Domain realized_target_domain =
|
const Domain realized_target_domain =
|
||||||
RealizeOnDomainOperation::compute_realized_transformation_domain(context, target_domain);
|
RealizeOnDomainOperation::compute_realized_transformation_domain(
|
||||||
|
context, target_domain, should_realize_translation);
|
||||||
|
|
||||||
/* The input have an almost identical domain to the realized target domain, so no need to realize
|
/* The input have an almost identical domain to the realized target domain, so no need to realize
|
||||||
* it and the operation is not needed. */
|
* it and the operation is not needed. */
|
||||||
|
|||||||
@@ -425,6 +425,15 @@ class CornerPinOperation : public NodeOperation {
|
|||||||
|
|
||||||
return is_clipped_x || is_clipped_y || output_needed || use_anisotropic;
|
return is_clipped_x || is_clipped_y || output_needed || use_anisotropic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Domain compute_domain() override
|
||||||
|
{
|
||||||
|
Domain domain = this->get_input("Image").domain();
|
||||||
|
/* Reset the location of the domain such that translations take effect, this will result in
|
||||||
|
* clipping but is more expected for the user. */
|
||||||
|
domain.transformation.location() = float2(0.0f);
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static NodeOperation *get_compositor_operation(Context &context, DNode node)
|
static NodeOperation *get_compositor_operation(Context &context, DNode node)
|
||||||
|
|||||||
@@ -1023,6 +1023,19 @@ class FileOutputOperation : public NodeOperation {
|
|||||||
{
|
{
|
||||||
return context().get_render_data().scemode & R_MULTIVIEW;
|
return context().get_render_data().scemode & R_MULTIVIEW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Domain compute_domain() override
|
||||||
|
{
|
||||||
|
Domain domain = NodeOperation::compute_domain();
|
||||||
|
if (!this->is_multi_layer()) {
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset the location of the domain in multi-layer case such that translations take effect,
|
||||||
|
* this will result in clipping but is more expected for the user. */
|
||||||
|
domain.transformation.location() = float2(0.0f);
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static NodeOperation *get_compositor_operation(Context &context, DNode node)
|
static NodeOperation *get_compositor_operation(Context &context, DNode node)
|
||||||
|
|||||||
Reference in New Issue
Block a user