Blender V4.5
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 if (isnan(data.winmat.w.x)) {
163 /* Can happen in weird corner case (see #134320).
164 * Simply fall back to something that we can render with. */
165 data.winmat = math::projection::orthographic(0.01f, 0.01f, 0.01f, 0.01f, -1000.0f, +1000.0f);
166 }
167 }
168 else if (inst_.render) {
169 const Render *re = inst_.render->re;
170
171 RE_GetCameraWindow(inst_.render->re, camera_eval, data.winmat.ptr());
172
173 RE_GetCameraModelMatrix(re, camera_eval, data.viewinv.ptr());
174 data.viewmat = math::invert(data.viewinv);
175
176 rctf viewplane = re->viewplane;
177 BKE_camera_params_crop_viewplane(&viewplane, UNPACK2(display_extent), &film_rect);
178
180 re->clip_start,
181 re->clip_end,
182 viewplane,
183 overscan_,
184 data.winmat.ptr());
185 }
186 else {
187 data.viewmat = float4x4::identity();
188 data.viewinv = float4x4::identity();
189 data.winmat = math::projection::perspective(-0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1.0f);
190 }
191
192 data.wininv = math::invert(data.winmat);
193 data.persmat = data.winmat * data.viewmat;
194 data.persinv = math::invert(data.persmat);
195
196 is_camera_object_ = false;
197 if (camera_eval && camera_eval->type == OB_CAMERA) {
198 const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data);
199 data.clip_near = cam->clip_start;
200 data.clip_far = cam->clip_end;
201#if 0 /* TODO(fclem): Make fisheye properties inside blender. */
202 data.fisheye_fov = cam->fisheye_fov;
203 data.fisheye_lens = cam->fisheye_lens;
204 data.equirect_bias.x = -cam->longitude_min + M_PI_2;
205 data.equirect_bias.y = -cam->latitude_min + M_PI_2;
206 data.equirect_scale.x = cam->longitude_min - cam->longitude_max;
207 data.equirect_scale.y = cam->latitude_min - cam->latitude_max;
208 /* Combine with uv_scale/bias to avoid doing extra computation. */
209 data.equirect_bias += data.uv_bias * data.equirect_scale;
210 data.equirect_scale *= data.uv_scale;
211
212 data.equirect_scale_inv = 1.0f / data.equirect_scale;
213#else
214 data.fisheye_fov = data.fisheye_lens = -1.0f;
215 data.equirect_bias = float2(0.0f);
216 data.equirect_scale = float2(0.0f);
217#endif
218 is_camera_object_ = true;
219 }
220 else if (inst_.drw_view) {
221 /* \note Follow camera parameters where distances are positive in front of the camera. */
222 data.clip_near = -inst_.drw_view->near_clip();
223 data.clip_far = -inst_.drw_view->far_clip();
224 data.fisheye_fov = data.fisheye_lens = -1.0f;
225 data.equirect_bias = float2(0.0f);
226 data.equirect_scale = float2(0.0f);
227 }
228
229 data_.initialized = true;
230
231 update_bounds();
232}
233
234void Camera::update_bounds()
235{
236 float left, right, bottom, top, near, far;
237 projmat_dimensions(data_.winmat.ptr(), &left, &right, &bottom, &top, &near, &far);
238
239 BoundBox bbox;
240 bbox.vec[0][2] = bbox.vec[3][2] = bbox.vec[7][2] = bbox.vec[4][2] = -near;
241 bbox.vec[0][0] = bbox.vec[3][0] = left;
242 bbox.vec[4][0] = bbox.vec[7][0] = right;
243 bbox.vec[0][1] = bbox.vec[4][1] = bottom;
244 bbox.vec[7][1] = bbox.vec[3][1] = top;
245
246 /* Get the coordinates of the far plane. */
247 if (!this->is_orthographic()) {
248 float sca_far = far / near;
249 left *= sca_far;
250 right *= sca_far;
251 bottom *= sca_far;
252 top *= sca_far;
253 }
254
255 bbox.vec[1][2] = bbox.vec[2][2] = bbox.vec[6][2] = bbox.vec[5][2] = -far;
256 bbox.vec[1][0] = bbox.vec[2][0] = left;
257 bbox.vec[6][0] = bbox.vec[5][0] = right;
258 bbox.vec[1][1] = bbox.vec[5][1] = bottom;
259 bbox.vec[2][1] = bbox.vec[6][1] = top;
260
261 bound_sphere.center = {0.0f, 0.0f, 0.0f};
262 bound_sphere.radius = 0.0f;
263
264 for (auto i : IndexRange(8)) {
265 bound_sphere.center += float3(bbox.vec[i]);
266 }
267 bound_sphere.center /= 8.0f;
268 for (auto i : IndexRange(8)) {
269 float dist_sqr = math::distance_squared(bound_sphere.center, float3(bbox.vec[i]));
270 bound_sphere.radius = max_ff(bound_sphere.radius, dist_sqr);
271 }
272 bound_sphere.radius = sqrtf(bound_sphere.radius);
273
274 /* Transform into world space. */
275 bound_sphere.center = math::transform_point(data_.viewinv, bound_sphere.center);
276
277 /* Compute diagonal length. */
278 float2 p0 = float2(bbox.vec[0]) / (this->is_perspective() ? bbox.vec[0][2] : 1.0f);
279 float2 p1 = float2(bbox.vec[7]) / (this->is_perspective() ? bbox.vec[7][2] : 1.0f);
281}
282
283CameraParams Camera::v3d_camera_params_get() const
284{
285 BLI_assert(inst_.drw_view);
286
289
290 if (inst_.rv3d->persp == RV3D_CAMOB && inst_.is_viewport_image_render) {
291 /* We are rendering camera view, no need for pan/zoom params from viewport. */
293 }
294 else {
296 }
297
298 return params;
299}
300
302
303} // 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
#define sqrtf(x)
uint top
#define isnan
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
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