Blender V5.0
blender/camera.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "scene/camera.h"
6#include "scene/bake.h"
7#include "scene/osl.h"
8#include "scene/scene.h"
9
10#include "blender/sync.h"
11#include "blender/util.h"
12
13#include "util/log.h"
14
16
17/* Blender Camera Intermediate: we first convert both the offline and 3d view
18 * render camera to this, and from there convert to our native camera format. */
19
21 public:
22 explicit BlenderCamera(BL::RenderSettings &b_render)
23 {
26 };
27
32
33 float nearclip = 1e-5f;
34 float farclip = 1e5f;
35
37 float ortho_scale = 1.0f;
38
39 float lens = 50.0f;
40 float shuttertime = 1.0f;
43
46
47 float aperturesize = 0.0f;
49 float aperturerotation = 0.0f;
50 float focaldistance = 10.0f;
51
54 float zoom = 1.0f;
55
57
58 float aperture_ratio = 1.0f;
59
62 float fisheye_lens = 10.5f;
68 float interocular_distance = 0.065f;
69 float convergence_distance = 30.0f * 0.065f;
70 bool use_pole_merge = false;
71 float pole_merge_angle_from = (60.0f * M_PI_F / 180.0f);
72 float pole_merge_angle_to = (75.0f * M_PI_F / 180.0f);
73
79
85
87 float sensor_width = 36.0f;
88 float sensor_height = 24.0f;
89
90 int full_width = 0;
91 int full_height = 0;
92
93 int render_width = 0;
95
99 float pano_aspectratio = 0.0f;
100
101 float passepartout_alpha = 0.5f;
102
104
106
108};
109
110static float blender_camera_focal_distance(BL::RenderEngine &b_engine,
111 BL::Object &b_ob,
112 BL::Camera &b_camera,
113 BlenderCamera *bcam)
114{
115 BL::Object b_dof_object = b_camera.dof().focus_object();
116
117 if (!b_dof_object) {
118 return b_camera.dof().focus_distance();
119 }
120
121 Transform dofmat = get_transform(b_dof_object.matrix_world());
122
123 const string focus_subtarget = b_camera.dof().focus_subtarget();
124 if (b_dof_object.pose() && !focus_subtarget.empty()) {
125 BL::PoseBone b_bone = b_dof_object.pose().bones[focus_subtarget];
126 if (b_bone) {
127 dofmat = dofmat * get_transform(b_bone.matrix());
128 }
129 }
130
131 /* for dof object, return distance along camera Z direction */
132 BL::Array<float, 16> b_ob_matrix;
133 b_engine.camera_model_matrix(b_ob, bcam->use_spherical_stereo, b_ob_matrix);
134 const Transform obmat = transform_clear_scale(get_transform(b_ob_matrix));
135 const float3 view_dir = normalize(transform_get_column(&obmat, 2));
136 const float3 dof_dir = transform_get_column(&obmat, 3) - transform_get_column(&dofmat, 3);
137 return fabsf(dot(view_dir, dof_dir));
138}
139
140static PanoramaType blender_panorama_type_to_cycles(const BL::Camera::panorama_type_enum type)
141{
142 switch (type) {
143 case BL::Camera::panorama_type_EQUIRECTANGULAR:
145 case BL::Camera::panorama_type_EQUIANGULAR_CUBEMAP_FACE:
147 case BL::Camera::panorama_type_MIRRORBALL:
148 return PANORAMA_MIRRORBALL;
149 case BL::Camera::panorama_type_FISHEYE_EQUIDISTANT:
151 case BL::Camera::panorama_type_FISHEYE_EQUISOLID:
153 case BL::Camera::panorama_type_FISHEYE_LENS_POLYNOMIAL:
155 case BL::Camera::panorama_type_CENTRAL_CYLINDRICAL:
157 }
158 /* Could happen if loading a newer file that has an unsupported type. */
160}
161
163 BL::RenderEngine &b_engine,
164 BL::Object &b_ob,
165 BL::BlendData &b_data,
166 bool skip_panorama = false)
167{
168 BL::ID b_ob_data = b_ob.data();
169
170 if (b_ob_data.is_a(&RNA_Camera)) {
171 BL::Camera b_camera(b_ob_data);
172
173 bcam->nearclip = b_camera.clip_start();
174 bcam->farclip = b_camera.clip_end();
175
176 switch (b_camera.type()) {
177 case BL::Camera::type_ORTHO:
179 break;
180 case BL::Camera::type_CUSTOM:
181 bcam->type = skip_panorama ? CAMERA_PERSPECTIVE : CAMERA_CUSTOM;
182 break;
183 case BL::Camera::type_PANO:
184 bcam->type = skip_panorama ? CAMERA_PERSPECTIVE : CAMERA_PANORAMA;
185 break;
186 case BL::Camera::type_PERSP:
187 default:
188 bcam->type = CAMERA_PERSPECTIVE;
189 break;
190 }
191
192 bcam->panorama_type = blender_panorama_type_to_cycles(b_camera.panorama_type());
193 bcam->fisheye_fov = b_camera.fisheye_fov();
194 bcam->fisheye_lens = b_camera.fisheye_lens();
195 bcam->latitude_min = b_camera.latitude_min();
196 bcam->latitude_max = b_camera.latitude_max();
197 bcam->longitude_min = b_camera.longitude_min();
198 bcam->longitude_max = b_camera.longitude_max();
199
200 bcam->fisheye_polynomial_k0 = b_camera.fisheye_polynomial_k0();
201 bcam->fisheye_polynomial_k1 = b_camera.fisheye_polynomial_k1();
202 bcam->fisheye_polynomial_k2 = b_camera.fisheye_polynomial_k2();
203 bcam->fisheye_polynomial_k3 = b_camera.fisheye_polynomial_k3();
204 bcam->fisheye_polynomial_k4 = b_camera.fisheye_polynomial_k4();
205
206 bcam->central_cylindrical_range_u_min = b_camera.central_cylindrical_range_u_min();
207 bcam->central_cylindrical_range_u_max = b_camera.central_cylindrical_range_u_max();
208 bcam->central_cylindrical_range_v_min = b_camera.central_cylindrical_range_v_min();
209 bcam->central_cylindrical_range_v_max = b_camera.central_cylindrical_range_v_max();
210 bcam->central_cylindrical_radius = b_camera.central_cylindrical_radius();
211
212 bcam->interocular_distance = b_camera.stereo().interocular_distance();
213 if (b_camera.stereo().convergence_mode() == BL::CameraStereoData::convergence_mode_PARALLEL) {
215 }
216 else {
217 bcam->convergence_distance = b_camera.stereo().convergence_distance();
218 }
219 bcam->use_spherical_stereo = b_engine.use_spherical_stereo(b_ob);
220
221 bcam->use_pole_merge = b_camera.stereo().use_pole_merge();
222 bcam->pole_merge_angle_from = b_camera.stereo().pole_merge_angle_from();
223 bcam->pole_merge_angle_to = b_camera.stereo().pole_merge_angle_to();
224
225 bcam->ortho_scale = b_camera.ortho_scale();
226
227 bcam->lens = b_camera.lens();
228
229 bcam->passepartout_alpha = b_camera.show_passepartout() ? b_camera.passepartout_alpha() : 0.0f;
230
231 if (b_camera.dof().use_dof()) {
232 /* allow f/stop number to change aperture_size but still
233 * give manual control over aperture radius */
234 float fstop = b_camera.dof().aperture_fstop();
235 fstop = max(fstop, 1e-5f);
236
237 if (bcam->type == CAMERA_ORTHOGRAPHIC || bcam->type == CAMERA_CUSTOM) {
238 bcam->aperturesize = 1.0f / (2.0f * fstop);
239 }
240 else {
241 bcam->aperturesize = (bcam->lens * 1e-3f) / (2.0f * fstop);
242 }
243
244 bcam->apertureblades = b_camera.dof().aperture_blades();
245 bcam->aperturerotation = b_camera.dof().aperture_rotation();
246 bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera, bcam);
247 bcam->aperture_ratio = b_camera.dof().aperture_ratio();
248 }
249 else {
250 /* DOF is turned of for the camera. */
251 bcam->aperturesize = 0.0f;
252 bcam->apertureblades = 0;
253 bcam->aperturerotation = 0.0f;
254 bcam->focaldistance = 0.0f;
255 bcam->aperture_ratio = 1.0f;
256 }
257
258 bcam->shift.x = b_engine.camera_shift_x(b_ob, bcam->use_spherical_stereo);
259 bcam->shift.y = b_camera.shift_y();
260
261 bcam->sensor_width = b_camera.sensor_width();
262 bcam->sensor_height = b_camera.sensor_height();
263
264 if (b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO) {
266 }
267 else if (b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL) {
269 }
270 else {
272 }
273
274 if (bcam->type == CAMERA_CUSTOM) {
275 bcam->custom_props = RNA_pointer_get(&b_camera.ptr, "cycles_custom");
276 bcam->custom_bytecode_hash = b_camera.custom_bytecode_hash();
277 if (!bcam->custom_bytecode_hash.empty()) {
278 bcam->custom_bytecode = b_camera.custom_bytecode();
279 }
280 else {
282 b_data, b_camera, b_camera.custom_filepath());
283 }
284 }
285 }
286 else if (b_ob_data.is_a(&RNA_Light)) {
287 /* Can also look through spot light. */
288 BL::SpotLight b_light(b_ob_data);
289 const float lens = 16.0f / tanf(b_light.spot_size() * 0.5f);
290 if (lens > 0.0f) {
291 bcam->lens = lens;
292 }
293 }
294
295 bcam->motion_steps = object_motion_steps(b_ob, b_ob);
296}
297
299 const CameraType type,
300 const PanoramaType panorama_type)
301{
303
304 if (type == CAMERA_PANORAMA) {
305 if (panorama_type == PANORAMA_MIRRORBALL) {
306 /* Mirror ball camera is looking into the negative Y direction
307 * which matches texture mirror ball mapping.
308 */
309 result = tfm * make_transform(
310 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
311 }
312 else {
313 /* Make it so environment camera needs to be pointed in the direction
314 * of the positive x-axis to match an environment texture, this way
315 * it is looking at the center of the texture
316 */
317 result = tfm * make_transform(
318 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f);
319 }
320 }
321 else {
322 /* Note the blender camera points along the negative z-axis. */
323 result = tfm * transform_scale(1.0f, 1.0f, -1.0f);
324 }
325
327}
328
330 const int width,
331 const int height,
332 BoundBox2D &viewplane,
333 float &aspectratio,
334 float &sensor_size)
335{
336 /* dimensions */
337 const float xratio = (float)width * bcam->pixelaspect.x;
338 const float yratio = (float)height * bcam->pixelaspect.y;
339
340 /* compute x/y aspect and ratio */
341 float2 aspect;
342 bool horizontal_fit;
343
344 /* sensor fitting */
345 if (bcam->sensor_fit == BlenderCamera::AUTO) {
346 horizontal_fit = (xratio > yratio);
347 sensor_size = bcam->sensor_width;
348 }
349 else if (bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
350 horizontal_fit = true;
351 sensor_size = bcam->sensor_width;
352 }
353 else {
354 horizontal_fit = false;
355 sensor_size = bcam->sensor_height;
356 }
357
358 if (horizontal_fit) {
359 aspectratio = xratio / yratio;
360 aspect = make_float2(aspectratio, 1.0f);
361 }
362 else {
363 aspectratio = yratio / xratio;
364 aspect = make_float2(1.0f, aspectratio);
365 }
366
367 /* modify aspect for orthographic scale */
368 if (bcam->type == CAMERA_ORTHOGRAPHIC) {
369 aspect *= bcam->ortho_scale / (aspectratio * 2.0f);
370 aspectratio = bcam->ortho_scale / 2.0f;
371 }
372
373 if (bcam->type == CAMERA_PANORAMA || bcam->type == CAMERA_CUSTOM) {
374 /* Account for camera shift. */
375 float2 dv = bcam->shift;
376 if (bcam->pano_aspectratio != 0.0f) {
377 dv *= aspectratio / bcam->pano_aspectratio;
378 }
379
380 /* Set viewplane for panoramic or custom camera. */
381 viewplane = bcam->pano_viewplane.offset(dv);
382 }
383 else {
384 /* Account for camera shift and 3d camera view offset. */
385 const float2 dv = 2.0f * (aspectratio * bcam->shift + bcam->offset * aspect * 2.0f);
386
387 /* Set viewplane for perspective or orthographic camera. */
388 viewplane = (BoundBox2D(aspect) * bcam->zoom).offset(dv);
389 }
390}
391
393 public:
394 BlenderCameraParamQuery(PointerRNA custom_props) : custom_props(custom_props) {}
395 virtual ~BlenderCameraParamQuery() = default;
396
397 bool get_float(ustring name, vector<float> &data) override
398 {
399 PropertyRNA *prop = get_prop(name);
400 if (!prop) {
401 return false;
402 }
403 if (RNA_property_array_check(prop)) {
404 data.resize(RNA_property_array_length(&custom_props, prop));
405 RNA_property_float_get_array(&custom_props, prop, data.data());
406 }
407 else {
408 data.resize(1);
409 data[0] = RNA_property_float_get(&custom_props, prop);
410 }
411 return true;
412 }
413
414 bool get_int(ustring name, vector<int> &data) override
415 {
416 PropertyRNA *prop = get_prop(name);
417 if (!prop) {
418 return false;
419 }
420 int array_len = 0;
421 if (RNA_property_array_check(prop)) {
422 array_len = RNA_property_array_length(&custom_props, prop);
423 }
424
425 /* OSL represents booleans as integers, but we represent them as boolean-type
426 * properties in RNA, so convert here. */
427 if (RNA_property_type(prop) == PROP_BOOLEAN) {
428 if (array_len > 0) {
429 /* Can't use std::vector<bool> here since it's a weird special case. */
430 array<bool> bool_data(array_len);
431 RNA_property_boolean_get_array(&custom_props, prop, bool_data.data());
432 std::copy(bool_data.begin(), bool_data.end(), std::back_inserter(data));
433 }
434 else {
435 data.push_back(RNA_property_boolean_get(&custom_props, prop));
436 }
437 }
438 else if (RNA_property_type(prop) == PROP_ENUM) {
439 const char *identifier = "";
440 const int value = RNA_property_enum_get(&custom_props, prop);
441 if (RNA_property_enum_identifier(nullptr, &custom_props, prop, value, &identifier)) {
442 data.push_back(atoi(identifier));
443 }
444 else {
445 data.push_back(value);
446 }
447 }
448 else {
449 if (array_len > 0) {
450 data.resize(array_len);
451 RNA_property_int_get_array(&custom_props, prop, data.data());
452 }
453 else {
454 data.push_back(RNA_property_int_get(&custom_props, prop));
455 }
456 }
457 return true;
458 }
459
460 bool get_string(ustring name, string &data) override
461 {
462 PropertyRNA *prop = get_prop(name);
463 if (!prop) {
464 return false;
465 }
466 data = RNA_property_string_get(&custom_props, prop);
467 return true;
468 }
469
470 private:
471 PointerRNA custom_props;
472
473 PropertyRNA *get_prop(ustring param)
474 {
475 string name = string_printf("[\"%s\"]", param.c_str());
476 return RNA_struct_find_property(&custom_props, name.c_str());
477 }
478};
479
481 Scene *scene,
482 BlenderCamera *bcam,
483 const int width,
484 const int height,
485 const char *viewname,
486 PointerRNA *cscene)
487{
488 float aspectratio;
489 float sensor_size;
490
491 /* viewplane */
492 BoundBox2D viewplane;
493 blender_camera_viewplane(bcam, width, height, viewplane, aspectratio, sensor_size);
494
495 cam->set_viewplane_left(viewplane.left);
496 cam->set_viewplane_right(viewplane.right);
497 cam->set_viewplane_top(viewplane.top);
498 cam->set_viewplane_bottom(viewplane.bottom);
499
500 cam->set_full_width(width);
501 cam->set_full_height(height);
502
503 /* Set panorama or custom sensor. */
504 if ((bcam->type == CAMERA_PANORAMA &&
507 bcam->type == CAMERA_CUSTOM)
508 {
509 const float fit_xratio = (float)bcam->render_width * bcam->pixelaspect.x;
510 const float fit_yratio = (float)bcam->render_height * bcam->pixelaspect.y;
511 bool horizontal_fit;
512 float sensor_size;
513
514 if (bcam->sensor_fit == BlenderCamera::AUTO) {
515 horizontal_fit = (fit_xratio > fit_yratio);
516 sensor_size = bcam->sensor_width;
517 }
518 else if (bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
519 horizontal_fit = true;
520 sensor_size = bcam->sensor_width;
521 }
522 else { /* vertical */
523 horizontal_fit = false;
524 sensor_size = bcam->sensor_height;
525 }
526
527 if (horizontal_fit) {
528 cam->set_sensorwidth(sensor_size);
529 cam->set_sensorheight(sensor_size * fit_yratio / fit_xratio);
530 }
531 else {
532 cam->set_sensorwidth(sensor_size * fit_xratio / fit_yratio);
533 cam->set_sensorheight(sensor_size);
534 }
535 }
536
537 /* Sync custom camera parameters. */
538 if (scene != nullptr) {
539 if (bcam->type == CAMERA_CUSTOM) {
541 cam->set_osl_camera(
542 scene, params, bcam->custom_filepath, bcam->custom_bytecode_hash, bcam->custom_bytecode);
543 }
544 else {
545 cam->clear_osl_camera(scene);
546 }
547 }
548
549 /* clipping distances */
550 cam->set_nearclip(bcam->nearclip);
551 cam->set_farclip(bcam->farclip);
552
553 /* type */
554 cam->set_camera_type(bcam->type);
555
556 /* panorama */
557 cam->set_panorama_type(bcam->panorama_type);
558 cam->set_fisheye_fov(bcam->fisheye_fov);
559 cam->set_fisheye_lens(bcam->fisheye_lens);
560 cam->set_latitude_min(bcam->latitude_min);
561 cam->set_latitude_max(bcam->latitude_max);
562
563 cam->set_fisheye_polynomial_k0(bcam->fisheye_polynomial_k0);
564 cam->set_fisheye_polynomial_k1(bcam->fisheye_polynomial_k1);
565 cam->set_fisheye_polynomial_k2(bcam->fisheye_polynomial_k2);
566 cam->set_fisheye_polynomial_k3(bcam->fisheye_polynomial_k3);
567 cam->set_fisheye_polynomial_k4(bcam->fisheye_polynomial_k4);
568
569 cam->set_longitude_min(bcam->longitude_min);
570 cam->set_longitude_max(bcam->longitude_max);
571
572 cam->set_central_cylindrical_range_u_min(bcam->central_cylindrical_range_u_min);
573 cam->set_central_cylindrical_range_u_max(bcam->central_cylindrical_range_u_max);
574 cam->set_central_cylindrical_range_v_min(bcam->central_cylindrical_range_v_min /
576 cam->set_central_cylindrical_range_v_max(bcam->central_cylindrical_range_v_max /
578
579 /* panorama stereo */
580 cam->set_interocular_distance(bcam->interocular_distance);
581 cam->set_convergence_distance(bcam->convergence_distance);
582 cam->set_use_spherical_stereo(bcam->use_spherical_stereo);
583
584 if (cam->get_use_spherical_stereo()) {
585 if (strcmp(viewname, "left") == 0) {
586 cam->set_stereo_eye(Camera::STEREO_LEFT);
587 }
588 else if (strcmp(viewname, "right") == 0) {
589 cam->set_stereo_eye(Camera::STEREO_RIGHT);
590 }
591 else {
592 cam->set_stereo_eye(Camera::STEREO_NONE);
593 }
594 }
595
596 cam->set_use_pole_merge(bcam->use_pole_merge);
597 cam->set_pole_merge_angle_from(bcam->pole_merge_angle_from);
598 cam->set_pole_merge_angle_to(bcam->pole_merge_angle_to);
599
600 /* anamorphic lens bokeh */
601 cam->set_aperture_ratio(bcam->aperture_ratio);
602
603 /* perspective */
604 cam->set_fov(2.0f * atanf((0.5f * sensor_size) / bcam->lens / aspectratio));
605 cam->set_focaldistance(bcam->focaldistance);
606 cam->set_aperturesize(bcam->aperturesize);
607 cam->set_blades(bcam->apertureblades);
608 cam->set_bladesrotation(bcam->aperturerotation);
609
610 /* transform */
611 cam->set_matrix(blender_camera_matrix(bcam->matrix, bcam->type, bcam->panorama_type));
612
613 array<Transform> motion;
614 motion.resize(bcam->motion_steps, cam->get_matrix());
615 cam->set_motion(motion);
616 cam->set_use_perspective_motion(false);
617
618 cam->set_shuttertime(bcam->shuttertime);
619 cam->set_fov_pre(cam->get_fov());
620 cam->set_fov_post(cam->get_fov());
621 cam->set_motion_position(bcam->motion_position);
622
623 cam->set_rolling_shutter_type(bcam->rolling_shutter_type);
624 cam->set_rolling_shutter_duration(bcam->rolling_shutter_duration);
625
626 cam->set_shutter_curve(bcam->shutter_curve);
627
628 /* border */
629 cam->set_border_left(bcam->border.left);
630 cam->set_border_right(bcam->border.right);
631 cam->set_border_top(bcam->border.top);
632 cam->set_border_bottom(bcam->border.bottom);
633
634 cam->set_viewport_camera_border_left(bcam->viewport_camera_border.left);
635 cam->set_viewport_camera_border_right(bcam->viewport_camera_border.right);
636 cam->set_viewport_camera_border_top(bcam->viewport_camera_border.top);
637 cam->set_viewport_camera_border_bottom(bcam->viewport_camera_border.bottom);
638
639 bcam->offscreen_dicing_scale = RNA_float_get(cscene, "offscreen_dicing_scale");
640 cam->set_offscreen_dicing_scale(bcam->offscreen_dicing_scale);
641}
642
643/* Sync Render Camera */
644
646 const BL::RenderSettings::motion_blur_position_enum type)
647{
648 switch (type) {
649 case BL::RenderSettings::motion_blur_position_START:
651 case BL::RenderSettings::motion_blur_position_CENTER:
653 case BL::RenderSettings::motion_blur_position_END:
654 return MOTION_POSITION_END;
655 }
656 /* Could happen if loading a newer file that has an unsupported type. */
658}
659
660void BlenderSync::sync_camera(BL::RenderSettings &b_render,
661 const int width,
662 const int height,
663 const char *viewname)
664{
665 BlenderCamera bcam(b_render);
666
667 /* pixel aspect */
668 bcam.pixelaspect.x = b_render.pixel_aspect_x();
669 bcam.pixelaspect.y = b_render.pixel_aspect_y();
670 bcam.shuttertime = b_render.motion_blur_shutter();
672 b_render.motion_blur_position());
673
674 BL::CurveMapping b_shutter_curve(b_render.motion_blur_shutter_curve());
676
677 PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
679 cscene,
680 "rolling_shutter_type",
683 bcam.rolling_shutter_duration = RNA_float_get(&cscene, "rolling_shutter_duration");
684
685 /* border */
686 if (b_render.use_border()) {
687 bcam.border.left = b_render.border_min_x();
688 bcam.border.right = b_render.border_max_x();
689 bcam.border.bottom = b_render.border_min_y();
690 bcam.border.top = b_render.border_max_y();
691 }
692
693 /* camera object */
694 BL::Object b_ob = get_camera_object(PointerRNA_NULL, PointerRNA_NULL);
695
696 if (b_ob) {
697 BL::Array<float, 16> b_ob_matrix;
698 blender_camera_from_object(&bcam, b_engine, b_ob, b_data);
699 b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
700 bcam.matrix = get_transform(b_ob_matrix);
701 scene->bake_manager->set_use_camera(b_render.bake().view_from() ==
702 BL::BakeSettings::view_from_ACTIVE_CAMERA);
703 }
704 else {
705 scene->bake_manager->set_use_camera(false);
706 }
707
708 /* sync */
709 Camera *cam = scene->camera;
710 blender_camera_sync(cam, scene, &bcam, width, height, viewname, &cscene);
711
712 /* dicing camera */
713 b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
714 if (b_ob) {
715 BL::Array<float, 16> b_ob_matrix;
716 blender_camera_from_object(&bcam, b_engine, b_ob, b_data);
717 b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
718 bcam.matrix = get_transform(b_ob_matrix);
719
720 blender_camera_sync(scene->dicing_camera, nullptr, &bcam, width, height, viewname, &cscene);
721 }
722 else {
723 *scene->dicing_camera = *cam;
724 }
725}
726
727BL::Object BlenderSync::get_camera_object(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d)
728{
729 BL::Object b_camera_override = b_engine.camera_override();
730 if (b_camera_override) {
731 return b_camera_override;
732 }
733
734 if (b_v3d && b_rv3d && b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA &&
735 b_v3d.use_local_camera())
736 {
737 return b_v3d.camera();
738 }
739
740 return b_scene.camera();
741}
742
743BL::Object BlenderSync::get_dicing_camera_object(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d)
744{
745 PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
746 BL::Object b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
747 if (b_ob) {
748 return b_ob;
749 }
750
751 return get_camera_object(b_v3d, b_rv3d);
752}
753
754void BlenderSync::sync_camera_motion(BL::RenderSettings &b_render,
755 BL::Object &b_ob,
756 const int width,
757 const int height,
758 const float motion_time)
759{
760 if (!b_ob) {
761 return;
762 }
763
764 Camera *cam = scene->camera;
765 BL::Array<float, 16> b_ob_matrix;
766 b_engine.camera_model_matrix(b_ob, cam->get_use_spherical_stereo(), b_ob_matrix);
767 Transform tfm = get_transform(b_ob_matrix);
768 tfm = blender_camera_matrix(tfm, cam->get_camera_type(), cam->get_panorama_type());
769
770 if (motion_time == 0.0f) {
771 /* When motion blur is not centered in frame, cam->matrix gets reset. */
772 cam->set_matrix(tfm);
773 }
774
775 /* Set transform in motion array. */
776 const int motion_step = cam->motion_step(motion_time);
777 if (motion_step >= 0) {
778 array<Transform> motion = cam->get_motion();
779 motion[motion_step] = tfm;
780 cam->set_motion(motion);
781 }
782
783 if (cam->get_camera_type() == CAMERA_PERSPECTIVE) {
784 BlenderCamera bcam(b_render);
785
786 /* TODO(sergey): Consider making it a part of BlenderCamera(). */
787 bcam.pixelaspect.x = b_render.pixel_aspect_x();
788 bcam.pixelaspect.y = b_render.pixel_aspect_y();
789
790 blender_camera_from_object(&bcam, b_engine, b_ob, b_data);
791
792 BoundBox2D viewplane;
793 float aspectratio;
794 float sensor_size;
795 blender_camera_viewplane(&bcam, width, height, viewplane, aspectratio, sensor_size);
796 /* TODO(sergey): De-duplicate calculation with camera sync. */
797 const float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio);
798 if (fov != cam->get_fov()) {
799 LOG_DEBUG << "Camera " << b_ob.name() << " FOV change detected.";
800 if (motion_time == 0.0f) {
801 cam->set_fov(fov);
802 }
803 else if (motion_time == -1.0f) {
804 cam->set_fov_pre(fov);
805 cam->set_use_perspective_motion(true);
806 }
807 else if (motion_time == 1.0f) {
808 cam->set_fov_post(fov);
809 cam->set_use_perspective_motion(true);
810 }
811 }
812 }
813}
814
815/* Sync 3D View Camera */
816
817static void blender_camera_view_subset(BL::RenderEngine &b_engine,
818 BL::RenderSettings &b_render,
819 BL::Scene &b_scene,
820 BL::BlendData &b_data,
821 BL::Object &b_ob,
822 BL::SpaceView3D &b_v3d,
823 BL::RegionView3D &b_rv3d,
824 const int width,
825 const int height,
826 BoundBox2D &view_box,
827 BoundBox2D &cam_box,
828 float &view_aspect);
829
831 BL::RenderEngine &b_engine,
832 BL::Scene &b_scene,
833 BL::BlendData &b_data,
834 BL::SpaceView3D &b_v3d,
835 BL::RegionView3D &b_rv3d,
836 const int width,
837 const int height,
838 bool skip_panorama = false)
839{
840 /* 3d view parameters */
841 bcam->nearclip = b_v3d.clip_start();
842 bcam->farclip = b_v3d.clip_end();
843 bcam->lens = b_v3d.lens();
844 bcam->shuttertime = b_scene.render().motion_blur_shutter();
845
846 BL::CurveMapping b_shutter_curve(b_scene.render().motion_blur_shutter_curve());
847 curvemapping_to_array(b_shutter_curve, bcam->shutter_curve, RAMP_TABLE_SIZE);
848
849 if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
850 /* camera view */
851 BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera();
852
853 if (b_ob) {
854 blender_camera_from_object(bcam, b_engine, b_ob, b_data, skip_panorama);
855
856 if (!skip_panorama && (bcam->type == CAMERA_PANORAMA || bcam->type == CAMERA_CUSTOM)) {
857 /* in panorama or custom camera view, we map viewplane to camera border */
858 BoundBox2D view_box;
859 BoundBox2D cam_box;
860 float view_aspect;
861
862 BL::RenderSettings b_render_settings(b_scene.render());
864 b_render_settings,
865 b_scene,
866 b_data,
867 b_ob,
868 b_v3d,
869 b_rv3d,
870 width,
871 height,
872 view_box,
873 cam_box,
874 view_aspect);
875
876 bcam->pano_viewplane = view_box.make_relative_to(cam_box);
877 bcam->pano_aspectratio = view_aspect;
878 }
879 else {
880 /* magic zoom formula */
881 bcam->zoom = b_rv3d.view_camera_zoom();
882 bcam->zoom = (1.41421f + bcam->zoom / 50.0f);
883 bcam->zoom *= bcam->zoom;
884 bcam->zoom = 2.0f / bcam->zoom;
885
886 /* offset */
887 bcam->offset = get_float2(b_rv3d.view_camera_offset());
888 }
889 }
890 }
891 else if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
892 /* orthographic view */
893 bcam->farclip *= 0.5f;
894 bcam->nearclip = -bcam->farclip;
895
896 float sensor_size;
897 if (bcam->sensor_fit == BlenderCamera::VERTICAL) {
898 sensor_size = bcam->sensor_height;
899 }
900 else {
901 sensor_size = bcam->sensor_width;
902 }
903
905 bcam->ortho_scale = b_rv3d.view_distance() * sensor_size / b_v3d.lens();
906 }
907
908 bcam->zoom *= 2.0f;
909
910 /* 3d view transform */
911 bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
912
913 /* dimensions */
914 bcam->full_width = width;
915 bcam->full_height = height;
916}
917
918static void blender_camera_view_subset(BL::RenderEngine &b_engine,
919 BL::RenderSettings &b_render,
920 BL::Scene &b_scene,
921 BL::BlendData &b_data,
922 BL::Object &b_ob,
923 BL::SpaceView3D &b_v3d,
924 BL::RegionView3D &b_rv3d,
925 const int width,
926 const int height,
927 BoundBox2D &view_box,
928 BoundBox2D &cam_box,
929 float &view_aspect)
930{
931 BoundBox2D cam;
933 float cam_aspect;
934 float sensor_size;
935
936 /* Get viewport viewplane. */
937 BlenderCamera view_bcam(b_render);
939 &view_bcam, b_engine, b_scene, b_data, b_v3d, b_rv3d, width, height, true);
940
941 blender_camera_viewplane(&view_bcam, width, height, view, view_aspect, sensor_size);
942
943 /* Get camera viewplane. */
944 BlenderCamera cam_bcam(b_render);
945 blender_camera_from_object(&cam_bcam, b_engine, b_ob, b_data, true);
946
947 /* Camera border is affect by aspect, viewport is not. */
948 cam_bcam.pixelaspect.x = b_render.pixel_aspect_x();
949 cam_bcam.pixelaspect.y = b_render.pixel_aspect_y();
950
952 &cam_bcam, cam_bcam.full_width, cam_bcam.full_height, cam, cam_aspect, sensor_size);
953
954 /* Return */
955 view_box = view * (1.0f / view_aspect);
956 cam_box = cam * (1.0f / cam_aspect);
957}
958
959static void blender_camera_border_subset(BL::RenderEngine &b_engine,
960 BL::RenderSettings &b_render,
961 BL::Scene &b_scene,
962 BL::BlendData &b_data,
963 BL::SpaceView3D &b_v3d,
964 BL::RegionView3D &b_rv3d,
965 BL::Object &b_ob,
966 const int width,
967 const int height,
968 const BoundBox2D &border,
970{
971 /* Determine camera viewport subset. */
972 BoundBox2D view_box;
973 BoundBox2D cam_box;
974 float view_aspect;
976 b_render,
977 b_scene,
978 b_data,
979 b_ob,
980 b_v3d,
981 b_rv3d,
982 width,
983 height,
984 view_box,
985 cam_box,
986 view_aspect);
987
988 /* Determine viewport subset matching given border. */
989 cam_box = cam_box.make_relative_to(view_box);
990 *result = cam_box.subset(border);
991}
992
994 BL::RenderEngine &b_engine,
995 BL::RenderSettings &b_render,
996 BL::Scene &b_scene,
997 BL::BlendData &b_data,
998 BL::SpaceView3D &b_v3d,
999 BL::RegionView3D &b_rv3d,
1000 const int width,
1001 const int height)
1002{
1003 bool is_camera_view;
1004
1005 /* camera view? */
1006 is_camera_view = b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA;
1007
1008 if (!is_camera_view) {
1009 /* for non-camera view check whether render border is enabled for viewport
1010 * and if so use border from 3d viewport
1011 * assume viewport has got correctly clamped border already
1012 */
1013 if (b_v3d.use_render_border()) {
1014 bcam->border.left = b_v3d.render_border_min_x();
1015 bcam->border.right = b_v3d.render_border_max_x();
1016 bcam->border.bottom = b_v3d.render_border_min_y();
1017 bcam->border.top = b_v3d.render_border_max_y();
1018 }
1019 return;
1020 }
1021
1022 BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera();
1023
1024 if (!b_ob) {
1025 return;
1026 }
1027
1028 /* Determine camera border inside the viewport. */
1029 const BoundBox2D full_border;
1031 b_render,
1032 b_scene,
1033 b_data,
1034 b_v3d,
1035 b_rv3d,
1036 b_ob,
1037 width,
1038 height,
1039 full_border,
1040 &bcam->viewport_camera_border);
1041
1042 if (b_render.use_border()) {
1043 bcam->border.left = b_render.border_min_x();
1044 bcam->border.right = b_render.border_max_x();
1045 bcam->border.bottom = b_render.border_min_y();
1046 bcam->border.top = b_render.border_max_y();
1047 }
1048 else if (bcam->passepartout_alpha == 1.0f) {
1049 bcam->border = full_border;
1050 }
1051 else {
1052 return;
1053 }
1054
1055 /* Determine viewport subset matching camera border. */
1057 b_render,
1058 b_scene,
1059 b_data,
1060 b_v3d,
1061 b_rv3d,
1062 b_ob,
1063 width,
1064 height,
1065 bcam->border,
1066 &bcam->border);
1067 bcam->border = bcam->border.clamp();
1068}
1069
1070void BlenderSync::sync_view(BL::SpaceView3D &b_v3d,
1071 BL::RegionView3D &b_rv3d,
1072 const int width,
1073 const int height)
1074{
1075 BL::RenderSettings b_render_settings(b_scene.render());
1076 BlenderCamera bcam(b_render_settings);
1077 blender_camera_from_view(&bcam, b_engine, b_scene, b_data, b_v3d, b_rv3d, width, height);
1079 &bcam, b_engine, b_render_settings, b_scene, b_data, b_v3d, b_rv3d, width, height);
1080 PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
1081 blender_camera_sync(scene->camera, scene, &bcam, width, height, "", &cscene);
1082
1083 /* dicing camera */
1084 BL::Object b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
1085 if (b_ob) {
1086 BL::Array<float, 16> b_ob_matrix;
1087 blender_camera_from_object(&bcam, b_engine, b_ob, b_data);
1088 b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
1089 bcam.matrix = get_transform(b_ob_matrix);
1090
1091 blender_camera_sync(scene->dicing_camera, nullptr, &bcam, width, height, "", &cscene);
1092 }
1093 else {
1094 *scene->dicing_camera = *scene->camera;
1095 }
1096}
1097
1099 BL::RegionView3D &b_rv3d,
1100 Camera *cam,
1101 const int width,
1102 const int height)
1103{
1105 bool use_border = false;
1106
1107 params.full_width = width;
1108 params.full_height = height;
1109
1110 if (b_v3d && b_rv3d && b_rv3d.view_perspective() != BL::RegionView3D::view_perspective_CAMERA) {
1111 use_border = b_v3d.use_render_border();
1112 }
1113 else {
1114 /* the camera can always have a passepartout */
1115 use_border = true;
1116 }
1117
1118 if (use_border) {
1119 /* border render */
1120 /* the viewport may offset the border outside the view */
1121 const BoundBox2D border = cam->border.clamp();
1122 params.full_x = (int)(border.left * (float)width);
1123 params.full_y = (int)(border.bottom * (float)height);
1124 params.width = (int)(border.right * (float)width) - params.full_x;
1125 params.height = (int)(border.top * (float)height) - params.full_y;
1126
1127 /* survive in case border goes out of view or becomes too small */
1128 params.width = max(params.width, 1);
1129 params.height = max(params.height, 1);
1130 }
1131 else {
1132 params.width = width;
1133 params.height = height;
1134 }
1135
1136 params.window_width = params.width;
1137 params.window_height = params.height;
1138
1139 return params;
1140}
1141
unsigned int uint
struct Camera Camera
static AppView * view
@ PROP_BOOLEAN
Definition RNA_types.hh:162
@ PROP_ENUM
Definition RNA_types.hh:166
static float blender_camera_focal_distance(BL::RenderEngine &b_engine, BL::Object &b_ob, BL::Camera &b_camera, BlenderCamera *bcam)
static void blender_camera_border_subset(BL::RenderEngine &b_engine, BL::RenderSettings &b_render, BL::Scene &b_scene, BL::BlendData &b_data, BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, BL::Object &b_ob, const int width, const int height, const BoundBox2D &border, BoundBox2D *result)
static void blender_camera_sync(Camera *cam, Scene *scene, BlenderCamera *bcam, const int width, const int height, const char *viewname, PointerRNA *cscene)
static MotionPosition blender_motion_blur_position_type_to_cycles(const BL::RenderSettings::motion_blur_position_enum type)
static void blender_camera_from_object(BlenderCamera *bcam, BL::RenderEngine &b_engine, BL::Object &b_ob, BL::BlendData &b_data, bool skip_panorama=false)
static PanoramaType blender_panorama_type_to_cycles(const BL::Camera::panorama_type_enum type)
static void blender_camera_view_subset(BL::RenderEngine &b_engine, BL::RenderSettings &b_render, BL::Scene &b_scene, BL::BlendData &b_data, BL::Object &b_ob, BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, const int width, const int height, BoundBox2D &view_box, BoundBox2D &cam_box, float &view_aspect)
static void blender_camera_border(BlenderCamera *bcam, BL::RenderEngine &b_engine, BL::RenderSettings &b_render, BL::Scene &b_scene, BL::BlendData &b_data, BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, const int width, const int height)
static void blender_camera_viewplane(BlenderCamera *bcam, const int width, const int height, BoundBox2D &viewplane, float &aspectratio, float &sensor_size)
static Transform blender_camera_matrix(const Transform &tfm, const CameraType type, const PanoramaType panorama_type)
static void blender_camera_from_view(BlenderCamera *bcam, BL::RenderEngine &b_engine, BL::Scene &b_scene, BL::BlendData &b_data, BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, const int width, const int height, bool skip_panorama=false)
BMesh const char void * data
virtual ~BlenderCameraParamQuery()=default
bool get_string(ustring name, string &data) override
bool get_float(ustring name, vector< float > &data) override
bool get_int(ustring name, vector< int > &data) override
BlenderCameraParamQuery(PointerRNA custom_props)
float central_cylindrical_radius
float rolling_shutter_duration
float central_cylindrical_range_u_min
enum BlenderCamera::@062236323244027147140205312151046053276234130136 sensor_fit
MotionPosition motion_position
string custom_bytecode_hash
float fisheye_polynomial_k2
float fisheye_polynomial_k1
BlenderCamera(BL::RenderSettings &b_render)
array< float > shutter_curve
float fisheye_polynomial_k0
float central_cylindrical_range_v_min
float fisheye_polynomial_k4
BoundBox2D pano_viewplane
Camera::RollingShutterType rolling_shutter_type
BoundBox2D border
PointerRNA custom_props
float central_cylindrical_range_v_max
float pole_merge_angle_from
float fisheye_polynomial_k3
PanoramaType panorama_type
float central_cylindrical_range_u_max
BoundBox2D viewport_camera_border
void sync_camera(BL::RenderSettings &b_render, const int width, const int height, const char *viewname)
void sync_view(BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, const int width, const int height)
static BufferParams get_buffer_params(BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, const int width, const int height)
BoundBox2D clamp(const float mn=0.0f, const float mx=1.0f)
Definition boundbox.h:262
BoundBox2D make_relative_to(const BoundBox2D &other) const
Definition boundbox.h:250
BoundBox2D offset(const float2 offset) const
Definition boundbox.h:274
float bottom
Definition boundbox.h:200
float top
Definition boundbox.h:201
float right
Definition boundbox.h:199
BoundBox2D subset(const BoundBox2D &other) const
Definition boundbox.h:238
float left
Definition boundbox.h:198
OSLCameraParamQuery()=default
T * resize(const size_t newsize)
nullptr float
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
static void curvemapping_to_array(BL::CurveMapping &cumap, array< float > &data, const int size)
static uint object_motion_steps(BL::Object &b_parent, BL::Object &b_ob, const int max_steps=INT_MAX)
static int render_resolution_x(BL::RenderSettings &b_render)
static int render_resolution_y(BL::RenderSettings &b_render)
static int get_enum(PointerRNA &ptr, const char *name, int num_values=-1, int default_value=-1)
static string blender_absolute_path(BL::BlendData &b_data, BL::ID &b_id, const string &path)
static float2 get_float2(const BL::Array< float, 2 > &array)
static Transform get_transform(const BL::Array< float, 16 > &array)
#define M_PI_2_F
#define RAMP_TABLE_SIZE
#define CCL_NAMESPACE_END
VecBase< float, D > normalize(VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
MotionPosition
@ MOTION_POSITION_END
@ MOTION_POSITION_START
@ MOTION_POSITION_CENTER
PanoramaType
@ PANORAMA_MIRRORBALL
@ PANORAMA_FISHEYE_EQUISOLID
@ PANORAMA_CENTRAL_CYLINDRICAL
@ PANORAMA_EQUIANGULAR_CUBEMAP_FACE
@ PANORAMA_FISHEYE_EQUIDISTANT
@ PANORAMA_FISHEYE_LENS_POLYNOMIAL
@ PANORAMA_EQUIRECTANGULAR
CameraType
@ CAMERA_PERSPECTIVE
@ CAMERA_PANORAMA
@ CAMERA_CUSTOM
@ CAMERA_ORTHOGRAPHIC
#define LOG_DEBUG
Definition log.h:107
ccl_device_inline float2 one_float2()
Definition math_float2.h:18
CCL_NAMESPACE_BEGIN ccl_device_inline float2 zero_float2()
Definition math_float2.h:13
const char * name
#define fabsf
#define atanf
#define make_float2
#define tanf
#define M_PI_F
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_enum_identifier(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_identifier)
bool RNA_property_array_check(PropertyRNA *prop)
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_boolean_get_array(PointerRNA *ptr, PropertyRNA *prop, bool *values)
PropertyType RNA_property_type(PropertyRNA *prop)
const PointerRNA PointerRNA_NULL
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
float RNA_float_get(PointerRNA *ptr, const char *name)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
std::string RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
#define FLT_MAX
Definition stdcycles.h:14
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition string.cpp:23
RollingShutterType
@ ROLLING_SHUTTER_NUM_TYPES
@ ROLLING_SHUTTER_NONE
BoundBox2D border
int motion_step(const float time) const
void clear_osl_camera(Scene *scene)
void set_osl_camera(Scene *scene, OSLCameraParamQuery &params, const std::string &filepath, const std::string &bytecode_hash="", const std::string &bytecode="")
@ STEREO_LEFT
@ STEREO_NONE
@ STEREO_RIGHT
float x
float y
max
Definition text_draw.cc:251
ccl_device_inline float3 transform_get_column(const Transform *t, const int column)
Definition transform.h:354
ccl_device_inline Transform transform_identity()
Definition transform.h:322
ccl_device_inline Transform transform_scale(const float3 s)
Definition transform.h:280
ccl_device_inline Transform transform_inverse(const Transform tfm)
Definition transform.h:525
ccl_device_inline Transform make_transform(const float a, const float b, const float c, const float d, const float e, const float f, const float g, const float h, const float i, const float j, const float k, const float l)
Definition transform.h:159
ccl_device_inline Transform transform_clear_scale(const Transform &tfm)
Definition transform.h:400