Realtime Compositor: Implement scale node
This patch implements the Scale node for the realtime compositor. Differential Revision: https://developer.blender.org/D15758 Reviewed By: Clement Foucault
This commit is contained in:
parent
e254d8867d
commit
0fd39da3a9
|
@ -1337,15 +1337,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
|||
#define CMP_CHAN_RGB 1
|
||||
#define CMP_CHAN_A 2
|
||||
|
||||
/* scale node type, in custom1 */
|
||||
#define CMP_SCALE_RELATIVE 0
|
||||
#define CMP_SCALE_ABSOLUTE 1
|
||||
#define CMP_SCALE_SCENEPERCENT 2
|
||||
#define CMP_SCALE_RENDERPERCENT 3
|
||||
/* custom2 */
|
||||
#define CMP_SCALE_RENDERSIZE_FRAME_ASPECT (1 << 0)
|
||||
#define CMP_SCALE_RENDERSIZE_FRAME_CROP (1 << 1)
|
||||
|
||||
/* track position node, in custom1 */
|
||||
#define CMP_TRACKPOS_ABSOLUTE 0
|
||||
#define CMP_TRACKPOS_RELATIVE_START 1
|
||||
|
|
|
@ -25,7 +25,7 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
|
|||
NodeOutput *output_socket = this->get_output_socket(0);
|
||||
|
||||
switch (bnode->custom1) {
|
||||
case CMP_SCALE_RELATIVE: {
|
||||
case CMP_NODE_SCALE_RELATIVE: {
|
||||
ScaleRelativeOperation *operation = new ScaleRelativeOperation();
|
||||
converter.add_operation(operation);
|
||||
|
||||
|
@ -39,7 +39,7 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
|
|||
|
||||
break;
|
||||
}
|
||||
case CMP_SCALE_SCENEPERCENT: {
|
||||
case CMP_NODE_SCALE_RENDER_PERCENT: {
|
||||
SetValueOperation *scale_factor_operation = new SetValueOperation();
|
||||
scale_factor_operation->set_value(context.get_render_percentage_as_factor());
|
||||
converter.add_operation(scale_factor_operation);
|
||||
|
@ -59,13 +59,14 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
|
|||
|
||||
break;
|
||||
}
|
||||
case CMP_SCALE_RENDERPERCENT: {
|
||||
case CMP_NODE_SCALE_RENDER_SIZE: {
|
||||
const RenderData *rd = context.get_render_data();
|
||||
const float render_size_factor = context.get_render_percentage_as_factor();
|
||||
ScaleFixedSizeOperation *operation = new ScaleFixedSizeOperation();
|
||||
/* framing options */
|
||||
operation->set_is_aspect((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_ASPECT) != 0);
|
||||
operation->set_is_crop((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_CROP) != 0);
|
||||
operation->set_is_aspect(
|
||||
ELEM(bnode->custom2, CMP_NODE_SCALE_RENDER_SIZE_FIT, CMP_NODE_SCALE_RENDER_SIZE_CROP));
|
||||
operation->set_is_crop(bnode->custom2 == CMP_NODE_SCALE_RENDER_SIZE_CROP);
|
||||
operation->set_offset(bnode->custom3, bnode->custom4);
|
||||
operation->set_new_width(rd->xsch * render_size_factor);
|
||||
operation->set_new_height(rd->ysch * render_size_factor);
|
||||
|
@ -79,7 +80,7 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
|
|||
|
||||
break;
|
||||
}
|
||||
case CMP_SCALE_ABSOLUTE: {
|
||||
case CMP_NODE_SCALE_ABSOLUTE: {
|
||||
/* TODO: what is the use of this one.... perhaps some issues when the ui was updated... */
|
||||
ScaleAbsoluteOperation *operation = new ScaleAbsoluteOperation();
|
||||
converter.add_operation(operation);
|
||||
|
|
|
@ -2029,6 +2029,21 @@ typedef enum CMPNodeFlipMode {
|
|||
CMP_NODE_FLIP_X_Y = 2,
|
||||
} CMPNodeFlipMode;
|
||||
|
||||
/* Scale Node. Stored in custom1. */
|
||||
typedef enum CMPNodeScaleMethod {
|
||||
CMP_NODE_SCALE_RELATIVE = 0,
|
||||
CMP_NODE_SCALE_ABSOLUTE = 1,
|
||||
CMP_NODE_SCALE_RENDER_PERCENT = 2,
|
||||
CMP_NODE_SCALE_RENDER_SIZE = 3,
|
||||
} CMPNodeScaleMethod;
|
||||
|
||||
/* Scale Node. Stored in custom2. */
|
||||
typedef enum CMPNodeScaleRenderSizeMethod {
|
||||
CMP_NODE_SCALE_RENDER_SIZE_STRETCH = 0,
|
||||
CMP_NODE_SCALE_RENDER_SIZE_FIT = 1,
|
||||
CMP_NODE_SCALE_RENDER_SIZE_CROP = 2,
|
||||
} CMPNodeScaleRenderSizeMethod;
|
||||
|
||||
/* Filter Node. Stored in custom1. */
|
||||
typedef enum CMPNodeFilterMethod {
|
||||
CMP_NODE_FILTER_SOFT = 0,
|
||||
|
|
|
@ -7190,18 +7190,18 @@ static void def_cmp_scale(StructRNA *srna)
|
|||
PropertyRNA *prop;
|
||||
|
||||
static const EnumPropertyItem space_items[] = {
|
||||
{CMP_SCALE_RELATIVE, "RELATIVE", 0, "Relative", ""},
|
||||
{CMP_SCALE_ABSOLUTE, "ABSOLUTE", 0, "Absolute", ""},
|
||||
{CMP_SCALE_SCENEPERCENT, "SCENE_SIZE", 0, "Scene Size", ""},
|
||||
{CMP_SCALE_RENDERPERCENT, "RENDER_SIZE", 0, "Render Size", ""},
|
||||
{CMP_NODE_SCALE_RELATIVE, "RELATIVE", 0, "Relative", ""},
|
||||
{CMP_NODE_SCALE_ABSOLUTE, "ABSOLUTE", 0, "Absolute", ""},
|
||||
{CMP_NODE_SCALE_RENDER_PERCENT, "SCENE_SIZE", 0, "Scene Size", ""},
|
||||
{CMP_NODE_SCALE_RENDER_SIZE, "RENDER_SIZE", 0, "Render Size", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
/* matching bgpic_camera_frame_items[] */
|
||||
static const EnumPropertyItem space_frame_items[] = {
|
||||
{0, "STRETCH", 0, "Stretch", ""},
|
||||
{CMP_SCALE_RENDERSIZE_FRAME_ASPECT, "FIT", 0, "Fit", ""},
|
||||
{CMP_SCALE_RENDERSIZE_FRAME_ASPECT | CMP_SCALE_RENDERSIZE_FRAME_CROP, "CROP", 0, "Crop", ""},
|
||||
{CMP_NODE_SCALE_RENDER_SIZE_STRETCH, "STRETCH", 0, "Stretch", ""},
|
||||
{CMP_NODE_SCALE_RENDER_SIZE_FIT, "FIT", 0, "Fit", ""},
|
||||
{CMP_NODE_SCALE_RENDER_SIZE_CROP, "CROP", 0, "Crop", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
* \ingroup cmpnodes
|
||||
*/
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_float3x3.hh"
|
||||
#include "BLI_math_base.hh"
|
||||
#include "BLI_math_vec_types.hh"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
@ -20,16 +25,26 @@ namespace blender::nodes::node_composite_scale_cc {
|
|||
|
||||
static void cmp_node_scale_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
|
||||
b.add_input<decl::Float>(N_("X")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
|
||||
b.add_input<decl::Float>(N_("Y")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
|
||||
b.add_input<decl::Color>(N_("Image"))
|
||||
.default_value({1.0f, 1.0f, 1.0f, 1.0f})
|
||||
.compositor_domain_priority(0);
|
||||
b.add_input<decl::Float>(N_("X"))
|
||||
.default_value(1.0f)
|
||||
.min(0.0001f)
|
||||
.max(CMP_SCALE_MAX)
|
||||
.compositor_expects_single_value();
|
||||
b.add_input<decl::Float>(N_("Y"))
|
||||
.default_value(1.0f)
|
||||
.min(0.0001f)
|
||||
.max(CMP_SCALE_MAX)
|
||||
.compositor_expects_single_value();
|
||||
b.add_output<decl::Color>(N_("Image"));
|
||||
}
|
||||
|
||||
static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
|
||||
{
|
||||
bNodeSocket *sock;
|
||||
bool use_xy_scale = ELEM(node->custom1, CMP_SCALE_RELATIVE, CMP_SCALE_ABSOLUTE);
|
||||
bool use_xy_scale = ELEM(node->custom1, CMP_NODE_SCALE_RELATIVE, CMP_NODE_SCALE_ABSOLUTE);
|
||||
|
||||
/* Only show X/Y scale factor inputs for modes using them! */
|
||||
for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
|
||||
|
@ -43,7 +58,7 @@ static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), Poin
|
|||
{
|
||||
uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
|
||||
|
||||
if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
|
||||
if (RNA_enum_get(ptr, "space") == CMP_NODE_SCALE_RENDER_SIZE) {
|
||||
uiLayout *row;
|
||||
uiItemR(layout,
|
||||
ptr,
|
||||
|
@ -65,7 +80,129 @@ class ScaleOperation : public NodeOperation {
|
|||
|
||||
void execute() override
|
||||
{
|
||||
get_input("Image").pass_through(get_result("Image"));
|
||||
Result &input = get_input("Image");
|
||||
Result &result = get_result("Image");
|
||||
input.pass_through(result);
|
||||
|
||||
const float3x3 transformation = float3x3::from_translation_rotation_scale(
|
||||
get_translation(), 0.0f, get_scale());
|
||||
|
||||
result.transform(transformation);
|
||||
result.get_realization_options().interpolation = Interpolation::Bilinear;
|
||||
}
|
||||
|
||||
float2 get_scale()
|
||||
{
|
||||
switch (get_scale_method()) {
|
||||
case CMP_NODE_SCALE_RELATIVE:
|
||||
return get_scale_relative();
|
||||
case CMP_NODE_SCALE_ABSOLUTE:
|
||||
return get_scale_absolute();
|
||||
case CMP_NODE_SCALE_RENDER_PERCENT:
|
||||
return get_scale_render_percent();
|
||||
case CMP_NODE_SCALE_RENDER_SIZE:
|
||||
return get_scale_render_size();
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return float2(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
/* Scale by the input factors. */
|
||||
float2 get_scale_relative()
|
||||
{
|
||||
return float2(get_input("X").get_float_value_default(1.0f),
|
||||
get_input("Y").get_float_value_default(1.0f));
|
||||
}
|
||||
|
||||
/* Scale such that the new size matches the input absolute size. */
|
||||
float2 get_scale_absolute()
|
||||
{
|
||||
const float2 input_size = float2(get_input("Image").domain().size);
|
||||
const float2 absolute_size = float2(get_input("X").get_float_value_default(1.0f),
|
||||
get_input("Y").get_float_value_default(1.0f));
|
||||
return absolute_size / input_size;
|
||||
}
|
||||
|
||||
/* Scale by the render resolution percentage. */
|
||||
float2 get_scale_render_percent()
|
||||
{
|
||||
return float2(context().get_scene()->r.size / 100.0f);
|
||||
}
|
||||
|
||||
float2 get_scale_render_size()
|
||||
{
|
||||
switch (get_scale_render_size_method()) {
|
||||
case CMP_NODE_SCALE_RENDER_SIZE_STRETCH:
|
||||
return get_scale_render_size_stretch();
|
||||
case CMP_NODE_SCALE_RENDER_SIZE_FIT:
|
||||
return get_scale_render_size_fit();
|
||||
case CMP_NODE_SCALE_RENDER_SIZE_CROP:
|
||||
return get_scale_render_size_crop();
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return float2(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
/* Scale such that the new size matches the render size. Since the input is freely scaled, it is
|
||||
* potentially stretched, hence the name. */
|
||||
float2 get_scale_render_size_stretch()
|
||||
{
|
||||
const float2 input_size = float2(get_input("Image").domain().size);
|
||||
const float2 render_size = float2(context().get_output_size());
|
||||
return render_size / input_size;
|
||||
}
|
||||
|
||||
/* Scale such that the dimension with the smaller scaling factor matches that of the render size
|
||||
* while maintaining the input's aspect ratio. Since the other dimension is guaranteed not to
|
||||
* exceed the render size region due to its larger scaling factor, the image is said to be fit
|
||||
* inside that region, hence the name. */
|
||||
float2 get_scale_render_size_fit()
|
||||
{
|
||||
const float2 input_size = float2(get_input("Image").domain().size);
|
||||
const float2 render_size = float2(context().get_output_size());
|
||||
const float2 scale = render_size / input_size;
|
||||
return float2(math::min(scale.x, scale.y));
|
||||
}
|
||||
|
||||
/* Scale such that the dimension with the larger scaling factor matches that of the render size
|
||||
* while maintaining the input's aspect ratio. Since the other dimension is guaranteed to exceed
|
||||
* the render size region due to its lower scaling factor, the image will be cropped inside that
|
||||
* region, hence the name. */
|
||||
float2 get_scale_render_size_crop()
|
||||
{
|
||||
const float2 input_size = float2(get_input("Image").domain().size);
|
||||
const float2 render_size = float2(context().get_output_size());
|
||||
const float2 scale = render_size / input_size;
|
||||
return float2(math::max(scale.x, scale.y));
|
||||
}
|
||||
|
||||
float2 get_translation()
|
||||
{
|
||||
/* Only the render size option supports offset translation. */
|
||||
if (get_scale_method() != CMP_NODE_SCALE_RENDER_SIZE) {
|
||||
return float2(0.0f);
|
||||
}
|
||||
|
||||
/* Translate by the offset factor relative to the new size. */
|
||||
const float2 input_size = float2(get_input("Image").domain().size);
|
||||
return get_offset() * input_size * get_scale();
|
||||
}
|
||||
|
||||
CMPNodeScaleMethod get_scale_method()
|
||||
{
|
||||
return (CMPNodeScaleMethod)bnode().custom1;
|
||||
}
|
||||
|
||||
CMPNodeScaleRenderSizeMethod get_scale_render_size_method()
|
||||
{
|
||||
return (CMPNodeScaleRenderSizeMethod)bnode().custom2;
|
||||
}
|
||||
|
||||
float2 get_offset()
|
||||
{
|
||||
return float2(bnode().custom3, bnode().custom4);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue