Blender  V3.3
eevee_lights.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2016 Blender Foundation. */
3 
8 #include "BLI_sys_types.h" /* bool */
9 
10 #include "BKE_object.h"
11 
12 #include "DEG_depsgraph_query.h"
13 
14 #include "eevee_private.h"
15 
16 void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4])
17 {
18  copy_v3_v3(r_mat[0], evli->rightvec);
19  copy_v3_v3(r_mat[1], evli->upvec);
20  negate_v3_v3(r_mat[2], evli->forwardvec);
21  copy_v3_v3(r_mat[3], evli->position);
22  r_mat[0][3] = 0.0f;
23  r_mat[1][3] = 0.0f;
24  r_mat[2][3] = 0.0f;
25  r_mat[3][3] = 1.0f;
26 }
27 
28 static float light_attenuation_radius_get(const Light *la,
29  float light_threshold,
30  float light_power)
31 {
32  if (la->mode & LA_CUSTOM_ATTENUATION) {
33  return la->att_dist;
34  }
35  /* Compute the distance (using the inverse square law)
36  * at which the light power reaches the light_threshold. */
37  return sqrtf(max_ff(1e-16, light_power / max_ff(1e-16, light_threshold)));
38 }
39 
40 static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, const float scale[3])
41 {
42  if (la->type == LA_SPOT) {
43  /* Spot size & blend */
44  evli->sizex = scale[0] / scale[2];
45  evli->sizey = scale[1] / scale[2];
46  evli->spotsize = cosf(la->spotsize * 0.5f);
47  evli->spotblend = (1.0f - evli->spotsize) * la->spotblend;
48  evli->radius = max_ff(0.001f, la->area_size);
49  }
50  else if (la->type == LA_AREA) {
51  evli->sizex = max_ff(0.003f, la->area_size * scale[0] * 0.5f);
53  evli->sizey = max_ff(0.003f, la->area_sizey * scale[1] * 0.5f);
54  }
55  else {
56  evli->sizey = max_ff(0.003f, la->area_size * scale[1] * 0.5f);
57  }
58  /* For volume point lighting. */
59  evli->radius = max_ff(0.001f, hypotf(evli->sizex, evli->sizey) * 0.5f);
60  }
61  else if (la->type == LA_SUN) {
62  evli->radius = max_ff(0.001f, tanf(min_ff(la->sun_angle, DEG2RADF(179.9f)) / 2.0f));
63  }
64  else {
65  evli->radius = max_ff(0.001f, la->area_size);
66  }
67 }
68 
69 static float light_shape_power_get(const Light *la, const EEVEE_Light *evli)
70 {
71  float power;
72  /* Make illumination power constant */
73  if (la->type == LA_AREA) {
74  power = 1.0f / (evli->sizex * evli->sizey * 4.0f * M_PI) * /* 1/(w*h*Pi) */
75  0.8f; /* XXX: Empirical, Fit cycles power. */
77  /* Scale power to account for the lower area of the ellipse compared to the surrounding
78  * rectangle. */
79  power *= 4.0f / M_PI;
80  }
81  }
82  else if (ELEM(la->type, LA_SPOT, LA_LOCAL)) {
83  power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI); /* `1/(4*(r^2)*(Pi^2))` */
84 
85  /* for point lights (a.k.a radius == 0.0) */
86  // power = M_PI * M_PI * 0.78; /* XXX: Empirical, Fit cycles power. */
87  }
88  else { /* LA_SUN */
89  power = 1.0f / (evli->radius * evli->radius * M_PI);
90  /* Make illumination power closer to cycles for bigger radii. Cycles uses a cos^3 term that we
91  * cannot reproduce so we account for that by scaling the light power. This function is the
92  * result of a rough manual fitting. */
93  power += 1.0f / (2.0f * M_PI); /* `power *= 1 + (r^2)/2` */
94  }
95  return power;
96 }
97 
98 static float light_shape_power_volume_get(const Light *la,
99  const EEVEE_Light *evli,
100  float area_power)
101 {
102  /* Volume light is evaluated as point lights. Remove the shape power. */
103  float power = 1.0f / area_power;
104 
105  if (la->type == LA_AREA) {
106  /* Match cycles. Empirical fit... must correspond to some constant. */
107  power *= 0.0792f * M_PI;
108  /* This corrects for area light most representative point trick. The fit was found by
109  * reducing the average error compared to cycles. */
110  float area = evli->sizex * evli->sizey;
111  float tmp = M_PI_2 / (M_PI_2 + sqrtf(area));
112  /* Lerp between 1.0 and the limit (1 / pi). */
113  power *= tmp + (1.0f - tmp) * M_1_PI;
114  }
115  else if (ELEM(la->type, LA_SPOT, LA_LOCAL)) {
116  /* Match cycles. Empirical fit... must correspond to some constant. */
117  power *= 0.0792f;
118  }
119  else { /* LA_SUN */
120  /* Nothing to do. */
121  }
122  return power;
123 }
124 
125 /* Update buffer with light data */
126 static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
127 {
128  const Light *la = (Light *)ob->data;
129  float mat[4][4], scale[3];
130 
131  const DRWContextState *draw_ctx = DRW_context_state_get();
132  const float light_threshold = draw_ctx->scene->eevee.light_threshold;
133 
134  /* Position */
135  copy_v3_v3(evli->position, ob->obmat[3]);
136 
137  /* Color */
138  copy_v3_v3(evli->color, &la->r);
139 
140  evli->diff = la->diff_fac;
141  evli->spec = la->spec_fac;
142  evli->volume = la->volume_fac;
143 
144  float max_power = max_fff(la->r, la->g, la->b) * fabsf(la->energy / 100.0f);
145  float surface_max_power = max_ff(evli->diff, evli->spec) * max_power;
146  float volume_max_power = evli->volume * max_power;
147 
148  /* Influence Radii. */
149  float att_radius = light_attenuation_radius_get(la, light_threshold, surface_max_power);
150  float att_radius_volume = light_attenuation_radius_get(la, light_threshold, volume_max_power);
151  /* Take the inverse square of this distance. */
152  evli->invsqrdist = 1.0f / max_ff(1e-4f, square_f(att_radius));
153  evli->invsqrdist_volume = 1.0f / max_ff(1e-4f, square_f(att_radius_volume));
154 
155  /* Vectors */
156  normalize_m4_m4_ex(mat, ob->obmat, scale);
157  copy_v3_v3(evli->forwardvec, mat[2]);
158  normalize_v3(evli->forwardvec);
159  negate_v3(evli->forwardvec);
160 
161  copy_v3_v3(evli->rightvec, mat[0]);
162  normalize_v3(evli->rightvec);
163 
164  copy_v3_v3(evli->upvec, mat[1]);
165  normalize_v3(evli->upvec);
166 
167  /* Make sure we have a consistent Right Hand coord frame.
168  * (in case of negatively scaled Z axis) */
169  float cross[3];
170  cross_v3_v3v3(cross, evli->rightvec, evli->forwardvec);
171  if (dot_v3v3(cross, evli->upvec) < 0.0) {
172  negate_v3(evli->upvec);
173  }
174 
175  light_shape_parameters_set(evli, la, scale);
176 
177  /* Light Type */
178  evli->light_type = (float)la->type;
179  if ((la->type == LA_AREA) && ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) {
181  }
182 
183  float shape_power = light_shape_power_get(la, evli);
184  mul_v3_fl(evli->color, shape_power * la->energy);
185 
186  evli->volume *= light_shape_power_volume_get(la, evli, shape_power);
187 
188  /* No shadow by default */
189  evli->shadow_id = -1.0f;
190 }
191 
193 {
194  EEVEE_LightsInfo *linfo = sldata->lights;
195  linfo->num_light = 0;
196 
197  EEVEE_shadows_cache_init(sldata, vedata);
198 }
199 
201 {
202  EEVEE_LightsInfo *linfo = sldata->lights;
203  const Light *la = (Light *)ob->data;
204 
205  if (linfo->num_light >= MAX_LIGHT) {
206  printf("Too many lights in the scene !!!\n");
207  return;
208  }
209 
210  /* Early out if light has no power. */
211  if (la->energy == 0.0f || is_zero_v3(&la->r)) {
212  return;
213  }
214 
215  EEVEE_Light *evli = linfo->light_data + linfo->num_light;
216  eevee_light_setup(ob, evli);
217 
218  if (la->mode & LA_SHADOW) {
219  if (la->type == LA_SUN) {
220  EEVEE_shadows_cascade_add(linfo, evli, ob);
221  }
222  else if (ELEM(la->type, LA_SPOT, LA_LOCAL, LA_AREA)) {
223  EEVEE_shadows_cube_add(linfo, evli, ob);
224  }
225  }
226 
227  linfo->num_light++;
228 }
229 
231 {
232  EEVEE_LightsInfo *linfo = sldata->lights;
233 
234  sldata->common_data.la_num_light = linfo->num_light;
235 
236  /* Clamp volume lights power. */
237  float upper_bound = vedata->stl->effects->volume_light_clamp;
238  for (int i = 0; i < linfo->num_light; i++) {
239  EEVEE_Light *evli = linfo->light_data + i;
240 
241  float power = max_fff(UNPACK3(evli->color)) * evli->volume;
242  if (power > 0.0f && evli->light_type != LA_SUN) {
243  /* The limit of the power attenuation function when the distance to the light goes to 0 is
244  * `2 / r^2` where r is the light radius. We need to find the right radius that emits at most
245  * the volume light upper bound. Inverting the function we get: */
246  float min_radius = 1.0f / sqrtf(0.5f * upper_bound / power);
247  /* Square it here to avoid a multiplication inside the shader. */
248  evli->volume_radius = square_f(max_ff(min_radius, evli->radius));
249  }
250  }
251 
252  GPU_uniformbuf_update(sldata->light_ubo, &linfo->light_data);
253 }
typedef float(TangentPoint)[2]
General operations, lookup, etc. for blender objects.
MINLINE float max_fff(float a, float b, float c)
#define M_1_PI
Definition: BLI_math_base.h:41
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
#define M_PI_2
Definition: BLI_math_base.h:23
MINLINE float square_f(float a)
#define M_PI
Definition: BLI_math_base.h:20
void normalize_m4_m4_ex(float R[4][4], const float M[4][4], float r_scale[3]) ATTR_NONNULL()
Definition: math_matrix.c:1956
#define DEG2RADF(_deg)
MINLINE float normalize_v3(float r[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
#define UNPACK3(a)
#define ELEM(...)
#define LA_AREA
#define LA_SPOT
#define LA_AREA_ELLIPSE
#define LA_SUN
#define LA_SHADOW
#define LA_LOCAL
#define LA_CUSTOM_ATTENUATION
#define LA_AREA_DISK
#define LA_AREA_RECT
void GPU_uniformbuf_update(GPUUniformBuf *ubo, const void *data)
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
#define cosf(x)
Definition: cuda/compat.h:101
#define tanf(x)
Definition: cuda/compat.h:104
const DRWContextState * DRW_context_state_get(void)
static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
Definition: eevee_lights.c:126
void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
Definition: eevee_lights.c:230
void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
Definition: eevee_lights.c:200
void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
Definition: eevee_lights.c:192
void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4])
Definition: eevee_lights.c:16
static float light_shape_power_get(const Light *la, const EEVEE_Light *evli)
Definition: eevee_lights.c:69
static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, const float scale[3])
Definition: eevee_lights.c:40
static float light_shape_power_volume_get(const Light *la, const EEVEE_Light *evli, float area_power)
Definition: eevee_lights.c:98
static float light_attenuation_radius_get(const Light *la, float light_threshold, float light_power)
Definition: eevee_lights.c:28
void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
Definition: eevee_shadows.c:81
#define LAMPTYPE_AREA_ELLIPSE
void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob)
void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob)
#define MAX_LIGHT
Definition: eevee_private.h:35
#define hypotf(x, y)
Definition: metal/compat.h:226
#define fabsf(x)
Definition: metal/compat.h:219
#define sqrtf(x)
Definition: metal/compat.h:243
static void area(int d1, int d2, int e1, int e2, float weights[2])
vec_base< T, 3 > cross(const vec_base< T, 3 > &a, const vec_base< T, 3 > &b)
struct Scene * scene
Definition: DRW_render.h:979
EEVEE_StorageList * stl
float rightvec[3]
float color[3]
float forwardvec[3]
float upvec[3]
float light_type
float invsqrdist
float invsqrdist_volume
float volume_radius
float position[3]
struct EEVEE_Light light_data[MAX_LIGHT]
struct EEVEE_EffectsInfo * effects
struct EEVEE_CommonUniformBuffer common_data
struct GPUUniformBuf * light_ubo
struct EEVEE_LightsInfo * lights
float sun_angle
float r
float energy
float att_dist
float spec_fac
float area_sizey
short area_shape
float spotblend
float g
float spotsize
float area_size
float b
float volume_fac
short type
float diff_fac
float obmat[4][4]
void * data
float light_threshold
struct SceneEEVEE eevee