Blender V4.5
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) {
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 if (RNA_property_array_check(prop)) {
403 data.resize(RNA_property_array_length(&custom_props, prop));
404 RNA_property_float_get_array(&custom_props, prop, data.data());
405 }
406 else {
407 data.resize(1);
408 data[0] = RNA_property_float_get(&custom_props, prop);
409 }
410 return true;
411 }
412
413 bool get_int(ustring name, vector<int> &data) override
414 {
415 PropertyRNA *prop = get_prop(name);
416 if (!prop)
417 return false;
418
419 int array_len = 0;
420 if (RNA_property_array_check(prop)) {
421 array_len = RNA_property_array_length(&custom_props, prop);
422 }
423
424 /* OSL represents booleans as integers, but we represent them as boolean-type
425 * properties in RNA, so convert here. */
426 if (RNA_property_type(prop) == PROP_BOOLEAN) {
427 if (array_len > 0) {
428 /* Can't use std::vector<bool> here since it's a weird special case. */
429 array<bool> bool_data(array_len);
430 RNA_property_boolean_get_array(&custom_props, prop, bool_data.data());
431 std::copy(bool_data.begin(), bool_data.end(), std::back_inserter(data));
432 }
433 else {
434 data.push_back(RNA_property_boolean_get(&custom_props, prop));
435 }
436 }
437 else {
438 if (array_len > 0) {
439 data.resize(array_len);
440 RNA_property_int_get_array(&custom_props, prop, data.data());
441 }
442 else {
443 data.push_back(RNA_property_int_get(&custom_props, prop));
444 }
445 }
446 return true;
447 }
448
449 bool get_string(ustring name, string &data) override
450 {
451 PropertyRNA *prop = get_prop(name);
452 if (!prop)
453 return false;
454 data = RNA_property_string_get(&custom_props, prop);
455 return true;
456 }
457
458 private:
459 PointerRNA custom_props;
460
461 PropertyRNA *get_prop(ustring param)
462 {
463 string name = string_printf("[\"%s\"]", param.c_str());
464 return RNA_struct_find_property(&custom_props, name.c_str());
465 }
466};
467
469 Scene *scene,
470 BlenderCamera *bcam,
471 const int width,
472 const int height,
473 const char *viewname,
474 PointerRNA *cscene)
475{
476 float aspectratio;
477 float sensor_size;
478
479 /* viewplane */
480 BoundBox2D viewplane;
481 blender_camera_viewplane(bcam, width, height, viewplane, aspectratio, sensor_size);
482
483 cam->set_viewplane_left(viewplane.left);
484 cam->set_viewplane_right(viewplane.right);
485 cam->set_viewplane_top(viewplane.top);
486 cam->set_viewplane_bottom(viewplane.bottom);
487
488 cam->set_full_width(width);
489 cam->set_full_height(height);
490
491 /* Set panorama or custom sensor. */
492 if ((bcam->type == CAMERA_PANORAMA &&
495 bcam->type == CAMERA_CUSTOM)
496 {
497 const float fit_xratio = (float)bcam->render_width * bcam->pixelaspect.x;
498 const float fit_yratio = (float)bcam->render_height * bcam->pixelaspect.y;
499 bool horizontal_fit;
500 float sensor_size;
501
502 if (bcam->sensor_fit == BlenderCamera::AUTO) {
503 horizontal_fit = (fit_xratio > fit_yratio);
504 sensor_size = bcam->sensor_width;
505 }
506 else if (bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
507 horizontal_fit = true;
508 sensor_size = bcam->sensor_width;
509 }
510 else { /* vertical */
511 horizontal_fit = false;
512 sensor_size = bcam->sensor_height;
513 }
514
515 if (horizontal_fit) {
516 cam->set_sensorwidth(sensor_size);
517 cam->set_sensorheight(sensor_size * fit_yratio / fit_xratio);
518 }
519 else {
520 cam->set_sensorwidth(sensor_size * fit_xratio / fit_yratio);
521 cam->set_sensorheight(sensor_size);
522 }
523 }
524
525 /* Sync custom camera parameters. */
526 if (scene != nullptr) {
527 if (bcam->type == CAMERA_CUSTOM) {
529 cam->set_osl_camera(
530 scene, params, bcam->custom_filepath, bcam->custom_bytecode_hash, bcam->custom_bytecode);
531 }
532 else {
533 cam->clear_osl_camera(scene);
534 }
535 }
536
537 /* clipping distances */
538 cam->set_nearclip(bcam->nearclip);
539 cam->set_farclip(bcam->farclip);
540
541 /* type */
542 cam->set_camera_type(bcam->type);
543
544 /* panorama */
545 cam->set_panorama_type(bcam->panorama_type);
546 cam->set_fisheye_fov(bcam->fisheye_fov);
547 cam->set_fisheye_lens(bcam->fisheye_lens);
548 cam->set_latitude_min(bcam->latitude_min);
549 cam->set_latitude_max(bcam->latitude_max);
550
551 cam->set_fisheye_polynomial_k0(bcam->fisheye_polynomial_k0);
552 cam->set_fisheye_polynomial_k1(bcam->fisheye_polynomial_k1);
553 cam->set_fisheye_polynomial_k2(bcam->fisheye_polynomial_k2);
554 cam->set_fisheye_polynomial_k3(bcam->fisheye_polynomial_k3);
555 cam->set_fisheye_polynomial_k4(bcam->fisheye_polynomial_k4);
556
557 cam->set_longitude_min(bcam->longitude_min);
558 cam->set_longitude_max(bcam->longitude_max);
559
560 cam->set_central_cylindrical_range_u_min(bcam->central_cylindrical_range_u_min);
561 cam->set_central_cylindrical_range_u_max(bcam->central_cylindrical_range_u_max);
562 cam->set_central_cylindrical_range_v_min(bcam->central_cylindrical_range_v_min /
564 cam->set_central_cylindrical_range_v_max(bcam->central_cylindrical_range_v_max /
566
567 /* panorama stereo */
568 cam->set_interocular_distance(bcam->interocular_distance);
569 cam->set_convergence_distance(bcam->convergence_distance);
570 cam->set_use_spherical_stereo(bcam->use_spherical_stereo);
571
572 if (cam->get_use_spherical_stereo()) {
573 if (strcmp(viewname, "left") == 0) {
574 cam->set_stereo_eye(Camera::STEREO_LEFT);
575 }
576 else if (strcmp(viewname, "right") == 0) {
577 cam->set_stereo_eye(Camera::STEREO_RIGHT);
578 }
579 else {
580 cam->set_stereo_eye(Camera::STEREO_NONE);
581 }
582 }
583
584 cam->set_use_pole_merge(bcam->use_pole_merge);
585 cam->set_pole_merge_angle_from(bcam->pole_merge_angle_from);
586 cam->set_pole_merge_angle_to(bcam->pole_merge_angle_to);
587
588 /* anamorphic lens bokeh */
589 cam->set_aperture_ratio(bcam->aperture_ratio);
590
591 /* perspective */
592 cam->set_fov(2.0f * atanf((0.5f * sensor_size) / bcam->lens / aspectratio));
593 cam->set_focaldistance(bcam->focaldistance);
594 cam->set_aperturesize(bcam->aperturesize);
595 cam->set_blades(bcam->apertureblades);
596 cam->set_bladesrotation(bcam->aperturerotation);
597
598 /* transform */
599 cam->set_matrix(blender_camera_matrix(bcam->matrix, bcam->type, bcam->panorama_type));
600
601 array<Transform> motion;
602 motion.resize(bcam->motion_steps, cam->get_matrix());
603 cam->set_motion(motion);
604 cam->set_use_perspective_motion(false);
605
606 cam->set_shuttertime(bcam->shuttertime);
607 cam->set_fov_pre(cam->get_fov());
608 cam->set_fov_post(cam->get_fov());
609 cam->set_motion_position(bcam->motion_position);
610
611 cam->set_rolling_shutter_type(bcam->rolling_shutter_type);
612 cam->set_rolling_shutter_duration(bcam->rolling_shutter_duration);
613
614 cam->set_shutter_curve(bcam->shutter_curve);
615
616 /* border */
617 cam->set_border_left(bcam->border.left);
618 cam->set_border_right(bcam->border.right);
619 cam->set_border_top(bcam->border.top);
620 cam->set_border_bottom(bcam->border.bottom);
621
622 cam->set_viewport_camera_border_left(bcam->viewport_camera_border.left);
623 cam->set_viewport_camera_border_right(bcam->viewport_camera_border.right);
624 cam->set_viewport_camera_border_top(bcam->viewport_camera_border.top);
625 cam->set_viewport_camera_border_bottom(bcam->viewport_camera_border.bottom);
626
627 bcam->offscreen_dicing_scale = RNA_float_get(cscene, "offscreen_dicing_scale");
628 cam->set_offscreen_dicing_scale(bcam->offscreen_dicing_scale);
629}
630
631/* Sync Render Camera */
632
634 const BL::RenderSettings::motion_blur_position_enum type)
635{
636 switch (type) {
637 case BL::RenderSettings::motion_blur_position_START:
639 case BL::RenderSettings::motion_blur_position_CENTER:
641 case BL::RenderSettings::motion_blur_position_END:
642 return MOTION_POSITION_END;
643 }
644 /* Could happen if loading a newer file that has an unsupported type. */
646}
647
648void BlenderSync::sync_camera(BL::RenderSettings &b_render,
649 BL::Object &b_override,
650 const int width,
651 const int height,
652 const char *viewname)
653{
654 BlenderCamera bcam(b_render);
655
656 /* pixel aspect */
657 bcam.pixelaspect.x = b_render.pixel_aspect_x();
658 bcam.pixelaspect.y = b_render.pixel_aspect_y();
659 bcam.shuttertime = b_render.motion_blur_shutter();
661 b_render.motion_blur_position());
662
663 BL::CurveMapping b_shutter_curve(b_render.motion_blur_shutter_curve());
665
666 PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
668 cscene,
669 "rolling_shutter_type",
672 bcam.rolling_shutter_duration = RNA_float_get(&cscene, "rolling_shutter_duration");
673
674 /* border */
675 if (b_render.use_border()) {
676 bcam.border.left = b_render.border_min_x();
677 bcam.border.right = b_render.border_max_x();
678 bcam.border.bottom = b_render.border_min_y();
679 bcam.border.top = b_render.border_max_y();
680 }
681
682 /* camera object */
683 BL::Object b_ob = b_scene.camera();
684
685 if (b_override) {
686 b_ob = b_override;
687 }
688
689 if (b_ob) {
690 BL::Array<float, 16> b_ob_matrix;
691 blender_camera_from_object(&bcam, b_engine, b_ob, b_data);
692 b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
693 bcam.matrix = get_transform(b_ob_matrix);
694 scene->bake_manager->set_use_camera(b_render.bake().view_from() ==
695 BL::BakeSettings::view_from_ACTIVE_CAMERA);
696 }
697 else {
698 scene->bake_manager->set_use_camera(false);
699 }
700
701 /* sync */
702 Camera *cam = scene->camera;
703 blender_camera_sync(cam, scene, &bcam, width, height, viewname, &cscene);
704
705 /* dicing camera */
706 b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
707 if (b_ob) {
708 BL::Array<float, 16> b_ob_matrix;
709 blender_camera_from_object(&bcam, b_engine, b_ob, b_data);
710 b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
711 bcam.matrix = get_transform(b_ob_matrix);
712
713 blender_camera_sync(scene->dicing_camera, nullptr, &bcam, width, height, viewname, &cscene);
714 }
715 else {
716 *scene->dicing_camera = *cam;
717 }
718}
719
720BL::Object BlenderSync::get_dicing_camera_object(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d)
721{
722 PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
723 BL::Object b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
724 if (b_ob) {
725 return b_ob;
726 }
727
728 BL::Object b_camera_override = b_engine.camera_override();
729 if (b_camera_override) {
730 return b_camera_override;
731 }
732
733 if (b_v3d && b_rv3d && b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA &&
734 b_v3d.use_local_camera())
735 {
736 return b_v3d.camera();
737 }
738
739 return b_scene.camera();
740}
741
742void BlenderSync::sync_camera_motion(BL::RenderSettings &b_render,
743 BL::Object &b_ob,
744 const int width,
745 const int height,
746 const float motion_time)
747{
748 if (!b_ob) {
749 return;
750 }
751
752 Camera *cam = scene->camera;
753 BL::Array<float, 16> b_ob_matrix;
754 b_engine.camera_model_matrix(b_ob, cam->get_use_spherical_stereo(), b_ob_matrix);
755 Transform tfm = get_transform(b_ob_matrix);
756 tfm = blender_camera_matrix(tfm, cam->get_camera_type(), cam->get_panorama_type());
757
758 if (motion_time == 0.0f) {
759 /* When motion blur is not centered in frame, cam->matrix gets reset. */
760 cam->set_matrix(tfm);
761 }
762
763 /* Set transform in motion array. */
764 const int motion_step = cam->motion_step(motion_time);
765 if (motion_step >= 0) {
766 array<Transform> motion = cam->get_motion();
767 motion[motion_step] = tfm;
768 cam->set_motion(motion);
769 }
770
771 if (cam->get_camera_type() == CAMERA_PERSPECTIVE) {
772 BlenderCamera bcam(b_render);
773
774 /* TODO(sergey): Consider making it a part of BlenderCamera(). */
775 bcam.pixelaspect.x = b_render.pixel_aspect_x();
776 bcam.pixelaspect.y = b_render.pixel_aspect_y();
777
778 blender_camera_from_object(&bcam, b_engine, b_ob, b_data);
779
780 BoundBox2D viewplane;
781 float aspectratio;
782 float sensor_size;
783 blender_camera_viewplane(&bcam, width, height, viewplane, aspectratio, sensor_size);
784 /* TODO(sergey): De-duplicate calculation with camera sync. */
785 const float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio);
786 if (fov != cam->get_fov()) {
787 VLOG_WORK << "Camera " << b_ob.name() << " FOV change detected.";
788 if (motion_time == 0.0f) {
789 cam->set_fov(fov);
790 }
791 else if (motion_time == -1.0f) {
792 cam->set_fov_pre(fov);
793 cam->set_use_perspective_motion(true);
794 }
795 else if (motion_time == 1.0f) {
796 cam->set_fov_post(fov);
797 cam->set_use_perspective_motion(true);
798 }
799 }
800 }
801}
802
803/* Sync 3D View Camera */
804
805static void blender_camera_view_subset(BL::RenderEngine &b_engine,
806 BL::RenderSettings &b_render,
807 BL::Scene &b_scene,
808 BL::BlendData &b_data,
809 BL::Object &b_ob,
810 BL::SpaceView3D &b_v3d,
811 BL::RegionView3D &b_rv3d,
812 const int width,
813 const int height,
814 BoundBox2D &view_box,
815 BoundBox2D &cam_box,
816 float &view_aspect);
817
819 BL::RenderEngine &b_engine,
820 BL::Scene &b_scene,
821 BL::BlendData &b_data,
822 BL::SpaceView3D &b_v3d,
823 BL::RegionView3D &b_rv3d,
824 const int width,
825 const int height,
826 bool skip_panorama = false)
827{
828 /* 3d view parameters */
829 bcam->nearclip = b_v3d.clip_start();
830 bcam->farclip = b_v3d.clip_end();
831 bcam->lens = b_v3d.lens();
832 bcam->shuttertime = b_scene.render().motion_blur_shutter();
833
834 BL::CurveMapping b_shutter_curve(b_scene.render().motion_blur_shutter_curve());
835 curvemapping_to_array(b_shutter_curve, bcam->shutter_curve, RAMP_TABLE_SIZE);
836
837 if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
838 /* camera view */
839 BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera();
840
841 if (b_ob) {
842 blender_camera_from_object(bcam, b_engine, b_ob, b_data, skip_panorama);
843
844 if (!skip_panorama && (bcam->type == CAMERA_PANORAMA || bcam->type == CAMERA_CUSTOM)) {
845 /* in panorama or custom camera view, we map viewplane to camera border */
846 BoundBox2D view_box;
847 BoundBox2D cam_box;
848 float view_aspect;
849
850 BL::RenderSettings b_render_settings(b_scene.render());
852 b_render_settings,
853 b_scene,
854 b_data,
855 b_ob,
856 b_v3d,
857 b_rv3d,
858 width,
859 height,
860 view_box,
861 cam_box,
862 view_aspect);
863
864 bcam->pano_viewplane = view_box.make_relative_to(cam_box);
865 bcam->pano_aspectratio = view_aspect;
866 }
867 else {
868 /* magic zoom formula */
869 bcam->zoom = b_rv3d.view_camera_zoom();
870 bcam->zoom = (1.41421f + bcam->zoom / 50.0f);
871 bcam->zoom *= bcam->zoom;
872 bcam->zoom = 2.0f / bcam->zoom;
873
874 /* offset */
875 bcam->offset = get_float2(b_rv3d.view_camera_offset());
876 }
877 }
878 }
879 else if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
880 /* orthographic view */
881 bcam->farclip *= 0.5f;
882 bcam->nearclip = -bcam->farclip;
883
884 float sensor_size;
885 if (bcam->sensor_fit == BlenderCamera::VERTICAL) {
886 sensor_size = bcam->sensor_height;
887 }
888 else {
889 sensor_size = bcam->sensor_width;
890 }
891
893 bcam->ortho_scale = b_rv3d.view_distance() * sensor_size / b_v3d.lens();
894 }
895
896 bcam->zoom *= 2.0f;
897
898 /* 3d view transform */
899 bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
900
901 /* dimensions */
902 bcam->full_width = width;
903 bcam->full_height = height;
904}
905
906static void blender_camera_view_subset(BL::RenderEngine &b_engine,
907 BL::RenderSettings &b_render,
908 BL::Scene &b_scene,
909 BL::BlendData &b_data,
910 BL::Object &b_ob,
911 BL::SpaceView3D &b_v3d,
912 BL::RegionView3D &b_rv3d,
913 const int width,
914 const int height,
915 BoundBox2D &view_box,
916 BoundBox2D &cam_box,
917 float &view_aspect)
918{
919 BoundBox2D cam;
921 float cam_aspect;
922 float sensor_size;
923
924 /* Get viewport viewplane. */
925 BlenderCamera view_bcam(b_render);
927 &view_bcam, b_engine, b_scene, b_data, b_v3d, b_rv3d, width, height, true);
928
929 blender_camera_viewplane(&view_bcam, width, height, view, view_aspect, sensor_size);
930
931 /* Get camera viewplane. */
932 BlenderCamera cam_bcam(b_render);
933 blender_camera_from_object(&cam_bcam, b_engine, b_ob, b_data, true);
934
935 /* Camera border is affect by aspect, viewport is not. */
936 cam_bcam.pixelaspect.x = b_render.pixel_aspect_x();
937 cam_bcam.pixelaspect.y = b_render.pixel_aspect_y();
938
940 &cam_bcam, cam_bcam.full_width, cam_bcam.full_height, cam, cam_aspect, sensor_size);
941
942 /* Return */
943 view_box = view * (1.0f / view_aspect);
944 cam_box = cam * (1.0f / cam_aspect);
945}
946
947static void blender_camera_border_subset(BL::RenderEngine &b_engine,
948 BL::RenderSettings &b_render,
949 BL::Scene &b_scene,
950 BL::BlendData &b_data,
951 BL::SpaceView3D &b_v3d,
952 BL::RegionView3D &b_rv3d,
953 BL::Object &b_ob,
954 const int width,
955 const int height,
956 const BoundBox2D &border,
958{
959 /* Determine camera viewport subset. */
960 BoundBox2D view_box;
961 BoundBox2D cam_box;
962 float view_aspect;
964 b_render,
965 b_scene,
966 b_data,
967 b_ob,
968 b_v3d,
969 b_rv3d,
970 width,
971 height,
972 view_box,
973 cam_box,
974 view_aspect);
975
976 /* Determine viewport subset matching given border. */
977 cam_box = cam_box.make_relative_to(view_box);
978 *result = cam_box.subset(border);
979}
980
982 BL::RenderEngine &b_engine,
983 BL::RenderSettings &b_render,
984 BL::Scene &b_scene,
985 BL::BlendData &b_data,
986 BL::SpaceView3D &b_v3d,
987 BL::RegionView3D &b_rv3d,
988 const int width,
989 const int height)
990{
991 bool is_camera_view;
992
993 /* camera view? */
994 is_camera_view = b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA;
995
996 if (!is_camera_view) {
997 /* for non-camera view check whether render border is enabled for viewport
998 * and if so use border from 3d viewport
999 * assume viewport has got correctly clamped border already
1000 */
1001 if (b_v3d.use_render_border()) {
1002 bcam->border.left = b_v3d.render_border_min_x();
1003 bcam->border.right = b_v3d.render_border_max_x();
1004 bcam->border.bottom = b_v3d.render_border_min_y();
1005 bcam->border.top = b_v3d.render_border_max_y();
1006 }
1007 return;
1008 }
1009
1010 BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera();
1011
1012 if (!b_ob) {
1013 return;
1014 }
1015
1016 /* Determine camera border inside the viewport. */
1017 const BoundBox2D full_border;
1019 b_render,
1020 b_scene,
1021 b_data,
1022 b_v3d,
1023 b_rv3d,
1024 b_ob,
1025 width,
1026 height,
1027 full_border,
1028 &bcam->viewport_camera_border);
1029
1030 if (b_render.use_border()) {
1031 bcam->border.left = b_render.border_min_x();
1032 bcam->border.right = b_render.border_max_x();
1033 bcam->border.bottom = b_render.border_min_y();
1034 bcam->border.top = b_render.border_max_y();
1035 }
1036 else if (bcam->passepartout_alpha == 1.0f) {
1037 bcam->border = full_border;
1038 }
1039 else {
1040 return;
1041 }
1042
1043 /* Determine viewport subset matching camera border. */
1045 b_render,
1046 b_scene,
1047 b_data,
1048 b_v3d,
1049 b_rv3d,
1050 b_ob,
1051 width,
1052 height,
1053 bcam->border,
1054 &bcam->border);
1055 bcam->border = bcam->border.clamp();
1056}
1057
1058void BlenderSync::sync_view(BL::SpaceView3D &b_v3d,
1059 BL::RegionView3D &b_rv3d,
1060 const int width,
1061 const int height)
1062{
1063 BL::RenderSettings b_render_settings(b_scene.render());
1064 BlenderCamera bcam(b_render_settings);
1065 blender_camera_from_view(&bcam, b_engine, b_scene, b_data, b_v3d, b_rv3d, width, height);
1067 &bcam, b_engine, b_render_settings, b_scene, b_data, b_v3d, b_rv3d, width, height);
1068 PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
1069 blender_camera_sync(scene->camera, scene, &bcam, width, height, "", &cscene);
1070
1071 /* dicing camera */
1072 BL::Object b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera"));
1073 if (b_ob) {
1074 BL::Array<float, 16> b_ob_matrix;
1075 blender_camera_from_object(&bcam, b_engine, b_ob, b_data);
1076 b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
1077 bcam.matrix = get_transform(b_ob_matrix);
1078
1079 blender_camera_sync(scene->dicing_camera, nullptr, &bcam, width, height, "", &cscene);
1080 }
1081 else {
1082 *scene->dicing_camera = *scene->camera;
1083 }
1084}
1085
1087 BL::RegionView3D &b_rv3d,
1088 Camera *cam,
1089 const int width,
1090 const int height)
1091{
1093 bool use_border = false;
1094
1095 params.full_width = width;
1096 params.full_height = height;
1097
1098 if (b_v3d && b_rv3d && b_rv3d.view_perspective() != BL::RegionView3D::view_perspective_CAMERA) {
1099 use_border = b_v3d.use_render_border();
1100 }
1101 else {
1102 /* the camera can always have a passepartout */
1103 use_border = true;
1104 }
1105
1106 if (use_border) {
1107 /* border render */
1108 /* the viewport may offset the border outside the view */
1109 const BoundBox2D border = cam->border.clamp();
1110 params.full_x = (int)(border.left * (float)width);
1111 params.full_y = (int)(border.bottom * (float)height);
1112 params.width = (int)(border.right * (float)width) - params.full_x;
1113 params.height = (int)(border.top * (float)height) - params.full_y;
1114
1115 /* survive in case border goes out of view or becomes too small */
1116 params.width = max(params.width, 1);
1117 params.height = max(params.height, 1);
1118 }
1119 else {
1120 params.width = width;
1121 params.height = height;
1122 }
1123
1124 params.window_width = params.width;
1125 params.window_height = params.height;
1126
1127 return params;
1128}
1129
unsigned int uint
struct Camera Camera
static AppView * view
@ PROP_BOOLEAN
Definition RNA_types.hh:150
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
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
enum BlenderCamera::@361271043005007241065140066112377215043035242037 sensor_fit
BoundBox2D viewport_camera_border
void sync_camera(BL::RenderSettings &b_render, BL::Object &b_override, 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)
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 M_PI_F
#define RAMP_TABLE_SIZE
#define tanf(x)
#define CCL_NAMESPACE_END
#define atanf(x)
ccl_device_forceinline float2 make_float2(const float x, const float y)
#define fabsf(x)
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 VLOG_WORK
Definition log.h:74
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
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
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)
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)
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:321
ccl_device_inline Transform transform_identity()
Definition transform.h:289
ccl_device_inline Transform transform_scale(const float3 s)
Definition transform.h:247
ccl_device_inline Transform transform_inverse(const Transform tfm)
Definition transform.h:492
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:126
ccl_device_inline Transform transform_clear_scale(const Transform &tfm)
Definition transform.h:367