コード例 #1
0
static int set_origin_exec(bContext *C, wmOperator *op)
{
  SpaceClip *sc = CTX_wm_space_clip(C);
  MovieClip *clip = ED_space_clip_get_clip(sc);
  MovieTracking *tracking = &clip->tracking;
  Scene *scene = CTX_data_scene(C);
  Object *camera = get_camera_with_movieclip(scene, clip);
  int selected_count = count_selected_bundles(C);

  if (selected_count == 0) {
    BKE_report(op->reports,
               RPT_ERROR,
               "At least one track with bundle should be selected to "
               "define origin position");

    return OPERATOR_CANCELLED;
  }

  Object *object = get_orientation_object(C);
  if (object == NULL) {
    BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
    return OPERATOR_CANCELLED;
  }

  MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
  ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);

  float median[3] = {0.0f, 0.0f, 0.0f};
  zero_v3(median);
  for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
    if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE)) {
      add_v3_v3(median, track->bundle_pos);
    }
  }
  mul_v3_fl(median, 1.0f / selected_count);

  float mat[4][4], vec[3];
  BKE_tracking_get_camera_object_matrix(scene, camera, mat);
  mul_v3_m4v3(vec, mat, median);

  if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
    sub_v3_v3(object->loc, vec);
  }
  else {
    object_solver_inverted_matrix(scene, object, mat);
    mul_v3_m4v3(vec, mat, vec);
    copy_v3_v3(object->loc, vec);
  }

  DEG_id_tag_update(&clip->id, 0);
  DEG_id_tag_update(&object->id, ID_RECALC_TRANSFORM);

  WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
  WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);

  return OPERATOR_FINISHED;
}
コード例 #2
0
ファイル: view3d_snap.c プロジェクト: diekev/blender
static void bundle_midpoint(Scene *scene, Object *ob, float vec[3])
{
	MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
	MovieTracking *tracking;
	MovieTrackingObject *object;
	bool ok = false;
	float min[3], max[3], mat[4][4], pos[3], cammat[4][4];

	if (!clip)
		return;

	tracking = &clip->tracking;

	copy_m4_m4(cammat, ob->obmat);

	BKE_tracking_get_camera_object_matrix(scene, ob, mat);

	INIT_MINMAX(min, max);

	for (object = tracking->objects.first; object; object = object->next) {
		ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
		MovieTrackingTrack *track = tracksbase->first;
		float obmat[4][4];

		if (object->flag & TRACKING_OBJECT_CAMERA) {
			copy_m4_m4(obmat, mat);
		}
		else {
			float imat[4][4];

			BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, scene->r.cfra, imat);
			invert_m4(imat);

			mul_m4_m4m4(obmat, cammat, imat);
		}

		while (track) {
			if ((track->flag & TRACK_HAS_BUNDLE) && TRACK_SELECTED(track)) {
				ok = 1;
				mul_v3_m4v3(pos, obmat, track->bundle_pos);
				minmax_v3v3_v3(min, max, pos);
			}

			track = track->next;
		}
	}

	if (ok) {
		mid_v3_v3v3(vec, min, max);
	}
}
コード例 #3
0
/* Apply scale on all reconstructed cameras and bundles,
 * used by camera scale apply operator.
 */
void BKE_tracking_reconstruction_scale(MovieTracking *tracking, float scale[3])
{
	MovieTrackingObject *object;

	for (object = tracking->objects.first; object; object = object->next) {
		ListBase *tracksbase;
		MovieTrackingReconstruction *reconstruction;

		tracksbase = BKE_tracking_object_get_tracks(tracking, object);
		reconstruction = BKE_tracking_object_get_reconstruction(tracking, object);

		tracking_scale_reconstruction(tracksbase, reconstruction, scale);
	}
}
コード例 #4
0
ファイル: tracking_ops_orient.c プロジェクト: diekev/blender
static int set_axis_exec(bContext *C, wmOperator *op)
{
    SpaceClip *sc = CTX_wm_space_clip(C);
    MovieClip *clip = ED_space_clip_get_clip(sc);
    MovieTracking *tracking = &clip->tracking;
    MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
    Scene *scene = CTX_data_scene(C);
    Object *object;
    int axis = RNA_enum_get(op->ptr, "axis");

    if (count_selected_bundles(C) != 1) {
        BKE_report(op->reports,
                   RPT_ERROR,
                   "Single track with bundle should be selected to define axis");
        return OPERATOR_CANCELLED;
    }

    object = get_orientation_object(C);
    if (object == NULL) {
        BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
        return OPERATOR_CANCELLED;
    }

    ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking,
                           tracking_object);
    MovieTrackingTrack *track = tracksbase->first;
    while (track) {
        if (TRACK_VIEW_SELECTED(sc, track) &&
                (track->flag & TRACK_HAS_BUNDLE))
        {
            break;
        }
        track = track->next;
    }

    set_axis(scene, object, clip, tracking_object, track, axis == 0 ? 'X' : 'Y');

    DAG_id_tag_update(&clip->id, 0);
    DAG_id_tag_update(&object->id, OB_RECALC_OB);

    WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
    WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);

    return OPERATOR_FINISHED;
}
コード例 #5
0
static bool mouse_select_curve(bContext *C, float co[2], bool extend)
{
	SpaceClip *sc = CTX_wm_space_clip(C);
	MovieClip *clip = ED_space_clip_get_clip(sc);
	MovieTracking *tracking = &clip->tracking;
	MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
	MouseSelectUserData userdata;

	mouse_select_init_data(&userdata, co);
	clip_graph_tracking_values_iterate(sc,
	                                   (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
	                                   (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
	                                   &userdata, find_nearest_tracking_segment_cb,
	                                   NULL, find_nearest_tracking_segment_end_cb);

	if (userdata.track) {
		if (extend) {
			if (act_track == userdata.track) {
				/* currently only single curve can be selected (selected curve represents active track) */
				act_track = NULL;
			}
		}
		else if (act_track != userdata.track) {
			SelectUserData selectdata = {SEL_DESELECT};
			MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);

			tracking->act_track = userdata.track;
			if ((sc->flag & SC_SHOW_GRAPH_SEL_ONLY) == 0) {
				ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
				BKE_tracking_track_select(tracksbase, userdata.track, TRACK_AREA_ALL, false);
			}

			/* deselect all knots on newly selected curve */
			clip_graph_tracking_iterate(sc,
			                            (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
			                            (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
			                            &selectdata, toggle_selection_cb);
		}

		return true;
	}

	return false;
}
コード例 #6
0
static int dopesheet_select_channel_exec(bContext *C, wmOperator *op)
{
	SpaceClip *sc = CTX_wm_space_clip(C);
	MovieClip *clip = ED_space_clip_get_clip(sc);
	MovieTracking *tracking = &clip->tracking;
	MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
	MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
	MovieTrackingDopesheetChannel *channel;
	ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
	float location[2];
	const bool extend = RNA_boolean_get(op->ptr, "extend");
	int current_channel_index = 0, channel_index;
	const bool show_selected_only = (dopesheet->flag & TRACKING_DOPE_SELECTED_ONLY) != 0;

	RNA_float_get_array(op->ptr, "location", location);
	channel_index = -(location[1] - (CHANNEL_FIRST + CHANNEL_HEIGHT_HALF)) / CHANNEL_STEP;

	for (channel = dopesheet->channels.first; channel; channel = channel->next) {
		MovieTrackingTrack *track = channel->track;

		if (current_channel_index == channel_index) {
			if (extend)
				track->flag ^= TRACK_DOPE_SEL;
			else
				track->flag |= TRACK_DOPE_SEL;

			if (track->flag & TRACK_DOPE_SEL) {
				tracking->act_track = track;
				BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, true);
			}
			else if (show_selected_only == false) {
				BKE_tracking_track_deselect(track, TRACK_AREA_ALL);
			}
		}
		else if (!extend)
			track->flag &= ~TRACK_DOPE_SEL;

		current_channel_index++;
	}

	WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);

	return OPERATOR_FINISHED;
}
コード例 #7
0
/* Count tracks which has markers at both of keyframes. */
static int reconstruct_count_tracks_on_both_keyframes(MovieTracking *tracking, MovieTrackingObject *object)
{
	ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
	int tot = 0;
	int frame1 = object->keyframe1, frame2 = object->keyframe2;
	MovieTrackingTrack *track;

	track = tracksbase->first;
	while (track) {
		if (BKE_tracking_track_has_enabled_marker_at_frame(track, frame1)) {
			if (BKE_tracking_track_has_enabled_marker_at_frame(track, frame2)) {
				tot++;
			}
		}

		track = track->next;
	}

	return tot;
}
コード例 #8
0
static void compute_gradient_screen(RenderData *rd, NodeKeyingScreenData *keyingscreen_data, MovieClip *clip, CompBuf *screenbuf)
{
	MovieClipUser user = {0};
	MovieTracking *tracking = &clip->tracking;
	MovieTrackingTrack *track;
	VoronoiTriangulationPoint *triangulated_points;
	VoronoiSite *sites;
	ImBuf *ibuf;
	ListBase *tracksbase;
	ListBase edges = {NULL, NULL};
	int sites_total, triangulated_points_total, triangles_total;
	int (*triangles)[3];
	int i, x, y;
	float *rect = screenbuf->rect;

	if (keyingscreen_data->tracking_object[0]) {
		MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, keyingscreen_data->tracking_object);

		if (!object)
			return;

		tracksbase = BKE_tracking_object_get_tracks(tracking, object);
	}
	else
		tracksbase = BKE_tracking_get_active_tracks(tracking);

	sites_total = BLI_countlist(tracksbase);

	if (!sites_total)
		return;

	BKE_movieclip_user_set_frame(&user, rd->cfra);
	ibuf = BKE_movieclip_get_ibuf(clip, &user);

	sites = MEM_callocN(sizeof(VoronoiSite) * sites_total, "keyingscreen voronoi sites");
	track = tracksbase->first;
	i = 0;
	while (track) {
		VoronoiSite *site = &sites[i];
		MovieTrackingMarker *marker = BKE_tracking_marker_get(track, rd->cfra);
		ImBuf *pattern_ibuf = BKE_tracking_get_pattern_imbuf(ibuf, track, marker, TRUE, FALSE);
		int j;

		zero_v3(site->color);

		if (pattern_ibuf) {
			for (j = 0; j < pattern_ibuf->x * pattern_ibuf->y; j++) {
				if (pattern_ibuf->rect_float) {
					add_v3_v3(site->color, &pattern_ibuf->rect_float[4 * j]);
				}
				else {
					unsigned char *rrgb = (unsigned char *)pattern_ibuf->rect;

					site->color[0] += srgb_to_linearrgb((float)rrgb[4 * j + 0] / 255.0f);
					site->color[1] += srgb_to_linearrgb((float)rrgb[4 * j + 1] / 255.0f);
					site->color[2] += srgb_to_linearrgb((float)rrgb[4 * j + 2] / 255.0f);
				}
			}

			mul_v3_fl(site->color, 1.0f / (pattern_ibuf->x * pattern_ibuf->y));
			IMB_freeImBuf(pattern_ibuf);
		}

		site->co[0] = marker->pos[0] * screenbuf->x;
		site->co[1] = marker->pos[1] * screenbuf->y;

		track = track->next;
		i++;
	}

	IMB_freeImBuf(ibuf);

	BLI_voronoi_compute(sites, sites_total, screenbuf->x, screenbuf->y, &edges);

	BLI_voronoi_triangulate(sites, sites_total, &edges, screenbuf->x, screenbuf->y,
	                        &triangulated_points, &triangulated_points_total,
                            &triangles, &triangles_total);

	for (y = 0; y < screenbuf->y; y++) {
		for (x = 0; x < screenbuf->x; x++) {
			int index = 4 * (y * screenbuf->x + x);

			rect[index + 0] = rect[index + 1] = rect[index + 2] = 0.0f;
			rect[index + 3] = 1.0f;

			for (i = 0; i < triangles_total; i++) {
				int *triangle = triangles[i];
				VoronoiTriangulationPoint *a = &triangulated_points[triangle[0]],
				                          *b = &triangulated_points[triangle[1]],
				                          *c = &triangulated_points[triangle[2]];
				float co[2] = {x, y}, w[3];

				if (barycentric_coords_v2(a->co, b->co, c->co, co, w)) {
					if (barycentric_inside_triangle_v2(w)) {
						rect[index + 0] += a->color[0] * w[0] + b->color[0] * w[1] + c->color[0] * w[2];
						rect[index + 1] += a->color[1] * w[0] + b->color[1] * w[1] + c->color[1] * w[2];
						rect[index + 2] += a->color[2] * w[0] + b->color[2] * w[1] + c->color[2] * w[2];
					}
				}
			}
		}
	}

	MEM_freeN(triangulated_points);
	MEM_freeN(triangles);
	MEM_freeN(sites);
	BLI_freelistN(&edges);
}
コード例 #9
0
/* Create context for camera/object motion reconstruction.
 * Copies all data needed for reconstruction from movie
 * clip datablock, so editing this clip is safe during
 * reconstruction job is in progress.
 */
MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieClip *clip, MovieTrackingObject *object,
                                                                 int keyframe1, int keyframe2, int width, int height)
{
	MovieTracking *tracking = &clip->tracking;
	MovieReconstructContext *context = MEM_callocN(sizeof(MovieReconstructContext), "MovieReconstructContext data");
	ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
	float aspy = 1.0f / tracking->camera.pixel_aspect;
	int num_tracks = BLI_countlist(tracksbase);
	int sfra = INT_MAX, efra = INT_MIN;
	MovieTrackingTrack *track;

	BLI_strncpy(context->object_name, object->name, sizeof(context->object_name));
	context->is_camera = object->flag & TRACKING_OBJECT_CAMERA;
	context->motion_flag = tracking->settings.motion_flag;

	context->select_keyframes =
		(tracking->settings.reconstruction_flag & TRACKING_USE_KEYFRAME_SELECTION) != 0;

	tracking_cameraIntrinscisOptionsFromTracking(tracking,
                                                 width, height,
                                                 &context->camera_intrinsics_options);

	context->tracks_map = tracks_map_new(context->object_name, context->is_camera, num_tracks, 0);

	track = tracksbase->first;
	while (track) {
		int first = 0, last = track->markersnr - 1;
		MovieTrackingMarker *first_marker = &track->markers[0];
		MovieTrackingMarker *last_marker = &track->markers[track->markersnr - 1];

		/* find first not-disabled marker */
		while (first <= track->markersnr - 1 && first_marker->flag & MARKER_DISABLED) {
			first++;
			first_marker++;
		}

		/* find last not-disabled marker */
		while (last >= 0 && last_marker->flag & MARKER_DISABLED) {
			last--;
			last_marker--;
		}

		if (first < track->markersnr - 1)
			sfra = min_ii(sfra, first_marker->framenr);

		if (last >= 0)
			efra = max_ii(efra, last_marker->framenr);

		tracks_map_insert(context->tracks_map, track, NULL);

		track = track->next;
	}

	context->sfra = sfra;
	context->efra = efra;

	context->tracks = libmv_tracks_new(clip, tracksbase, width, height * aspy);
	context->keyframe1 = keyframe1;
	context->keyframe2 = keyframe2;
	context->refine_flags = reconstruct_refine_intrinsics_get_flags(tracking, object);

	return context;
}
コード例 #10
0
KeyingScreenOperation::TriangulationData *KeyingScreenOperation::buildVoronoiTriangulation()
{
	MovieClipUser user = {0};
	TriangulationData *triangulation;
	MovieTracking *tracking = &this->m_movieClip->tracking;
	MovieTrackingTrack *track;
	VoronoiSite *sites, *site;
	ImBuf *ibuf;
	ListBase *tracksbase;
	ListBase edges = {NULL, NULL};
	int sites_total;
	int i;
	int width = this->getWidth();
	int height = this->getHeight();
	int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber);

	if (this->m_trackingObject[0]) {
		MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, this->m_trackingObject);

		if (!object)
			return NULL;

		tracksbase = BKE_tracking_object_get_tracks(tracking, object);
	}
	else
		tracksbase = BKE_tracking_get_active_tracks(tracking);

	/* count sites */
	for (track = (MovieTrackingTrack *) tracksbase->first, sites_total = 0; track; track = track->next) {
		MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame);
		float pos[2];

		if (marker->flag & MARKER_DISABLED)
			continue;

		add_v2_v2v2(pos, marker->pos, track->offset);

		if (!IN_RANGE_INCL(pos[0], 0.0f, 1.0f) ||
		    !IN_RANGE_INCL(pos[1], 0.0f, 1.0f))
		{
			continue;
		}

		sites_total++;
	}

	if (!sites_total)
		return NULL;

	BKE_movieclip_user_set_frame(&user, clip_frame);
	ibuf = BKE_movieclip_get_ibuf(this->m_movieClip, &user);

	if (!ibuf)
		return NULL;

	triangulation = (TriangulationData *) MEM_callocN(sizeof(TriangulationData), "keying screen triangulation data");

	sites = (VoronoiSite *) MEM_callocN(sizeof(VoronoiSite) * sites_total, "keyingscreen voronoi sites");
	track = (MovieTrackingTrack *) tracksbase->first;
	for (track = (MovieTrackingTrack *) tracksbase->first, site = sites; track; track = track->next) {
		MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame);
		ImBuf *pattern_ibuf;
		int j;
		float pos[2];

		if (marker->flag & MARKER_DISABLED)
			continue;

		add_v2_v2v2(pos, marker->pos, track->offset);

		if (!IN_RANGE_INCL(pos[0], 0.0f, 1.0f) ||
		    !IN_RANGE_INCL(pos[1], 0.0f, 1.0f))
		{
			continue;
		}

		pattern_ibuf = BKE_tracking_get_pattern_imbuf(ibuf, track, marker, TRUE, FALSE);

		zero_v3(site->color);

		if (pattern_ibuf) {
			for (j = 0; j < pattern_ibuf->x * pattern_ibuf->y; j++) {
				if (pattern_ibuf->rect_float) {
					add_v3_v3(site->color, &pattern_ibuf->rect_float[4 * j]);
				}
				else {
					unsigned char *rrgb = (unsigned char *)pattern_ibuf->rect;

					site->color[0] += srgb_to_linearrgb((float)rrgb[4 * j + 0] / 255.0f);
					site->color[1] += srgb_to_linearrgb((float)rrgb[4 * j + 1] / 255.0f);
					site->color[2] += srgb_to_linearrgb((float)rrgb[4 * j + 2] / 255.0f);
				}
			}

			mul_v3_fl(site->color, 1.0f / (pattern_ibuf->x * pattern_ibuf->y));
			IMB_freeImBuf(pattern_ibuf);
		}

		site->co[0] = pos[0] * width;
		site->co[1] = pos[1] * height;

		site++;
	}

	IMB_freeImBuf(ibuf);

	BLI_voronoi_compute(sites, sites_total, width, height, &edges);

	BLI_voronoi_triangulate(sites, sites_total, &edges, width, height,
	                        &triangulation->triangulated_points, &triangulation->triangulated_points_total,
	                        &triangulation->triangles, &triangulation->triangles_total);

	MEM_freeN(sites);
	BLI_freelistN(&edges);

	if (triangulation->triangles_total) {
		rctf *rect;
		rect = triangulation->triangles_AABB =
			(rctf *) MEM_callocN(sizeof(rctf) * triangulation->triangles_total, "voronoi triangulation AABB");

		for (i = 0; i < triangulation->triangles_total; i++, rect++) {
			int *triangle = triangulation->triangles[i];
			VoronoiTriangulationPoint *a = &triangulation->triangulated_points[triangle[0]],
			                          *b = &triangulation->triangulated_points[triangle[1]],
			                          *c = &triangulation->triangulated_points[triangle[2]];

			float min[2], max[2];

			INIT_MINMAX2(min, max);

			minmax_v2v2_v2(min, max, a->co);
			minmax_v2v2_v2(min, max, b->co);
			minmax_v2v2_v2(min, max, c->co);

			rect->xmin = min[0];
			rect->ymin = min[1];

			rect->xmax = max[0];
			rect->ymax = max[1];
		}
	}

	return triangulation;
}
コード例 #11
0
static int set_plane_exec(bContext *C, wmOperator *op)
{
  SpaceClip *sc = CTX_wm_space_clip(C);
  MovieClip *clip = ED_space_clip_get_clip(sc);
  Scene *scene = CTX_data_scene(C);
  MovieTracking *tracking = &clip->tracking;
  MovieTrackingObject *tracking_object;
  MovieTrackingTrack *track, *axis_track = NULL, *act_track;
  ListBase *tracksbase;
  Object *object;
  Object *camera = get_camera_with_movieclip(scene, clip);
  Depsgraph *depsgraph = CTX_data_depsgraph(C);
  int tot = 0;
  float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
  int plane = RNA_enum_get(op->ptr, "plane");
  float rot[4][4] = {
      {0.0f, 0.0f, -1.0f, 0.0f},
      {0.0f, 1.0f, 0.0f, 0.0f},
      {1.0f, 0.0f, 0.0f, 0.0f},
      {0.0f, 0.0f, 0.0f, 1.0f},
  }; /* 90 degrees Y-axis rotation matrix */

  if (count_selected_bundles(C) != 3) {
    BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");

    return OPERATOR_CANCELLED;
  }

  tracking_object = BKE_tracking_object_get_active(tracking);
  tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
  act_track = BKE_tracking_track_get_active(tracking);

  object = get_orientation_object(C);
  if (object == NULL) {
    BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
    return OPERATOR_CANCELLED;
  }

  BKE_tracking_get_camera_object_matrix(scene, camera, mat);

  /* Get 3 bundles to use as reference. */
  track = tracksbase->first;
  while (track && tot < 3) {
    if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
      mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
      if (tot == 0 || track == act_track) {
        copy_v3_v3(orig, vec[tot]);
      }
      else {
        axis_track = track;
      }
      tot++;
    }
    track = track->next;
  }

  sub_v3_v3(vec[1], vec[0]);
  sub_v3_v3(vec[2], vec[0]);

  /* Construct ortho-normal basis. */
  unit_m4(mat);
  if (plane == 0) { /* floor */
    cross_v3_v3v3(mat[0], vec[1], vec[2]);
    copy_v3_v3(mat[1], vec[1]);
    cross_v3_v3v3(mat[2], mat[0], mat[1]);
  }
  else if (plane == 1) { /* wall */
    cross_v3_v3v3(mat[2], vec[1], vec[2]);
    copy_v3_v3(mat[1], vec[1]);
    cross_v3_v3v3(mat[0], mat[1], mat[2]);
  }

  normalize_v3(mat[0]);
  normalize_v3(mat[1]);
  normalize_v3(mat[2]);

  /* Move to origin point. */
  mat[3][0] = orig[0];
  mat[3][1] = orig[1];
  mat[3][2] = orig[2];

  if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
    invert_m4(mat);

    BKE_object_to_mat4(object, obmat);
    mul_m4_m4m4(mat, mat, obmat);
    mul_m4_m4m4(newmat, rot, mat);
    BKE_object_apply_mat4(object, newmat, 0, 0);

    /* Make camera have positive z-coordinate. */
    if (object->loc[2] < 0) {
      invert_m4(rot);
      mul_m4_m4m4(newmat, rot, mat);
      BKE_object_apply_mat4(object, newmat, 0, 0);
    }
  }
  else {
    BKE_object_apply_mat4(object, mat, 0, 0);
  }

  BKE_object_where_is_calc(depsgraph, scene, object);
  set_axis(scene, object, clip, tracking_object, axis_track, 'X');

  DEG_id_tag_update(&clip->id, 0);
  DEG_id_tag_update(&object->id, ID_RECALC_TRANSFORM);

  WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
  WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);

  return OPERATOR_FINISHED;
}