Realtime Compositor: Implement Track Position node

This patch implements the Track Position node for the realtime
compositor.

Differential Revision: https://developer.blender.org/D16387

Reviewed By: Clement Foucault
This commit is contained in:
Omar Emara 2022-11-23 12:55:16 +02:00
parent 571f373155
commit e0c5ff87b7
Notes: blender-bot 2023-06-06 13:53:24 +02:00
Referenced by issue #108492, Regression: Compositor Track Position node outputs incorrect Y values for Relative Start & Relative Frame
Referenced by pull request #108504, Fix #108492 : Compo Track Position node wrong Y for Relative Start/Frame
Referenced by commit 32a349d3a3, Fix #108492 : Compo Track Position node wrong Y for Relative Start/Frame
7 changed files with 263 additions and 23 deletions

View File

@ -1337,12 +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
/* track position node, in custom1 */
#define CMP_TRACKPOS_ABSOLUTE 0
#define CMP_TRACKPOS_RELATIVE_START 1
#define CMP_TRACKPOS_RELATIVE_FRAME 2
#define CMP_TRACKPOS_ABSOLUTE_FRAME 3
/* Cryptomatte source. */
#define CMP_CRYPTOMATTE_SRC_RENDER 0
#define CMP_CRYPTOMATTE_SRC_IMAGE 1

View File

@ -30,7 +30,7 @@ static TrackPositionOperation *create_motion_operation(NodeConverter &converter,
operation->set_track_name(trackpos_data->track_name);
operation->set_framenumber(frame_number);
operation->set_axis(axis);
operation->set_position(CMP_TRACKPOS_ABSOLUTE);
operation->set_position(CMP_NODE_TRACK_POSITION_ABSOLUTE);
operation->set_relative_frame(frame_number + delta);
operation->set_speed_output(true);
converter.add_operation(operation);
@ -49,7 +49,7 @@ void TrackPositionNode::convert_to_operations(NodeConverter &converter,
NodeOutput *output_speed = this->get_output_socket(2);
int frame_number;
if (editor_node->custom1 == CMP_TRACKPOS_ABSOLUTE_FRAME) {
if (editor_node->custom1 == CMP_NODE_TRACK_POSITION_ABSOLUTE_FRAME) {
frame_number = editor_node->custom2;
}
else {
@ -62,7 +62,7 @@ void TrackPositionNode::convert_to_operations(NodeConverter &converter,
operationX->set_track_name(trackpos_data->track_name);
operationX->set_framenumber(frame_number);
operationX->set_axis(0);
operationX->set_position(editor_node->custom1);
operationX->set_position(static_cast<CMPNodeTrackPositionMode>(editor_node->custom1));
operationX->set_relative_frame(editor_node->custom2);
converter.add_operation(operationX);
converter.map_output_socket(outputX, operationX->get_output_socket());
@ -73,7 +73,7 @@ void TrackPositionNode::convert_to_operations(NodeConverter &converter,
operationY->set_track_name(trackpos_data->track_name);
operationY->set_framenumber(frame_number);
operationY->set_axis(1);
operationY->set_position(editor_node->custom1);
operationX->set_position(static_cast<CMPNodeTrackPositionMode>(editor_node->custom1));
operationY->set_relative_frame(editor_node->custom2);
converter.add_operation(operationY);
converter.map_output_socket(outputY, operationY->get_output_socket());

View File

@ -19,7 +19,7 @@ TrackPositionOperation::TrackPositionOperation()
tracking_object_name_[0] = 0;
track_name_[0] = 0;
axis_ = 0;
position_ = CMP_TRACKPOS_ABSOLUTE;
position_ = CMP_NODE_TRACK_POSITION_ABSOLUTE;
relative_frame_ = 0;
speed_output_ = false;
flags_.is_set_operation = true;
@ -80,7 +80,7 @@ void TrackPositionOperation::calc_track_position()
swap_v2_v2(relative_pos_, marker_pos_);
}
}
else if (position_ == CMP_TRACKPOS_RELATIVE_START) {
else if (position_ == CMP_NODE_TRACK_POSITION_RELATIVE_START) {
int i;
for (i = 0; i < track->markersnr; i++) {
@ -93,7 +93,7 @@ void TrackPositionOperation::calc_track_position()
}
}
}
else if (position_ == CMP_TRACKPOS_RELATIVE_FRAME) {
else if (position_ == CMP_NODE_TRACK_POSITION_RELATIVE_FRAME) {
int relative_clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movie_clip_,
relative_frame_);

View File

@ -25,7 +25,7 @@ class TrackPositionOperation : public ConstantOperation {
char tracking_object_name_[64];
char track_name_[64];
int axis_;
int position_;
CMPNodeTrackPositionMode position_;
int relative_frame_;
bool speed_output_;
@ -63,7 +63,7 @@ class TrackPositionOperation : public ConstantOperation {
{
axis_ = value;
}
void set_position(int value)
void set_position(CMPNodeTrackPositionMode value)
{
position_ = value;
}

View File

@ -2048,6 +2048,14 @@ typedef enum CMPNodeToneMapType {
CMP_NODE_TONE_MAP_PHOTORECEPTOR = 1,
} CMPNodeToneMapType;
/* Track Position Node. Stored in custom1. */
typedef enum CMPNodeTrackPositionMode {
CMP_NODE_TRACK_POSITION_ABSOLUTE = 0,
CMP_NODE_TRACK_POSITION_RELATIVE_START = 1,
CMP_NODE_TRACK_POSITION_RELATIVE_FRAME = 2,
CMP_NODE_TRACK_POSITION_ABSOLUTE_FRAME = 3,
} CMPNodeTrackPositionMode;
/* Plane track deform node. */
enum {

View File

@ -8986,18 +8986,22 @@ static void def_cmp_trackpos(StructRNA *srna)
PropertyRNA *prop;
static const EnumPropertyItem position_items[] = {
{CMP_TRACKPOS_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Output absolute position of a marker"},
{CMP_TRACKPOS_RELATIVE_START,
{CMP_NODE_TRACK_POSITION_ABSOLUTE,
"ABSOLUTE",
0,
"Absolute",
"Output absolute position of a marker"},
{CMP_NODE_TRACK_POSITION_RELATIVE_START,
"RELATIVE_START",
0,
"Relative Start",
"Output position of a marker relative to first marker of a track"},
{CMP_TRACKPOS_RELATIVE_FRAME,
{CMP_NODE_TRACK_POSITION_RELATIVE_FRAME,
"RELATIVE_FRAME",
0,
"Relative Frame",
"Output position of a marker relative to marker at given frame number"},
{CMP_TRACKPOS_ABSOLUTE_FRAME,
{CMP_NODE_TRACK_POSITION_ABSOLUTE_FRAME,
"ABSOLUTE_FRAME",
0,
"Absolute Frame",

View File

@ -5,11 +5,16 @@
* \ingroup cmpnodes
*/
#include "BLI_index_range.hh"
#include "BLI_math_vec_types.hh"
#include "DNA_defaults.h"
#include "DNA_movieclip_types.h"
#include "DNA_tracking_types.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
#include "RNA_access.h"
@ -24,6 +29,8 @@
namespace blender::nodes::node_composite_trackpos_cc {
NODE_STORAGE_FUNCS(NodeTrackPosData)
static void cmp_node_trackpos_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("X"));
@ -97,7 +104,9 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN
uiItemR(layout, ptr, "position", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) {
if (ELEM(node->custom1,
CMP_NODE_TRACK_POSITION_RELATIVE_FRAME,
CMP_NODE_TRACK_POSITION_ABSOLUTE_FRAME)) {
uiItemR(layout, ptr, "frame_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
}
}
@ -111,9 +120,234 @@ class TrackPositionOperation : public NodeOperation {
void execute() override
{
get_result("X").allocate_invalid();
get_result("Y").allocate_invalid();
get_result("Speed").allocate_invalid();
MovieTrackingTrack *track = get_movie_tracking_track();
if (!track) {
execute_invalid();
return;
}
const float2 current_marker_position = compute_marker_position_at_frame(track, get_frame());
const int2 size = get_size();
execute_position(track, current_marker_position, size);
execute_speed(track, current_marker_position, size);
}
void execute_position(MovieTrackingTrack *track, float2 current_marker_position, int2 size)
{
const bool should_compute_x = should_compute_output("X");
const bool should_compute_y = should_compute_output("Y");
if (!should_compute_x && !should_compute_y) {
return;
}
/* Compute the position relative to the reference marker position. Multiply by the size to get
* the position in pixel space. */
const float2 reference_marker_position = compute_reference_marker_position(track);
const float2 position = (current_marker_position - reference_marker_position) * float2(size);
if (should_compute_x) {
Result &result = get_result("X");
result.allocate_single_value();
result.set_float_value(position.x);
}
if (should_compute_y) {
Result &result = get_result("Y");
result.allocate_single_value();
result.set_float_value(position.y);
}
}
void execute_speed(MovieTrackingTrack *track, float2 current_marker_position, int2 size)
{
if (!should_compute_output("Speed")) {
return;
}
/* Compute the speed as the difference between the previous marker position and the current
* marker position. Notice that we compute the speed from the current to the previous position,
* not the other way around. */
const float2 previous_marker_position = compute_temporally_neighbouring_marker_position(
track, current_marker_position, -1);
const float2 speed_toward_previous = previous_marker_position - current_marker_position;
/* Compute the speed as the difference between the current marker position and the next marker
* position. */
const float2 next_marker_position = compute_temporally_neighbouring_marker_position(
track, current_marker_position, 1);
const float2 speed_toward_next = current_marker_position - next_marker_position;
/* Encode both speeds in a 4D vector. Multiply by the size to get the speed in pixel space. */
const float4 speed = float4(speed_toward_previous, speed_toward_next) * float4(size, size);
Result &result = get_result("Speed");
result.allocate_single_value();
result.set_vector_value(speed);
}
void execute_invalid()
{
if (should_compute_output("X")) {
Result &result = get_result("X");
result.allocate_single_value();
result.set_float_value(0.0f);
}
if (should_compute_output("Y")) {
Result &result = get_result("Y");
result.allocate_single_value();
result.set_float_value(0.0f);
}
if (should_compute_output("Speed")) {
Result &result = get_result("Speed");
result.allocate_single_value();
result.set_vector_value(float4(0.0f));
}
}
/* Compute the position of the marker that is delta time away from the evaluation frame. If no
* marker exist for that particular frame or is disabled, the current marker position is
* returned. This is useful for computing the speed by providing small negative and positive
* delta times. */
float2 compute_temporally_neighbouring_marker_position(MovieTrackingTrack *track,
float2 current_marker_position,
int time_delta)
{
const int local_frame_number = BKE_movieclip_remap_scene_to_clip_frame(
get_movie_clip(), get_frame() + time_delta);
MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, local_frame_number);
if (marker == nullptr || marker->flag & MARKER_DISABLED) {
return current_marker_position;
}
return float2(marker->pos);
}
/* Compute the position of the reference marker which the output position will be computed
* relative to. For non-relative modes, this is just the zero origin or the tracking space. See
* the get_mode() method for more information. */
float2 compute_reference_marker_position(MovieTrackingTrack *track)
{
switch (get_mode()) {
case CMP_NODE_TRACK_POSITION_RELATIVE_START:
return compute_first_marker_position(track);
case CMP_NODE_TRACK_POSITION_RELATIVE_FRAME:
return compute_marker_position_at_frame(track, get_relative_frame());
default:
return float2(0.0f);
}
}
/* Compute the position of the first non-disabled marker in the track. */
float2 compute_first_marker_position(MovieTrackingTrack *track)
{
for (const int i : IndexRange(track->markersnr)) {
MovieTrackingMarker &marker = track->markers[i];
if (marker.flag & MARKER_DISABLED) {
continue;
}
return float2(marker.pos);
}
return float2(0.0f);
}
/* Compute the marker position at the given frame, if no such marker exist, return the position
* of the temporally nearest marker before it, if no such marker exist, return the position of
* the temporally nearest marker after it. */
float2 compute_marker_position_at_frame(MovieTrackingTrack *track, int frame)
{
const int local_frame_number = BKE_movieclip_remap_scene_to_clip_frame(get_movie_clip(),
frame);
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, local_frame_number);
return float2(marker->pos);
}
/* Get the movie tracking track corresponding to the given object and track names. If no such
* track exist, return nullptr. */
MovieTrackingTrack *get_movie_tracking_track()
{
MovieClip *movie_clip = get_movie_clip();
if (!movie_clip) {
return nullptr;
}
MovieTracking *movie_tracking = &movie_clip->tracking;
MovieTrackingObject *movie_tracking_object = BKE_tracking_object_get_named(
movie_tracking, node_storage(bnode()).tracking_object);
if (!movie_tracking_object) {
return nullptr;
}
return BKE_tracking_object_find_track_with_name(movie_tracking_object,
node_storage(bnode()).track_name);
}
/* Get the size of the movie clip at the evaluation frame. This is constant for all frames in
* most cases. */
int2 get_size()
{
MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
BKE_movieclip_user_set_frame(&user, get_frame());
int2 size;
BKE_movieclip_get_size(get_movie_clip(), &user, &size.x, &size.y);
return size;
}
/* In the CMP_NODE_TRACK_POSITION_RELATIVE_FRAME mode, this represents the offset that will be
* added to the current scene frame. See the get_mode() method for more information. */
int get_relative_frame()
{
return bnode().custom2;
}
/* Get the frame where the marker will be retrieved. This is the absolute frame for the absolute
* mode and the current scene frame otherwise. */
int get_frame()
{
if (get_mode() == CMP_NODE_TRACK_POSITION_ABSOLUTE_FRAME) {
return get_absolute_frame();
}
return context().get_frame_number();
}
/* In the CMP_NODE_TRACK_POSITION_ABSOLUTE_FRAME mode, this represents the frame where the marker
* will be retrieved. See the get_mode() method for more information. */
int get_absolute_frame()
{
return bnode().custom2;
}
/* CMP_NODE_TRACK_POSITION_ABSOLUTE:
* Returns the position and speed of the marker at the current scene frame relative to the zero
* origin of the tracking space.
*
* CMP_NODE_TRACK_POSITION_RELATIVE_START:
* Returns the position and speed of the marker at the current scene frame relative to the
* position of the first non-disabled marker in the track.
*
* CMP_NODE_TRACK_POSITION_RELATIVE_FRAME:
* Returns the position and speed of the marker at the current scene frame relative to the
* position of the marker at the current scene frame plus the user given relative frame.
*
* CMP_NODE_TRACK_POSITION_ABSOLUTE_FRAME:
* Returns the position and speed of the marker at the given absolute frame. */
CMPNodeTrackPositionMode get_mode()
{
return static_cast<CMPNodeTrackPositionMode>(bnode().custom1);
}
MovieClip *get_movie_clip()
{
return (MovieClip *)bnode().id;
}
};