Blender V4.3
kernel/camera/camera.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
11
13
14/* Perspective Camera */
15
17{
18 float blades = cam->blades;
19 float2 bokeh;
20
21 if (blades == 0.0f) {
22 /* sample disk */
23 bokeh = sample_uniform_disk(rand);
24 }
25 else {
26 /* sample polygon */
27 float rotation = cam->bladesrotation;
28 bokeh = regular_polygon_sample(blades, rotation, rand);
29 }
30
31 /* anamorphic lens bokeh */
32 bokeh.x *= cam->inv_aperture_ratio;
33
34 return bokeh;
35}
36
38 const float2 raster_xy,
39 const float2 rand_lens,
40 ccl_private Ray *ray)
41{
42 /* create ray form raster position */
43 ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
44 const float3 raster = float2_to_float3(raster_xy);
45 float3 Pcamera = transform_perspective(&rastertocamera, raster);
46
47 if (kernel_data.cam.have_perspective_motion) {
48 /* TODO(sergey): Currently we interpolate projected coordinate which
49 * gives nice looking result and which is simple, but is in fact a bit
50 * different comparing to constructing projective matrix from an
51 * interpolated field of view.
52 */
53 if (ray->time < 0.5f) {
54 ProjectionTransform rastertocamera_pre = kernel_data.cam.perspective_pre;
55 float3 Pcamera_pre = transform_perspective(&rastertocamera_pre, raster);
56 Pcamera = interp(Pcamera_pre, Pcamera, ray->time * 2.0f);
57 }
58 else {
59 ProjectionTransform rastertocamera_post = kernel_data.cam.perspective_post;
60 float3 Pcamera_post = transform_perspective(&rastertocamera_post, raster);
61 Pcamera = interp(Pcamera, Pcamera_post, (ray->time - 0.5f) * 2.0f);
62 }
63 }
64
66 float3 D = Pcamera;
67
68 /* modify ray for depth of field */
69 float aperturesize = kernel_data.cam.aperturesize;
70
71 if (aperturesize > 0.0f) {
72 /* sample point on aperture */
73 float2 lens_uv = camera_sample_aperture(&kernel_data.cam, rand_lens) * aperturesize;
74
75 /* compute point on plane of focus */
76 float ft = kernel_data.cam.focaldistance / D.z;
77 float3 Pfocus = D * ft;
78
79 /* update ray for effect of lens */
80 P = float2_to_float3(lens_uv);
81 D = normalize(Pfocus - P);
82 }
83
84 /* transform ray from camera to world */
85 Transform cameratoworld = kernel_data.cam.cameratoworld;
86
87 if (kernel_data.cam.num_motion_steps) {
89 kernel_data_array(camera_motion),
90 kernel_data.cam.num_motion_steps,
91 ray->time);
92 }
93
94 P = transform_point(&cameratoworld, P);
95 D = normalize(transform_direction(&cameratoworld, D));
96
97 bool use_stereo = kernel_data.cam.interocular_offset != 0.0f;
98 if (!use_stereo) {
99 /* No stereo */
100 ray->P = P;
101 ray->D = D;
102
103#ifdef __RAY_DIFFERENTIALS__
104 float3 Dcenter = transform_direction(&cameratoworld, Pcamera);
105 float3 Dcenter_normalized = normalize(Dcenter);
106
107 /* TODO: can this be optimized to give compact differentials directly? */
108 ray->dP = differential_zero_compact();
109 differential3 dD;
110 dD.dx = normalize(Dcenter + float4_to_float3(kernel_data.cam.dx)) - Dcenter_normalized;
111 dD.dy = normalize(Dcenter + float4_to_float3(kernel_data.cam.dy)) - Dcenter_normalized;
112 ray->dD = differential_make_compact(dD);
113#endif
114 }
115 else {
116 /* Spherical stereo */
118 ray->P = P;
119 ray->D = D;
120
121#ifdef __RAY_DIFFERENTIALS__
122 /* Ray differentials, computed from scratch using the raster coordinates
123 * because we don't want to be affected by depth of field. We compute
124 * ray origin and direction for the center and two neighboring pixels
125 * and simply take their differences. */
126 float3 Pnostereo = transform_point(&cameratoworld, zero_float3());
127
128 float3 Pcenter = Pnostereo;
129 float3 Dcenter = Pcamera;
130 Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
131 spherical_stereo_transform(&kernel_data.cam, &Pcenter, &Dcenter);
132
133 float3 Px = Pnostereo;
134 float3 Dx = transform_perspective(&rastertocamera,
135 make_float3(raster.x + 1.0f, raster.y, 0.0f));
136 Dx = normalize(transform_direction(&cameratoworld, Dx));
138
139 differential3 dP, dD;
140
141 dP.dx = Px - Pcenter;
142 dD.dx = Dx - Dcenter;
143
144 float3 Py = Pnostereo;
145 float3 Dy = transform_perspective(&rastertocamera,
146 make_float3(raster.x, raster.y + 1.0f, 0.0f));
147 Dy = normalize(transform_direction(&cameratoworld, Dy));
149
150 dP.dy = Py - Pcenter;
151 dD.dy = Dy - Dcenter;
152 ray->dD = differential_make_compact(dD);
153 ray->dP = differential_make_compact(dP);
154#endif
155 }
156
157 /* clipping */
158 float z_inv = 1.0f / normalize(Pcamera).z;
159 float nearclip = kernel_data.cam.nearclip * z_inv;
160 ray->P += nearclip * ray->D;
161 ray->dP += nearclip * ray->dD;
162 ray->tmin = 0.0f;
163 ray->tmax = kernel_data.cam.cliplength * z_inv;
164}
165
166/* Orthographic Camera */
168 const float2 raster_xy,
169 const float2 rand_lens,
170 ccl_private Ray *ray)
171{
172 /* create ray form raster position */
173 ProjectionTransform rastertocamera = kernel_data.cam.rastertocamera;
174 float3 Pcamera = transform_perspective(&rastertocamera, float2_to_float3(raster_xy));
175
176 float3 P;
177 float3 D = make_float3(0.0f, 0.0f, 1.0f);
178
179 /* modify ray for depth of field */
180 float aperturesize = kernel_data.cam.aperturesize;
181
182 if (aperturesize > 0.0f) {
183 /* sample point on aperture */
184 float2 lens_uv = camera_sample_aperture(&kernel_data.cam, rand_lens) * aperturesize;
185
186 /* compute point on plane of focus */
187 float3 Pfocus = D * kernel_data.cam.focaldistance;
188
189 /* Update ray for effect of lens */
190 float3 lens_uvw = float2_to_float3(lens_uv);
191
192 D = normalize(Pfocus - lens_uvw);
193 /* Compute position the ray will be if it traveled until it intersected the near clip plane.
194 * This allows for correct DOF while allowing near clipping. */
195 P = Pcamera + lens_uvw + (D * (kernel_data.cam.nearclip / D.z));
196 }
197 else {
198 P = Pcamera + make_float3(0.0f, 0.0f, kernel_data.cam.nearclip);
199 }
200 /* transform ray from camera to world */
201 Transform cameratoworld = kernel_data.cam.cameratoworld;
202
203 if (kernel_data.cam.num_motion_steps) {
205 kernel_data_array(camera_motion),
206 kernel_data.cam.num_motion_steps,
207 ray->time);
208 }
209
210 ray->P = transform_point(&cameratoworld, P);
211 ray->D = normalize(transform_direction(&cameratoworld, D));
212
213#ifdef __RAY_DIFFERENTIALS__
214 /* ray differential */
215 differential3 dP;
216 dP.dx = float4_to_float3(kernel_data.cam.dx);
217 dP.dy = float4_to_float3(kernel_data.cam.dx);
218
219 ray->dP = differential_make_compact(dP);
220 ray->dD = differential_zero_compact();
221#endif
222
223 /* clipping */
224 ray->tmin = 0.0f;
225 ray->tmax = kernel_data.cam.cliplength;
226}
227
228/* Panorama Camera */
229
231 float x,
232 float y)
233{
234 const ProjectionTransform rastertocamera = cam->rastertocamera;
235 float3 Pcamera = transform_perspective(&rastertocamera, make_float3(x, y, 0.0f));
236 return panorama_to_direction(cam, Pcamera.x, Pcamera.y);
237}
238
240 ccl_global const DecomposedTransform *cam_motion,
241 const float2 raster,
242 const float2 rand_lens,
243 ccl_private Ray *ray)
244{
245 /* create ray form raster position */
246 float3 P = zero_float3();
247 float3 D = camera_panorama_direction(cam, raster.x, raster.y);
248
249 /* indicates ray should not receive any light, outside of the lens */
250 if (is_zero(D)) {
251 ray->tmax = 0.0f;
252 return;
253 }
254
255 /* modify ray for depth of field */
256 float aperturesize = cam->aperturesize;
257
258#ifdef __RAY_DIFFERENTIALS__
259 /* keep pre-DoF value for differentials later */
260 float3 Dcenter = D;
261#endif
262
263 if (aperturesize > 0.0f) {
264 /* sample point on aperture */
265 float2 lens_uv = camera_sample_aperture(cam, rand_lens) * aperturesize;
266
267 /* compute point on plane of focus */
268 float3 Dfocus = normalize(D);
269 float3 Pfocus = Dfocus * cam->focaldistance;
270
271 /* calculate orthonormal coordinates perpendicular to Dfocus */
272 float3 U, V;
273 U = normalize(make_float3(1.0f, 0.0f, 0.0f) - Dfocus.x * Dfocus);
274 V = normalize(cross(Dfocus, U));
275
276 /* update ray for effect of lens */
277 P = U * lens_uv.x + V * lens_uv.y;
278 D = normalize(Pfocus - P);
279 }
280
281 /* transform ray from camera to world */
282 Transform cameratoworld = cam->cameratoworld;
283
284 if (cam->num_motion_steps) {
286 &cameratoworld, cam_motion, cam->num_motion_steps, ray->time);
287 }
288
289 /* Stereo transform */
290 bool use_stereo = cam->interocular_offset != 0.0f;
291 if (use_stereo) {
292 spherical_stereo_transform(cam, &P, &D);
293 }
294
295 P = transform_point(&cameratoworld, P);
296 D = normalize(transform_direction(&cameratoworld, D));
297
298 ray->P = P;
299 ray->D = D;
300
301#ifdef __RAY_DIFFERENTIALS__
302 /* Ray differentials, computed from scratch using the raster coordinates
303 * because we don't want to be affected by depth of field. We compute
304 * ray origin and direction for the center and two neighboring pixels
305 * and simply take their differences. */
306 float3 Dx = camera_panorama_direction(cam, raster.x + 1.0f, raster.y);
307 float3 Dy = camera_panorama_direction(cam, raster.x, raster.y + 1.0f);
308
309 if (use_stereo) {
310 float3 Pcenter = zero_float3();
311 float3 Px = zero_float3();
312 float3 Py = zero_float3();
313 spherical_stereo_transform(cam, &Pcenter, &Dcenter);
314 spherical_stereo_transform(cam, &Px, &Dx);
315 spherical_stereo_transform(cam, &Py, &Dy);
316
317 differential3 dP;
318 Pcenter = transform_point(&cameratoworld, Pcenter);
319 dP.dx = transform_point(&cameratoworld, Px) - Pcenter;
320 dP.dy = transform_point(&cameratoworld, Py) - Pcenter;
321 ray->dP = differential_make_compact(dP);
322 }
323 else {
324 ray->dP = differential_zero_compact();
325 }
326
327 differential3 dD;
328 Dcenter = normalize(transform_direction(&cameratoworld, Dcenter));
329 dD.dx = normalize(transform_direction(&cameratoworld, Dx)) - Dcenter;
330 dD.dy = normalize(transform_direction(&cameratoworld, Dy)) - Dcenter;
331 ray->dD = differential_make_compact(dD);
332#endif
333
334 /* clipping */
335 float nearclip = cam->nearclip;
336 ray->P += nearclip * ray->D;
337 ray->dP += nearclip * ray->dD;
338 ray->tmin = 0.0f;
339 ray->tmax = cam->cliplength;
340}
341
342/* Common */
343
345 int x,
346 int y,
347 const float2 filter_uv,
348 const float time,
349 const float2 lens_uv,
350 ccl_private Ray *ray)
351{
352 /* pixel filter */
353 int filter_table_offset = kernel_data.tables.filter_table_offset;
354 const float2 raster = make_float2(
355 x + lookup_table_read(kg, filter_uv.x, filter_table_offset, FILTER_TABLE_SIZE),
356 y + lookup_table_read(kg, filter_uv.y, filter_table_offset, FILTER_TABLE_SIZE));
357
358 /* motion blur */
359 if (kernel_data.cam.shuttertime == -1.0f) {
360 ray->time = 0.5f;
361 }
362 else {
363 /* TODO(sergey): Such lookup is unneeded when there's rolling shutter
364 * effect in use but rolling shutter duration is set to 0.0.
365 */
366 const int shutter_table_offset = kernel_data.cam.shutter_table_offset;
367 ray->time = lookup_table_read(kg, time, shutter_table_offset, SHUTTER_TABLE_SIZE);
368 /* TODO(sergey): Currently single rolling shutter effect type only
369 * where scan-lines are acquired from top to bottom and whole scan-line
370 * is acquired at once (no delay in acquisition happens between pixels
371 * of single scan-line).
372 *
373 * Might want to support more models in the future.
374 */
375 if (kernel_data.cam.rolling_shutter_type) {
376 /* Time corresponding to a fully rolling shutter only effect:
377 * top of the frame is time 0.0, bottom of the frame is time 1.0.
378 */
379 const float time = 1.0f - (float)y / kernel_data.cam.height;
380 const float duration = kernel_data.cam.rolling_shutter_duration;
381 if (duration != 0.0f) {
382 /* This isn't fully physical correct, but lets us to have simple
383 * controls in the interface. The idea here is basically sort of
384 * linear interpolation between how much rolling shutter effect
385 * exist on the frame and how much of it is a motion blur effect.
386 */
387 ray->time = (ray->time - 0.5f) * duration;
388 ray->time += (time - 0.5f) * (1.0f - duration) + 0.5f;
389 }
390 else {
391 ray->time = time;
392 }
393 }
394 }
395
396 /* sample */
397 if (kernel_data.cam.type == CAMERA_PERSPECTIVE) {
398 camera_sample_perspective(kg, raster, lens_uv, ray);
399 }
400 else if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
401 camera_sample_orthographic(kg, raster, lens_uv, ray);
402 }
403 else {
404 ccl_global const DecomposedTransform *cam_motion = kernel_data_array(camera_motion);
405 camera_sample_panorama(&kernel_data.cam, cam_motion, raster, lens_uv, ray);
406 }
407}
408
409/* Utilities */
410
412{
413 Transform cameratoworld = kernel_data.cam.cameratoworld;
414 return make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
415}
416
418{
419 Transform cameratoworld = kernel_data.cam.cameratoworld;
420 float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
421
422 if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
423 float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z);
424 return fabsf(dot((P - camP), camD));
425 }
426 else {
427 return len(P - camP);
428 }
429}
430
432{
433 if (kernel_data.cam.type != CAMERA_PANORAMA) {
434 Transform worldtocamera = kernel_data.cam.worldtocamera;
435 return transform_point(&worldtocamera, P).z;
436 }
437 else {
438 Transform cameratoworld = kernel_data.cam.cameratoworld;
439 float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
440 return len(P - camP);
441 }
442}
443
445{
446 Transform cameratoworld = kernel_data.cam.cameratoworld;
447
448 if (kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
449 float3 camD = make_float3(cameratoworld.x.z, cameratoworld.y.z, cameratoworld.z.z);
450 return -camD;
451 }
452 else {
453 float3 camP = make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
454 return normalize(camP - P);
455 }
456}
457
460 float3 P)
461{
462 if (kernel_data.cam.type != CAMERA_PANORAMA) {
463 /* perspective / ortho */
464 if (sd->object == PRIM_NONE && kernel_data.cam.type == CAMERA_PERSPECTIVE)
465 P += camera_position(kg);
466
467 ProjectionTransform tfm = kernel_data.cam.worldtondc;
468 return transform_perspective(&tfm, P);
469 }
470 else {
471 /* panorama */
472 Transform tfm = kernel_data.cam.worldtocamera;
473
474 if (sd->object != OBJECT_NONE)
475 P = normalize(transform_point(&tfm, P));
476 else
478
480
481 return make_float3(uv.x, uv.y, 0.0f);
482 }
483}
484
#define D
#define U
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
ccl_device_inline float3 panorama_to_direction(ccl_constant KernelCamera *cam, float u, float v)
ccl_device_inline void spherical_stereo_transform(ccl_constant KernelCamera *cam, ccl_private float3 *P, ccl_private float3 *D)
ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, float3 dir)
ccl_device_inline float3 transform_perspective(ccl_private const ProjectionTransform *t, const float3 a)
double time
#define kernel_data
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_array(name)
#define ccl_device
#define ccl_constant
#define ccl_private
#define ccl_device_inline
#define ccl_global
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
ccl_device_forceinline float2 make_float2(const float x, const float y)
#define fabsf(x)
ccl_device_forceinline float differential_make_compact(const float dD)
ccl_device_forceinline float differential_zero_compact()
int len
draw_view in_light_buf[] float
ccl_device void camera_sample_perspective(KernelGlobals kg, const float2 raster_xy, const float2 rand_lens, ccl_private Ray *ray)
CCL_NAMESPACE_BEGIN ccl_device float2 camera_sample_aperture(ccl_constant KernelCamera *cam, const float2 rand)
ccl_device_inline float3 camera_position(KernelGlobals kg)
ccl_device_inline float camera_distance(KernelGlobals kg, float3 P)
ccl_device_inline float3 camera_world_to_ndc(KernelGlobals kg, ccl_private ShaderData *sd, float3 P)
ccl_device_inline float3 camera_direction_from_point(KernelGlobals kg, float3 P)
ccl_device void camera_sample_orthographic(KernelGlobals kg, const float2 raster_xy, const float2 rand_lens, ccl_private Ray *ray)
ccl_device_inline void camera_sample(KernelGlobals kg, int x, int y, const float2 filter_uv, const float time, const float2 lens_uv, ccl_private Ray *ray)
ccl_device_inline float3 camera_panorama_direction(ccl_constant KernelCamera *cam, float x, float y)
ccl_device_inline float camera_z_depth(KernelGlobals kg, float3 P)
ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam, ccl_global const DecomposedTransform *cam_motion, const float2 raster, const float2 rand_lens, ccl_private Ray *ray)
#define FILTER_TABLE_SIZE
#define PRIM_NONE
#define OBJECT_NONE
ShaderData
#define SHUTTER_TABLE_SIZE
@ CAMERA_PERSPECTIVE
@ CAMERA_PANORAMA
@ CAMERA_ORTHOGRAPHIC
CCL_NAMESPACE_BEGIN ccl_device float lookup_table_read(KernelGlobals kg, float x, int offset, int size)
ccl_device_inline bool is_zero(const float2 a)
ccl_device_inline float cross(const float2 a, const float2 b)
ccl_device_inline float2 interp(const float2 a, const float2 b, float t)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:15
ccl_device float2 regular_polygon_sample(float corners, float rotation, const float2 rand)
CCL_NAMESPACE_BEGIN ccl_device float2 sample_uniform_disk(const float2 rand)
float4 y
Definition transform.h:24
float4 x
Definition transform.h:24
float4 z
Definition transform.h:24
float x
float y
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
ccl_device void transform_motion_array_interpolate(ccl_private Transform *tfm, ccl_global const DecomposedTransform *motion, uint numsteps, float time)
Definition transform.h:482
ccl_device_inline float3 transform_direction(ccl_private const Transform *t, const float3 a)
Definition transform.h:94
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
Definition transform.h:63
ccl_device_inline float3 float2_to_float3(const float2 a)
Definition util/math.h:525
ccl_device_inline float3 float4_to_float3(const float4 a)
Definition util/math.h:535
CCL_NAMESPACE_BEGIN struct Window V