Blender  V3.3
eevee_shadows_cascade.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2019 Blender Foundation. */
3 
8 #include "BLI_rect.h"
9 #include "BLI_sys_types.h" /* bool */
10 
11 #include "BKE_object.h"
12 
13 #include "eevee_private.h"
14 
15 #include "BLI_rand.h" /* needs to be after for some reason. */
16 
18 {
19  if (linfo->cascade_len >= MAX_SHADOW_CASCADE) {
20  return;
21  }
22 
23  const Light *la = (Light *)ob->data;
24  EEVEE_Shadow *sh_data = linfo->shadow_data + linfo->shadow_len;
25  EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + linfo->cascade_len;
26  EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render + linfo->cascade_len;
27 
29 
30  linfo->shadow_cascade_light_indices[linfo->cascade_len] = linfo->num_light;
31  evli->shadow_id = linfo->shadow_len++;
32  sh_data->type_data_id = linfo->cascade_len++;
33  csm_data->tex_id = linfo->num_cascade_layer;
34  csm_render->cascade_fade = la->cascade_fade;
35  csm_render->cascade_count = la->cascade_count;
36  csm_render->cascade_exponent = la->cascade_exponent;
37  csm_render->cascade_max_dist = la->cascade_max_dist;
38  csm_render->original_bias = max_ff(la->bias, 0.0f);
39 
40  linfo->num_cascade_layer += la->cascade_count;
41 }
42 
43 static void shadow_cascade_random_matrix_set(float mat[4][4], float radius, int sample_ofs)
44 {
45  float jitter[3];
46 #ifndef DEBUG_SHADOW_DISTRIBUTION
47  EEVEE_sample_ellipse(sample_ofs, mat[0], mat[1], radius, radius, jitter);
48 #else
49  for (int i = 0; i <= sample_ofs; i++) {
50  EEVEE_sample_ellipse(i, mat[0], mat[1], radius, radius, jitter);
51  float p[3];
52  add_v3_v3v3(p, jitter, mat[2]);
53  DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
54  }
55 #endif
56  add_v3_v3(mat[2], jitter);
57  orthogonalize_m4(mat, 2);
58 }
59 
60 static double round_to_digits(double value, int digits)
61 {
62  double factor = pow(10.0, digits - ceil(log10(fabs(value))));
63  return round(value * factor) / factor;
64 }
65 
66 static void frustum_min_bounding_sphere(const float corners[8][3],
67  float r_center[3],
68  float *r_radius)
69 {
70 #if 0 /* Simple solution but waste too much space. */
71  float minvec[3], maxvec[3];
72 
73  /* compute the bounding box */
74  INIT_MINMAX(minvec, maxvec);
75  for (int i = 0; i < 8; i++) {
76  minmax_v3v3_v3(minvec, maxvec, corners[i]);
77  }
78 
79  /* compute the bounding sphere of this box */
80  r_radius = len_v3v3(minvec, maxvec) * 0.5f;
81  add_v3_v3v3(r_center, minvec, maxvec);
82  mul_v3_fl(r_center, 0.5f);
83 #else
84  /* Find averaged center. */
85  zero_v3(r_center);
86  for (int i = 0; i < 8; i++) {
87  add_v3_v3(r_center, corners[i]);
88  }
89  mul_v3_fl(r_center, 1.0f / 8.0f);
90 
91  /* Search the largest distance from the sphere center. */
92  *r_radius = 0.0f;
93  for (int i = 0; i < 8; i++) {
94  float rad = len_squared_v3v3(corners[i], r_center);
95  if (rad > *r_radius) {
96  *r_radius = rad;
97  }
98  }
99 
100  /* TODO: try to reduce the radius further by moving the center.
101  * Remember we need a __stable__ solution! */
102 
103  /* Try to reduce float imprecision leading to shimmering. */
104  *r_radius = (float)round_to_digits(sqrtf(*r_radius), 3);
105 #endif
106 }
107 
109  EEVEE_Light *evli,
110  DRWView *view,
111  float view_near,
112  float view_far,
113  int sample_ofs)
114 {
115  EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
116  EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + (int)shdw_data->type_data_id;
117  EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render +
118  (int)shdw_data->type_data_id;
119  int cascade_count = csm_render->cascade_count;
120  float cascade_fade = csm_render->cascade_fade;
121  float cascade_max_dist = csm_render->cascade_max_dist;
122  float cascade_exponent = csm_render->cascade_exponent;
123 
124  float jitter_ofs[2];
125  double ht_point[2];
126  double ht_offset[2] = {0.0, 0.0};
127  const uint ht_primes[2] = {2, 3};
128 
129  BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
130 
131  /* Not really sure why we need 4.0 factor here. */
132  jitter_ofs[0] = (ht_point[0] * 2.0 - 1.0) * 4.0 / linfo->shadow_cascade_size;
133  jitter_ofs[1] = (ht_point[1] * 2.0 - 1.0) * 4.0 / linfo->shadow_cascade_size;
134 
135  /* Camera Matrices */
136  float persinv[4][4], vp_projmat[4][4];
137  DRW_view_persmat_get(view, persinv, true);
138  DRW_view_winmat_get(view, vp_projmat, false);
139  bool is_persp = DRW_view_is_persp_get(view);
140 
141  /* obmat = Object Space > World Space */
142  /* viewmat = World Space > View Space */
143  float(*viewmat)[4] = csm_render->viewmat;
144  eevee_light_matrix_get(evli, viewmat);
145  /* At this point, viewmat == normalize_m4(obmat) */
146 
147  if (linfo->soft_shadows) {
148  shadow_cascade_random_matrix_set(viewmat, evli->radius, sample_ofs);
149  }
150 
151  copy_m4_m4(csm_render->viewinv, viewmat);
152  invert_m4(viewmat);
153 
154  copy_v3_v3(csm_data->shadow_vec, csm_render->viewinv[2]);
155 
156  /* Compute near and far value based on all shadow casters cumulated AABBs. */
157  float sh_near = -1.0e30f, sh_far = 1.0e30f;
158  BoundBox shcaster_bounds;
160  &shcaster_bounds, linfo->shcaster_aabb.min, linfo->shcaster_aabb.max);
161 #ifdef DEBUG_CSM
162  float dbg_col1[4] = {1.0f, 0.5f, 0.6f, 1.0f};
163  DRW_debug_bbox(&shcaster_bounds, dbg_col1);
164 #endif
165  for (int i = 0; i < 8; i++) {
166  mul_m4_v3(viewmat, shcaster_bounds.vec[i]);
167  sh_near = max_ff(sh_near, shcaster_bounds.vec[i][2]);
168  sh_far = min_ff(sh_far, shcaster_bounds.vec[i][2]);
169  }
170 #ifdef DEBUG_CSM
171  float dbg_col2[4] = {0.5f, 1.0f, 0.6f, 1.0f};
172  float pts[2][3] = {{0.0, 0.0, sh_near}, {0.0, 0.0, sh_far}};
173  mul_m4_v3(csm_render->viewinv, pts[0]);
174  mul_m4_v3(csm_render->viewinv, pts[1]);
175  DRW_debug_sphere(pts[0], 1.0f, dbg_col1);
176  DRW_debug_sphere(pts[1], 1.0f, dbg_col2);
177 #endif
178  /* The rest of the function is assuming inverted Z. */
179  /* Add a little bias to avoid invalid matrices. */
180  sh_far = -(sh_far - 1e-3);
181  sh_near = -sh_near;
182 
183  /* The technique consists into splitting
184  * the view frustum into several sub-frustum
185  * that are individually receiving one shadow map */
186 
187  float csm_start, csm_end;
188 
189  if (is_persp) {
190  csm_start = view_near;
191  csm_end = max_ff(view_far, -cascade_max_dist);
192  /* Avoid artifacts */
193  csm_end = min_ff(view_near, csm_end);
194  }
195  else {
196  csm_start = -view_far;
197  csm_end = view_far;
198  }
199 
200  /* init near/far */
201  for (int c = 0; c < MAX_CASCADE_NUM; c++) {
202  csm_data->split_start[c] = csm_end;
203  csm_data->split_end[c] = csm_end;
204  }
205 
206  /* Compute split planes */
207  float splits_start_ndc[MAX_CASCADE_NUM];
208  float splits_end_ndc[MAX_CASCADE_NUM];
209 
210  {
211  /* Nearest plane */
212  float p[4] = {1.0f, 1.0f, csm_start, 1.0f};
213  /* TODO: we don't need full m4 multiply here */
214  mul_m4_v4(vp_projmat, p);
215  splits_start_ndc[0] = p[2];
216  if (is_persp) {
217  splits_start_ndc[0] /= p[3];
218  }
219  }
220 
221  {
222  /* Farthest plane */
223  float p[4] = {1.0f, 1.0f, csm_end, 1.0f};
224  /* TODO: we don't need full m4 multiply here */
225  mul_m4_v4(vp_projmat, p);
226  splits_end_ndc[cascade_count - 1] = p[2];
227  if (is_persp) {
228  splits_end_ndc[cascade_count - 1] /= p[3];
229  }
230  }
231 
232  csm_data->split_start[0] = csm_start;
233  csm_data->split_end[cascade_count - 1] = csm_end;
234 
235  for (int c = 1; c < cascade_count; c++) {
236  /* View Space */
237  float linear_split = interpf(csm_end, csm_start, c / (float)cascade_count);
238  float exp_split = csm_start * powf(csm_end / csm_start, c / (float)cascade_count);
239 
240  if (is_persp) {
241  csm_data->split_start[c] = interpf(exp_split, linear_split, cascade_exponent);
242  }
243  else {
244  csm_data->split_start[c] = linear_split;
245  }
246  csm_data->split_end[c - 1] = csm_data->split_start[c];
247 
248  /* Add some overlap for smooth transition */
249  csm_data->split_start[c] = interpf((c > 1) ? csm_data->split_end[c - 2] :
250  csm_data->split_start[0],
251  csm_data->split_end[c - 1],
252  cascade_fade);
253 
254  /* NDC Space */
255  {
256  float p[4] = {1.0f, 1.0f, csm_data->split_start[c], 1.0f};
257  /* TODO: we don't need full m4 multiply here */
258  mul_m4_v4(vp_projmat, p);
259  splits_start_ndc[c] = p[2];
260 
261  if (is_persp) {
262  splits_start_ndc[c] /= p[3];
263  }
264  }
265 
266  {
267  float p[4] = {1.0f, 1.0f, csm_data->split_end[c - 1], 1.0f};
268  /* TODO: we don't need full m4 multiply here */
269  mul_m4_v4(vp_projmat, p);
270  splits_end_ndc[c - 1] = p[2];
271 
272  if (is_persp) {
273  splits_end_ndc[c - 1] /= p[3];
274  }
275  }
276  }
277 
278  /* Set last cascade split fade distance into the first split_start. */
279  float prev_split = (cascade_count > 1) ? csm_data->split_end[cascade_count - 2] :
280  csm_data->split_start[0];
281  csm_data->split_start[0] = interpf(
282  prev_split, csm_data->split_end[cascade_count - 1], cascade_fade);
283 
284  /* For each cascade */
285  for (int c = 0; c < cascade_count; c++) {
286  float(*projmat)[4] = csm_render->projmat[c];
287  /* Given 8 frustum corners */
288  float corners[8][3] = {
289  /* Near Cap */
290  {1.0f, -1.0f, splits_start_ndc[c]},
291  {-1.0f, -1.0f, splits_start_ndc[c]},
292  {-1.0f, 1.0f, splits_start_ndc[c]},
293  {1.0f, 1.0f, splits_start_ndc[c]},
294  /* Far Cap */
295  {1.0f, -1.0f, splits_end_ndc[c]},
296  {-1.0f, -1.0f, splits_end_ndc[c]},
297  {-1.0f, 1.0f, splits_end_ndc[c]},
298  {1.0f, 1.0f, splits_end_ndc[c]},
299  };
300 
301  /* Transform them into world space */
302  for (int i = 0; i < 8; i++) {
303  mul_project_m4_v3(persinv, corners[i]);
304  }
305 
306  float center[3];
307  frustum_min_bounding_sphere(corners, center, &(csm_render->radius[c]));
308 
309 #ifdef DEBUG_CSM
310  float dbg_col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
311  if (c < 3) {
312  dbg_col[c] = 1.0f;
313  }
314  DRW_debug_bbox((const BoundBox *)&corners, dbg_col);
315  DRW_debug_sphere(center, csm_render->radius[c], dbg_col);
316 #endif
317 
318  /* Project into light-space. */
319  mul_m4_v3(viewmat, center);
320 
321  /* Snap projection center to nearest texel to cancel shimmering. */
322  float shadow_origin[2], shadow_texco[2];
323  /* Light to texture space. */
324  mul_v2_v2fl(
325  shadow_origin, center, linfo->shadow_cascade_size / (2.0f * csm_render->radius[c]));
326 
327  /* Find the nearest texel. */
328  shadow_texco[0] = roundf(shadow_origin[0]);
329  shadow_texco[1] = roundf(shadow_origin[1]);
330 
331  /* Compute offset. */
332  sub_v2_v2(shadow_texco, shadow_origin);
333  /* Texture to light space. */
334  mul_v2_fl(shadow_texco, (2.0f * csm_render->radius[c]) / linfo->shadow_cascade_size);
335 
336  /* Apply offset. */
337  add_v2_v2(center, shadow_texco);
338 
339  /* Expand the projection to cover frustum range */
340  rctf rect_cascade;
341  BLI_rctf_init_pt_radius(&rect_cascade, center, csm_render->radius[c]);
342  orthographic_m4(projmat,
343  rect_cascade.xmin,
344  rect_cascade.xmax,
345  rect_cascade.ymin,
346  rect_cascade.ymax,
347  sh_near,
348  sh_far);
349 
350  /* Anti-Aliasing */
351  if (linfo->soft_shadows) {
352  add_v2_v2(projmat[3], jitter_ofs);
353  }
354 
355  float viewprojmat[4][4];
356  mul_m4_m4m4(viewprojmat, projmat, viewmat);
357  mul_m4_m4m4(csm_data->shadowmat[c], texcomat, viewprojmat);
358 
359 #ifdef DEBUG_CSM
360  DRW_debug_m4_as_bbox(viewprojmat, dbg_col, true);
361 #endif
362  }
363 
364  /* Bias is in clip-space, divide by range. */
365  shdw_data->bias = csm_render->original_bias * 0.05f / fabsf(sh_far - sh_near);
366  shdw_data->near = sh_near;
367  shdw_data->far = sh_far;
368 }
369 
372 {
373  for (int i = 0; i < csm_render->cascade_count; i++) {
374  if (view[i] == NULL) {
375  view[i] = DRW_view_create(csm_render->viewmat, csm_render->projmat[i], NULL, NULL, NULL);
376  }
377  else {
378  DRW_view_update(view[i], csm_render->viewmat, csm_render->projmat[i], NULL, NULL);
379  }
380  }
381 }
382 
384  EEVEE_Data *vedata,
385  DRWView *view,
386  int cascade_index)
387 {
388  EEVEE_PassList *psl = vedata->psl;
389  EEVEE_StorageList *stl = vedata->stl;
390  EEVEE_EffectsInfo *effects = stl->effects;
392  EEVEE_LightsInfo *linfo = sldata->lights;
393 
394  EEVEE_Light *evli = linfo->light_data + linfo->shadow_cascade_light_indices[cascade_index];
395  EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
396  EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + (int)shdw_data->type_data_id;
397  EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render +
398  (int)shdw_data->type_data_id;
399 
400  float near = DRW_view_near_distance_get(view);
401  float far = DRW_view_far_distance_get(view);
402 
403  eevee_shadow_cascade_setup(linfo, evli, view, near, far, effects->taa_current_sample - 1);
404 
405  /* Meh, Reusing the cube views. */
407  eevee_ensure_cascade_views(csm_render, g_data->cube_views);
408 
409  /* Render shadow cascades */
410  /* Render cascade separately: seems to be faster for the general case.
411  * The only time it's more beneficial is when the CPU culling overhead
412  * outweigh the instancing overhead. which is rarely the case. */
413  for (int j = 0; j < csm_render->cascade_count; j++) {
414  DRW_view_set_active(g_data->cube_views[j]);
415  int layer = csm_data->tex_id + j;
417  sldata->shadow_fb, sldata->shadow_cascade_pool, 0, layer, 0);
419  GPU_framebuffer_clear_depth(sldata->shadow_fb, 1.0f);
421  }
422 }
typedef float(TangentPoint)[2]
General operations, lookup, etc. for blender objects.
void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3])
Definition: object.cc:3645
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE float interpf(float a, float b, float t)
void orthographic_m4(float mat[4][4], float left, float right, float bottom, float top, float nearClip, float farClip)
Definition: math_geom.c:4517
void mul_project_m4_v3(const float M[4][4], float vec[3])
Definition: math_matrix.c:820
void orthogonalize_m4(float R[4][4], int axis)
Definition: math_matrix.c:1523
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
bool invert_m4(float R[4][4])
Definition: math_matrix.c:1206
void mul_m4_v4(const float M[4][4], float r[4])
Definition: math_matrix.c:862
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:867
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void zero_v3(float r[3])
MINLINE void mul_v2_v2fl(float r[2], const float a[2], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
Random number functions.
void BLI_halton_2d(const unsigned int prime[2], double offset[2], int n, double *r)
Definition: rand.cc:298
void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size)
Definition: rct.c:461
unsigned int uint
Definition: BLI_sys_types.h:67
#define INIT_MINMAX(min, max)
static AppView * view
NSNotificationCenter * center
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
BASIC_Shaders sh_data[GPU_SHADER_CFG_LEN]
Definition: basic_shader.c:33
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
#define powf(x, y)
Definition: cuda/compat.h:103
void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], const bool invert)
Definition: draw_debug.c:92
void DRW_debug_sphere(const float center[3], const float radius, const float color[4])
Definition: draw_debug.c:111
void DRW_debug_bbox(const BoundBox *bbox, const float color[4])
Definition: draw_debug.c:74
float DRW_view_near_distance_get(const DRWView *view)
void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse)
bool DRW_view_is_persp_get(const DRWView *view)
void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse)
DRWView * DRW_view_create(const float viewmat[4][4], const float winmat[4][4], const float(*culling_viewmat)[4], const float(*culling_winmat)[4], DRWCallVisibilityFn *visibility_fn)
void DRW_view_update(DRWView *view, const float viewmat[4][4], const float winmat[4][4], const float(*culling_viewmat)[4], const float(*culling_winmat)[4])
float DRW_view_far_distance_get(const DRWView *view)
void DRW_draw_pass(DRWPass *pass)
void DRW_view_set_active(const DRWView *view)
static struct @318 g_data
void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4])
Definition: eevee_lights.c:16
#define MAX_SHADOW_CASCADE
Definition: eevee_private.h:38
void EEVEE_sample_ellipse(int sample_ofs, const float x_axis[3], const float y_axis[3], float size_x, float size_y, float rsample[3])
static const float texcomat[4][4]
#define MAX_CASCADE_NUM
Definition: eevee_private.h:36
void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh)
Definition: eevee_shadows.c:19
static void eevee_ensure_cascade_views(EEVEE_ShadowCascadeRender *csm_render, DRWView *view[MAX_CASCADE_NUM])
static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, DRWView *view, float view_near, float view_far, int sample_ofs)
static double round_to_digits(double value, int digits)
void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view, int cascade_index)
void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, Object *ob)
static void frustum_min_bounding_sphere(const float corners[8][3], float r_center[3], float *r_radius)
static void shadow_cascade_random_matrix_set(float mat[4][4], float radius, int sample_ofs)
void GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
ccl_device_inline float2 fabs(const float2 &a)
Definition: math_float2.h:222
ccl_device_inline float3 ceil(const float3 &a)
Definition: math_float3.h:363
ccl_device_inline float3 pow(float3 v, float e)
Definition: math_float3.h:533
#define fabsf(x)
Definition: metal/compat.h:219
#define sqrtf(x)
Definition: metal/compat.h:243
static unsigned c
Definition: RandGen.cpp:83
float vec[8][3]
EEVEE_StorageList * stl
EEVEE_PassList * psl
struct EEVEE_Light light_data[MAX_LIGHT]
uchar shadow_cascade_light_indices[MAX_SHADOW_CASCADE]
struct EEVEE_Shadow shadow_data[MAX_SHADOW]
struct EEVEE_ShadowCascadeRender shadow_cascade_render[MAX_SHADOW_CASCADE]
struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE]
struct DRWPass * shadow_pass
float projmat[MAX_CASCADE_NUM][4][4]
float type_data_id
struct EEVEE_PrivateData * g_data
struct EEVEE_EffectsInfo * effects
struct GPUFrameBuffer * shadow_fb
struct GPUTexture * shadow_cascade_pool
struct EEVEE_LightsInfo * lights
float cascade_exponent
int cascade_count
float cascade_max_dist
float cascade_fade
float bias
void * data
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70