Blender V4.3
overlay_next_camera.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#pragma once
10
11#include "BKE_camera.h"
12
14
15#include "BKE_tracking.h"
16
17#include "BLI_math_rotation.h"
18
19#include "DNA_camera_types.h"
20
21#include "ED_view3d.hh"
22
23#include "draw_manager_text.hh"
24#include "overlay_next_empty.hh"
26
27static float camera_offaxis_shiftx_get(const Scene *scene,
28 const Object *ob,
29 float corner_x,
30 bool right_eye)
31{
32 const Camera *cam = static_cast<const Camera *>(ob->data);
34 const char *viewnames[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
35 const float shiftx = BKE_camera_multiview_shift_x(&scene->r, ob, viewnames[right_eye]);
36 const float delta_shiftx = shiftx - cam->shiftx;
37 const float width = corner_x * 2.0f;
38 return delta_shiftx * width;
39 }
40
41 return 0.0;
42}
43
44namespace blender::draw::overlay {
46 public:
47 float &volume_start = color_[2];
48 float &volume_end = color_[3];
49 float &depth = color_[3];
50 float &focus = color_[3];
52 float &dist_color_id = matrix[0][3];
53 float &corner_x = matrix[0][3];
54 float &corner_y = matrix[1][3];
55 float &center_x = matrix[2][3];
56 float &clip_start = matrix[2][3];
57 float &mist_start = matrix[2][3];
58 float &center_y = matrix[3][3];
59 float &clip_end = matrix[3][3];
60 float &mist_end = matrix[3][3];
61
66
67 CameraInstanceData(const float4x4 &p_matrix, const float4 &color)
68 : ExtraInstanceData(p_matrix, color, 1.0f){};
69};
70
71class Cameras {
73
74 private:
75 PassSimple ps_ = {"Cameras"};
76
77 /* Camera background images with "Depth" switched to "Back".
78 * Shown in camera view behind all objects. */
79 PassMain background_ps_ = {"background_ps_"};
80 /* Camera background images with "Depth" switched to "Front".
81 * Shown in camera view in front of all objects. */
82 PassMain foreground_ps_ = {"foreground_ps_"};
83
84 /* Same as `background_ps_` with "View as Render" checked. */
85 PassMain background_scene_ps_ = {"background_scene_ps_"};
86 /* Same as `foreground_ps_` with "View as Render" checked. */
87 PassMain foreground_scene_ps_ = {"foreground_scene_ps_"};
88
89 View view_reference_images = {"view_reference_images"};
90 float view_dist = 0.0f;
91
92 struct CallBuffers {
93 const SelectionType selection_type_;
94 CameraInstanceBuf distances_buf = {selection_type_, "camera_distances_buf"};
95 CameraInstanceBuf frame_buf = {selection_type_, "camera_frame_buf"};
96 CameraInstanceBuf tria_buf = {selection_type_, "camera_tria_buf"};
97 CameraInstanceBuf tria_wire_buf = {selection_type_, "camera_tria_wire_buf"};
98 CameraInstanceBuf volume_buf = {selection_type_, "camera_volume_buf"};
99 CameraInstanceBuf volume_wire_buf = {selection_type_, "camera_volume_wire_buf"};
100 CameraInstanceBuf sphere_solid_buf = {selection_type_, "camera_sphere_solid_buf"};
101 LinePrimitiveBuf stereo_connect_lines = {selection_type_, "camera_dashed_lines_buf"};
102 LinePrimitiveBuf tracking_path = {selection_type_, "camera_tracking_path_buf"};
103 Empties::CallBuffers empties{selection_type_};
104 } call_buffers_;
105
106 static void view3d_reconstruction(const select::ID select_id,
107 const Scene *scene,
108 const View3D *v3d,
109 const float4 &color,
110 const ObjectRef &ob_ref,
111 const bool is_select,
112 Resources &res,
113 CallBuffers &call_buffers)
114 {
115 const DRWContextState *draw_ctx = DRW_context_state_get();
116 Object *ob = ob_ref.object;
117
118 MovieClip *clip = BKE_object_movieclip_get((Scene *)scene, ob, false);
119 if (clip == nullptr) {
120 return;
121 }
122
123 const bool is_solid_bundle = (v3d->bundle_drawtype == OB_EMPTY_SPHERE) &&
124 ((v3d->shading.type != OB_SOLID) || !XRAY_FLAG_ENABLED(v3d));
125
126 MovieTracking *tracking = &clip->tracking;
127 /* Index must start in 1, to mimic BKE_tracking_track_get_for_selection_index. */
128 int track_index = 1;
129
130 float4 bundle_color_custom;
131 float *bundle_color_solid = G_draw.block.color_bundle_solid;
132 float *bundle_color_unselected = G_draw.block.color_wire;
133 uchar4 text_color_selected, text_color_unselected;
134 /* Color Management: Exception here as texts are drawn in sRGB space directly. */
135 UI_GetThemeColor4ubv(TH_SELECT, text_color_selected);
136 UI_GetThemeColor4ubv(TH_TEXT, text_color_unselected);
137
138 float4x4 camera_mat;
140
141 const float4x4 object_to_world{ob->object_to_world().ptr()};
142
143 for (MovieTrackingObject *tracking_object :
144 ListBaseWrapper<MovieTrackingObject>(&tracking->objects))
145 {
146 float4x4 tracking_object_mat;
147
148 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
149 tracking_object_mat = camera_mat;
150 }
151 else {
152 const int framenr = BKE_movieclip_remap_scene_to_clip_frame(
153 clip, DEG_get_ctime(draw_ctx->depsgraph));
154
155 float4x4 object_mat;
157 tracking, tracking_object, framenr, object_mat.ptr());
158
159 tracking_object_mat = object_to_world * math::invert(object_mat);
160 }
161
162 for (MovieTrackingTrack *track :
163 ListBaseWrapper<MovieTrackingTrack>(&tracking_object->tracks))
164 {
165 if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
166 continue;
167 }
168 bool is_selected = TRACK_SELECTED(track);
169
170 float4x4 bundle_mat = math::translate(tracking_object_mat, float3(track->bundle_pos));
171
172 const float *bundle_color;
173 if (track->flag & TRACK_CUSTOMCOLOR) {
174 /* Meh, hardcoded srgb transform here. */
175 /* TODO: change the actual DNA color to be linear. */
176 srgb_to_linearrgb_v3_v3(bundle_color_custom, track->color);
177 bundle_color_custom[3] = 1.0;
178
179 bundle_color = bundle_color_custom;
180 }
181 else if (is_solid_bundle) {
182 bundle_color = bundle_color_solid;
183 }
184 else if (is_selected) {
185 bundle_color = color;
186 }
187 else {
188 bundle_color = bundle_color_unselected;
189 }
190
191 const select::ID track_select_id = is_select ? res.select_id(ob_ref, track_index++ << 16) :
192 select_id;
193 if (is_solid_bundle) {
194 if (is_selected) {
195 Empties::object_sync(track_select_id,
196 bundle_mat,
197 v3d->bundle_size,
198 v3d->bundle_drawtype,
199 color,
200 call_buffers.empties);
201 }
202
203 call_buffers.sphere_solid_buf.append(
204 ExtraInstanceData{bundle_mat, float4(float3(bundle_color), 1.0f), v3d->bundle_size},
205 track_select_id);
206 }
207 else {
208 Empties::object_sync(track_select_id,
209 bundle_mat,
210 v3d->bundle_size,
211 v3d->bundle_drawtype,
212 bundle_color,
213 call_buffers.empties);
214 }
215
216 if ((v3d->flag2 & V3D_SHOW_BUNDLENAME) && !is_select) {
218
220 bundle_mat[3],
221 track->name,
222 strlen(track->name),
223 10,
224 0,
226 is_selected ? text_color_selected : text_color_unselected);
227 }
228 }
229
230 if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA) &&
231 !is_select)
232 {
233 const MovieTrackingReconstruction *reconstruction = &tracking_object->reconstruction;
234
235 if (reconstruction->camnr) {
236 const MovieReconstructedCamera *camera = reconstruction->cameras;
237 float3 v0, v1 = float3(0.0f);
238 for (int a = 0; a < reconstruction->camnr; a++, camera++) {
239 v0 = v1;
240 v1 = math::transform_point(camera_mat, float3(camera->mat[3]));
241 if (a > 0) {
242 /* This one is suboptimal (gl_lines instead of gl_line_strip)
243 * but we keep this for simplicity */
244 call_buffers.tracking_path.append(v0, v1, TH_CAMERA_PATH);
245 }
246 }
247 }
248 }
249 }
250 }
251
256 static void stereoscopy_extra(const CameraInstanceData &instdata,
257 const select::ID select_id,
258 const Scene *scene,
259 const View3D *v3d,
260 const bool is_select,
261 Resources &res,
262 Object *ob,
263 CallBuffers &call_buffers)
264 {
265 CameraInstanceData stereodata = instdata;
266
267 const Camera *cam = static_cast<const Camera *>(ob->data);
268 const char *viewnames[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
269
270 const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) != 0;
271 const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) != 0;
272 const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME) != 0;
273
274 if (!is_stereo3d_cameras) {
275 /* Draw single camera. */
276 call_buffers.frame_buf.append(instdata, select_id);
277 }
278
279 for (const int eye : IndexRange(2)) {
280 ob = BKE_camera_multiview_render(scene, ob, viewnames[eye]);
281 BKE_camera_multiview_model_matrix(&scene->r, ob, viewnames[eye], stereodata.matrix.ptr());
282
283 stereodata.corner_x = instdata.corner_x;
284 stereodata.corner_y = instdata.corner_y;
285 stereodata.center_x = instdata.center_x +
286 camera_offaxis_shiftx_get(scene, ob, instdata.corner_x, eye);
287 stereodata.center_y = instdata.center_y;
288 stereodata.depth = instdata.depth;
289
290 if (is_stereo3d_cameras) {
291 call_buffers.frame_buf.append(stereodata, select_id);
292
293 /* Connecting line between cameras. */
294 call_buffers.stereo_connect_lines.append(stereodata.matrix.location(),
295 instdata.object_to_world_.location(),
297 select_id);
298 }
299
300 if (is_stereo3d_volume && !is_select) {
301 float r = (eye == 1) ? 2.0f : 1.0f;
302
303 stereodata.volume_start = -cam->clip_start;
304 stereodata.volume_end = -cam->clip_end;
305 /* Encode eye + intensity and alpha (see shader) */
306 copy_v2_fl2(stereodata.color_, r + 0.15f, 1.0f);
307 call_buffers.volume_wire_buf.append(stereodata, select_id);
308
309 if (v3d->stereo3d_volume_alpha > 0.0f) {
310 /* Encode eye + intensity and alpha (see shader) */
311 copy_v2_fl2(stereodata.color_, r + 0.999f, v3d->stereo3d_volume_alpha);
312 call_buffers.volume_buf.append(stereodata, select_id);
313 }
314 /* restore */
315 copy_v3_v3(stereodata.color_, instdata.color_);
316 }
317 }
318
319 if (is_stereo3d_plane && !is_select) {
320 if (cam->stereo.convergence_mode == CAM_S3D_TOE) {
321 /* There is no real convergence plane but we highlight the center
322 * point where the views are pointing at. */
323 // zero_v3(stereodata.mat[0]); /* We reconstruct from Z and Y */
324 // zero_v3(stereodata.mat[1]); /* Y doesn't change */
325 stereodata.matrix.z_axis() = float3(0.0f);
326 stereodata.matrix.location() = float3(0.0f);
327 for (int i : IndexRange(2)) {
328 float4x4 mat;
329 /* Need normalized version here. */
330 BKE_camera_multiview_model_matrix(&scene->r, ob, viewnames[i], mat.ptr());
331 stereodata.matrix.z_axis() += mat.z_axis();
332 stereodata.matrix.location() += mat.location() * 0.5f;
333 }
334 stereodata.matrix.z_axis() = math::normalize(stereodata.matrix.z_axis());
335 stereodata.matrix.x_axis() = math::cross(stereodata.matrix.y_axis(),
336 stereodata.matrix.z_axis());
337 }
338 else if (cam->stereo.convergence_mode == CAM_S3D_PARALLEL) {
339 /* Show plane at the given distance between the views even if it makes no sense. */
340 stereodata.matrix.location() = float3(0.0f);
341 for (int i : IndexRange(2)) {
342 float4x4 mat;
343 BKE_camera_multiview_model_matrix_scaled(&scene->r, ob, viewnames[i], mat.ptr());
344 stereodata.matrix.location() += mat.location() * 0.5f;
345 }
346 }
347 else if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
348 /* Nothing to do. Everything is already setup. */
349 }
350 stereodata.volume_start = -cam->stereo.convergence_distance;
351 stereodata.volume_end = -cam->stereo.convergence_distance;
352 /* Encode eye + intensity and alpha (see shader) */
353 copy_v2_fl2(stereodata.color_, 0.1f, 1.0f);
354 call_buffers.volume_wire_buf.append(stereodata, select_id);
355
356 if (v3d->stereo3d_convergence_alpha > 0.0f) {
357 /* Encode eye + intensity and alpha (see shader) */
358 copy_v2_fl2(stereodata.color_, 0.0f, v3d->stereo3d_convergence_alpha);
359 call_buffers.volume_buf.append(stereodata, select_id);
360 }
361 }
362 }
363
364 bool enabled_ = false;
365
366 public:
367 Cameras(const SelectionType selection_type) : call_buffers_{selection_type} {};
368
369 void begin_sync(Resources &res, State &state, View &view)
370 {
371 enabled_ = state.space_type == SPACE_VIEW3D;
372
373 if (!enabled_) {
374 return;
375 }
376
377 view_dist = state.view_dist_get(view.winmat());
378
379 call_buffers_.distances_buf.clear();
380 call_buffers_.frame_buf.clear();
381 call_buffers_.tria_buf.clear();
382 call_buffers_.tria_wire_buf.clear();
383 call_buffers_.volume_buf.clear();
384 call_buffers_.volume_wire_buf.clear();
385 call_buffers_.sphere_solid_buf.clear();
386 call_buffers_.stereo_connect_lines.clear();
387 call_buffers_.tracking_path.clear();
388 Empties::begin_sync(call_buffers_.empties);
389
390 /* Init image passes. */
391 auto init_pass = [&](PassMain &pass, DRWState draw_state) {
392 pass.init();
393 pass.state_set(draw_state, state.clipping_plane_count);
394 pass.shader_set(res.shaders.image_plane.get());
395 pass.bind_ubo("globalsBlock", &res.globals_buf);
396 res.select_bind(pass);
397 };
398
399 DRWState draw_state;
401 init_pass(background_ps_, draw_state);
402
404 init_pass(background_scene_ps_, draw_state);
405
407 init_pass(foreground_ps_, draw_state);
408 init_pass(foreground_scene_ps_, draw_state);
409 }
410
412 const ObjectRef &ob_ref, ShapeCache &shapes, Manager &manager, Resources &res, State &state)
413 {
414 if (!enabled_) {
415 return;
416 }
417
418 Object *ob = ob_ref.object;
419 const select::ID select_id = res.select_id(ob_ref);
420 CameraInstanceData data(ob->object_to_world(), res.object_wire_color(ob_ref, state));
421
422 const View3D *v3d = state.v3d;
423 const Scene *scene = state.scene;
424 const RegionView3D *rv3d = state.rv3d;
425
426 const Camera *cam = static_cast<Camera *>(ob->data);
427 const Object *camera_object = DEG_get_evaluated_object(state.depsgraph, v3d->camera);
428 const bool is_select = call_buffers_.selection_type_ == SelectionType::ENABLED;
429 const bool is_active = (ob == camera_object);
430 const bool is_camera_view = (is_active && (rv3d->persp == RV3D_CAMOB));
431
432 const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
433 const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
434 const bool is_stereo3d_display_extra = is_active && is_multiview && (!is_camera_view) &&
435 ((v3d->stereo3d_flag) != 0);
436 const bool is_selection_camera_stereo = is_select && is_camera_view && is_multiview &&
437 is_stereo3d_view;
438
439 float3 scale = math::to_scale(data.matrix);
440 /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here. */
441 if (is_selection_camera_stereo) {
442 scale = float3(1.0f);
443 }
444 else if (ELEM(0.0f, scale.x, scale.y, scale.z)) {
445 /* Avoid division by 0. */
446 return;
447 }
448 float4x3 vecs;
449 float2 aspect_ratio;
450 float2 shift;
451 float drawsize;
452
454 cam,
455 cam->drawsize,
456 is_camera_view,
457 1.0f / scale,
458 aspect_ratio,
459 shift,
460 &drawsize,
461 vecs.ptr());
462
463 /* Apply scale to simplify the rest of the drawing. */
464 for (int i = 0; i < 4; i++) {
465 vecs[i] *= scale;
466 /* Project to z=-1 plane. Makes positioning / scaling easier. (see shader) */
467 mul_v2_fl(vecs[i], 1.0f / std::abs(vecs[i].z));
468 }
469
470 /* Frame coords */
471 const float2 center = (vecs[0].xy() + vecs[2].xy()) * 0.5f;
472 const float2 corner = vecs[0].xy() - center.xy();
473 data.corner_x = corner.x;
474 data.corner_y = corner.y;
475 data.center_x = center.x;
476 data.center_y = center.y;
477 data.depth = vecs[0].z;
478
479 if (is_camera_view) {
480 /* TODO(Miguel Pozo) */
482 /* Only draw the frame. */
483 if (is_multiview) {
484 float4x4 mat;
485 const bool is_right = v3d->multiview_eye == STEREO_RIGHT_ID;
486 const char *view_name = is_right ? STEREO_RIGHT_NAME : STEREO_LEFT_NAME;
487 BKE_camera_multiview_model_matrix(&scene->r, ob, view_name, mat.ptr());
488 data.center_x += camera_offaxis_shiftx_get(scene, ob, data.corner_x, is_right);
489 for (int i : IndexRange(4)) {
490 /* Partial copy to avoid overriding packed data. */
491 copy_v3_v3(data.matrix[i], mat[i].xyz());
492 }
493 }
494 data.depth *= -1.0f; /* Hides the back of the camera wires (see shader). */
495 call_buffers_.frame_buf.append(data, select_id);
496 }
497 }
498 else {
499 /* Stereo cameras, volumes, plane drawing. */
500 if (is_stereo3d_display_extra) {
501 stereoscopy_extra(data, select_id, scene, v3d, is_select, res, ob, call_buffers_);
502 }
503 else {
504 call_buffers_.frame_buf.append(data, select_id);
505 }
506 }
507
508 if (!is_camera_view) {
509 /* Triangle. */
510 float tria_size = 0.7f * drawsize / fabsf(data.depth);
511 float tria_margin = 0.1f * drawsize / fabsf(data.depth);
512 data.center_x = center.x;
513 data.center_y = center.y + data.corner_y + tria_margin + tria_size;
514 data.corner_x = data.corner_y = -tria_size;
515 (is_active ? call_buffers_.tria_buf : call_buffers_.tria_wire_buf).append(data, select_id);
516 }
517
518 if (cam->flag & CAM_SHOWLIMITS) {
519 /* Scale focus point. */
520 data.matrix.x_axis() *= cam->drawsize;
521 data.matrix.y_axis() *= cam->drawsize;
522
523 data.dist_color_id = (is_active) ? 3 : 2;
524 data.focus = -BKE_camera_object_dof_distance(ob);
525 data.clip_start = cam->clip_start;
526 data.clip_end = cam->clip_end;
527 call_buffers_.distances_buf.append(data, select_id);
528 }
529
530 if (cam->flag & CAM_SHOWMIST) {
531 World *world = scene->world;
532 if (world) {
533 data.dist_color_id = (is_active) ? 1 : 0;
534 data.focus = 1.0f; /* Disable */
535 data.mist_start = world->miststa;
536 data.mist_end = world->miststa + world->mistdist;
537 call_buffers_.distances_buf.append(data, select_id);
538 }
539 }
540
541 /* Motion Tracking. */
542 if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) != 0) {
543 view3d_reconstruction(select_id,
544 scene,
545 v3d,
546 res.object_wire_color(ob_ref, state),
547 ob_ref,
548 is_select,
549 res,
550 call_buffers_);
551 }
552
553 if (is_camera_view && (cam->flag & CAM_SHOW_BG_IMAGE) &&
554 !BLI_listbase_is_empty(&cam->bg_images))
555 {
556 sync_camera_images(
557 ob_ref, select_id, shapes, manager, state, res, call_buffers_.selection_type_);
558 }
559 }
560
561 void end_sync(Resources &res, ShapeCache &shapes, const State &state)
562 {
563 if (!enabled_) {
564 return;
565 }
566
567 ps_.init();
568 res.select_bind(ps_);
569
570 {
571 PassSimple::Sub &sub_pass = ps_.sub("volume");
574 state.clipping_plane_count);
575 sub_pass.shader_set(res.shaders.extra_shape.get());
576 sub_pass.bind_ubo("globalsBlock", &res.globals_buf);
577 call_buffers_.volume_buf.end_sync(sub_pass, shapes.camera_volume.get());
578 }
579 {
580 PassSimple::Sub &sub_pass = ps_.sub("volume_wire");
583 state.clipping_plane_count);
584 sub_pass.shader_set(res.shaders.extra_shape.get());
585 sub_pass.bind_ubo("globalsBlock", &res.globals_buf);
586 call_buffers_.volume_wire_buf.end_sync(sub_pass, shapes.camera_volume_wire.get());
587 }
588
589 {
590 PassSimple::Sub &sub_pass = ps_.sub("camera_shapes");
593 state.clipping_plane_count);
594 sub_pass.shader_set(res.shaders.extra_shape.get());
595 sub_pass.bind_ubo("globalsBlock", &res.globals_buf);
596 call_buffers_.distances_buf.end_sync(sub_pass, shapes.camera_distances.get());
597 call_buffers_.frame_buf.end_sync(sub_pass, shapes.camera_frame.get());
598 call_buffers_.tria_buf.end_sync(sub_pass, shapes.camera_tria.get());
599 call_buffers_.tria_wire_buf.end_sync(sub_pass, shapes.camera_tria_wire.get());
600 call_buffers_.sphere_solid_buf.end_sync(sub_pass, shapes.sphere_low_detail.get());
601 }
602 {
603 PassSimple::Sub &sub_pass = ps_.sub("camera_extra_wire");
606 state.clipping_plane_count);
607 sub_pass.shader_set(res.shaders.extra_wire.get());
608 sub_pass.bind_ubo("globalsBlock", &res.globals_buf);
609 call_buffers_.stereo_connect_lines.end_sync(sub_pass);
610 call_buffers_.tracking_path.end_sync(sub_pass);
611 }
612 {
613 PassSimple::Sub &sub_pass = ps_.sub("empties");
614 Empties::end_sync(res, shapes, state, sub_pass, call_buffers_.empties);
615 }
616 }
617
618 void draw(Framebuffer &framebuffer, Manager &manager, View &view)
619 {
620 if (!enabled_) {
621 return;
622 }
623
624 GPU_framebuffer_bind(framebuffer);
625 manager.submit(ps_, view);
626 }
627
628 void draw_scene_background_images(Framebuffer &framebuffer, Manager &manager, View &view)
629 {
630 if (!enabled_) {
631 return;
632 }
633
634 GPU_framebuffer_bind(framebuffer);
635 manager.submit(background_scene_ps_, view);
636 manager.submit(foreground_scene_ps_, view);
637 }
638
639 void draw_background_images(Framebuffer &framebuffer, Manager &manager, View &view)
640 {
641 if (!enabled_) {
642 return;
643 }
644
645 GPU_framebuffer_bind(framebuffer);
646 manager.submit(background_ps_, view);
647 }
648
649 void draw_in_front(Framebuffer &framebuffer, Manager &manager, View &view)
650 {
651 if (!enabled_) {
652 return;
653 }
654
655 view_reference_images.sync(view.viewmat(),
656 winmat_polygon_offset(view.winmat(), view_dist, -1.0f));
657 GPU_framebuffer_bind(framebuffer);
658 manager.submit(foreground_ps_, view_reference_images);
659 }
660
661 private:
662 void sync_camera_images(const ObjectRef &ob_ref,
663 select::ID select_id,
664 ShapeCache &shapes,
665 Manager &manager,
666 const State &state,
667 Resources &res,
668 const SelectionType selection_type)
669 {
670 Object *ob = ob_ref.object;
671 const Camera *cam = static_cast<Camera *>(ob->data);
672
673 const bool show_frame = BKE_object_empty_image_frame_is_visible_in_view3d(ob, state.rv3d);
674
675 if (!show_frame || selection_type != SelectionType::DISABLED) {
676 return;
677 }
678
679 const bool stereo_eye = Images::images_stereo_eye(state.scene, state.v3d) == STEREO_LEFT_ID;
680 const char *viewname = (stereo_eye == STEREO_LEFT_ID) ? STEREO_RIGHT_NAME : STEREO_LEFT_NAME;
681 float4x4 modelmat;
682 BKE_camera_multiview_model_matrix(&state.scene->r, ob, viewname, modelmat.ptr());
683
684 for (const CameraBGImage *bgpic : ConstListBaseWrapper<CameraBGImage>(&cam->bg_images)) {
685 if (bgpic->flag & CAM_BGIMG_FLAG_DISABLED) {
686 continue;
687 }
688
689 float aspect = 1.0;
690 bool use_alpha_premult;
691 bool use_view_transform = false;
692 float4x4 mat;
693
694 /* retrieve the image we want to show, continue to next when no image could be found */
695 GPUTexture *tex = image_camera_background_texture_get(
696 bgpic, state, res, aspect, use_alpha_premult, use_view_transform);
697
698 if (tex) {
699 image_camera_background_matrix_get(cam, bgpic, state, aspect, mat);
700
701 const bool is_foreground = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != 0;
702 /* Alpha is clamped just below 1.0 to fix background images to interfere with foreground
703 * images. Without this a background image with 1.0 will be rendered on top of a
704 * transparent foreground image due to the different blending modes they use. */
705 const float4 color_premult_alpha{1.0f, 1.0f, 1.0f, std::min(bgpic->alpha, 0.999999f)};
706
707 PassMain &pass = is_foreground ?
708 (use_view_transform ? foreground_scene_ps_ : foreground_ps_) :
709 (use_view_transform ? background_scene_ps_ : background_ps_);
710 pass.bind_texture("imgTexture", tex);
711 pass.push_constant("imgPremultiplied", use_alpha_premult);
712 pass.push_constant("imgAlphaBlend", true);
713 pass.push_constant("isCameraBackground", true);
714 pass.push_constant("depthSet", true);
715 pass.push_constant("ucolor", color_premult_alpha);
716 ResourceHandle res_handle = manager.resource_handle(mat);
717 pass.draw(shapes.quad_solid.get(), res_handle, select_id.get());
718 }
719 }
720 }
721
722 static void image_camera_background_matrix_get(const Camera *cam,
723 const CameraBGImage *bgpic,
724 const State &state,
725 const float image_aspect,
726 float4x4 &rmat)
727 {
728 float4x4 rotate, scale = float4x4::identity(), translate = float4x4::identity();
729
730 axis_angle_to_mat4_single(rotate.ptr(), 'Z', -bgpic->rotation);
731
732 /* Normalized Object space camera frame corners. */
733 float cam_corners[4][3];
734 BKE_camera_view_frame(state.scene, cam, cam_corners);
735 float cam_width = fabsf(cam_corners[0][0] - cam_corners[3][0]);
736 float cam_height = fabsf(cam_corners[0][1] - cam_corners[1][1]);
737 float cam_aspect = cam_width / cam_height;
738
739 if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) {
740 /* Crop. */
741 if (image_aspect > cam_aspect) {
742 scale[0][0] *= cam_height * image_aspect;
743 scale[1][1] *= cam_height;
744 }
745 else {
746 scale[0][0] *= cam_width;
747 scale[1][1] *= cam_width / image_aspect;
748 }
749 }
750 else if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
751 /* Fit. */
752 if (image_aspect > cam_aspect) {
753 scale[0][0] *= cam_width;
754 scale[1][1] *= cam_width / image_aspect;
755 }
756 else {
757 scale[0][0] *= cam_height * image_aspect;
758 scale[1][1] *= cam_height;
759 }
760 }
761 else {
762 /* Stretch. */
763 scale[0][0] *= cam_width;
764 scale[1][1] *= cam_height;
765 }
766
767 translate[3][0] = bgpic->offset[0];
768 translate[3][1] = bgpic->offset[1];
769 translate[3][2] = cam_corners[0][2];
770 if (cam->type == CAM_ORTHO) {
771 translate[3].xy() *= cam->ortho_scale;
772 }
773 /* These lines are for keeping 2.80 behavior and could be removed to keep 2.79 behavior. */
774 translate[3][0] *= min_ff(1.0f, cam_aspect);
775 translate[3][1] /= max_ff(1.0f, cam_aspect) * (image_aspect / cam_aspect);
776 /* quad is -1..1 so divide by 2. */
777 scale[0][0] *= 0.5f * bgpic->scale * ((bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0);
778 scale[1][1] *= 0.5f * bgpic->scale * ((bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0);
779 /* Camera shift. (middle of cam_corners) */
780 translate[3][0] += (cam_corners[0][0] + cam_corners[2][0]) * 0.5f;
781 translate[3][1] += (cam_corners[0][1] + cam_corners[2][1]) * 0.5f;
782
783 rmat = translate * rotate * scale;
784 }
785
786 GPUTexture *image_camera_background_texture_get(const CameraBGImage *bgpic,
787 const State &state,
788 Resources &res,
789 float &r_aspect,
790 bool &r_use_alpha_premult,
791 bool &r_use_view_transform)
792 {
793 ::Image *image = bgpic->ima;
794 ImageUser *iuser = (ImageUser *)&bgpic->iuser;
795 MovieClip *clip = nullptr;
796 GPUTexture *tex = nullptr;
797 float aspect_x, aspect_y;
798 int width, height;
799 int ctime = int(DEG_get_ctime(state.depsgraph));
800 r_use_alpha_premult = false;
801 r_use_view_transform = false;
802
803 switch (bgpic->source) {
805 if (image == nullptr) {
806 return nullptr;
807 }
808 r_use_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL);
809 r_use_view_transform = (image->flag & IMA_VIEW_AS_RENDER) != 0;
810
811 BKE_image_user_frame_calc(image, iuser, ctime);
812 if (image->source == IMA_SRC_SEQUENCE && !(iuser->flag & IMA_USER_FRAME_IN_RANGE)) {
813 /* Frame is out of range, don't show. */
814 return nullptr;
815 }
816
817 Images::stereo_setup(state.scene, state.v3d, image, iuser);
818
819 iuser->scene = (Scene *)state.scene;
821 iuser->scene = nullptr;
822
823 if (tex == nullptr) {
824 return nullptr;
825 }
826
829
830 aspect_x = bgpic->ima->aspx;
831 aspect_y = bgpic->ima->aspy;
832 break;
833 }
834
836 if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) {
837 if (state.scene->camera) {
838 clip = BKE_object_movieclip_get((Scene *)state.scene, state.scene->camera, true);
839 }
840 }
841 else {
842 clip = bgpic->clip;
843 }
844
845 if (clip == nullptr) {
846 return nullptr;
847 }
848
851 if (tex == nullptr) {
852 return nullptr;
853 }
854
855 aspect_x = clip->aspx;
856 aspect_y = clip->aspy;
857 r_use_view_transform = true;
858
859 BKE_movieclip_get_size(clip, &bgpic->cuser, &width, &height);
860
861 /* Save for freeing. */
862 res.bg_movie_clips.append(clip);
863 break;
864 }
865
866 default:
867 /* Unsupported type. */
868 return nullptr;
869 }
870
871 r_aspect = (width * aspect_x) / (height * aspect_y);
872 return tex;
873 }
874};
875
876} // namespace blender::draw::overlay
Camera data-block and utility functions.
float BKE_camera_multiview_shift_x(const struct RenderData *rd, const struct Object *camera, const char *viewname)
float BKE_camera_object_dof_distance(const struct Object *ob)
struct Object * BKE_camera_multiview_render(const struct Scene *scene, struct Object *camera, const char *viewname)
void BKE_camera_multiview_model_matrix(const struct RenderData *rd, const struct Object *camera, const char *viewname, float r_modelmat[4][4])
void BKE_camera_multiview_model_matrix_scaled(const struct RenderData *rd, const struct Object *camera, const char *viewname, float r_modelmat[4][4])
void BKE_camera_view_frame(const struct Scene *scene, const struct Camera *camera, float r_vec[4][3])
void BKE_camera_view_frame_ex(const struct Scene *scene, const struct Camera *camera, float drawsize, bool do_clip, const float scale[3], float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3])
void BKE_image_user_frame_calc(Image *ima, ImageUser *iuser, int cfra)
GPUTexture * BKE_image_get_gpu_viewer_texture(Image *image, ImageUser *iuser)
Definition image_gpu.cc:481
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)
struct GPUTexture * BKE_movieclip_get_gpu_texture(struct MovieClip *clip, struct MovieClipUser *cuser)
MovieClip * BKE_object_movieclip_get(Scene *scene, const Object *ob, bool use_default)
bool BKE_object_empty_image_frame_is_visible_in_view3d(const Object *ob, const RegionView3D *rv3d)
void BKE_tracking_get_camera_object_matrix(const struct Object *camera_object, float mat[4][4])
#define TRACK_SELECTED(track)
void BKE_tracking_camera_get_reconstructed_interpolate(struct MovieTracking *tracking, struct MovieTrackingObject *tracking_object, float framenr, float mat[4][4])
Definition tracking.cc:2146
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
void axis_angle_to_mat4_single(float R[4][4], char axis, float angle)
MINLINE void copy_v2_fl2(float v[2], float x, float y)
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define ELEM(...)
float DEG_get_ctime(const Depsgraph *graph)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ CAM_S3D_PARALLEL
@ CAM_S3D_OFFAXIS
@ CAM_S3D_TOE
@ CAM_SHOWLIMITS
@ CAM_SHOW_BG_IMAGE
@ CAM_SHOWMIST
@ CAM_BGIMG_FLAG_FLIP_X
@ CAM_BGIMG_FLAG_FLIP_Y
@ CAM_BGIMG_FLAG_CAMERA_CROP
@ CAM_BGIMG_FLAG_CAMERACLIP
@ CAM_BGIMG_FLAG_CAMERA_ASPECT
@ CAM_BGIMG_FLAG_DISABLED
@ CAM_BGIMG_FLAG_FOREGROUND
@ CAM_BGIMG_SOURCE_IMAGE
@ CAM_BGIMG_SOURCE_MOVIE
@ CAM_ORTHO
@ IMA_SRC_SEQUENCE
@ IMA_USER_FRAME_IN_RANGE
@ IMA_VIEW_AS_RENDER
@ IMA_ALPHA_PREMUL
@ OB_SOLID
@ OB_EMPTY_SPHERE
#define STEREO_LEFT_NAME
@ R_MULTIVIEW
@ SCE_VIEWS_FORMAT_STEREO_3D
#define STEREO_RIGHT_NAME
@ STEREO_LEFT_ID
@ STEREO_RIGHT_ID
@ SPACE_VIEW3D
@ TRACK_CUSTOMCOLOR
@ TRACK_HAS_BUNDLE
@ TRACKING_OBJECT_CAMERA
@ RV3D_CAMOB
@ V3D_SHOW_BUNDLENAME
@ V3D_SHOW_CAMERAPATH
@ V3D_SHOW_RECONSTRUCTION
@ V3D_S3D_DISPCAMERAS
@ V3D_S3D_DISPPLANE
@ V3D_S3D_DISPVOLUME
#define XRAY_FLAG_ENABLED(v3d)
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
int GPU_texture_original_height(const GPUTexture *texture)
int GPU_texture_original_width(const GPUTexture *texture)
@ TH_CAMERA_PATH
@ TH_SELECT
@ TH_TEXT
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
void append(const T &value)
void submit(PassSimple &pass, View &view)
ResourceHandle resource_handle(const ObjectRef &ref, float inflate_bounds=0.0f)
void sync(const float4x4 &view_mat, const float4x4 &win_mat, int view_id=0)
Definition draw_view.cc:20
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:616
void state_set(DRWState state, int clip_plane_count=0)
Definition draw_pass.hh:954
void bind_ubo(const char *name, GPUUniformBuf *buffer)
void shader_set(GPUShader *shader)
Definition draw_pass.hh:971
void begin_sync(Resources &res, State &state, View &view)
void draw_background_images(Framebuffer &framebuffer, Manager &manager, View &view)
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
void draw_scene_background_images(Framebuffer &framebuffer, Manager &manager, View &view)
void object_sync(const ObjectRef &ob_ref, ShapeCache &shapes, Manager &manager, Resources &res, State &state)
void draw_in_front(Framebuffer &framebuffer, Manager &manager, View &view)
void end_sync(Resources &res, ShapeCache &shapes, const State &state)
Cameras(const SelectionType selection_type)
void end_sync(Resources &res, ShapeCache &shapes, const State &state)
void object_sync(const ObjectRef &ob_ref, ShapeCache &shapes, Manager &manager, Resources &res, const State &state)
void begin_sync(Resources &res, const State &state, const View &view)
static void stereo_setup(const Scene *scene, const View3D *v3d, ::Image *ima, ImageUser *iuser)
static eStereoViews images_stereo_eye(const Scene *scene, const View3D *v3d)
append
#define fabsf(x)
DRW_Global G_draw
DRWTextStore * DRW_text_cache_ensure()
bool DRW_state_is_image_render()
const DRWContextState * DRW_context_state_get()
void DRW_text_cache_add(DRWTextStore *dt, const float co[3], const char *str, const int str_len, short xoffs, short yoffs, short flag, const uchar col[4], const bool shadow, const bool align_center)
@ DRW_TEXT_CACHE_GLOBALSPACE
@ DRW_TEXT_CACHE_STRING_PTR
DRWState
Definition draw_state.hh:25
@ DRW_STATE_BLEND_ALPHA
Definition draw_state.hh:55
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_BLEND_ALPHA_UNDER_PREMUL
Definition draw_state.hh:65
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
@ DRW_STATE_CULL_BACK
Definition draw_state.hh:43
@ DRW_STATE_BLEND_ALPHA_PREMUL
Definition draw_state.hh:57
@ DRW_STATE_DEPTH_GREATER
Definition draw_state.hh:40
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
const ProjectiveReconstruction & reconstruction
Definition intersect.cc:198
static ulong state[N]
static float4x4 winmat_polygon_offset(float4x4 winmat, float view_dist, float offset)
detail::Pass< command::DrawMultiBuf > PassMain
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
CartesianBasis invert(const CartesianBasis &basis)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
MatBase< T, NumCol, NumRow > translate(const MatBase< T, NumCol, NumRow > &mat, const VectorT &translation)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
VecBase< T, 3 > to_scale(const MatBase< T, NumCol, NumRow > &mat)
MatBase< T, NumCol, NumRow > rotate(const MatBase< T, NumCol, NumRow > &mat, const RotationT &rotation)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
ListBaseWrapperTemplate< ListBase, T > ListBaseWrapper
VecBase< float, 3 > float3
static float camera_offaxis_shiftx_get(Scene *scene, Object *ob, const OVERLAY_CameraInstanceData *instdata, bool right_eye)
static float camera_offaxis_shiftx_get(const Scene *scene, const Object *ob, float corner_x, bool right_eye)
struct MovieClip * clip
struct ImageUser iuser
struct MovieClipUser cuser
struct Image * ima
struct CameraStereoSettings stereo
float ortho_scale
Depsgraph * depsgraph
GlobalsUboStorage block
char multiview_eye
float bundle_size
struct Object * camera
float stereo3d_volume_alpha
View3DShading shading
char bundle_drawtype
short stereo3d_flag
float stereo3d_convergence_alpha
const c_style_mat & ptr() const
VecBase< T, 2 > xy() const
CameraInstanceData(const float4x4 &p_matrix, const float4 &color)
CameraInstanceData(const CameraInstanceData &data)
void append(const float3 &start, const float3 &end, const float4 &color, select::ID select_id=select::SelectMap::select_invalid_id())
const float4 & object_wire_color(const ObjectRef &ob_ref, ThemeColorID theme_id) const
void end_sync(PassSimple::Sub &pass, gpu::Batch *shape)
void append(const InstanceDataT &data, select::ID select_id)
void select_bind(PassSimple &pass)
const ID select_id(const ObjectRef &ob_ref, uint sub_object_id=0)