Blender  V2.93
eevee_shadows_cube.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2019, Blender Foundation.
17  */
18 
23 #include "eevee_private.h"
24 
26 {
27  if (linfo->cube_len >= MAX_SHADOW_CUBE) {
28  return;
29  }
30 
31  const Light *la = (Light *)ob->data;
32  EEVEE_Shadow *sh_data = linfo->shadow_data + linfo->shadow_len;
33 
34  /* Always update dupli lights as EEVEE_LightEngineData is not saved.
35  * Same issue with dupli shadow casters. */
36  bool update = (ob->base_flag & BASE_FROM_DUPLI) != 0;
37  if (!update) {
39  if (led->need_update) {
40  update = true;
41  led->need_update = false;
42  }
43  }
44 
45  if (update) {
46  BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], linfo->cube_len);
47  }
48 
49  sh_data->near = max_ff(la->clipsta, 1e-8f);
50  sh_data->bias = max_ff(la->bias * 0.05f, 0.0f);
52 
53  /* Saving light bounds for later. */
54  BoundSphere *cube_bound = linfo->shadow_bounds + linfo->cube_len;
55  copy_v3_v3(cube_bound->center, evli->position);
56  cube_bound->radius = sqrt(1.0f / evli->invsqrdist);
57 
58  linfo->shadow_cube_light_indices[linfo->cube_len] = linfo->num_light;
59  evli->shadow_id = linfo->shadow_len++;
60  sh_data->type_data_id = linfo->cube_len++;
61 
62  /* Same as linfo->cube_len, no need to save. */
63  linfo->num_cube_layer++;
64 }
65 
67  int sample_ofs,
68  float ws_sample_pos[3])
69 {
70  float jitter[3];
71 #ifdef DEBUG_SHADOW_DISTRIBUTION
72  int i = 0;
73 start:
74 #else
75  int i = sample_ofs;
76 #endif
77  switch ((int)evli->light_type) {
78  case LA_AREA:
79  EEVEE_sample_rectangle(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
80  break;
81  case (int)LAMPTYPE_AREA_ELLIPSE:
82  EEVEE_sample_ellipse(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
83  break;
84  default:
85  EEVEE_sample_ball(i, evli->radius, jitter);
86  }
87 #ifdef DEBUG_SHADOW_DISTRIBUTION
88  float p[3];
89  add_v3_v3v3(p, jitter, ws_sample_pos);
90  DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
91  if (i++ < sample_ofs) {
92  goto start;
93  }
94 #endif
95  add_v3_v3(ws_sample_pos, jitter);
96 }
97 
98 /* Return true if sample has changed and light needs to be updated. */
99 bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs)
100 {
101  EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
102  EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + (int)shdw_data->type_data_id;
103 
104  eevee_light_matrix_get(evli, cube_data->shadowmat);
105 
106  shdw_data->far = max_ff(sqrt(1.0f / evli->invsqrdist), 3e-4);
107  shdw_data->near = min_ff(shdw_data->near, shdw_data->far - 1e-4);
108 
109  bool update = false;
110 
111  if (linfo->soft_shadows) {
112  shadow_cube_random_position_set(evli, sample_ofs, cube_data->shadowmat[3]);
113  /* Update if position changes (avoid infinite update if soft shadows does not move).
114  * Other changes are caught by depsgraph tagging. This one is for update between samples. */
115  update = !compare_v3v3(cube_data->shadowmat[3], cube_data->position, 1e-10f);
127  /* NOTE: this has implication for spotlight rendering optimization
128  * (see EEVEE_shadows_draw_cubemap). */
129  float angular_texel_size = 2.0f * DEG2RADF(90) / (float)linfo->shadow_cube_size;
130  EEVEE_random_rotation_m4(sample_ofs, angular_texel_size, cube_data->shadowmat);
131  }
132 
133  copy_v3_v3(cube_data->position, cube_data->shadowmat[3]);
134  invert_m4(cube_data->shadowmat);
135 
136  return update;
137 }
138 
140  float near, float far, int cube_res, const float viewmat[4][4], DRWView *view[6])
141 {
142  float winmat[4][4];
143  float side = near;
144 
145  /* TODO: shadow-cube array. */
146  if (true) {
147  /* This half texel offset is used to ensure correct filtering between faces. */
148  /* FIXME: This exhibit float precision issue with lower cube_res.
149  * But it seems to be caused by the perspective_m4. */
150  side *= ((float)cube_res + 1.0f) / (float)(cube_res);
151  }
152 
153  perspective_m4(winmat, -side, side, -side, side, near, far);
154 
155  for (int i = 0; i < 6; i++) {
156  float tmp[4][4];
157  mul_m4_m4m4(tmp, cubefacemat[i], viewmat);
158 
159  if (view[i] == NULL) {
160  view[i] = DRW_view_create(tmp, winmat, NULL, NULL, NULL);
161  }
162  else {
163  DRW_view_update(view[i], tmp, winmat, NULL, NULL);
164  }
165  }
166 }
167 
168 /* Does a spot angle fits a single cubeface. */
169 static bool spot_angle_fit_single_face(const EEVEE_Light *evli)
170 {
171  /* alpha = spot/cone half angle. */
172  /* beta = scaled spot/cone half angle. */
173  float cos_alpha = evli->spotsize;
174  float sin_alpha = sqrtf(max_ff(0.0f, 1.0f - cos_alpha * cos_alpha));
175  float cos_beta = min_ff(cos_alpha / hypotf(cos_alpha, sin_alpha * evli->sizex),
176  cos_alpha / hypotf(cos_alpha, sin_alpha * evli->sizey));
177  /* Don't use 45 degrees because AA jitter can offset the face. */
178  return cos_beta > cosf(DEG2RADF(42.0f));
179 }
180 
181 void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index)
182 {
183  EEVEE_PassList *psl = vedata->psl;
184  EEVEE_StorageList *stl = vedata->stl;
185  EEVEE_PrivateData *g_data = stl->g_data;
186  EEVEE_LightsInfo *linfo = sldata->lights;
187 
188  EEVEE_Light *evli = linfo->light_data + linfo->shadow_cube_light_indices[cube_index];
189  EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
190  EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + (int)shdw_data->type_data_id;
191 
192  eevee_ensure_cube_views(shdw_data->near,
193  shdw_data->far,
194  linfo->shadow_cube_size,
195  cube_data->shadowmat,
196  g_data->cube_views);
197 
198  /* Render shadow cube */
199  /* Render 6 faces separately: seems to be faster for the general case.
200  * The only time it's more beneficial is when the CPU culling overhead
201  * outweigh the instancing overhead. which is rarely the case. */
202  for (int j = 0; j < 6; j++) {
203  /* Optimization: Only render the needed faces. */
204  /* Skip all but -Z face. */
205  if (evli->light_type == LA_SPOT && j != 5 && spot_angle_fit_single_face(evli)) {
206  continue;
207  }
208  /* Skip +Z face. */
209  if (evli->light_type != LA_LOCAL && j == 4) {
210  continue;
211  }
212  /* TODO(fclem): some cube sides can be invisible in the main views. Cull them. */
213  // if (frustum_intersect(g_data->cube_views[j], main_view))
214  // continue;
215 
216  DRW_view_set_active(g_data->cube_views[j]);
217  int layer = cube_index * 6 + j;
218  GPU_framebuffer_texture_layer_attach(sldata->shadow_fb, sldata->shadow_cube_pool, 0, layer, 0);
220  GPU_framebuffer_clear_depth(sldata->shadow_fb, 1.0f);
222  }
223 
224  BLI_BITMAP_SET(&linfo->sh_cube_update[0], cube_index, false);
225 }
typedef float(TangentPoint)[2]
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:78
#define BLI_BITMAP_SET(_bitmap, _index, _set)
Definition: BLI_bitmap.h:93
sqrt(x)+1/max(0
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
void perspective_m4(float mat[4][4], const float left, const float right, const float bottom, const float top, const float nearClip, const float farClip)
Definition: math_geom.c:4830
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
bool invert_m4(float R[4][4])
Definition: math_matrix.c:1187
#define DEG2RADF(_deg)
MINLINE bool compare_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
@ BASE_FROM_DUPLI
#define LA_AREA
#define LA_SPOT
#define LA_LOCAL
static AppView * view
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
BASIC_Shaders sh_data[GPU_SHADER_CFG_LEN]
Definition: basic_engine.c:76
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
void DRW_debug_sphere(const float center[3], const float radius, const float color[4])
Definition: draw_debug.c:126
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])
void DRW_view_set_active(DRWView *view)
void DRW_draw_pass(DRWPass *pass)
EEVEE_LightEngineData * EEVEE_light_data_ensure(Object *ob)
Definition: eevee_data.c:359
void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4])
Definition: eevee_lights.c:32
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])
#define LAMPTYPE_AREA_ELLIPSE
void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4])
#define MAX_SHADOW_CUBE
Definition: eevee_private.h:54
void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3])
static const float cubefacemat[6][4][4]
void EEVEE_sample_rectangle(int sample_ofs, const float x_axis[3], const float y_axis[3], float size_x, float size_y, float rsample[3])
void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh)
Definition: eevee_shadows.c:34
static void eevee_ensure_cube_views(float near, float far, int cube_res, const float viewmat[4][4], DRWView *view[6])
bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs)
void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, Object *ob)
static bool spot_angle_fit_single_face(const EEVEE_Light *evli)
static void shadow_cube_random_position_set(const EEVEE_Light *evli, int sample_ofs, float ws_sample_pos[3])
void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index)
void GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
#define cosf(x)
#define hypotf(x, y)
#define sqrtf(x)
static void update(bNodeTree *ntree)
float center[3]
Definition: DRW_render.h:87
float radius
Definition: DRW_render.h:87
EEVEE_StorageList * stl
EEVEE_PassList * psl
float rightvec[3]
float upvec[3]
float light_type
float invsqrdist
float position[3]
struct EEVEE_Light light_data[MAX_LIGHT]
struct EEVEE_Shadow shadow_data[MAX_SHADOW]
struct EEVEE_ShadowCube shadow_cube_data[MAX_SHADOW_CUBE]
struct BoundSphere shadow_bounds[MAX_LIGHT]
BLI_bitmap sh_cube_update[BLI_BITMAP_SIZE(MAX_SHADOW_CUBE)]
uchar shadow_cube_light_indices[MAX_SHADOW_CUBE]
struct DRWPass * shadow_pass
struct DRWView * cube_views[6]
float type_data_id
struct EEVEE_PrivateData * g_data
struct GPUTexture * shadow_cube_pool
struct GPUFrameBuffer * shadow_fb
struct EEVEE_LightsInfo * lights
float clipsta
float bias
short base_flag
void * data