diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-11-15 16:44:45 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-11-15 20:16:30 +0300 |
commit | 516e000aa9762c6b19c64ce46e5dd458cd04a1fb (patch) | |
tree | daef7a7f7e8211e212aa24bc9a8a8322d7eef25f /source/blender/draw/engines/eevee/eevee_lights.c | |
parent | d082b18d877f2da661ee2a48fdf3c69d67406e86 (diff) |
Eevee: Add Light Threshold value
This is an important change. Starting from now, all lights have a finite
influence radius (similar to the old sphere option for BI).
In order to avoid costly setup time, this distance is first computed
automatically based on a light threshold. The distance is computed
at the light origin and using the inverse square falloff. The setting
can be found inside the render settings panel > shadow tab.
This light threshold does not take the light shape into account an may not
suit every case. That's why we provide a per lamp override where you can
just set the cutt off distance (Light Properties Panel > Light >
Custom Distance).
The influence distance is also used as shadow far clip distance.
This influence distance does not concerns sun lights that still have a
far clip distance.
---
This change is important because it makes it possible to cull lights
an improve performance drastically in the future.
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_lights.c')
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_lights.c | 123 |
1 files changed, 81 insertions, 42 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 5336e197d02..b946a49ea14 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -57,8 +57,9 @@ extern char datatoc_shadow_store_frag_glsl[]; extern char datatoc_shadow_copy_frag_glsl[]; extern char datatoc_concentric_samples_lib_glsl[]; -/* Prototype */ +/* Prototypes */ static void eevee_light_setup(Object *ob, EEVEE_Light *evli); +static float light_attenuation_radius_get(Lamp *la, float light_threshold); /* *********** LIGHT BITS *********** */ static void lightbits_set_single(EEVEE_LightBits *bitf, uint idx, bool val) @@ -337,6 +338,9 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) { EEVEE_LampsInfo *linfo = sldata->lamps; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const float threshold = draw_ctx->scene->eevee.light_threshold; + /* Step 1 find all lamps in the scene and setup them */ if (linfo->num_light >= MAX_LIGHT) { printf("Too many lights in the scene !!!\n"); @@ -399,7 +403,7 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) /* Saving lamp bounds for later. */ BLI_assert(linfo->cpu_cube_len >= 0 && linfo->cpu_cube_len < MAX_LIGHT); copy_v3_v3(linfo->shadow_bounds[linfo->cpu_cube_len].center, ob->obmat[3]); - linfo->shadow_bounds[linfo->cpu_cube_len].radius = la->clipend; + linfo->shadow_bounds[linfo->cpu_cube_len].radius = light_attenuation_radius_get(la, threshold); EEVEE_ShadowCubeData *data = &led->data.scd; /* Store indices. */ @@ -590,37 +594,25 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_lights_update(sldata, vedata); } -/* Update buffer with lamp data */ -static void eevee_light_setup(Object *ob, EEVEE_Light *evli) +float light_attenuation_radius_get(Lamp *la, float light_threshold) { - Lamp *la = (Lamp *)ob->data; - float mat[4][4], scale[3], power; - - /* Position */ - copy_v3_v3(evli->position, ob->obmat[3]); - - /* Color */ - copy_v3_v3(evli->color, &la->r); - - evli->spec = la->spec_fac; - - /* Influence Radius */ - evli->dist = la->dist; - - /* Vectors */ - normalize_m4_m4_ex(mat, ob->obmat, scale); - copy_v3_v3(evli->forwardvec, mat[2]); - normalize_v3(evli->forwardvec); - negate_v3(evli->forwardvec); - - copy_v3_v3(evli->rightvec, mat[0]); - normalize_v3(evli->rightvec); - - copy_v3_v3(evli->upvec, mat[1]); - normalize_v3(evli->upvec); + if (la->mode & LA_CUSTOM_ATTENUATION) + return la->att_dist; + + /* Compute max light power. */ + float power = max_fff(la->r, la->g, la->b); + power *= fabsf(la->energy); + power *= max_ff(1.0f, la->spec_fac); + /* Compute the distance (using the inverse square law) + * at which the light power reaches the light_threshold. */ + float distance = sqrtf(max_ff(1e-16, power / max_ff(1e-16, light_threshold))); + return distance; +} - /* Spot size & blend */ +static void light_shape_parameters_set(EEVEE_Light *evli, const Lamp *la, float scale[3]) +{ if (la->type == LA_SPOT) { + /* Spot size & blend */ evli->sizex = scale[0] / scale[2]; evli->sizey = scale[1] / scale[2]; evli->spotsize = cosf(la->spotsize * 0.5f); @@ -639,16 +631,16 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) else { evli->radius = max_ff(0.001f, la->area_size); } +} - /* Lamp Type */ - evli->lamptype = (float)la->type; - +static float light_shape_power_get(const Lamp *la, const EEVEE_Light *evli) +{ + float power; /* Make illumination power constant */ if (la->type == LA_AREA) { power = 1.0f / (evli->sizex * evli->sizey * 4.0f * M_PI) * /* 1/(w*h*Pi) */ 80.0f; /* XXX : Empirical, Fit cycles power */ if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) { - evli->lamptype = LAMPTYPE_AREA_ELLIPSE; /* Scale power to account for the lower area of the ellipse compared to the surrounding rectangle. */ power *= 4.0f / M_PI; } @@ -664,8 +656,54 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli) power = 1.0f / (evli->radius * evli->radius * M_PI); /* 1/(r²*Pi) */ /* Make illumation power closer to cycles for bigger radii. Cycles uses a cos^3 term that we cannot reproduce * so we account for that by scaling the light power. This function is the result of a rough manual fitting. */ - power *= 1.0f + evli->radius * evli->radius * 0.5f; + power += 1.0f / (2.0f * M_PI); /* power *= 1 + r²/2 */ + } + return power; +} + +/* Update buffer with lamp data */ +static void eevee_light_setup(Object *ob, EEVEE_Light *evli) +{ + Lamp *la = (Lamp *)ob->data; + float mat[4][4], scale[3], power, att_radius; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + const float light_threshold = draw_ctx->scene->eevee.light_threshold; + + /* Position */ + copy_v3_v3(evli->position, ob->obmat[3]); + + /* Color */ + copy_v3_v3(evli->color, &la->r); + + evli->spec = la->spec_fac; + + /* Influence Radius */ + att_radius = light_attenuation_radius_get(la, light_threshold); + /* Take the inverse square of this distance. */ + evli->invsqrdist = 1.0 / max_ff(1e-4f, att_radius * att_radius); + + /* Vectors */ + normalize_m4_m4_ex(mat, ob->obmat, scale); + copy_v3_v3(evli->forwardvec, mat[2]); + normalize_v3(evli->forwardvec); + negate_v3(evli->forwardvec); + + copy_v3_v3(evli->rightvec, mat[0]); + normalize_v3(evli->rightvec); + + copy_v3_v3(evli->upvec, mat[1]); + normalize_v3(evli->upvec); + + light_shape_parameters_set(evli, la, scale); + + /* Lamp Type */ + evli->lamptype = (float)la->type; + if ((la->type == LA_AREA) && ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) { + evli->lamptype = LAMPTYPE_AREA_ELLIPSE; } + + power = light_shape_power_get(la, evli); mul_v3_fl(evli->color, power * la->energy); /* No shadow by default */ @@ -789,7 +827,7 @@ static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_La ubo_data->bias = 0.05f * la->bias; ubo_data->near = la->clipsta; - ubo_data->far = la->clipend; + ubo_data->far = 1.0f / (evli->invsqrdist * evli->invsqrdist); ubo_data->exp = (linfo->shadow_method == SHADOW_VSM) ? la->bleedbias : la->bleedexp; evli->shadowid = (float)(sh_data->shadow_id); @@ -1180,6 +1218,8 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; EEVEE_LampsInfo *linfo = sldata->lamps; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const float light_threshold = draw_ctx->scene->eevee.light_threshold; Object *ob; int i; @@ -1196,7 +1236,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) Lamp *la = (Lamp *)ob->data; BoundSphere bsphere = { .center = {ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]}, - .radius = la->clipend + .radius = light_attenuation_radius_get(la, light_threshold) }; cube_visible[i] = DRW_culling_sphere_test(&bsphere); } @@ -1236,14 +1276,13 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_ShadowCubeData *evscd = &led->data.scd; EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + evscd->cube_id; - perspective_m4(winmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend); - srd->clip_near = la->clipsta; - srd->clip_far = la->clipend; - copy_v3_v3(srd->position, cube_data->position); - + srd->clip_far = light_attenuation_radius_get(la, light_threshold); srd->stored_texel_size = 1.0 / (float)linfo->shadow_cube_store_size; srd->exponent = la->bleedexp; + copy_v3_v3(srd->position, cube_data->position); + + perspective_m4(winmat, -srd->clip_near, srd->clip_near, -srd->clip_near, srd->clip_near, srd->clip_near, srd->clip_far); DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); |