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:
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
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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_);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue