2023-06-14 16:52:36 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2024-12-27 21:50:31 +01:00
|
|
|
#include <algorithm>
|
|
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "scene/camera.h"
|
|
|
|
|
#include "scene/mesh.h"
|
|
|
|
|
#include "scene/object.h"
|
2025-04-25 19:27:30 +02:00
|
|
|
#include "scene/osl.h"
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "scene/scene.h"
|
|
|
|
|
#include "scene/stats.h"
|
|
|
|
|
#include "scene/tables.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "device/device.h"
|
2012-10-15 21:12:58 +00:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "util/log.h"
|
|
|
|
|
#include "util/math_cdf.h"
|
2024-12-26 17:53:59 +01:00
|
|
|
#include "util/tbb.h"
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "util/time.h"
|
|
|
|
|
#include "util/vector.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "kernel/camera/camera.h"
|
2018-01-12 02:14:27 +01:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
2015-10-27 13:16:04 +05:00
|
|
|
static float shutter_curve_eval(float x, array<float> &shutter_curve)
|
|
|
|
|
{
|
2016-10-24 12:26:12 +02:00
|
|
|
if (shutter_curve.size() == 0) {
|
2016-05-08 00:28:21 +02:00
|
|
|
return 1.0f;
|
2016-10-24 12:26:12 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-01-09 03:05:57 +01:00
|
|
|
x = saturatef(x) * shutter_curve.size() - 1;
|
2024-12-29 17:32:00 +01:00
|
|
|
const int index = (int)x;
|
|
|
|
|
const float frac = x - index;
|
2016-05-08 00:28:21 +02:00
|
|
|
if (index < shutter_curve.size() - 1) {
|
2023-05-12 19:55:46 +02:00
|
|
|
return mix(shutter_curve[index], shutter_curve[index + 1], frac);
|
2015-10-27 13:16:04 +05:00
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
return shutter_curve[shutter_curve.size() - 1];
|
2015-10-27 13:16:04 +05:00
|
|
|
}
|
|
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
NODE_DEFINE(Camera)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("camera", create);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_FLOAT(shuttertime, "Shutter Time", 1.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
static NodeEnum motion_position_enum;
|
|
|
|
|
motion_position_enum.insert("start", MOTION_POSITION_START);
|
|
|
|
|
motion_position_enum.insert("center", MOTION_POSITION_CENTER);
|
|
|
|
|
motion_position_enum.insert("end", MOTION_POSITION_END);
|
|
|
|
|
SOCKET_ENUM(motion_position, "Motion Position", motion_position_enum, MOTION_POSITION_CENTER);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
static NodeEnum rolling_shutter_type_enum;
|
|
|
|
|
rolling_shutter_type_enum.insert("none", ROLLING_SHUTTER_NONE);
|
|
|
|
|
rolling_shutter_type_enum.insert("top", ROLLING_SHUTTER_TOP);
|
|
|
|
|
SOCKET_ENUM(rolling_shutter_type,
|
|
|
|
|
"Rolling Shutter Type",
|
|
|
|
|
rolling_shutter_type_enum,
|
|
|
|
|
ROLLING_SHUTTER_NONE);
|
|
|
|
|
SOCKET_FLOAT(rolling_shutter_duration, "Rolling Shutter Duration", 0.1f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_FLOAT_ARRAY(shutter_curve, "Shutter Curve", array<float>());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_FLOAT(aperturesize, "Aperture Size", 0.0f);
|
|
|
|
|
SOCKET_FLOAT(focaldistance, "Focal Distance", 10.0f);
|
2016-06-12 17:12:25 +02:00
|
|
|
SOCKET_UINT(blades, "Blades", 0);
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_TRANSFORM(matrix, "Matrix", transform_identity());
|
2018-03-10 01:36:09 +01:00
|
|
|
SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
static NodeEnum type_enum;
|
|
|
|
|
type_enum.insert("perspective", CAMERA_PERSPECTIVE);
|
|
|
|
|
type_enum.insert("orthograph", CAMERA_ORTHOGRAPHIC);
|
|
|
|
|
type_enum.insert("panorama", CAMERA_PANORAMA);
|
2025-04-25 19:27:30 +02:00
|
|
|
type_enum.insert("custom", CAMERA_CUSTOM);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(camera_type, "Type", type_enum, CAMERA_PERSPECTIVE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
static NodeEnum panorama_type_enum;
|
|
|
|
|
panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR);
|
2022-10-28 14:30:18 +02:00
|
|
|
panorama_type_enum.insert("equiangular_cubemap_face", PANORAMA_EQUIANGULAR_CUBEMAP_FACE);
|
2016-05-08 00:28:21 +02:00
|
|
|
panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL);
|
|
|
|
|
panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT);
|
|
|
|
|
panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID);
|
2021-12-07 18:54:36 +01:00
|
|
|
panorama_type_enum.insert("fisheye_lens_polynomial", PANORAMA_FISHEYE_LENS_POLYNOMIAL);
|
2024-07-29 15:03:57 +02:00
|
|
|
panorama_type_enum.insert("panorama_central_cylindrical", PANORAMA_CENTRAL_CYLINDRICAL);
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F);
|
|
|
|
|
SOCKET_FLOAT(fisheye_lens, "Fisheye Lens", 10.5f);
|
|
|
|
|
SOCKET_FLOAT(latitude_min, "Latitude Min", -M_PI_2_F);
|
|
|
|
|
SOCKET_FLOAT(latitude_max, "Latitude Max", M_PI_2_F);
|
|
|
|
|
SOCKET_FLOAT(longitude_min, "Longitude Min", -M_PI_F);
|
|
|
|
|
SOCKET_FLOAT(longitude_max, "Longitude Max", M_PI_F);
|
|
|
|
|
SOCKET_FLOAT(fov, "FOV", M_PI_4_F);
|
|
|
|
|
SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F);
|
|
|
|
|
SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-12-07 18:54:36 +01:00
|
|
|
SOCKET_FLOAT(fisheye_polynomial_k0, "Fisheye Polynomial K0", 0.0f);
|
|
|
|
|
SOCKET_FLOAT(fisheye_polynomial_k1, "Fisheye Polynomial K1", 0.0f);
|
|
|
|
|
SOCKET_FLOAT(fisheye_polynomial_k2, "Fisheye Polynomial K2", 0.0f);
|
|
|
|
|
SOCKET_FLOAT(fisheye_polynomial_k3, "Fisheye Polynomial K3", 0.0f);
|
|
|
|
|
SOCKET_FLOAT(fisheye_polynomial_k4, "Fisheye Polynomial K4", 0.0f);
|
|
|
|
|
|
2024-07-29 15:03:57 +02:00
|
|
|
SOCKET_FLOAT(central_cylindrical_range_u_min, "Central Cylindrical Range U Min", -M_PI_F);
|
|
|
|
|
SOCKET_FLOAT(central_cylindrical_range_u_max, "Central Cylindrical Range U Max", M_PI_F);
|
|
|
|
|
SOCKET_FLOAT(central_cylindrical_range_v_min, "Central Cylindrical Range V Min", -1.0f);
|
|
|
|
|
SOCKET_FLOAT(central_cylindrical_range_v_max, "Central Cylindrical Range V Max", 1.0f);
|
|
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
static NodeEnum stereo_eye_enum;
|
|
|
|
|
stereo_eye_enum.insert("none", STEREO_NONE);
|
|
|
|
|
stereo_eye_enum.insert("left", STEREO_LEFT);
|
|
|
|
|
stereo_eye_enum.insert("right", STEREO_RIGHT);
|
|
|
|
|
SOCKET_ENUM(stereo_eye, "Stereo Eye", stereo_eye_enum, STEREO_NONE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-06-21 16:24:56 +02:00
|
|
|
SOCKET_BOOLEAN(use_spherical_stereo, "Use Spherical Stereo", false);
|
|
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_FLOAT(interocular_distance, "Interocular Distance", 0.065f);
|
|
|
|
|
SOCKET_FLOAT(convergence_distance, "Convergence Distance", 30.0f * 0.065f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_BOOLEAN(use_pole_merge, "Use Pole Merge", false);
|
|
|
|
|
SOCKET_FLOAT(pole_merge_angle_from, "Pole Merge Angle From", 60.0f * M_PI_F / 180.0f);
|
|
|
|
|
SOCKET_FLOAT(pole_merge_angle_to, "Pole Merge Angle To", 75.0f * M_PI_F / 180.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_FLOAT(sensorwidth, "Sensor Width", 0.036f);
|
|
|
|
|
SOCKET_FLOAT(sensorheight, "Sensor Height", 0.024f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_FLOAT(nearclip, "Near Clip", 1e-5f);
|
|
|
|
|
SOCKET_FLOAT(farclip, "Far Clip", 1e5f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_FLOAT(viewplane.left, "Viewplane Left", 0);
|
|
|
|
|
SOCKET_FLOAT(viewplane.right, "Viewplane Right", 0);
|
|
|
|
|
SOCKET_FLOAT(viewplane.bottom, "Viewplane Bottom", 0);
|
|
|
|
|
SOCKET_FLOAT(viewplane.top, "Viewplane Top", 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
SOCKET_FLOAT(border.left, "Border Left", 0);
|
|
|
|
|
SOCKET_FLOAT(border.right, "Border Right", 0);
|
|
|
|
|
SOCKET_FLOAT(border.bottom, "Border Bottom", 0);
|
|
|
|
|
SOCKET_FLOAT(border.top, "Border Top", 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_FLOAT(viewport_camera_border.left, "Viewport Border Left", 0);
|
|
|
|
|
SOCKET_FLOAT(viewport_camera_border.right, "Viewport Border Right", 0);
|
|
|
|
|
SOCKET_FLOAT(viewport_camera_border.bottom, "Viewport Border Bottom", 0);
|
|
|
|
|
SOCKET_FLOAT(viewport_camera_border.top, "Viewport Border Top", 0);
|
|
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
SOCKET_FLOAT(offscreen_dicing_scale, "Offscreen Dicing Scale", 1.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_INT(full_width, "Full Width", 1024);
|
|
|
|
|
SOCKET_INT(full_height, "Full Height", 512);
|
|
|
|
|
|
|
|
|
|
SOCKET_BOOLEAN(use_perspective_motion, "Use Perspective Motion", false);
|
|
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
Camera::Camera() : Node(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2015-10-27 13:16:04 +05:00
|
|
|
shutter_table_offset = TABLE_OFFSET_INVALID;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
width = 1024;
|
|
|
|
|
height = 512;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2015-07-21 15:36:35 +02:00
|
|
|
use_perspective_motion = false;
|
2012-04-30 12:49:26 +00:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
shutter_curve.resize(RAMP_TABLE_SIZE);
|
|
|
|
|
for (int i = 0; i < shutter_curve.size(); ++i) {
|
|
|
|
|
shutter_curve[i] = 1.0f;
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-08 00:28:21 +02:00
|
|
|
compute_auto_viewplane();
|
2012-06-06 23:27:43 +00:00
|
|
|
|
2018-03-08 05:33:55 +01:00
|
|
|
screentoworld = projection_identity();
|
|
|
|
|
rastertoworld = projection_identity();
|
|
|
|
|
ndctoworld = projection_identity();
|
|
|
|
|
rastertocamera = projection_identity();
|
2011-04-27 11:58:34 +00:00
|
|
|
cameratoworld = transform_identity();
|
2018-03-08 05:33:55 +01:00
|
|
|
worldtoraster = projection_identity();
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-04-04 20:06:22 +02:00
|
|
|
full_rastertocamera = projection_identity();
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
dx = zero_float3();
|
|
|
|
|
dy = zero_float3();
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
need_device_update = true;
|
2015-05-14 19:08:13 +05:00
|
|
|
need_flags_update = true;
|
2012-09-04 13:29:07 +00:00
|
|
|
previous_need_motion = -1;
|
2018-01-12 20:22:55 +01:00
|
|
|
|
2018-06-11 12:54:17 +02:00
|
|
|
memset((void *)&kernel_camera, 0, sizeof(kernel_camera));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
Camera::~Camera() = default;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2014-02-14 18:40:31 +01:00
|
|
|
void Camera::compute_auto_viewplane()
|
|
|
|
|
{
|
2025-04-25 19:27:30 +02:00
|
|
|
if (camera_type == CAMERA_PANORAMA || camera_type == CAMERA_CUSTOM) {
|
2015-09-08 13:07:08 +05:00
|
|
|
viewplane.left = 0.0f;
|
|
|
|
|
viewplane.right = 1.0f;
|
|
|
|
|
viewplane.bottom = 0.0f;
|
2014-02-14 18:40:31 +01:00
|
|
|
viewplane.top = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2024-12-29 17:32:00 +01:00
|
|
|
const float aspect = (float)full_width / (float)full_height;
|
2021-01-18 07:43:42 +01:00
|
|
|
if (full_width >= full_height) {
|
2015-09-08 13:07:08 +05:00
|
|
|
viewplane.left = -aspect;
|
|
|
|
|
viewplane.right = aspect;
|
|
|
|
|
viewplane.bottom = -1.0f;
|
|
|
|
|
viewplane.top = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
viewplane.left = -1.0f;
|
|
|
|
|
viewplane.right = 1.0f;
|
|
|
|
|
viewplane.bottom = -1.0f / aspect;
|
|
|
|
|
viewplane.top = 1.0f / aspect;
|
|
|
|
|
}
|
2014-02-14 18:40:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-12 20:22:55 +01:00
|
|
|
void Camera::update(Scene *scene)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const Scene::MotionType need_motion = scene->need_motion();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 20:22:55 +01:00
|
|
|
if (previous_need_motion != need_motion) {
|
|
|
|
|
/* scene's motion model could have been changed since previous device
|
|
|
|
|
* camera update this could happen for example in case when one render
|
|
|
|
|
* layer has got motion pass and another not */
|
|
|
|
|
need_device_update = true;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!is_modified()) {
|
2011-04-27 11:58:34 +00:00
|
|
|
return;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const scoped_callback_timer timer([scene](double time) {
|
2020-10-01 23:16:01 +02:00
|
|
|
if (scene->update_stats) {
|
|
|
|
|
scene->update_stats->camera.times.add_entry({"update", time});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2015-01-27 21:36:14 +05:00
|
|
|
/* Full viewport to camera border in the viewport. */
|
2024-12-29 17:32:00 +01:00
|
|
|
const Transform fulltoborder = transform_from_viewplane(viewport_camera_border);
|
|
|
|
|
const Transform bordertofull = transform_inverse(fulltoborder);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-05 16:23:34 +11:00
|
|
|
/* NDC to raster. */
|
2024-12-29 17:32:00 +01:00
|
|
|
const Transform ndctoraster = transform_scale(width, height, 1.0f) * bordertofull;
|
|
|
|
|
const Transform full_ndctoraster = transform_scale(full_width, full_height, 1.0f) * bordertofull;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-05 16:23:34 +11:00
|
|
|
/* Raster to screen. */
|
2024-12-29 17:32:00 +01:00
|
|
|
const Transform screentondc = fulltoborder * transform_from_viewplane(viewplane);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const Transform screentoraster = ndctoraster * screentondc;
|
|
|
|
|
const Transform rastertoscreen = transform_inverse(screentoraster);
|
|
|
|
|
const Transform full_screentoraster = full_ndctoraster * screentondc;
|
|
|
|
|
const Transform full_rastertoscreen = transform_inverse(full_screentoraster);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-05 16:23:34 +11:00
|
|
|
/* Screen to camera. */
|
2018-03-08 05:33:55 +01:00
|
|
|
ProjectionTransform cameratoscreen;
|
2023-09-17 09:01:48 +10:00
|
|
|
if (camera_type == CAMERA_PERSPECTIVE) {
|
2018-03-08 05:33:55 +01:00
|
|
|
cameratoscreen = projection_perspective(fov, nearclip, farclip);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (camera_type == CAMERA_ORTHOGRAPHIC) {
|
2018-03-08 05:33:55 +01:00
|
|
|
cameratoscreen = projection_orthographic(nearclip, farclip);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2018-03-08 05:33:55 +01:00
|
|
|
cameratoscreen = projection_identity();
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const ProjectionTransform screentocamera = projection_inverse(cameratoscreen);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
rastertocamera = screentocamera * rastertoscreen;
|
2019-04-04 20:06:22 +02:00
|
|
|
full_rastertocamera = screentocamera * full_rastertoscreen;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
cameratoworld = matrix;
|
|
|
|
|
screentoworld = cameratoworld * screentocamera;
|
|
|
|
|
rastertoworld = cameratoworld * rastertocamera;
|
|
|
|
|
ndctoworld = rastertoworld * ndctoraster;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-21 01:00:03 +00:00
|
|
|
/* note we recompose matrices instead of taking inverses of the above, this
|
|
|
|
|
* is needed to avoid inverting near degenerate matrices that happen due to
|
|
|
|
|
* precision issues with large scenes */
|
|
|
|
|
worldtocamera = transform_inverse(matrix);
|
|
|
|
|
worldtoscreen = cameratoscreen * worldtocamera;
|
|
|
|
|
worldtondc = screentondc * worldtoscreen;
|
|
|
|
|
worldtoraster = ndctoraster * worldtondc;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* differentials */
|
2020-11-04 11:17:38 +01:00
|
|
|
if (camera_type == CAMERA_ORTHOGRAPHIC) {
|
2018-03-08 05:33:55 +01:00
|
|
|
dx = transform_perspective_direction(&rastertocamera, make_float3(1, 0, 0));
|
|
|
|
|
dy = transform_perspective_direction(&rastertocamera, make_float3(0, 1, 0));
|
|
|
|
|
full_dx = transform_perspective_direction(&full_rastertocamera, make_float3(1, 0, 0));
|
|
|
|
|
full_dy = transform_perspective_direction(&full_rastertocamera, make_float3(0, 1, 0));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
else if (camera_type == CAMERA_PERSPECTIVE) {
|
2012-04-16 08:35:21 +00:00
|
|
|
dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) -
|
|
|
|
|
transform_perspective(&rastertocamera, make_float3(0, 0, 0));
|
|
|
|
|
dy = transform_perspective(&rastertocamera, make_float3(0, 1, 0)) -
|
|
|
|
|
transform_perspective(&rastertocamera, make_float3(0, 0, 0));
|
2016-04-11 22:49:09 +02:00
|
|
|
full_dx = transform_perspective(&full_rastertocamera, make_float3(1, 0, 0)) -
|
|
|
|
|
transform_perspective(&full_rastertocamera, make_float3(0, 0, 0));
|
|
|
|
|
full_dy = transform_perspective(&full_rastertocamera, make_float3(0, 1, 0)) -
|
|
|
|
|
transform_perspective(&full_rastertocamera, make_float3(0, 0, 0));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2012-02-28 16:44:54 +00:00
|
|
|
else {
|
2021-02-17 01:47:18 +01:00
|
|
|
dx = zero_float3();
|
|
|
|
|
dy = zero_float3();
|
2012-02-28 16:44:54 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
dx = transform_direction(&cameratoworld, dx);
|
|
|
|
|
dy = transform_direction(&cameratoworld, dy);
|
2016-04-11 22:49:09 +02:00
|
|
|
full_dx = transform_direction(&cameratoworld, full_dx);
|
|
|
|
|
full_dy = transform_direction(&cameratoworld, full_dy);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
if (camera_type == CAMERA_PERSPECTIVE) {
|
2018-01-12 00:50:34 +01:00
|
|
|
float3 v = transform_perspective(&full_rastertocamera,
|
2025-02-28 19:50:23 +01:00
|
|
|
make_float3(full_width, full_height, 0.0f));
|
2018-01-12 00:50:34 +01:00
|
|
|
frustum_right_normal = normalize(make_float3(v.z, 0.0f, -v.x));
|
|
|
|
|
frustum_top_normal = normalize(make_float3(0.0f, v.z, -v.y));
|
2020-10-26 12:49:37 +01:00
|
|
|
|
2025-02-28 19:50:23 +01:00
|
|
|
v = transform_perspective(&full_rastertocamera, make_float3(0.0f, 0.0f, 0.0f));
|
2020-10-26 12:49:37 +01:00
|
|
|
frustum_left_normal = normalize(make_float3(-v.z, 0.0f, v.x));
|
|
|
|
|
frustum_bottom_normal = normalize(make_float3(0.0f, -v.z, v.y));
|
2018-01-12 00:50:34 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 20:22:55 +01:00
|
|
|
/* Compute kernel camera data. */
|
|
|
|
|
KernelCamera *kcam = &kernel_camera;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* store matrices */
|
|
|
|
|
kcam->screentoworld = screentoworld;
|
|
|
|
|
kcam->rastertoworld = rastertoworld;
|
|
|
|
|
kcam->rastertocamera = rastertocamera;
|
|
|
|
|
kcam->cameratoworld = cameratoworld;
|
2012-11-21 01:00:03 +00:00
|
|
|
kcam->worldtocamera = worldtocamera;
|
|
|
|
|
kcam->worldtoscreen = worldtoscreen;
|
2012-04-30 12:49:26 +00:00
|
|
|
kcam->worldtoraster = worldtoraster;
|
2012-11-21 01:00:03 +00:00
|
|
|
kcam->worldtondc = worldtondc;
|
2018-03-08 05:33:55 +01:00
|
|
|
kcam->ndctoworld = ndctoworld;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-30 12:49:26 +00:00
|
|
|
/* camera motion */
|
2018-03-10 01:36:09 +01:00
|
|
|
kcam->num_motion_steps = 0;
|
2015-07-21 15:36:35 +02:00
|
|
|
kcam->have_perspective_motion = 0;
|
2018-03-10 01:36:09 +01:00
|
|
|
kernel_camera_motion.clear();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-10 01:36:09 +01:00
|
|
|
/* Test if any of the transforms are actually different. */
|
|
|
|
|
bool have_motion = false;
|
|
|
|
|
for (size_t i = 0; i < motion.size(); i++) {
|
|
|
|
|
have_motion = have_motion || motion[i] != matrix;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-30 12:49:26 +00:00
|
|
|
if (need_motion == Scene::MOTION_PASS) {
|
2025-04-25 19:27:30 +02:00
|
|
|
if (camera_type == CAMERA_PANORAMA || camera_type == CAMERA_CUSTOM) {
|
2018-03-10 01:36:09 +01:00
|
|
|
if (have_motion) {
|
|
|
|
|
kcam->motion_pass_pre = transform_inverse(motion[0]);
|
|
|
|
|
kcam->motion_pass_post = transform_inverse(motion[motion.size() - 1]);
|
2012-05-07 10:53:09 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2018-03-10 00:37:07 +01:00
|
|
|
kcam->motion_pass_pre = kcam->worldtocamera;
|
|
|
|
|
kcam->motion_pass_post = kcam->worldtocamera;
|
2012-04-30 12:49:26 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-04-30 12:49:26 +00:00
|
|
|
else {
|
2024-10-15 11:42:11 +02:00
|
|
|
if (have_motion || fov != fov_pre || fov != fov_post) {
|
|
|
|
|
/* Note the values for perspective_pre/perspective_post calculated for MOTION_PASS are
|
|
|
|
|
* different to those calculated for MOTION_BLUR below, so the code has not been combined.
|
|
|
|
|
*/
|
2024-12-29 17:32:00 +01:00
|
|
|
const ProjectionTransform cameratoscreen_pre = projection_perspective(
|
2024-10-15 11:42:11 +02:00
|
|
|
fov_pre, nearclip, farclip);
|
2024-12-29 17:32:00 +01:00
|
|
|
const ProjectionTransform cameratoscreen_post = projection_perspective(
|
2024-10-15 11:42:11 +02:00
|
|
|
fov_post, nearclip, farclip);
|
2024-12-29 17:32:00 +01:00
|
|
|
const ProjectionTransform cameratoraster_pre = screentoraster * cameratoscreen_pre;
|
|
|
|
|
const ProjectionTransform cameratoraster_post = screentoraster * cameratoscreen_post;
|
2024-10-15 11:42:11 +02:00
|
|
|
kcam->perspective_pre = cameratoraster_pre * transform_inverse(motion[0]);
|
|
|
|
|
kcam->perspective_post = cameratoraster_post *
|
|
|
|
|
transform_inverse(motion[motion.size() - 1]);
|
2012-05-07 10:53:09 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2018-03-10 00:37:07 +01:00
|
|
|
kcam->perspective_pre = worldtoraster;
|
|
|
|
|
kcam->perspective_post = worldtoraster;
|
2012-04-30 12:49:26 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-04-30 12:49:26 +00:00
|
|
|
else if (need_motion == Scene::MOTION_BLUR) {
|
2018-03-10 01:36:09 +01:00
|
|
|
if (have_motion) {
|
|
|
|
|
kernel_camera_motion.resize(motion.size());
|
|
|
|
|
transform_motion_decompose(kernel_camera_motion.data(), motion.data(), motion.size());
|
|
|
|
|
kcam->num_motion_steps = motion.size();
|
2012-05-02 09:33:45 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-10 00:37:07 +01:00
|
|
|
/* TODO(sergey): Support other types of camera. */
|
2020-11-04 11:17:38 +01:00
|
|
|
if (use_perspective_motion && camera_type == CAMERA_PERSPECTIVE) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const ProjectionTransform screentocamera_pre = projection_inverse(
|
2018-03-10 00:37:07 +01:00
|
|
|
projection_perspective(fov_pre, nearclip, farclip));
|
2024-12-29 17:32:00 +01:00
|
|
|
const ProjectionTransform screentocamera_post = projection_inverse(
|
2018-03-10 00:37:07 +01:00
|
|
|
projection_perspective(fov_post, nearclip, farclip));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-10 00:37:07 +01:00
|
|
|
kcam->perspective_pre = screentocamera_pre * rastertoscreen;
|
|
|
|
|
kcam->perspective_post = screentocamera_post * rastertoscreen;
|
2015-07-21 15:36:35 +02:00
|
|
|
kcam->have_perspective_motion = 1;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2015-07-21 15:36:35 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* depth of field */
|
2011-09-16 13:14:02 +00:00
|
|
|
kcam->aperturesize = aperturesize;
|
2024-06-17 17:42:38 +02:00
|
|
|
kcam->focaldistance = max(focaldistance, 1e-5f);
|
2011-09-16 13:14:02 +00:00
|
|
|
kcam->blades = (blades < 3) ? 0.0f : blades;
|
|
|
|
|
kcam->bladesrotation = bladesrotation;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* motion blur */
|
2013-01-23 16:56:02 +00:00
|
|
|
kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime : -1.0f;
|
2022-04-19 16:28:14 +02:00
|
|
|
kcam->motion_position = motion_position;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* type */
|
2020-11-04 11:17:38 +01:00
|
|
|
kcam->type = camera_type;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-08-27 10:51:50 +02:00
|
|
|
/* anamorphic lens bokeh */
|
|
|
|
|
kcam->inv_aperture_ratio = 1.0f / aperture_ratio;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-04 16:20:51 +00:00
|
|
|
/* panorama */
|
|
|
|
|
kcam->panorama_type = panorama_type;
|
|
|
|
|
kcam->fisheye_fov = fisheye_fov;
|
|
|
|
|
kcam->fisheye_lens = fisheye_lens;
|
2015-01-14 23:14:45 +05:00
|
|
|
kcam->equirectangular_range = make_float4(longitude_min - longitude_max,
|
|
|
|
|
-longitude_min,
|
|
|
|
|
latitude_min - latitude_max,
|
|
|
|
|
-latitude_min + M_PI_2_F);
|
2021-12-07 18:54:36 +01:00
|
|
|
kcam->fisheye_lens_polynomial_bias = fisheye_polynomial_k0;
|
2021-12-07 23:12:13 -05:00
|
|
|
kcam->fisheye_lens_polynomial_coefficients = make_float4(
|
|
|
|
|
fisheye_polynomial_k1, fisheye_polynomial_k2, fisheye_polynomial_k3, fisheye_polynomial_k4);
|
2024-07-29 15:03:57 +02:00
|
|
|
kcam->central_cylindrical_range = make_float4(-central_cylindrical_range_u_min,
|
|
|
|
|
-central_cylindrical_range_u_max,
|
|
|
|
|
central_cylindrical_range_v_min,
|
|
|
|
|
central_cylindrical_range_v_max);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Multi-View: Cycles - Spherical Stereo support (VR Panoramas)
This is a new option for panorama cameras to render
stereo that can be used in virtual reality devices
The option is available under the camera panel when Multi-View is enabled (Views option in the Render Layers panel)
Known limitations:
------------------
* Parallel convergence is not supported (you need to set a convergence distance really high to simulate this effect).
* Pivot was not supposed to affect the render but it does, this has to be looked at, but for now set it to CENTER
* Derivatives in perspective camera need to be pre-computed or we shuld get rid of kcam->dx/dy (Sergey words, I don't fully grasp the implication shere)
* This works in perspective mode and in panorama mode. However, for fully benefit from this effect in perspective mode you need to render a cube map. (there is an addon for this, developed separately, perhaps we could include it in master).
* We have no support for "neck distance" at the moment. This is supposed to help with objects at short distances.
* We have no support to rotate the "Up Axis" of the stereo plane. Meaning, we hardcode 0,0,1 as UP, and create the stereo pair related to that. (although we could take the camera local UP when rendering panoramas, this wouldn't work for perspective cameras.
* We have no support for interocular distance attenuation based on the proximity of the poles (which helps to reduce the pole rotation effect/artifact).
THIS NEEDS DOCS - both in 2.78 release log and the Blender manual.
Meanwhile you can read about it here: http://code.blender.org/2015/03/1451
This patch specifically dates from March 2015, as you can see in the code.blender.org post. Many thanks to all the reviewers, testers and minor sponsors who helped me maintain spherical-stereo for 1 year.
All that said, have fun with this. This feature was what got me started with Multi-View development (at the time what I was looking for was Fulldome stereo support, but the implementation is the same). In order to make this into Blender I had to make it aiming at a less-specic user-case Thus Multi-View started. (this was December 2012, during Siggraph Asia and a chat I had with Paul Bourke during the conference). I don't have the original patch anymore, but you can find a re-based version of it from March 2013, right before I start with the Multi-View project https://developer.blender.org/P332
Reviewers: sergey, dingto
Subscribers: #cycles
Differential Revision: https://developer.blender.org/D1223
2016-03-10 09:28:29 -03:00
|
|
|
switch (stereo_eye) {
|
|
|
|
|
case STEREO_LEFT:
|
|
|
|
|
kcam->interocular_offset = -interocular_distance * 0.5f;
|
|
|
|
|
break;
|
|
|
|
|
case STEREO_RIGHT:
|
|
|
|
|
kcam->interocular_offset = interocular_distance * 0.5f;
|
|
|
|
|
break;
|
|
|
|
|
case STEREO_NONE:
|
|
|
|
|
default:
|
|
|
|
|
kcam->interocular_offset = 0.0f;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Multi-View: Cycles - Spherical Stereo support (VR Panoramas)
This is a new option for panorama cameras to render
stereo that can be used in virtual reality devices
The option is available under the camera panel when Multi-View is enabled (Views option in the Render Layers panel)
Known limitations:
------------------
* Parallel convergence is not supported (you need to set a convergence distance really high to simulate this effect).
* Pivot was not supposed to affect the render but it does, this has to be looked at, but for now set it to CENTER
* Derivatives in perspective camera need to be pre-computed or we shuld get rid of kcam->dx/dy (Sergey words, I don't fully grasp the implication shere)
* This works in perspective mode and in panorama mode. However, for fully benefit from this effect in perspective mode you need to render a cube map. (there is an addon for this, developed separately, perhaps we could include it in master).
* We have no support for "neck distance" at the moment. This is supposed to help with objects at short distances.
* We have no support to rotate the "Up Axis" of the stereo plane. Meaning, we hardcode 0,0,1 as UP, and create the stereo pair related to that. (although we could take the camera local UP when rendering panoramas, this wouldn't work for perspective cameras.
* We have no support for interocular distance attenuation based on the proximity of the poles (which helps to reduce the pole rotation effect/artifact).
THIS NEEDS DOCS - both in 2.78 release log and the Blender manual.
Meanwhile you can read about it here: http://code.blender.org/2015/03/1451
This patch specifically dates from March 2015, as you can see in the code.blender.org post. Many thanks to all the reviewers, testers and minor sponsors who helped me maintain spherical-stereo for 1 year.
All that said, have fun with this. This feature was what got me started with Multi-View development (at the time what I was looking for was Fulldome stereo support, but the implementation is the same). In order to make this into Blender I had to make it aiming at a less-specic user-case Thus Multi-View started. (this was December 2012, during Siggraph Asia and a chat I had with Paul Bourke during the conference). I don't have the original patch anymore, but you can find a re-based version of it from March 2013, right before I start with the Multi-View project https://developer.blender.org/P332
Reviewers: sergey, dingto
Subscribers: #cycles
Differential Revision: https://developer.blender.org/D1223
2016-03-10 09:28:29 -03:00
|
|
|
kcam->convergence_distance = convergence_distance;
|
2016-05-17 14:12:29 +02:00
|
|
|
if (use_pole_merge) {
|
|
|
|
|
kcam->pole_merge_angle_from = pole_merge_angle_from;
|
|
|
|
|
kcam->pole_merge_angle_to = pole_merge_angle_to;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
kcam->pole_merge_angle_from = -1.0f;
|
|
|
|
|
kcam->pole_merge_angle_to = -1.0f;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-04 16:20:51 +00:00
|
|
|
/* sensor size */
|
|
|
|
|
kcam->sensorwidth = sensorwidth;
|
|
|
|
|
kcam->sensorheight = sensorheight;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-07 10:53:09 +00:00
|
|
|
/* render size */
|
|
|
|
|
kcam->width = width;
|
|
|
|
|
kcam->height = height;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* store differentials */
|
2024-12-19 09:41:55 +01:00
|
|
|
kcam->dx = make_float4(dx);
|
|
|
|
|
kcam->dy = make_float4(dy);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* clipping */
|
|
|
|
|
kcam->nearclip = nearclip;
|
|
|
|
|
kcam->cliplength = (farclip == FLT_MAX) ? FLT_MAX : farclip - nearclip;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-11-20 14:42:34 +05:00
|
|
|
/* Rolling shutter effect */
|
|
|
|
|
kcam->rolling_shutter_type = rolling_shutter_type;
|
|
|
|
|
kcam->rolling_shutter_duration = rolling_shutter_duration;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 20:22:55 +01:00
|
|
|
/* Set further update flags */
|
2020-11-04 11:17:38 +01:00
|
|
|
clear_modified();
|
2018-01-12 20:22:55 +01:00
|
|
|
need_device_update = true;
|
|
|
|
|
need_flags_update = true;
|
2015-02-02 22:06:31 +05:00
|
|
|
previous_need_motion = need_motion;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-29 17:16:44 +10:00
|
|
|
void Camera::device_update(Device * /*device*/, DeviceScene *dscene, Scene *scene)
|
2018-01-12 20:22:55 +01:00
|
|
|
{
|
|
|
|
|
update(scene);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!need_device_update) {
|
2018-01-12 20:22:55 +01:00
|
|
|
return;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const scoped_callback_timer timer([scene](double time) {
|
2020-10-01 23:16:01 +02:00
|
|
|
if (scene->update_stats) {
|
|
|
|
|
scene->update_stats->camera.times.add_entry({"device_update", time});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2018-01-12 20:22:55 +01:00
|
|
|
scene->lookup_tables->remove_table(&shutter_table_offset);
|
|
|
|
|
if (kernel_camera.shuttertime != -1.0f) {
|
|
|
|
|
vector<float> shutter_table;
|
2024-12-26 17:53:55 +01:00
|
|
|
util_cdf_inverted(
|
|
|
|
|
SHUTTER_TABLE_SIZE,
|
|
|
|
|
0.0f,
|
|
|
|
|
1.0f,
|
2025-01-01 18:15:54 +01:00
|
|
|
[this](const float x) { return shutter_curve_eval(x, shutter_curve); },
|
2024-12-26 17:53:55 +01:00
|
|
|
false,
|
|
|
|
|
shutter_table);
|
2018-01-12 20:22:55 +01:00
|
|
|
shutter_table_offset = scene->lookup_tables->add_table(dscene, shutter_table);
|
|
|
|
|
kernel_camera.shutter_table_offset = (int)shutter_table_offset;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 20:22:55 +01:00
|
|
|
dscene->data.cam = kernel_camera;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const size_t num_motion_steps = kernel_camera_motion.size();
|
2018-03-10 01:36:09 +01:00
|
|
|
if (num_motion_steps) {
|
|
|
|
|
DecomposedTransform *camera_motion = dscene->camera_motion.alloc(num_motion_steps);
|
2024-12-27 21:50:31 +01:00
|
|
|
std::copy_n(kernel_camera_motion.data(), num_motion_steps, camera_motion);
|
2018-03-10 01:36:09 +01:00
|
|
|
dscene->camera_motion.copy_to_device();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
dscene->camera_motion.free();
|
|
|
|
|
}
|
2018-01-12 20:22:55 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-27 15:47:55 +05:00
|
|
|
void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scene *scene)
|
2015-02-02 22:06:31 +05:00
|
|
|
{
|
2015-05-14 19:08:13 +05:00
|
|
|
if (!need_device_update && !need_flags_update) {
|
2015-02-02 22:06:31 +05:00
|
|
|
return;
|
|
|
|
|
}
|
2020-07-10 11:49:52 +02:00
|
|
|
|
2025-04-09 19:33:57 +02:00
|
|
|
kernel_camera.is_inside_volume = 0;
|
|
|
|
|
|
2020-07-10 11:49:52 +02:00
|
|
|
KernelIntegrator *kintegrator = &dscene->data.integrator;
|
|
|
|
|
if (kintegrator->use_volumes) {
|
|
|
|
|
BoundBox viewplane_boundbox = viewplane_bounds_get();
|
|
|
|
|
|
|
|
|
|
/* Parallel object update, with grain size to avoid too much threading overhead
|
|
|
|
|
* for individual objects. */
|
|
|
|
|
static const int OBJECTS_PER_TASK = 32;
|
|
|
|
|
parallel_for(blocked_range<size_t>(0, scene->objects.size(), OBJECTS_PER_TASK),
|
|
|
|
|
[&](const blocked_range<size_t> &r) {
|
|
|
|
|
for (size_t i = r.begin(); i != r.end(); i++) {
|
|
|
|
|
Object *object = scene->objects[i];
|
2020-11-04 11:17:38 +01:00
|
|
|
if (object->get_geometry()->has_volume &&
|
2020-07-10 11:49:52 +02:00
|
|
|
viewplane_boundbox.intersects(object->bounds)) {
|
|
|
|
|
/* TODO(sergey): Consider adding more grained check. */
|
2022-06-16 19:39:13 +02:00
|
|
|
VLOG_INFO << "Detected camera inside volume.";
|
2025-04-09 19:33:57 +02:00
|
|
|
kernel_camera.is_inside_volume = 1;
|
2020-07-10 11:49:52 +02:00
|
|
|
parallel_for_cancel();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-04-09 19:33:57 +02:00
|
|
|
if (!kernel_camera.is_inside_volume) {
|
2022-06-16 19:39:13 +02:00
|
|
|
VLOG_INFO << "Camera is outside of the volume.";
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2014-09-16 23:49:59 +06:00
|
|
|
}
|
2020-07-10 11:49:52 +02:00
|
|
|
|
2025-04-09 19:33:57 +02:00
|
|
|
dscene->data.cam.is_inside_volume = kernel_camera.is_inside_volume;
|
|
|
|
|
|
2015-02-02 22:06:31 +05:00
|
|
|
need_device_update = false;
|
2015-05-14 19:08:13 +05:00
|
|
|
need_flags_update = false;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-27 13:16:04 +05:00
|
|
|
void Camera::device_free(Device * /*device*/, DeviceScene *dscene, Scene *scene)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-08 01:44:01 +02:00
|
|
|
scene->lookup_tables->remove_table(&shutter_table_offset);
|
2018-03-10 01:36:09 +01:00
|
|
|
dscene->camera_motion.free();
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 18:48:14 +02:00
|
|
|
float3 Camera::transform_full_raster_to_world(const float raster_x, const float raster_y)
|
2014-09-16 23:49:59 +06:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
float3 D;
|
|
|
|
|
float3 P;
|
2020-11-04 11:17:38 +01:00
|
|
|
if (camera_type == CAMERA_PERSPECTIVE) {
|
2025-04-09 18:48:14 +02:00
|
|
|
D = transform_perspective(&full_rastertocamera, make_float3(raster_x, raster_y, 0.0f));
|
2024-12-29 17:32:00 +01:00
|
|
|
const float3 Pclip = normalize(D);
|
2021-02-17 01:47:18 +01:00
|
|
|
P = zero_float3();
|
2014-09-16 23:49:59 +06:00
|
|
|
/* TODO(sergey): Aperture support? */
|
|
|
|
|
P = transform_point(&cameratoworld, P);
|
|
|
|
|
D = normalize(transform_direction(&cameratoworld, D));
|
|
|
|
|
/* TODO(sergey): Clipping is conditional in kernel, and hence it could
|
|
|
|
|
* be mistakes in here, currently leading to wrong camera-in-volume
|
|
|
|
|
* detection.
|
|
|
|
|
*/
|
2015-01-19 19:28:28 +05:00
|
|
|
P += nearclip * D / Pclip.z;
|
2014-09-16 23:49:59 +06:00
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
else if (camera_type == CAMERA_ORTHOGRAPHIC) {
|
2014-09-16 23:49:59 +06:00
|
|
|
D = make_float3(0.0f, 0.0f, 1.0f);
|
|
|
|
|
/* TODO(sergey): Aperture support? */
|
2025-04-09 18:48:14 +02:00
|
|
|
P = transform_perspective(&full_rastertocamera, make_float3(raster_x, raster_y, 0.0f));
|
2014-09-16 23:49:59 +06:00
|
|
|
P = transform_point(&cameratoworld, P);
|
|
|
|
|
D = normalize(transform_direction(&cameratoworld, D));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
assert(!"unsupported camera type");
|
|
|
|
|
}
|
|
|
|
|
return P;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BoundBox Camera::viewplane_bounds_get()
|
|
|
|
|
{
|
|
|
|
|
/* TODO(sergey): This is all rather stupid, but is there a way to perform
|
2019-08-11 22:41:04 +10:00
|
|
|
* checks we need in a more clear and smart fashion? */
|
2014-09-16 23:49:59 +06:00
|
|
|
BoundBox bounds = BoundBox::empty;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-06-18 17:35:16 +02:00
|
|
|
const float max_aperture_size = aperture_ratio < 1.0f ? aperturesize / aperture_ratio :
|
|
|
|
|
aperturesize;
|
|
|
|
|
|
2025-04-25 19:27:30 +02:00
|
|
|
if (camera_type == CAMERA_PANORAMA || camera_type == CAMERA_CUSTOM) {
|
2024-06-18 17:35:16 +02:00
|
|
|
const float extend = max_aperture_size + nearclip;
|
Multi-View: Cycles - Spherical Stereo support (VR Panoramas)
This is a new option for panorama cameras to render
stereo that can be used in virtual reality devices
The option is available under the camera panel when Multi-View is enabled (Views option in the Render Layers panel)
Known limitations:
------------------
* Parallel convergence is not supported (you need to set a convergence distance really high to simulate this effect).
* Pivot was not supposed to affect the render but it does, this has to be looked at, but for now set it to CENTER
* Derivatives in perspective camera need to be pre-computed or we shuld get rid of kcam->dx/dy (Sergey words, I don't fully grasp the implication shere)
* This works in perspective mode and in panorama mode. However, for fully benefit from this effect in perspective mode you need to render a cube map. (there is an addon for this, developed separately, perhaps we could include it in master).
* We have no support for "neck distance" at the moment. This is supposed to help with objects at short distances.
* We have no support to rotate the "Up Axis" of the stereo plane. Meaning, we hardcode 0,0,1 as UP, and create the stereo pair related to that. (although we could take the camera local UP when rendering panoramas, this wouldn't work for perspective cameras.
* We have no support for interocular distance attenuation based on the proximity of the poles (which helps to reduce the pole rotation effect/artifact).
THIS NEEDS DOCS - both in 2.78 release log and the Blender manual.
Meanwhile you can read about it here: http://code.blender.org/2015/03/1451
This patch specifically dates from March 2015, as you can see in the code.blender.org post. Many thanks to all the reviewers, testers and minor sponsors who helped me maintain spherical-stereo for 1 year.
All that said, have fun with this. This feature was what got me started with Multi-View development (at the time what I was looking for was Fulldome stereo support, but the implementation is the same). In order to make this into Blender I had to make it aiming at a less-specic user-case Thus Multi-View started. (this was December 2012, during Siggraph Asia and a chat I had with Paul Bourke during the conference). I don't have the original patch anymore, but you can find a re-based version of it from March 2013, right before I start with the Multi-View project https://developer.blender.org/P332
Reviewers: sergey, dingto
Subscribers: #cycles
Differential Revision: https://developer.blender.org/D1223
2016-03-10 09:28:29 -03:00
|
|
|
if (use_spherical_stereo == false) {
|
2024-06-18 17:35:16 +02:00
|
|
|
bounds.grow(make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w), extend);
|
Multi-View: Cycles - Spherical Stereo support (VR Panoramas)
This is a new option for panorama cameras to render
stereo that can be used in virtual reality devices
The option is available under the camera panel when Multi-View is enabled (Views option in the Render Layers panel)
Known limitations:
------------------
* Parallel convergence is not supported (you need to set a convergence distance really high to simulate this effect).
* Pivot was not supposed to affect the render but it does, this has to be looked at, but for now set it to CENTER
* Derivatives in perspective camera need to be pre-computed or we shuld get rid of kcam->dx/dy (Sergey words, I don't fully grasp the implication shere)
* This works in perspective mode and in panorama mode. However, for fully benefit from this effect in perspective mode you need to render a cube map. (there is an addon for this, developed separately, perhaps we could include it in master).
* We have no support for "neck distance" at the moment. This is supposed to help with objects at short distances.
* We have no support to rotate the "Up Axis" of the stereo plane. Meaning, we hardcode 0,0,1 as UP, and create the stereo pair related to that. (although we could take the camera local UP when rendering panoramas, this wouldn't work for perspective cameras.
* We have no support for interocular distance attenuation based on the proximity of the poles (which helps to reduce the pole rotation effect/artifact).
THIS NEEDS DOCS - both in 2.78 release log and the Blender manual.
Meanwhile you can read about it here: http://code.blender.org/2015/03/1451
This patch specifically dates from March 2015, as you can see in the code.blender.org post. Many thanks to all the reviewers, testers and minor sponsors who helped me maintain spherical-stereo for 1 year.
All that said, have fun with this. This feature was what got me started with Multi-View development (at the time what I was looking for was Fulldome stereo support, but the implementation is the same). In order to make this into Blender I had to make it aiming at a less-specic user-case Thus Multi-View started. (this was December 2012, during Siggraph Asia and a chat I had with Paul Bourke during the conference). I don't have the original patch anymore, but you can find a re-based version of it from March 2013, right before I start with the Multi-View project https://developer.blender.org/P332
Reviewers: sergey, dingto
Subscribers: #cycles
Differential Revision: https://developer.blender.org/D1223
2016-03-10 09:28:29 -03:00
|
|
|
}
|
|
|
|
|
else {
|
2024-12-29 17:32:00 +01:00
|
|
|
const float half_eye_distance = interocular_distance * 0.5f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-10-28 21:42:20 +02:00
|
|
|
bounds.grow(
|
|
|
|
|
make_float3(cameratoworld.x.w + half_eye_distance, cameratoworld.y.w, cameratoworld.z.w),
|
2024-06-18 17:35:16 +02:00
|
|
|
extend);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-10-28 21:42:20 +02:00
|
|
|
bounds.grow(
|
|
|
|
|
make_float3(cameratoworld.z.w, cameratoworld.y.w + half_eye_distance, cameratoworld.z.w),
|
2024-06-18 17:35:16 +02:00
|
|
|
extend);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-10-28 21:42:20 +02:00
|
|
|
bounds.grow(
|
|
|
|
|
make_float3(cameratoworld.x.w - half_eye_distance, cameratoworld.y.w, cameratoworld.z.w),
|
2024-06-18 17:35:16 +02:00
|
|
|
extend);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-10-28 21:42:20 +02:00
|
|
|
bounds.grow(
|
|
|
|
|
make_float3(cameratoworld.x.w, cameratoworld.y.w - half_eye_distance, cameratoworld.z.w),
|
2024-06-18 17:35:16 +02:00
|
|
|
extend);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
Multi-View: Cycles - Spherical Stereo support (VR Panoramas)
This is a new option for panorama cameras to render
stereo that can be used in virtual reality devices
The option is available under the camera panel when Multi-View is enabled (Views option in the Render Layers panel)
Known limitations:
------------------
* Parallel convergence is not supported (you need to set a convergence distance really high to simulate this effect).
* Pivot was not supposed to affect the render but it does, this has to be looked at, but for now set it to CENTER
* Derivatives in perspective camera need to be pre-computed or we shuld get rid of kcam->dx/dy (Sergey words, I don't fully grasp the implication shere)
* This works in perspective mode and in panorama mode. However, for fully benefit from this effect in perspective mode you need to render a cube map. (there is an addon for this, developed separately, perhaps we could include it in master).
* We have no support for "neck distance" at the moment. This is supposed to help with objects at short distances.
* We have no support to rotate the "Up Axis" of the stereo plane. Meaning, we hardcode 0,0,1 as UP, and create the stereo pair related to that. (although we could take the camera local UP when rendering panoramas, this wouldn't work for perspective cameras.
* We have no support for interocular distance attenuation based on the proximity of the poles (which helps to reduce the pole rotation effect/artifact).
THIS NEEDS DOCS - both in 2.78 release log and the Blender manual.
Meanwhile you can read about it here: http://code.blender.org/2015/03/1451
This patch specifically dates from March 2015, as you can see in the code.blender.org post. Many thanks to all the reviewers, testers and minor sponsors who helped me maintain spherical-stereo for 1 year.
All that said, have fun with this. This feature was what got me started with Multi-View development (at the time what I was looking for was Fulldome stereo support, but the implementation is the same). In order to make this into Blender I had to make it aiming at a less-specic user-case Thus Multi-View started. (this was December 2012, during Siggraph Asia and a chat I had with Paul Bourke during the conference). I don't have the original patch anymore, but you can find a re-based version of it from March 2013, right before I start with the Multi-View project https://developer.blender.org/P332
Reviewers: sergey, dingto
Subscribers: #cycles
Differential Revision: https://developer.blender.org/D1223
2016-03-10 09:28:29 -03:00
|
|
|
}
|
2014-10-02 20:37:05 +02:00
|
|
|
else {
|
2024-06-18 17:35:16 +02:00
|
|
|
/* max_aperture_size = Max horizontal distance a ray travels from aperture edge to focus point.
|
|
|
|
|
* Scale that value based on the ratio between focaldistance and nearclip to figure out the
|
|
|
|
|
* horizontal distance the DOF ray will travel before reaching the nearclip plane, where it
|
|
|
|
|
* will start rendering from.
|
|
|
|
|
* In some cases (focus distance is close to camera, and nearclip plane is far from camera),
|
|
|
|
|
* this scaled value is larger than nearclip, in which case we add it to `extend` to extend the
|
|
|
|
|
* bounding box to account for these rays.
|
|
|
|
|
*
|
|
|
|
|
* ----------------- nearclip plane
|
|
|
|
|
* / scaled_horz_dof_ray, nearclip
|
|
|
|
|
* /
|
|
|
|
|
* /
|
2024-06-19 10:42:13 +02:00
|
|
|
* / max_aperture_size, focaldistance
|
2024-06-18 17:35:16 +02:00
|
|
|
* /|
|
|
|
|
|
* / |
|
|
|
|
|
* / |
|
|
|
|
|
* / |
|
|
|
|
|
* ------ max_aperture_size, 0
|
|
|
|
|
* 0, 0
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const float scaled_horz_dof_ray = (max_aperture_size > 0.0f) ?
|
|
|
|
|
max_aperture_size * (nearclip / focaldistance) :
|
|
|
|
|
0.0f;
|
|
|
|
|
const float extend = max_aperture_size + max(nearclip, scaled_horz_dof_ray);
|
|
|
|
|
|
2025-04-09 18:48:14 +02:00
|
|
|
bounds.grow(transform_full_raster_to_world(0.0f, 0.0f), extend);
|
|
|
|
|
bounds.grow(transform_full_raster_to_world(0.0f, (float)full_height), extend);
|
|
|
|
|
bounds.grow(transform_full_raster_to_world((float)full_width, (float)full_height), extend);
|
|
|
|
|
bounds.grow(transform_full_raster_to_world((float)full_width, 0.0f), extend);
|
2020-11-04 11:17:38 +01:00
|
|
|
if (camera_type == CAMERA_PERSPECTIVE) {
|
2015-04-13 22:08:51 +10:00
|
|
|
/* Center point has the most distance in local Z axis,
|
2014-10-02 20:37:05 +02:00
|
|
|
* use it to construct bounding box/
|
|
|
|
|
*/
|
2025-04-09 18:48:14 +02:00
|
|
|
bounds.grow(transform_full_raster_to_world(0.5f * full_width, 0.5f * full_height), extend);
|
2014-10-02 20:37:05 +02:00
|
|
|
}
|
2014-09-16 23:49:59 +06:00
|
|
|
}
|
|
|
|
|
return bounds;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
float Camera::world_to_raster_size(const float3 P)
|
2016-04-11 22:49:09 +02:00
|
|
|
{
|
2018-01-12 00:50:34 +01:00
|
|
|
float res = 1.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
if (camera_type == CAMERA_ORTHOGRAPHIC) {
|
2018-01-12 00:50:34 +01:00
|
|
|
res = min(len(full_dx), len(full_dy));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
if (offscreen_dicing_scale > 1.0f) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const float3 p = transform_point(&worldtocamera, P);
|
|
|
|
|
const float3 v1 = transform_perspective(&full_rastertocamera,
|
|
|
|
|
make_float3(full_width, full_height, 0.0f));
|
|
|
|
|
const float3 v2 = transform_perspective(&full_rastertocamera, zero_float3());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
/* Create point clamped to frustum */
|
|
|
|
|
float3 c;
|
2020-10-26 12:49:37 +01:00
|
|
|
c.x = max(v2.x, min(v1.x, p.x));
|
|
|
|
|
c.y = max(v2.y, min(v1.y, p.y));
|
2018-01-12 00:50:34 +01:00
|
|
|
c.z = max(0.0f, p.z);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-26 12:49:37 +01:00
|
|
|
/* Check right side */
|
|
|
|
|
float f_dist = len(p - c) / sqrtf((v1.x * v1.x + v1.y * v1.y) * 0.5f);
|
|
|
|
|
if (f_dist < 0.0f) {
|
|
|
|
|
/* Check left side */
|
|
|
|
|
f_dist = len(p - c) / sqrtf((v2.x * v2.x + v2.y * v2.y) * 0.5f);
|
|
|
|
|
}
|
2018-01-12 00:50:34 +01:00
|
|
|
if (f_dist > 0.0f) {
|
|
|
|
|
res += res * f_dist * (offscreen_dicing_scale - 1.0f);
|
|
|
|
|
}
|
2016-04-11 22:49:09 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
else if (camera_type == CAMERA_PERSPECTIVE) {
|
2016-04-11 22:49:09 +02:00
|
|
|
/* Calculate as if point is directly ahead of the camera. */
|
2024-12-29 17:32:00 +01:00
|
|
|
const float3 raster = make_float3(0.5f * full_width, 0.5f * full_height, 0.0f);
|
|
|
|
|
const float3 Pcamera = transform_perspective(&full_rastertocamera, raster);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-11 22:49:09 +02:00
|
|
|
/* dDdx */
|
2024-12-29 17:32:00 +01:00
|
|
|
const float3 Ddiff = transform_direction(&cameratoworld, Pcamera);
|
|
|
|
|
const float3 dx = len_squared(full_dx) < len_squared(full_dy) ? full_dx : full_dy;
|
|
|
|
|
const float3 dDdx = normalize(Ddiff + dx) - normalize(Ddiff);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-11 22:49:09 +02:00
|
|
|
/* dPdx */
|
2024-12-29 17:32:00 +01:00
|
|
|
const float dist = len(transform_point(&worldtocamera, P));
|
|
|
|
|
const float3 D = normalize(Ddiff);
|
2018-01-12 00:50:34 +01:00
|
|
|
res = len(dist * dDdx - dot(dist * dDdx, D) * D);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-01 21:14:11 +10:00
|
|
|
/* Decent approx distance to frustum
|
|
|
|
|
* (doesn't handle corners correctly, but not that big of a deal) */
|
2018-01-12 00:50:34 +01:00
|
|
|
float f_dist = 0.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
if (offscreen_dicing_scale > 1.0f) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const float3 p = transform_point(&worldtocamera, P);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
/* Distance from the four planes */
|
2024-12-29 17:32:00 +01:00
|
|
|
const float r = dot(p, frustum_right_normal);
|
|
|
|
|
const float t = dot(p, frustum_top_normal);
|
|
|
|
|
const float l = dot(p, frustum_left_normal);
|
|
|
|
|
const float b = dot(p, frustum_bottom_normal);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
if (r <= 0.0f && l <= 0.0f && t <= 0.0f && b <= 0.0f) {
|
|
|
|
|
/* Point is inside frustum */
|
|
|
|
|
f_dist = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
else if (r > 0.0f && l > 0.0f && t > 0.0f && b > 0.0f) {
|
|
|
|
|
/* Point is behind frustum */
|
|
|
|
|
f_dist = len(p);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Point may be behind or off to the side, need to check */
|
2024-12-29 17:32:00 +01:00
|
|
|
const float3 along_right = make_float3(
|
|
|
|
|
-frustum_right_normal.z, 0.0f, frustum_right_normal.x);
|
|
|
|
|
const float3 along_left = make_float3(frustum_left_normal.z, 0.0f, -frustum_left_normal.x);
|
|
|
|
|
const float3 along_top = make_float3(0.0f, -frustum_top_normal.z, frustum_top_normal.y);
|
|
|
|
|
const float3 along_bottom = make_float3(
|
|
|
|
|
0.0f, frustum_bottom_normal.z, -frustum_bottom_normal.y);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
float dist[] = {r, l, t, b};
|
|
|
|
|
float3 along[] = {along_right, along_left, along_top, along_bottom};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
bool test_o = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
float *d = dist;
|
|
|
|
|
float3 *a = along;
|
|
|
|
|
for (int i = 0; i < 4; i++, d++, a++) {
|
|
|
|
|
/* Test if we should check this side at all */
|
|
|
|
|
if (*d > 0.0f) {
|
|
|
|
|
if (dot(p, *a) >= 0.0f) {
|
|
|
|
|
/* We are in front of the back edge of this side of the frustum */
|
|
|
|
|
f_dist = max(f_dist, *d);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2019-05-01 21:14:11 +10:00
|
|
|
/* Possibly far enough behind the frustum to use distance to origin instead of edge
|
|
|
|
|
*/
|
2018-01-12 00:50:34 +01:00
|
|
|
test_o = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
if (test_o) {
|
|
|
|
|
f_dist = (f_dist > 0) ? min(f_dist, len(p)) : len(p);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
if (f_dist > 0.0f) {
|
|
|
|
|
res += len(dDdx - dot(dDdx, D) * D) * f_dist * (offscreen_dicing_scale - 1.0f);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-11 22:49:09 +02:00
|
|
|
}
|
2025-04-25 19:27:30 +02:00
|
|
|
else if (camera_type == CAMERA_PANORAMA || camera_type == CAMERA_CUSTOM) {
|
2024-12-29 17:32:00 +01:00
|
|
|
const float3 D = transform_point(&worldtocamera, P);
|
|
|
|
|
const float dist = len(D);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-27 21:50:31 +01:00
|
|
|
Ray ray = {};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-12 02:14:27 +01:00
|
|
|
/* Distortion can become so great that the results become meaningless, there
|
|
|
|
|
* may be a better way to do this, but calculating differentials from the
|
|
|
|
|
* point directly ahead seems to produce good enough results. */
|
2025-04-25 19:27:30 +02:00
|
|
|
if (camera_type == CAMERA_CUSTOM) {
|
|
|
|
|
camera_sample_custom(nullptr,
|
|
|
|
|
&kernel_camera,
|
|
|
|
|
kernel_camera_motion.data(),
|
|
|
|
|
0.5f * make_float2(full_width, full_height),
|
|
|
|
|
zero_float2(),
|
|
|
|
|
&ray);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2018-01-12 02:14:27 +01:00
|
|
|
#if 0
|
2025-04-25 19:27:30 +02:00
|
|
|
float2 dir = direction_to_panorama(&kernel_camera, kernel_camera_motion.data(), normalize(D));
|
|
|
|
|
float3 raster = transform_perspective(&full_cameratoraster, make_float3(dir.x, dir.y, 0.0f));
|
|
|
|
|
|
|
|
|
|
ray.t = 1.0f;
|
|
|
|
|
camera_sample_panorama(
|
|
|
|
|
&kernel_camera, kernel_camera_motion.data(), raster.x, raster.y, 0.0f, 0.0f, &ray);
|
|
|
|
|
if (ray.t == 0.0f) {
|
|
|
|
|
/* No differentials, just use from directly ahead. */
|
|
|
|
|
camera_sample_panorama(&kernel_camera,
|
|
|
|
|
kernel_camera_motion.data(),
|
|
|
|
|
0.5f * make_float2(full_width, full_height),
|
|
|
|
|
zero_float2(),
|
|
|
|
|
&ray);
|
|
|
|
|
}
|
|
|
|
|
#else
|
2019-04-17 08:16:53 +02:00
|
|
|
camera_sample_panorama(&kernel_camera,
|
|
|
|
|
kernel_camera_motion.data(),
|
2023-05-24 18:56:58 +02:00
|
|
|
0.5f * make_float2(full_width, full_height),
|
|
|
|
|
zero_float2(),
|
2019-04-17 08:16:53 +02:00
|
|
|
&ray);
|
2018-01-12 02:14:27 +01:00
|
|
|
#endif
|
2025-04-25 19:27:30 +02:00
|
|
|
}
|
2018-01-12 02:14:27 +01:00
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
/* TODO: would it help to use more accurate differentials here? */
|
2022-08-11 16:53:11 +02:00
|
|
|
return differential_transfer_compact(ray.dP, ray.D, ray.dD, dist);
|
2016-04-11 22:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
2018-01-12 00:50:34 +01:00
|
|
|
return res;
|
2016-04-11 22:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
2018-03-10 01:36:09 +01:00
|
|
|
bool Camera::use_motion() const
|
|
|
|
|
{
|
|
|
|
|
return motion.size() > 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-09 19:33:57 +02:00
|
|
|
bool Camera::set_screen_size(const int width_, int height_)
|
2020-11-04 11:17:38 +01:00
|
|
|
{
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
if (width_ != width || height_ != height) {
|
2020-11-04 11:17:38 +01:00
|
|
|
width = width_;
|
|
|
|
|
height = height_;
|
|
|
|
|
tag_modified();
|
2025-04-09 19:33:57 +02:00
|
|
|
return true;
|
2020-11-04 11:17:38 +01:00
|
|
|
}
|
2025-04-09 19:33:57 +02:00
|
|
|
|
|
|
|
|
return false;
|
2020-11-04 11:17:38 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
float Camera::motion_time(const int step) const
|
2018-03-10 01:36:09 +01:00
|
|
|
{
|
|
|
|
|
return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
int Camera::motion_step(const float time) const
|
2018-03-10 01:36:09 +01:00
|
|
|
{
|
|
|
|
|
if (use_motion()) {
|
|
|
|
|
for (int step = 0; step < motion.size(); step++) {
|
|
|
|
|
if (time == motion_time(step)) {
|
|
|
|
|
return step;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-10 01:36:09 +01:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-25 19:27:30 +02:00
|
|
|
void Camera::set_osl_camera(Scene *scene,
|
|
|
|
|
OSLCameraParamQuery ¶ms,
|
|
|
|
|
const std::string &filepath,
|
|
|
|
|
const std::string &bytecode_hash,
|
|
|
|
|
const std::string &bytecode)
|
|
|
|
|
{
|
|
|
|
|
#ifdef WITH_OSL
|
|
|
|
|
/* Load the shader. */
|
|
|
|
|
const char *hash;
|
|
|
|
|
|
|
|
|
|
if (!filepath.empty()) {
|
|
|
|
|
hash = scene->osl_manager->shader_load_filepath(filepath);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
hash = scene->osl_manager->shader_test_loaded(bytecode_hash);
|
|
|
|
|
if (!hash)
|
|
|
|
|
hash = scene->osl_manager->shader_load_bytecode(bytecode_hash, bytecode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool changed = false;
|
|
|
|
|
|
|
|
|
|
if (!hash) {
|
|
|
|
|
changed = (!script_name.empty() || !script_params.empty());
|
|
|
|
|
script_name = "";
|
|
|
|
|
script_params.clear();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
changed = (script_name != hash);
|
|
|
|
|
script_name = hash;
|
|
|
|
|
|
|
|
|
|
OSLShaderInfo *info = scene->osl_manager->shader_loaded_info(hash);
|
|
|
|
|
|
|
|
|
|
/* Fetch parameter values. */
|
|
|
|
|
std::set<ustring> used_params;
|
|
|
|
|
for (int i = 0; i < info->query.nparams(); i++) {
|
|
|
|
|
const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
|
|
|
|
|
|
|
|
|
|
/* Skip unsupported types. */
|
|
|
|
|
if (param->varlenarray || param->isstruct || param->type.arraylen > 1 || param->isoutput ||
|
|
|
|
|
param->isclosure)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
vector<uint8_t> raw_data;
|
|
|
|
|
int vec_size = (int)param->type.aggregate;
|
|
|
|
|
if (param->type.basetype == TypeDesc::INT) {
|
|
|
|
|
vector<int> data;
|
|
|
|
|
if (!params.get_int(param->name, data) || data.size() != vec_size)
|
|
|
|
|
continue;
|
|
|
|
|
raw_data.resize(sizeof(int) * vec_size);
|
|
|
|
|
memcpy(raw_data.data(), data.data(), sizeof(int) * vec_size);
|
|
|
|
|
}
|
|
|
|
|
else if (param->type.basetype == TypeDesc::FLOAT) {
|
|
|
|
|
vector<float> data;
|
|
|
|
|
if (!params.get_float(param->name, data) || data.size() != vec_size)
|
|
|
|
|
continue;
|
|
|
|
|
raw_data.resize(sizeof(float) * vec_size);
|
|
|
|
|
memcpy(raw_data.data(), data.data(), sizeof(float) * vec_size);
|
|
|
|
|
}
|
|
|
|
|
else if (param->type.basetype == TypeDesc::STRING) {
|
|
|
|
|
string data;
|
|
|
|
|
if (!params.get_string(param->name, data))
|
|
|
|
|
continue;
|
|
|
|
|
raw_data.resize(data.length() + 1);
|
|
|
|
|
memcpy(raw_data.data(), data.c_str(), data.length() + 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto entry = std::make_pair(raw_data, param->type);
|
|
|
|
|
auto it = script_params.find(param->name);
|
|
|
|
|
if (it == script_params.end()) {
|
|
|
|
|
script_params[param->name] = entry;
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
else if (it->second != entry) {
|
|
|
|
|
it->second = entry;
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
used_params.insert(param->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Remove unused parameters. */
|
|
|
|
|
for (auto it = script_params.begin(); it != script_params.end();) {
|
|
|
|
|
if (used_params.count(it->first))
|
|
|
|
|
it++;
|
|
|
|
|
else {
|
|
|
|
|
it = script_params.erase(it);
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (changed) {
|
|
|
|
|
tag_modified();
|
|
|
|
|
scene->osl_manager->tag_update();
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
(void)scene;
|
|
|
|
|
(void)params;
|
|
|
|
|
(void)filepath;
|
|
|
|
|
(void)bytecode_hash;
|
|
|
|
|
(void)bytecode;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Camera::clear_osl_camera(Scene *scene)
|
|
|
|
|
{
|
|
|
|
|
#ifdef WITH_OSL
|
|
|
|
|
if (script_name == "") {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
script_name = "";
|
|
|
|
|
script_params.clear();
|
|
|
|
|
|
|
|
|
|
scene->osl_manager->tag_update();
|
|
|
|
|
#else
|
|
|
|
|
(void)scene;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint Camera::get_kernel_features() const
|
|
|
|
|
{
|
|
|
|
|
uint kernel_features = 0;
|
|
|
|
|
|
|
|
|
|
if (!script_name.empty()) {
|
|
|
|
|
kernel_features |= KERNEL_FEATURE_OSL_CAMERA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return kernel_features;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-27 21:36:14 +05:00
|
|
|
CCL_NAMESPACE_END
|