Blender V5.0
eevee_camera.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_bounds.hh"
10#include "BLI_rect.h"
11
12#include "DRW_render.hh"
13
14#include "DNA_camera_types.h"
15#include "DNA_view3d_types.h"
16
17#include "RE_engine.h"
18#include "RE_pipeline.h"
19#include "render_types.h"
20
21#include "eevee_camera.hh"
22#include "eevee_instance.hh"
23
24namespace blender::eevee {
25
26/* -------------------------------------------------------------------- */
29
30void Camera::init()
31{
32 const Object *camera_eval = inst_.camera_eval_object;
33
34 CameraData &data = data_;
35
36 if (camera_eval && camera_eval->type == OB_CAMERA) {
37 const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data);
38 switch (cam->type) {
39 default:
40 case CAM_PERSP:
41 data.type = CAMERA_PERSP;
42 break;
43 case CAM_ORTHO:
44 data.type = CAMERA_ORTHO;
45 break;
46#if 0 /* TODO(fclem): Make fisheye properties inside blender. */
47 case CAM_PANO: {
48 switch (cam->panorama_type) {
49 default:
50 case CAM_PANO_EQUIRECTANGULAR:
52 break;
53 case CAM_PANO_FISHEYE_EQUIDISTANT:
55 break;
56 case CAM_PANO_FISHEYE_EQUISOLID:
58 break;
59 case CAM_PANO_MIRRORBALL:
61 break;
62 }
63 }
64#endif
65 }
66 }
67 else if (inst_.drw_view) {
68 data.type = inst_.drw_view->is_persp() ? CAMERA_PERSP : CAMERA_ORTHO;
69 }
70 else {
71 /* Light-probe baking. */
72 data.type = CAMERA_PERSP;
73 }
74
75 float overscan = 0.0f;
76 if ((inst_.scene->eevee.flag & SCE_EEVEE_OVERSCAN) && (inst_.drw_view || inst_.render)) {
77 overscan = inst_.scene->eevee.overscan / 100.0f;
78 if (inst_.drw_view && (inst_.rv3d->dist == 0.0f || v3d_camera_params_get().lens == 0.0f)) {
79 /* In these cases we need to use the v3d winmat as-is. */
80 overscan = 0.0f;
81 }
82 }
83 overscan_changed_ = assign_if_different(overscan_, overscan);
84 camera_changed_ = assign_if_different(last_camera_object_, inst_.camera_orig_object);
85}
86
87void Camera::sync()
88{
89 const Object *camera_eval = inst_.camera_eval_object;
90
91 CameraData &data = data_;
92
93 int2 display_extent = inst_.film.display_extent_get();
94 int2 film_extent = inst_.film.film_extent_get();
95 int2 film_offset = inst_.film.film_offset_get();
96 /* Over-scan in film pixel. Not the same as `render_overscan_get`. */
97 int film_overscan = Film::overscan_pixels_get(overscan_, film_extent);
98
99 rcti film_rect;
100 BLI_rcti_init(&film_rect,
101 film_offset.x,
102 film_offset.x + film_extent.x,
103 film_offset.y,
104 film_offset.y + film_extent.y);
105
106 Bounds<float2> uv_region = {float2(0.0f), float2(display_extent)};
107 if (inst_.drw_view) {
108 float2 uv_scale = float4(inst_.rv3d->viewcamtexcofac).xy();
109 float2 uv_bias = float4(inst_.rv3d->viewcamtexcofac).zw();
110 /* UV region inside the display extent reference frame. */
111 uv_region.min = (-uv_bias * float2(display_extent)) / uv_scale;
112 uv_region.max = uv_region.min + (float2(display_extent) / uv_scale);
113 }
114
115 data.uv_scale = float2(film_extent + film_overscan * 2) / uv_region.size();
116 data.uv_bias = (float2(film_offset - film_overscan) - uv_region.min) / uv_region.size();
117
118 if (inst_.is_baking()) {
119 /* Any view so that shadows and light culling works during irradiance bake. */
120 draw::View &view = inst_.volume_probes.bake.view_z_;
121 data.viewmat = view.viewmat();
122 data.viewinv = view.viewinv();
123 data.winmat = view.winmat();
124 data.type = CAMERA_ORTHO;
125
126 /* \note Follow camera parameters where distances are positive in front of the camera. */
127 data.clip_near = -view.far_clip();
128 data.clip_far = -view.near_clip();
129 data.fisheye_fov = data.fisheye_lens = -1.0f;
130 data.equirect_bias = float2(0.0f);
131 data.equirect_scale = float2(0.0f);
132 data.uv_scale = float2(1.0f);
133 data.uv_bias = float2(0.0f);
134 }
135 else if (inst_.drw_view) {
136 data.viewmat = inst_.drw_view->viewmat();
137 data.viewinv = inst_.drw_view->viewinv();
138
139 CameraParams params = v3d_camera_params_get();
140
141 if (inst_.rv3d->dist > 0.0f && params.lens > 0.0f) {
142 BKE_camera_params_compute_viewplane(&params, UNPACK2(display_extent), 1.0f, 1.0f);
143
144 BLI_assert(BLI_rctf_size_x(&params.viewplane) > 0.0f);
145 BLI_assert(BLI_rctf_size_y(&params.viewplane) > 0.0f);
146
147 BKE_camera_params_crop_viewplane(&params.viewplane, UNPACK2(display_extent), &film_rect);
148
150 params.clip_start,
151 params.clip_end,
152 params.viewplane,
153 overscan_,
154 data.winmat.ptr());
155 }
156 else {
157 /* Can happen for the case of XR or if `rv3d->dist == 0`.
158 * In this case the produced winmat is degenerate. So just revert to the input matrix. */
159 data.winmat = inst_.drw_view->winmat();
160 }
161 }
162 else if (inst_.render) {
163 const Render *re = inst_.render->re;
164
165 RE_GetCameraWindow(inst_.render->re, camera_eval, data.winmat.ptr());
166
167 RE_GetCameraModelMatrix(re, camera_eval, data.viewinv.ptr());
168 data.viewmat = math::invert(data.viewinv);
169
170 rctf viewplane = re->viewplane;
171 BKE_camera_params_crop_viewplane(&viewplane, UNPACK2(display_extent), &film_rect);
172
174 re->clip_start,
175 re->clip_end,
176 viewplane,
177 overscan_,
178 data.winmat.ptr());
179 }
180 else {
181 data.viewmat = float4x4::identity();
182 data.viewinv = float4x4::identity();
183 data.winmat = math::projection::perspective(-0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1.0f);
184 }
185
186 /* Compute a part of the frustrum planes. In some cases (#134320, #148258)
187 * the window matrix becomes degenerate during render or draw_view.
188 * Simply fall back to something we can render with. */
189 float bottom = (-data.winmat[3][1] - 1.f) / data.winmat[1][1];
190 if (std::isnan(bottom) || std::isinf(std::abs(bottom))) {
191 data.winmat = math::projection::orthographic(0.01f, 0.01f, 0.01f, 0.01f, -1000.0f, +1000.0f);
192 }
193
194 data.wininv = math::invert(data.winmat);
195 data.persmat = data.winmat * data.viewmat;
196 data.persinv = math::invert(data.persmat);
197
198 is_camera_object_ = false;
199 if (camera_eval && camera_eval->type == OB_CAMERA) {
200 const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data);
201 data.clip_near = cam->clip_start;
202 data.clip_far = cam->clip_end;
203#if 0 /* TODO(fclem): Make fisheye properties inside blender. */
204 data.fisheye_fov = cam->fisheye_fov;
205 data.fisheye_lens = cam->fisheye_lens;
206 data.equirect_bias.x = -cam->longitude_min + M_PI_2;
207 data.equirect_bias.y = -cam->latitude_min + M_PI_2;
208 data.equirect_scale.x = cam->longitude_min - cam->longitude_max;
209 data.equirect_scale.y = cam->latitude_min - cam->latitude_max;
210 /* Combine with uv_scale/bias to avoid doing extra computation. */
211 data.equirect_bias += data.uv_bias * data.equirect_scale;
212 data.equirect_scale *= data.uv_scale;
213
214 data.equirect_scale_inv = 1.0f / data.equirect_scale;
215#else
216 data.fisheye_fov = data.fisheye_lens = -1.0f;
217 data.equirect_bias = float2(0.0f);
218 data.equirect_scale = float2(0.0f);
219#endif
220 is_camera_object_ = true;
221 }
222 else if (inst_.drw_view) {
223 /* \note Follow camera parameters where distances are positive in front of the camera. */
224 data.clip_near = -inst_.drw_view->near_clip();
225 data.clip_far = -inst_.drw_view->far_clip();
226 data.fisheye_fov = data.fisheye_lens = -1.0f;
227 data.equirect_bias = float2(0.0f);
228 data.equirect_scale = float2(0.0f);
229 }
230
231 data_.initialized = true;
232
233 update_bounds();
234}
235
236void Camera::update_bounds()
237{
238 float left, right, bottom, top, near, far;
239 projmat_dimensions(data_.winmat.ptr(), &left, &right, &bottom, &top, &near, &far);
240
241 BoundBox bbox;
242 bbox.vec[0][2] = bbox.vec[3][2] = bbox.vec[7][2] = bbox.vec[4][2] = -near;
243 bbox.vec[0][0] = bbox.vec[3][0] = left;
244 bbox.vec[4][0] = bbox.vec[7][0] = right;
245 bbox.vec[0][1] = bbox.vec[4][1] = bottom;
246 bbox.vec[7][1] = bbox.vec[3][1] = top;
247
248 /* Get the coordinates of the far plane. */
249 if (!this->is_orthographic()) {
250 float sca_far = far / near;
251 left *= sca_far;
252 right *= sca_far;
253 bottom *= sca_far;
254 top *= sca_far;
255 }
256
257 bbox.vec[1][2] = bbox.vec[2][2] = bbox.vec[6][2] = bbox.vec[5][2] = -far;
258 bbox.vec[1][0] = bbox.vec[2][0] = left;
259 bbox.vec[6][0] = bbox.vec[5][0] = right;
260 bbox.vec[1][1] = bbox.vec[5][1] = bottom;
261 bbox.vec[2][1] = bbox.vec[6][1] = top;
262
263 bound_sphere.center = {0.0f, 0.0f, 0.0f};
264 bound_sphere.radius = 0.0f;
265
266 for (auto i : IndexRange(8)) {
267 bound_sphere.center += float3(bbox.vec[i]);
268 }
269 bound_sphere.center /= 8.0f;
270 for (auto i : IndexRange(8)) {
271 float dist_sqr = math::distance_squared(bound_sphere.center, float3(bbox.vec[i]));
272 bound_sphere.radius = max_ff(bound_sphere.radius, dist_sqr);
273 }
274 bound_sphere.radius = sqrtf(bound_sphere.radius);
275
276 /* Transform into world space. */
277 bound_sphere.center = math::transform_point(data_.viewinv, bound_sphere.center);
278
279 /* Compute diagonal length. */
280 float2 p0 = float2(bbox.vec[0]) / (this->is_perspective() ? bbox.vec[0][2] : 1.0f);
281 float2 p1 = float2(bbox.vec[7]) / (this->is_perspective() ? bbox.vec[7][2] : 1.0f);
283}
284
285CameraParams Camera::v3d_camera_params_get() const
286{
287 BLI_assert(inst_.drw_view);
288
291
292 if (inst_.rv3d->persp == RV3D_CAMOB && inst_.is_viewport_image_render) {
293 /* We are rendering camera view, no need for pan/zoom params from viewport. */
295 }
296 else {
298 }
299
300 return params;
301}
302
304
305} // namespace blender::eevee
void BKE_camera_params_init(CameraParams *params)
void BKE_camera_params_crop_viewplane(rctf *viewplane, int winx, int winy, const rcti *region)
void BKE_camera_params_from_view3d(CameraParams *params, const struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d)
void BKE_camera_params_from_object(CameraParams *params, const struct Object *cam_ob)
void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy)
struct CameraParams CameraParams
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE float max_ff(float a, float b)
#define M_PI_2
void projmat_dimensions(const float winmat[4][4], float *r_left, float *r_right, float *r_bottom, float *r_top, float *r_near, float *r_far)
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.cc:414
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
#define UNPACK2(a)
@ CAM_PERSP
@ CAM_PANO
@ CAM_ORTHO
@ OB_CAMERA
@ SCE_EEVEE_OVERSCAN
@ RV3D_CAMOB
static AppView * view
BMesh const char void * data
bool is_orthographic() const
Camera(Instance &inst, CameraData &data)
bool is_perspective() const
static int overscan_pixels_get(float overscan, int2 extent)
const RegionView3D * rv3d
uint top
void RE_GetCameraModelMatrix(const Render *re, const Object *camera, float r_modelmat[4][4])
void RE_GetCameraWindow(Render *re, const Object *camera, float r_winmat[4][4])
void RE_GetWindowMatrixWithOverscan(bool is_ortho, float clip_start, float clip_end, rctf viewplane, float overscan, float r_winmat[4][4])
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static int left
MatBase< T, 4, 4 > orthographic(T left, T right, T bottom, T top, T near_clip, T far_clip)
Create an orthographic projection matrix using OpenGL coordinate convention: Maps each axis range to ...
MatBase< T, 4, 4 > perspective(T left, T right, T bottom, T top, T near_clip, T far_clip)
Create a perspective projection matrix using OpenGL coordinate convention: Maps each axis range to [-...
T distance(const T &a, const T &b)
CartesianBasis invert(const CartesianBasis &basis)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
bool assign_if_different(T &old_value, T new_value)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
#define sqrtf
float vec[8][3]
float clip_start
float clip_end
rctf viewplane
const c_style_mat & ptr() const
VecBase< T, 2 > zw() const
VecBase< T, 2 > xy() const
i
Definition text_draw.cc:230