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