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
8
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 {
72 using CameraInstanceBuf = ShapeInstanceBuf<ExtraInstanceData>;
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 :
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
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
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;
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
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 {
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
827 width = GPU_texture_original_width(tex);
828 height = GPU_texture_original_height(tex);
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
850 tex = BKE_movieclip_get_gpu_texture(clip, (MovieClipUser *)&bgpic->cuser);
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_ORTHO
@ CAM_S3D_PARALLEL
@ CAM_S3D_OFFAXIS
@ CAM_S3D_TOE
@ CAM_SHOWLIMITS
@ CAM_SHOW_BG_IMAGE
@ CAM_SHOWMIST
@ CAM_BGIMG_SOURCE_IMAGE
@ CAM_BGIMG_SOURCE_MOVIE
struct Camera Camera
struct CameraBGImage CameraBGImage
@ 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
@ IMA_ALPHA_PREMUL
@ IMA_USER_FRAME_IN_RANGE
@ IMA_VIEW_AS_RENDER
@ IMA_SRC_SEQUENCE
struct ImageUser ImageUser
struct Image Image
struct MovieClipUser MovieClipUser
struct MovieClip MovieClip
@ OB_SOLID
@ OB_EMPTY_SPHERE
#define STEREO_LEFT_NAME
struct Scene Scene
@ 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
@ V3D_SHOW_BUNDLENAME
@ V3D_SHOW_CAMERAPATH
@ V3D_SHOW_RECONSTRUCTION
@ RV3D_CAMOB
@ V3D_S3D_DISPCAMERAS
@ V3D_S3D_DISPPLANE
@ V3D_S3D_DISPVOLUME
#define XRAY_FLAG_ENABLED(v3d)
static AppView * view
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
int GPU_texture_original_height(const GPUTexture *texture)
int GPU_texture_original_width(const GPUTexture *texture)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between world
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between camera
@ 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 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
detail::PassBase< command::DrawCommandBuf > Sub
Definition draw_pass.hh:462
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)
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
#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
static ulong state[N]
static float4x4 winmat_polygon_offset(float4x4 winmat, float view_dist, float offset)
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
MatBase< float, 4, 3 > float4x3
VecBase< float, 3 > float3
static float camera_offaxis_shiftx_get(Scene *scene, Object *ob, const OVERLAY_CameraInstanceData *instdata, bool right_eye)
static void image_camera_background_matrix_get(const Camera *cam, const CameraBGImage *bgpic, const DRWContextState *draw_ctx, const float image_aspect, float rmat[4][4])
static GPUTexture * image_camera_background_texture_get(CameraBGImage *bgpic, const DRWContextState *draw_ctx, OVERLAY_PrivateData *pd, float *r_aspect, bool *r_use_alpha_premult, bool *r_use_view_transform)
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
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
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 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)
int xy[2]
Definition wm_draw.cc:170