Blender V5.0
node_composite_trackpos.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_index_range.hh"
11#include "BLI_string_utf8.h"
12
13#include "DNA_defaults.h"
14#include "DNA_movieclip_types.h"
15#include "DNA_tracking_types.h"
16
17#include "BKE_context.hh"
18#include "BKE_lib_id.hh"
19#include "BKE_movieclip.h"
20#include "BKE_tracking.h"
21
22#include "RNA_access.hh"
23#include "RNA_prototypes.hh"
24
25#include "UI_interface.hh"
27#include "UI_resources.hh"
28
29#include "COM_node_operation.hh"
30
32
34
36
37static const EnumPropertyItem mode_items[] = {
39 "ABSOLUTE",
40 0,
41 N_("Absolute"),
42 N_("Returns the position and speed of the marker at the current scene frame relative to the "
43 "zero origin of the tracking space")},
45 "RELATIVE_START",
46 0,
47 N_("Relative Start"),
48 N_("Returns the position and speed of the marker at the current scene frame relative to the "
49 "position of the first non-disabled marker in the track")},
51 "RELATIVE_FRAME",
52 0,
53 N_("Relative Frame"),
54 N_("Returns the position and speed of the marker at the current scene frame relative to the "
55 "position of the marker at the current scene frame plus the user given relative frame")},
57 "ABSOLUTE_FRAME",
58 0,
59 N_("Absolute Frame"),
60 N_("Returns the position and speed of the marker at the given absolute frame")},
61 {0, nullptr, 0, nullptr, nullptr},
62};
63
65{
66 b.add_input<decl::Menu>("Mode")
68 .static_items(mode_items)
70 b.add_input<decl::Int>("Frame").usage_by_menu(
72
73 b.add_output<decl::Float>("X");
74 b.add_output<decl::Float>("Y");
75 b.add_output<decl::Vector>("Speed").subtype(PROP_VELOCITY).dimensions(4);
76}
77
78static void init(const bContext *C, PointerRNA *ptr)
79{
80 bNode *node = (bNode *)ptr->data;
81
83 node->storage = data;
84
85 const Scene *scene = CTX_data_scene(C);
86 if (scene->clip) {
87 MovieClip *clip = scene->clip;
88 MovieTracking *tracking = &clip->tracking;
89
90 node->id = &clip->id;
91 id_us_plus(&clip->id);
92
93 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
94 STRNCPY_UTF8(data->tracking_object, tracking_object->name);
95
96 if (tracking_object->active_track) {
97 STRNCPY_UTF8(data->track_name, tracking_object->active_track->name);
98 }
99 }
100}
101
103{
104 bNode *node = (bNode *)ptr->data;
105
106 uiTemplateID(layout, C, ptr, "clip", nullptr, "CLIP_OT_open", nullptr);
107
108 if (node->id) {
109 MovieClip *clip = (MovieClip *)node->id;
110 MovieTracking *tracking = &clip->tracking;
111 MovieTrackingObject *tracking_object;
112 uiLayout *col;
114 PointerRNA tracking_ptr = RNA_pointer_create_discrete(&clip->id, &RNA_MovieTracking, tracking);
115
116 col = &layout->column(false);
117 col->prop_search(ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA);
118
119 tracking_object = BKE_tracking_object_get_named(tracking, data->tracking_object);
120 if (tracking_object) {
122 &clip->id, &RNA_MovieTrackingObject, tracking_object);
123
124 col->prop_search(ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA);
125 }
126 else {
127 layout->prop(ptr, "track_name", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_ANIM_DATA);
128 }
129 }
130}
131
132using namespace blender::compositor;
133
135 public:
137
138 void execute() override
139 {
141
142 if (!track) {
144 return;
145 }
146
147 const float2 current_marker_position = compute_marker_position_at_frame(track, get_frame());
148 const int2 size = get_size();
149
150 execute_position(track, current_marker_position, size);
151 execute_speed(track, current_marker_position, size);
152 }
153
154 void execute_position(MovieTrackingTrack *track, float2 current_marker_position, int2 size)
155 {
156 const bool should_compute_x = should_compute_output("X");
157 const bool should_compute_y = should_compute_output("Y");
158 if (!should_compute_x && !should_compute_y) {
159 return;
160 }
161
162 /* Compute the position relative to the reference marker position. Multiply by the size to get
163 * the position in pixel space. */
164 const float2 reference_marker_position = compute_reference_marker_position(track);
165 const float2 position = (current_marker_position - reference_marker_position) * float2(size);
166
167 if (should_compute_x) {
168 Result &result = get_result("X");
169 result.allocate_single_value();
170 result.set_single_value(position.x);
171 }
172
173 if (should_compute_y) {
174 Result &result = get_result("Y");
175 result.allocate_single_value();
176 result.set_single_value(position.y);
177 }
178 }
179
180 void execute_speed(MovieTrackingTrack *track, float2 current_marker_position, int2 size)
181 {
182 if (!should_compute_output("Speed")) {
183 return;
184 }
185
186 /* Compute the speed as the difference between the previous marker position and the current
187 * marker position. Notice that we compute the speed from the current to the previous position,
188 * not the other way around. */
189 const float2 previous_marker_position = compute_temporally_neighboring_marker_position(
190 track, current_marker_position, -1);
191 const float2 speed_toward_previous = previous_marker_position - current_marker_position;
192
193 /* Compute the speed as the difference between the current marker position and the next marker
194 * position. */
195 const float2 next_marker_position = compute_temporally_neighboring_marker_position(
196 track, current_marker_position, 1);
197 const float2 speed_toward_next = current_marker_position - next_marker_position;
198
199 /* Encode both speeds in a 4D vector. Multiply by the size to get the speed in pixel space. */
200 const float4 speed = float4(speed_toward_previous * float2(size),
201 speed_toward_next * float2(size));
202
203 Result &result = get_result("Speed");
204 result.allocate_single_value();
205 result.set_single_value(speed);
206 }
207
209 {
210 if (should_compute_output("X")) {
211 Result &result = get_result("X");
212 result.allocate_single_value();
213 result.set_single_value(0.0f);
214 }
215 if (should_compute_output("Y")) {
216 Result &result = get_result("Y");
217 result.allocate_single_value();
218 result.set_single_value(0.0f);
219 }
220 if (should_compute_output("Speed")) {
221 Result &result = get_result("Speed");
222 result.allocate_single_value();
223 result.set_single_value(float4(0.0f));
224 }
225 }
226
227 /* Compute the position of the marker that is delta time away from the evaluation frame. If no
228 * marker exist for that particular frame or is disabled, the current marker position is
229 * returned. This is useful for computing the speed by providing small negative and positive
230 * delta times. */
232 float2 current_marker_position,
233 int time_delta)
234 {
235 const int local_frame_number = BKE_movieclip_remap_scene_to_clip_frame(
236 get_movie_clip(), get_frame() + time_delta);
237 MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, local_frame_number);
238
239 if (marker == nullptr || marker->flag & MARKER_DISABLED) {
240 return current_marker_position;
241 }
242
243 return float2(marker->pos);
244 }
245
246 /* Compute the position of the reference marker which the output position will be computed
247 * relative to. For non-relative modes, this is just the zero origin or the tracking space. See
248 * the get_mode() method for more information. */
263
264 /* Compute the position of the first non-disabled marker in the track. */
266 {
267 for (const int i : IndexRange(track->markersnr)) {
268 MovieTrackingMarker &marker = track->markers[i];
269
270 if (marker.flag & MARKER_DISABLED) {
271 continue;
272 }
273
274 return float2(marker.pos);
275 }
276
277 return float2(0.0f);
278 }
279
280 /* Compute the marker position at the given frame, if no such marker exist, return the position
281 * of the temporally nearest marker before it, if no such marker exist, return the position of
282 * the temporally nearest marker after it. */
284 {
285 const int local_frame_number = BKE_movieclip_remap_scene_to_clip_frame(get_movie_clip(),
286 frame);
287 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, local_frame_number);
288 return float2(marker->pos);
289 }
290
291 /* Get the movie tracking track corresponding to the given object and track names. If no such
292 * track exist, return nullptr. */
294 {
295 MovieClip *movie_clip = get_movie_clip();
296 if (!movie_clip) {
297 return nullptr;
298 }
299
300 MovieTracking *movie_tracking = &movie_clip->tracking;
301
302 MovieTrackingObject *movie_tracking_object = BKE_tracking_object_get_named(
303 movie_tracking, node_storage(bnode()).tracking_object);
304 if (!movie_tracking_object) {
305 return nullptr;
306 }
307
308 return BKE_tracking_object_find_track_with_name(movie_tracking_object,
309 node_storage(bnode()).track_name);
310 }
311
312 /* Get the size of the movie clip at the evaluation frame. This is constant for all frames in
313 * most cases. */
315 {
318
319 int2 size;
321
322 return size;
323 }
324
325 /* In the CMP_NODE_TRACK_POSITION_RELATIVE_FRAME mode, this represents the offset that will be
326 * added to the current scene frame. See the get_mode() method for more information. */
328 {
329 return this->get_input("Frame").get_single_value_default(0);
330 }
331
332 /* Get the frame where the marker will be retrieved. This is the absolute frame for the absolute
333 * mode and the current scene frame otherwise. */
335 {
337 return get_absolute_frame();
338 }
339
340 return context().get_frame_number();
341 }
342
343 /* In the CMP_NODE_TRACK_POSITION_ABSOLUTE_FRAME mode, this represents the frame where the marker
344 * will be retrieved. See the get_mode() method for more information. */
346 {
347 return this->get_input("Frame").get_single_value_default(0);
348 }
349
351 {
352 const Result &input = this->get_input("Mode");
353 const MenuValue default_menu_value = MenuValue(CMP_NODE_TRACK_POSITION_ABSOLUTE);
354 const MenuValue menu_value = input.get_single_value_default(default_menu_value);
355 return static_cast<CMPNodeTrackPositionMode>(menu_value.value);
356 }
357
359 {
360 return (MovieClip *)bnode().id;
361 }
362};
363
365{
366 return new TrackPositionOperation(context, node);
367}
368
369} // namespace blender::nodes::node_composite_trackpos_cc
370
372{
374
375 static blender::bke::bNodeType ntype;
376
377 cmp_node_type_base(&ntype, "CompositorNodeTrackPos", CMP_NODE_TRACKPOS);
378 ntype.ui_name = "Track Position";
379 ntype.ui_description =
380 "Provide information about motion tracking points, such as x and y values";
381 ntype.enum_name_legacy = "TRACKPOS";
382 ntype.nclass = NODE_CLASS_INPUT;
383 ntype.declare = file_ns::cmp_node_trackpos_declare;
384 ntype.draw_buttons = file_ns::node_composit_buts_trackpos;
385 ntype.initfunc_api = file_ns::init;
387 ntype, "NodeTrackPosData", node_free_standard_storage, node_copy_standard_storage);
388 ntype.get_compositor_operation = file_ns::get_compositor_operation;
389
391}
Scene * CTX_data_scene(const bContext *C)
void id_us_plus(ID *id)
Definition lib_id.cc:358
float BKE_movieclip_remap_scene_to_clip_frame(const struct MovieClip *clip, float framenr)
void BKE_movieclip_user_set_frame(struct MovieClipUser *user, int framenr)
void BKE_movieclip_get_size(struct MovieClip *clip, const struct MovieClipUser *user, int *r_width, int *r_height)
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
#define NODE_CLASS_INPUT
Definition BKE_node.hh:447
#define CMP_NODE_TRACKPOS
struct MovieTrackingObject * BKE_tracking_object_get_named(struct MovieTracking *tracking, const char *name)
Definition tracking.cc:1966
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:1358
struct MovieTrackingObject * BKE_tracking_object_get_active(const struct MovieTracking *tracking)
struct MovieTrackingMarker * BKE_tracking_marker_get_exact(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:1391
struct MovieTrackingTrack * BKE_tracking_object_find_track_with_name(struct MovieTrackingObject *tracking_object, const char *name)
Definition tracking.cc:1993
#define STRNCPY_UTF8(dst, src)
#define DNA_struct_default_get(struct_name)
CMPNodeTrackPositionMode
@ CMP_NODE_TRACK_POSITION_RELATIVE_START
@ CMP_NODE_TRACK_POSITION_ABSOLUTE_FRAME
@ CMP_NODE_TRACK_POSITION_RELATIVE_FRAME
@ CMP_NODE_TRACK_POSITION_ABSOLUTE
@ MARKER_DISABLED
#define NOD_REGISTER_NODE(REGISTER_FUNC)
@ PROP_VELOCITY
Definition RNA_types.hh:263
#define C
Definition RandGen.cpp:29
void uiTemplateID(uiLayout *layout, const bContext *C, PointerRNA *ptr, blender::StringRefNull propname, const char *newop, const char *openop, const char *unlinkop, int filter=UI_TEMPLATE_ID_FILTER_ALL, bool live_icon=false, std::optional< blender::StringRef > text=std::nullopt)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
BMesh const char void * data
void init()
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
bool should_compute_output(StringRef identifier)
NodeOperation(Context &context, DNode node)
Result & get_result(StringRef identifier)
Definition operation.cc:39
Result & get_input(StringRef identifier) const
Definition operation.cc:138
T get_single_value_default(const T &default_value) const
void execute_position(MovieTrackingTrack *track, float2 current_marker_position, int2 size)
void execute_speed(MovieTrackingTrack *track, float2 current_marker_position, int2 size)
float2 compute_marker_position_at_frame(MovieTrackingTrack *track, int frame)
float2 compute_temporally_neighboring_marker_position(MovieTrackingTrack *track, float2 current_marker_position, int time_delta)
uint col
#define input
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5414
static void cmp_node_trackpos_declare(NodeDeclarationBuilder &b)
static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
static void register_node_type_cmp_trackpos()
void cmp_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
struct MovieTracking tracking
MovieTrackingTrack * active_track
MovieTrackingMarker * markers
struct MovieClip * clip
struct ID * id
void * storage
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:348
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeDeclareFunction declare
Definition BKE_node.hh:362
void(* initfunc_api)(const bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:302
uiLayout & column(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238