Blender V5.0
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
27
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
38#include "BKE_object.hh"
39
40#include "DEG_depsgraph.hh"
41
42#include "view3d_intern.hh" /* own include */
43
45
46 /* -------------------------------------------------------------------- */
47 /* Context (assign these to vars before use) */
51
52 /* -------------------------------------------------------------------- */
53 /* internal vars */
54
55 /* for parenting calculation */
56 float view_mat_prev[4][4];
57
58 /* -------------------------------------------------------------------- */
59 /* optional capabilities */
60
62
63 /* -------------------------------------------------------------------- */
64 /* initial values */
65
68
69 /* Backup values. */
70
74 float ofs_backup[3];
75
77 float rot_backup[4];
83
90
92 void *obtfm;
93};
94
96{
97 return vctrl->root_parent ? vctrl->root_parent : vctrl->ctx_v3d->camera;
98}
99
101{
102 RegionView3D *rv3d = vctrl->ctx_rv3d;
103
104 if (rv3d->persp == RV3D_CAMOB) {
105 return view3d_cameracontrol_object(vctrl);
106 }
107
108 return nullptr;
109}
110
112 Scene *scene,
113 View3D *v3d,
114 RegionView3D *rv3d)
115{
116 View3DCameraControl *vctrl;
117
118 vctrl = MEM_callocN<View3DCameraControl>(__func__);
119
120 /* Store context */
121 vctrl->ctx_scene = scene;
122 vctrl->ctx_v3d = v3d;
123 vctrl->ctx_rv3d = rv3d;
124
125 vctrl->use_parent_root = v3d->camera != nullptr &&
127
128 vctrl->persp_backup = rv3d->persp;
129 vctrl->dist_backup = rv3d->dist;
130
131 /* check for flying ortho camera - which we can't support well
132 * we _could_ also check for an ortho camera but this is easier */
133 if ((rv3d->persp == RV3D_CAMOB) && (rv3d->is_persp == false)) {
134 ((Camera *)v3d->camera->data)->type = CAM_PERSP;
135 vctrl->is_ortho_cam = true;
136 }
137
138 if (rv3d->persp == RV3D_CAMOB) {
139 Object *ob_back;
140 if (vctrl->use_parent_root && (vctrl->root_parent = v3d->camera->parent)) {
141 while (vctrl->root_parent->parent) {
142 vctrl->root_parent = vctrl->root_parent->parent;
143 }
144 ob_back = vctrl->root_parent;
145 }
146 else {
147 ob_back = v3d->camera;
148 }
149
150 /* store the original camera loc and rot */
151 vctrl->obtfm = BKE_object_tfm_backup(ob_back);
152
154 negate_v3_v3(rv3d->ofs, v3d->camera->object_to_world().location());
155
156 rv3d->dist = 0.0;
157 }
158 else {
159 /* perspective or ortho */
160 if (rv3d->persp == RV3D_ORTHO) {
161 /* if ortho projection, make perspective */
162 rv3d->persp = RV3D_PERSP;
163 }
164
165 copy_qt_qt(vctrl->rot_backup, rv3d->viewquat);
166 copy_v3_v3(vctrl->ofs_backup, rv3d->ofs);
167
168 /* The dist defines a vector that is in front of the offset
169 * to rotate the view about.
170 * this is no good for fly mode because we
171 * want to rotate about the viewers center.
172 * but to correct the dist removal we must
173 * alter offset so the view doesn't jump. */
174
175 ED_view3d_distance_set(rv3d, 0.0f);
176 /* Done with correcting for the dist */
177 }
178
179 ED_view3d_to_m4(vctrl->view_mat_prev, rv3d->ofs, rv3d->viewquat, rv3d->dist);
180
181 return vctrl;
182}
183
194 Object *ob,
195 const float obmat[4][4],
196 const bool use_parent, /* Only use when applying lock. */
197 RegionView3D *rv3d,
198 const float view_mat[4][4])
199{
200 const bool use_protect = (ob->protectflag != 0);
201 bool view_changed = false;
202
204 if (use_protect) {
206 }
207
208 BKE_object_apply_mat4(ob, obmat, true, use_parent);
209
210 if (use_protect) {
211 float obmat_noprotect[4][4], obmat_protect[4][4];
212
213 BKE_object_to_mat4(ob, obmat_noprotect);
215 BKE_object_to_mat4(ob, obmat_protect);
216
217 if (!equals_m4m4(obmat_noprotect, obmat_protect)) {
218 /* Apply the lock protection back to the view, without this the view
219 * keeps moving, ignoring the object locking, causing jittering in some cases. */
220 float diff_mat[4][4];
221 float view_mat_protect[4][4];
222 float obmat_noprotect_inv[4][4];
223 invert_m4_m4(obmat_noprotect_inv, obmat_noprotect);
224 mul_m4_m4m4(diff_mat, obmat_protect, obmat_noprotect_inv);
225
226 mul_m4_m4m4(view_mat_protect, diff_mat, view_mat);
227 ED_view3d_from_m4(view_mat_protect, rv3d->ofs, rv3d->viewquat, &rv3d->dist);
228 view_changed = true;
229 }
230 }
231 return view_changed;
232}
233
234void ED_view3d_cameracontrol_update(View3DCameraControl *vctrl, /* args for keyframing */
235 const bool use_autokey,
236 bContext *C,
237 const bool do_rotate,
238 const bool do_translate)
239{
240 /* We are in camera view so apply the view offset and rotation to the view matrix
241 * and set the camera to the view. */
242
243 Scene *scene = vctrl->ctx_scene;
244 View3D *v3d = vctrl->ctx_v3d;
245 RegionView3D *rv3d = vctrl->ctx_rv3d;
246
247 ID *id_key;
248
249 float view_mat[4][4];
250 ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
251
252 /* transform the parent or the camera? */
253 if (vctrl->root_parent) {
254 Object *ob_update;
255
256 float prev_view_imat[4][4];
257 float diff_mat[4][4];
258 float parent_mat[4][4];
259
260 invert_m4_m4(prev_view_imat, vctrl->view_mat_prev);
261 mul_m4_m4m4(diff_mat, view_mat, prev_view_imat);
262 mul_m4_m4m4(parent_mat, diff_mat, vctrl->root_parent->object_to_world().ptr());
263
264 if (object_apply_mat4_with_protect(vctrl->root_parent, parent_mat, false, rv3d, view_mat)) {
265 /* Calculate again since the view locking changes the matrix. */
266 ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
267 }
268
269 ob_update = v3d->camera->parent;
270 while (ob_update) {
272 ob_update = ob_update->parent;
273 }
274
275 copy_m4_m4(vctrl->view_mat_prev, view_mat);
276
277 id_key = &vctrl->root_parent->id;
278 }
279 else {
280 float scale_mat[4][4];
281 float scale_back[3];
282
283 /* even though we handle the scale matrix, this still changes over time */
284 copy_v3_v3(scale_back, v3d->camera->scale);
285
286 size_to_mat4(scale_mat, v3d->camera->scale);
287 mul_m4_m4m4(view_mat, view_mat, scale_mat);
288
289 object_apply_mat4_with_protect(v3d->camera, view_mat, true, rv3d, view_mat);
290
292
293 copy_v3_v3(v3d->camera->scale, scale_back);
294
295 id_key = &v3d->camera->id;
296 }
297
298 /* record the motion */
299 if (use_autokey) {
300 ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
301 }
302}
303
305{
306 View3D *v3d = vctrl->ctx_v3d;
307 RegionView3D *rv3d = vctrl->ctx_rv3d;
308
309 if (restore) {
310 /* Revert to original view? */
311 if (vctrl->persp_backup == RV3D_CAMOB) { /* a camera view */
312 Object *ob_back = view3d_cameracontrol_object(vctrl);
313
314 /* store the original camera loc and rot */
315 BKE_object_tfm_restore(ob_back, vctrl->obtfm);
316
318 }
319 else {
320 /* Non Camera we need to reset the view back
321 * to the original location because the user canceled. */
322 copy_qt_qt(rv3d->viewquat, vctrl->rot_backup);
323 rv3d->persp = vctrl->persp_backup;
324 }
325 /* always, is set to zero otherwise */
326 copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
327 rv3d->dist = vctrl->dist_backup;
328 }
329 else if (vctrl->persp_backup == RV3D_CAMOB) { /* camera */
331
332 /* always, is set to zero otherwise */
333 copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
334 rv3d->dist = vctrl->dist_backup;
335 }
336 else { /* not camera */
337 /* Apply the fly mode view */
338 /* restore the dist */
340 /* Done with correcting for the dist */
341 }
342
343 if (vctrl->is_ortho_cam) {
344 ((Camera *)v3d->camera->data)->type = CAM_ORTHO;
345 }
346
347 if (vctrl->obtfm) {
348 MEM_freeN(vctrl->obtfm);
349 }
350
351 MEM_freeN(vctrl);
352}
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:1054
@ 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.
#define C
Definition RandGen.cpp:29
BPy_StructRNA * depsgraph
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
Definition DNA_ID.h:414
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)