Blender V4.3
view3d_camera_control.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
28#include "DNA_camera_types.h"
29#include "DNA_object_types.h"
30#include "DNA_scene_types.h"
31
32#include "MEM_guardedalloc.h"
33
34#include "BLI_math_matrix.h"
35#include "BLI_math_rotation.h"
36#include "BLI_math_vector.h"
37#include "BLI_utildefines.h"
38
39#include "BKE_object.hh"
40
41#include "DEG_depsgraph.hh"
42
43#include "view3d_intern.hh" /* own include */
44
46
47 /* -------------------------------------------------------------------- */
48 /* Context (assign these to vars before use) */
52
53 /* -------------------------------------------------------------------- */
54 /* internal vars */
55
56 /* for parenting calculation */
57 float view_mat_prev[4][4];
58
59 /* -------------------------------------------------------------------- */
60 /* optional capabilities */
61
63
64 /* -------------------------------------------------------------------- */
65 /* initial values */
66
69
70 /* Backup values. */
71
75 float ofs_backup[3];
76
78 float rot_backup[4];
84
91
93 void *obtfm;
94};
95
97{
98 return vctrl->root_parent ? vctrl->root_parent : vctrl->ctx_v3d->camera;
99}
100
102{
103 RegionView3D *rv3d = vctrl->ctx_rv3d;
104
105 if (rv3d->persp == RV3D_CAMOB) {
106 return view3d_cameracontrol_object(vctrl);
107 }
108
109 return nullptr;
110}
111
113 Scene *scene,
114 View3D *v3d,
115 RegionView3D *rv3d)
116{
117 View3DCameraControl *vctrl;
118
119 vctrl = static_cast<View3DCameraControl *>(MEM_callocN(sizeof(View3DCameraControl), __func__));
120
121 /* Store context */
122 vctrl->ctx_scene = scene;
123 vctrl->ctx_v3d = v3d;
124 vctrl->ctx_rv3d = rv3d;
125
126 vctrl->use_parent_root = v3d->camera != nullptr &&
128
129 vctrl->persp_backup = rv3d->persp;
130 vctrl->dist_backup = rv3d->dist;
131
132 /* check for flying ortho camera - which we can't support well
133 * we _could_ also check for an ortho camera but this is easier */
134 if ((rv3d->persp == RV3D_CAMOB) && (rv3d->is_persp == false)) {
135 ((Camera *)v3d->camera->data)->type = CAM_PERSP;
136 vctrl->is_ortho_cam = true;
137 }
138
139 if (rv3d->persp == RV3D_CAMOB) {
140 Object *ob_back;
141 if (vctrl->use_parent_root && (vctrl->root_parent = v3d->camera->parent)) {
142 while (vctrl->root_parent->parent) {
143 vctrl->root_parent = vctrl->root_parent->parent;
144 }
145 ob_back = vctrl->root_parent;
146 }
147 else {
148 ob_back = v3d->camera;
149 }
150
151 /* store the original camera loc and rot */
152 vctrl->obtfm = BKE_object_tfm_backup(ob_back);
153
155 negate_v3_v3(rv3d->ofs, v3d->camera->object_to_world().location());
156
157 rv3d->dist = 0.0;
158 }
159 else {
160 /* perspective or ortho */
161 if (rv3d->persp == RV3D_ORTHO) {
162 /* if ortho projection, make perspective */
163 rv3d->persp = RV3D_PERSP;
164 }
165
166 copy_qt_qt(vctrl->rot_backup, rv3d->viewquat);
167 copy_v3_v3(vctrl->ofs_backup, rv3d->ofs);
168
169 /* The dist defines a vector that is in front of the offset
170 * to rotate the view about.
171 * this is no good for fly mode because we
172 * want to rotate about the viewers center.
173 * but to correct the dist removal we must
174 * alter offset so the view doesn't jump. */
175
176 ED_view3d_distance_set(rv3d, 0.0f);
177 /* Done with correcting for the dist */
178 }
179
180 ED_view3d_to_m4(vctrl->view_mat_prev, rv3d->ofs, rv3d->viewquat, rv3d->dist);
181
182 return vctrl;
183}
184
195 Object *ob,
196 const float obmat[4][4],
197 const bool use_parent, /* Only use when applying lock. */
198 RegionView3D *rv3d,
199 const float view_mat[4][4])
200{
201 const bool use_protect = (ob->protectflag != 0);
202 bool view_changed = false;
203
205 if (use_protect) {
207 }
208
209 BKE_object_apply_mat4(ob, obmat, true, use_parent);
210
211 if (use_protect) {
212 float obmat_noprotect[4][4], obmat_protect[4][4];
213
214 BKE_object_to_mat4(ob, obmat_noprotect);
216 BKE_object_to_mat4(ob, obmat_protect);
217
218 if (!equals_m4m4(obmat_noprotect, obmat_protect)) {
219 /* Apply the lock protection back to the view, without this the view
220 * keeps moving, ignoring the object locking, causing jittering in some cases. */
221 float diff_mat[4][4];
222 float view_mat_protect[4][4];
223 float obmat_noprotect_inv[4][4];
224 invert_m4_m4(obmat_noprotect_inv, obmat_noprotect);
225 mul_m4_m4m4(diff_mat, obmat_protect, obmat_noprotect_inv);
226
227 mul_m4_m4m4(view_mat_protect, diff_mat, view_mat);
228 ED_view3d_from_m4(view_mat_protect, rv3d->ofs, rv3d->viewquat, &rv3d->dist);
229 view_changed = true;
230 }
231 }
232 return view_changed;
233}
234
235void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl, /* args for keyframing */
236 const bool use_autokey,
237 bContext *C,
238 const bool do_rotate,
239 const bool do_translate)
240{
241 /* We are in camera view so apply the view offset and rotation to the view matrix
242 * and set the camera to the view. */
243
244 Scene *scene = vctrl->ctx_scene;
245 View3D *v3d = vctrl->ctx_v3d;
246 RegionView3D *rv3d = vctrl->ctx_rv3d;
247
248 ID *id_key;
249
250 float view_mat[4][4];
251 ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
252
253 /* transform the parent or the camera? */
254 if (vctrl->root_parent) {
255 Object *ob_update;
256
257 float prev_view_imat[4][4];
258 float diff_mat[4][4];
259 float parent_mat[4][4];
260
261 invert_m4_m4(prev_view_imat, vctrl->view_mat_prev);
262 mul_m4_m4m4(diff_mat, view_mat, prev_view_imat);
263 mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->object_to_world().ptr());
264
265 if (object_apply_mat4_with_protect(vctrl->root_parent, parent_mat, false, rv3d, view_mat)) {
266 /* Calculate again since the view locking changes the matrix. */
267 ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
268 }
269
270 ob_update = v3d->camera->parent;
271 while (ob_update) {
273 ob_update = ob_update->parent;
274 }
275
276 copy_m4_m4(vctrl->view_mat_prev, view_mat);
277
278 id_key = &vctrl->root_parent->id;
279 }
280 else {
281 float scale_mat[4][4];
282 float scale_back[3];
283
284 /* even though we handle the scale matrix, this still changes over time */
285 copy_v3_v3(scale_back, v3d->camera->scale);
286
287 size_to_mat4(scale_mat, v3d->camera->scale);
288 mul_m4_m4m4(view_mat, view_mat, scale_mat);
289
290 object_apply_mat4_with_protect(v3d->camera, view_mat, true, rv3d, view_mat);
291
293
294 copy_v3_v3(v3d->camera->scale, scale_back);
295
296 id_key = &v3d->camera->id;
297 }
298
299 /* record the motion */
300 if (use_autokey) {
301 ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
302 }
303}
304
306{
307 View3D *v3d = vctrl->ctx_v3d;
308 RegionView3D *rv3d = vctrl->ctx_rv3d;
309
310 if (restore) {
311 /* Revert to original view? */
312 if (vctrl->persp_backup == RV3D_CAMOB) { /* a camera view */
313 Object *ob_back = view3d_cameracontrol_object(vctrl);
314
315 /* store the original camera loc and rot */
316 BKE_object_tfm_restore(ob_back, vctrl->obtfm);
317
319 }
320 else {
321 /* Non Camera we need to reset the view back
322 * to the original location because the user canceled. */
323 copy_qt_qt(rv3d->viewquat, vctrl->rot_backup);
324 rv3d->persp = vctrl->persp_backup;
325 }
326 /* always, is set to zero otherwise */
327 copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
328 rv3d->dist = vctrl->dist_backup;
329 }
330 else if (vctrl->persp_backup == RV3D_CAMOB) { /* camera */
332
333 /* always, is set to zero otherwise */
334 copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
335 rv3d->dist = vctrl->dist_backup;
336 }
337 else { /* not camera */
338 /* Apply the fly mode view */
339 /* restore the dist */
341 /* Done with correcting for the dist */
342 }
343
344 if (vctrl->is_ortho_cam) {
345 ((Camera *)v3d->camera->data)->type = CAM_ORTHO;
346 }
347
348 if (vctrl->obtfm) {
349 MEM_freeN(vctrl->obtfm);
350 }
351
352 MEM_freeN(vctrl);
353}
General operations, lookup, etc. for blender objects.
void BKE_object_tfm_restore(Object *ob, void *obtfm_pt)
void BKE_object_apply_mat4(Object *ob, const float mat[4][4], bool use_compat, bool use_parent)
void BKE_object_tfm_protected_backup(const Object *ob, ObjectTfmProtectedChannels *obtfm)
void BKE_object_tfm_protected_restore(Object *ob, const ObjectTfmProtectedChannels *obtfm, short protectflag)
void BKE_object_to_mat4(const Object *ob, float r_mat[4][4])
void * BKE_object_tfm_backup(Object *ob)
void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
#define BLI_INLINE
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void size_to_mat4(float R[4][4], const float size[3])
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void copy_qt_qt(float q[4], const float a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ CAM_PERSP
@ CAM_ORTHO
Object is a sort of wrapper for general info.
@ OB_TRANSFORM_ADJUST_ROOT_PARENT_FOR_VIEW_LOCK
@ RV3D_CAMOB
@ RV3D_PERSP
@ RV3D_ORTHO
void ED_view3d_distance_set(RegionView3D *rv3d, float dist)
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], float dist)
void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], const float *dist)
bool ED_view3d_camera_autokey(const Scene *scene, ID *id_key, bContext *C, bool do_rotate, bool do_translate)
Read Guarded memory(de)allocation.
const Depsgraph * depsgraph
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
Definition DNA_ID.h:413
short transflag
float scale[3]
short protectflag
struct Object * parent
struct Object * camera
View3DCameraControl * ED_view3d_cameracontrol_acquire(Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d)
BLI_INLINE Object * view3d_cameracontrol_object(const View3DCameraControl *vctrl)
static bool object_apply_mat4_with_protect(Object *ob, const float obmat[4][4], const bool use_parent, RegionView3D *rv3d, const float view_mat[4][4])
Object * ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl, const bool use_autokey, bContext *C, const bool do_rotate, const bool do_translate)
void ED_view3d_cameracontrol_release(View3DCameraControl *vctrl, const bool restore)