Blender V5.0
eevee_light.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "draw_debug.hh"
12
13#include "eevee_instance.hh"
14
15#include "eevee_light.hh"
16
17#include "DNA_defaults.h"
18#include "DNA_light_types.h"
19#include "DNA_sdna_type_ids.hh"
20
21#include "BKE_light.h"
22
23namespace blender::eevee {
24
25/* Convert by putting the least significant bits in the first component. */
27{
28 return {uint(data), uint(data >> uint64_t(32))};
29}
30
31/* -------------------------------------------------------------------- */
34
35static eLightType to_light_type(short blender_light_type,
36 short blender_area_type,
37 bool use_soft_falloff)
38{
39 switch (blender_light_type) {
40 default:
41 case LA_LOCAL:
42 return use_soft_falloff ? LIGHT_OMNI_DISK : LIGHT_OMNI_SPHERE;
43 case LA_SUN:
44 return LIGHT_SUN;
45 case LA_SPOT:
46 return use_soft_falloff ? LIGHT_SPOT_DISK : LIGHT_SPOT_SPHERE;
47 case LA_AREA:
48 return ELEM(blender_area_type, LA_AREA_DISK, LA_AREA_ELLIPSE) ? LIGHT_ELLIPSE : LIGHT_RECT;
49 }
50}
51
53
54/* -------------------------------------------------------------------- */
57
58void Light::sync(ShadowModule &shadows,
59 float4x4 object_to_world,
60 char visibility_flag,
61 const ::Light *la,
62 const LightLinking *light_linking /* = nullptr */,
63 float threshold)
64{
65 using namespace blender::math;
66
67 eLightType new_type = to_light_type(la->type, la->area_shape, la->mode & LA_USE_SOFT_FALLOFF);
68 if (assign_if_different(this->type, new_type)) {
69 shadow_discard_safe(shadows);
70 }
71
72 this->color = BKE_light_power(*la) * BKE_light_color(*la);
73 if (la->mode & LA_UNNORMALIZED) {
74 this->color *= BKE_light_area(*la, object_to_world);
75 }
76
78 object_to_world.view<3, 3>() = normalize_and_get_size(object_to_world.view<3, 3>(), scale);
79
80 /* Make sure we have consistent handedness (in case of negatively scaled Z axis). */
81 float3 back = cross(float3(object_to_world.x_axis()), float3(object_to_world.y_axis()));
82 if (dot(back, float3(object_to_world.z_axis())) < 0.0f) {
83 negate_v3(object_to_world.y_axis());
84 }
85
86 this->object_to_world = object_to_world;
87
88 shape_parameters_set(
89 la, scale, object_to_world.z_axis(), threshold, shadows.get_data().use_jitter);
90
91 const bool diffuse_visibility = (visibility_flag & OB_HIDE_DIFFUSE) == 0;
92 const bool glossy_visibility = (visibility_flag & OB_HIDE_GLOSSY) == 0;
93 const bool transmission_visibility = (visibility_flag & OB_HIDE_TRANSMISSION) == 0;
94 const bool volume_visibility = (visibility_flag & OB_HIDE_VOLUME_SCATTER) == 0;
95
96 float shape_power = shape_radiance_get();
97 float point_power = point_radiance_get();
98 this->power[LIGHT_DIFFUSE] = la->diff_fac * shape_power * diffuse_visibility;
99 this->power[LIGHT_SPECULAR] = la->spec_fac * shape_power * glossy_visibility;
100 this->power[LIGHT_TRANSMISSION] = la->transmission_fac * shape_power * transmission_visibility;
101 this->power[LIGHT_VOLUME] = la->volume_fac * point_power * volume_visibility;
102
103 this->lod_bias = shadows.global_lod_bias();
104 this->lod_min = shadow_lod_min_get(la);
105 this->filter_radius = la->shadow_filter_radius;
106 this->shadow_jitter = (la->mode & LA_SHADOW_JITTER) != 0;
107
108 if (la->mode & LA_SHADOW) {
109 shadow_ensure(shadows);
110 }
111 else {
112 shadow_discard_safe(shadows);
113 }
114
115 if (light_linking) {
116 this->light_set_membership = uint64_to_uint2(light_linking->runtime.light_set_membership);
117 this->shadow_set_membership = uint64_to_uint2(light_linking->runtime.shadow_set_membership);
118 }
119 else {
120 /* Set all bits if light linking is not used. */
121 this->light_set_membership = uint64_to_uint2(~uint64_t(0));
122 this->shadow_set_membership = uint64_to_uint2(~uint64_t(0));
123 }
124
125 this->initialized = true;
126}
127
128float Light::shadow_lod_min_get(const ::Light *la)
129{
130 /* Property is in mm. Convert to unit. */
131 float max_res_unit = la->shadow_maximum_resolution;
132 if (is_sun_light(this->type)) {
133 return log2f(max_res_unit * SHADOW_MAP_MAX_RES) - 1.0f;
134 }
135 /* Store absolute mode as negative. */
136 return (la->mode & LA_SHAD_RES_ABSOLUTE) ? -max_res_unit : max_res_unit;
137}
138
139void Light::shadow_discard_safe(ShadowModule &shadows)
140{
141 if (this->directional != nullptr) {
142 shadows.directional_pool.destruct(*directional);
143 this->directional = nullptr;
144 }
145 if (this->punctual != nullptr) {
146 shadows.punctual_pool.destruct(*punctual);
147 this->punctual = nullptr;
148 }
149}
150
151void Light::shadow_ensure(ShadowModule &shadows)
152{
153 if (is_sun_light(this->type) && this->directional == nullptr) {
154 this->directional = &shadows.directional_pool.construct(shadows);
155 }
156 else if (this->punctual == nullptr) {
157 this->punctual = &shadows.punctual_pool.construct(shadows);
158 }
159}
160
161float Light::attenuation_radius_get(const ::Light *la, float light_threshold, float light_power)
162{
163 if (la->mode & LA_CUSTOM_ATTENUATION) {
164 return la->att_dist;
165 }
166 /* Compute the distance (using the inverse square law)
167 * at which the light power reaches the light_threshold. */
168 /* TODO take area light scale into account. */
169 return sqrtf(light_power / light_threshold);
170}
171
172void Light::shape_parameters_set(const ::Light *la,
173 const float3 &scale,
174 const float3 &z_axis,
175 const float threshold,
176 const bool use_jitter)
177{
178 using namespace blender::math;
179
180 /* Compute influence radius first. Can be amended by shape later. */
181 if (is_local_light(this->type)) {
182 const float max_power = reduce_max(BKE_light_color(*la)) *
183 fabsf(BKE_light_power(*la) / 100.0f);
184 const float surface_max_power = max(la->diff_fac, la->spec_fac) * max_power;
185 const float volume_max_power = la->volume_fac * max_power;
186
187 float influence_radius_surface = attenuation_radius_get(la, threshold, surface_max_power);
188 float influence_radius_volume = attenuation_radius_get(la, threshold, volume_max_power);
189
190 this->local.influence_radius_max = max(influence_radius_surface, influence_radius_volume);
191 this->local.influence_radius_invsqr_surface = safe_rcp(square(influence_radius_surface));
192 this->local.influence_radius_invsqr_volume = safe_rcp(square(influence_radius_volume));
193 /* TODO(fclem): This is just duplicating a member for local lights. */
194 this->clip_far = float_as_int(this->local.influence_radius_max);
195 this->clip_near = float_as_int(this->local.influence_radius_max / 4000.0f);
196 }
197
198 float trace_scaling_fac = (use_jitter && (la->mode & LA_SHADOW_JITTER)) ?
199 la->shadow_jitter_overblur / 100.0f :
200 1.0f;
201
202 if (is_sun_light(this->type)) {
203 float sun_half_angle = min_ff(la->sun_angle, DEG2RADF(179.9f)) / 2.0f;
204 /* Use non-clamped radius for soft shadows. Avoid having a minimum blur. */
205 this->sun.shadow_angle = sun_half_angle * trace_scaling_fac;
206 /* Clamp to a minimum to distinguish between point lights and area light shadow. */
207 this->sun.shadow_angle = (sun_half_angle > 0.0f) ? max_ff(1e-8f, sun.shadow_angle) : 0.0f;
208 /* Clamp to minimum value before float imprecision artifacts appear. */
209 this->sun.shape_radius = clamp(tanf(sun_half_angle), 0.001f, 20.0f);
210 /* Stable shading direction. */
211 this->sun.direction = z_axis;
212 }
213 else if (is_area_light(this->type)) {
214 const bool is_irregular = ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE);
215 this->area.size = float2(la->area_size, is_irregular ? la->area_sizey : la->area_size);
216 /* Scale and clamp to minimum value before float imprecision artifacts appear. */
217 this->area.size *= scale.xy() / 2.0f;
218 this->area.shadow_scale = trace_scaling_fac;
219 this->local.shadow_radius = length(this->area.size) * trace_scaling_fac;
220 /* Set to default position. */
221 this->local.shadow_position = float3(0.0f);
222 /* Do not render lights that have no area. */
223 if (this->area.size.x * this->area.size.y < 0.00001f) {
224 /* Forces light to be culled. */
225 this->local.influence_radius_max = 0.0f;
226 }
227 /* Clamp to minimum value before float imprecision artifacts appear. */
228 this->area.size = max(float2(0.003f), this->area.size);
229 /* For volume point lighting. */
230 this->local.shape_radius = max(0.001f, length(this->area.size) / 2.0f);
231 }
232 else if (is_point_light(this->type)) {
233 /* Spot size & blend */
234 if (is_spot_light(this->type)) {
235 const float spot_size = cosf(la->spotsize * 0.5f);
236 const float spot_blend = (1.0f - spot_size) * la->spotblend;
237 this->spot.spot_size_inv = scale.z / max(scale.xy(), float2(1e-8f));
238 this->spot.spot_mul = 1.0f / max(1e-8f, spot_blend);
239 this->spot.spot_bias = -spot_size * this->spot.spot_mul;
240 this->spot.spot_tan = tanf(min(la->spotsize * 0.5f, float(M_PI_2 - 0.0001f)));
241 }
242 else {
243 /* Point light could access it. Make sure to avoid Undefined Behavior.
244 * In practice it is only ever used. */
245 this->spot.spot_size_inv = float2(1.0f);
246 this->spot.spot_mul = 0.0f;
247 this->spot.spot_bias = 1.0f;
248 this->spot.spot_tan = 0.0f;
249 }
250 /* Use unclamped radius for soft shadows. Avoid having a minimum blur. */
251 this->local.shadow_radius = max(0.0f, la->radius) * trace_scaling_fac;
252 /* Clamp to a minimum to distinguish between point lights and area light shadow. */
253 this->local.shadow_radius = (la->radius > 0.0f) ? max_ff(1e-8f, local.shadow_radius) : 0.0f;
254 /* Set to default position. */
255 this->local.shadow_position = float3(0.0f);
256 this->local.shape_radius = la->radius;
257 /* Clamp to minimum value before float imprecision artifacts appear. */
258 this->local.shape_radius = max(0.001f, this->local.shape_radius);
259 }
260}
261
262float Light::shape_radiance_get()
263{
264 using namespace blender::math;
265
266 /* Make illumination power constant. */
267 switch (this->type) {
268 case LIGHT_RECT:
269 case LIGHT_ELLIPSE: {
270 /* Rectangle area. */
271 float area = this->area.size.x * this->area.size.y * 4.0f;
272 /* Scale for the lower area of the ellipse compared to the surrounding rectangle. */
273 if (this->type == LIGHT_ELLIPSE) {
274 area *= M_PI / 4.0f;
275 }
276 /* Convert radiant flux to radiance. */
277 return float(M_1_PI) / area;
278 }
280 case LIGHT_OMNI_DISK:
282 case LIGHT_SPOT_DISK: {
283 /* Sphere area. */
284 float area = float(4.0f * M_PI) * square(this->local.shape_radius);
285 /* Convert radiant flux to radiance. */
286 return 1.0f / (area * float(M_PI));
287 }
288 case LIGHT_SUN_ORTHO:
289 case LIGHT_SUN: {
290 float inv_sin_sq = 1.0f + 1.0f / square(this->sun.shape_radius);
291 /* Convert irradiance to radiance. */
292 return float(M_1_PI) * inv_sin_sq;
293 }
294 }
296 return 0.0f;
297}
298
299float Light::point_radiance_get()
300{
301 /* Volume light is evaluated as point lights. */
302 switch (this->type) {
303 case LIGHT_RECT:
304 case LIGHT_ELLIPSE: {
305 /* This corrects for area light most representative point trick.
306 * The fit was found by reducing the average error compared to cycles. */
307 float area = this->area.size.x * this->area.size.y * 4.0f;
308 float tmp = M_PI_2 / (M_PI_2 + sqrtf(area));
309 /* Lerp between 1.0 and the limit (1 / pi). */
310 float mrp_scaling = tmp + (1.0f - tmp) * M_1_PI;
311 return float(M_1_PI) * mrp_scaling;
312 }
314 case LIGHT_OMNI_DISK:
316 case LIGHT_SPOT_DISK: {
317 /* Convert radiant flux to intensity. */
318 /* Inverse of sphere solid angle. */
319 return float(1.0 / (4.0 * M_PI));
320 }
321 case LIGHT_SUN_ORTHO:
322 case LIGHT_SUN: {
323 return 1.0f;
324 }
325 }
327 return 0.0f;
328}
329
330void Light::debug_draw()
331{
332 drw_debug_sphere(transform_location(this->object_to_world),
333 local.influence_radius_max,
334 float4(0.8f, 0.3f, 0.0f, 1.0f));
335}
336
338
339/* -------------------------------------------------------------------- */
342
344{
345 /* WATCH: Destructor order. Expect shadow module to be destructed later. */
346 for (Light &light : light_map_.values()) {
347 light.shadow_discard_safe(inst_.shadows);
348 }
349};
350
352{
353 if (assign_if_different(use_scene_lights_, inst_.use_scene_lights())) {
354 if (inst_.is_viewport()) {
355 /* Catch lookdev viewport properties updates. */
356 inst_.sampling.reset();
357 }
358 }
359
360 /* Disable sunlight if world has a volume shader as we consider the light cannot go through an
361 * infinite opaque medium. */
362 use_sun_lights_ = (inst_.world.has_volume_absorption() == false);
363
364 /* In begin_sync so it can be animated. */
365 if (assign_if_different(light_threshold_, max_ff(1e-16f, inst_.scene->eevee.light_threshold))) {
366 /* All local lights need to be re-sync. */
367 for (Light &light : light_map_.values()) {
368 if (!ELEM(light.type, LIGHT_SUN, LIGHT_SUN_ORTHO)) {
369 light.initialized = false;
370 }
371 }
372 }
373
374 sun_lights_len_ = 0;
375 local_lights_len_ = 0;
376
377 if (use_sun_lights_ && inst_.world.sun_threshold() > 0.0f) {
378 /* Create a placeholder light to be fed by the GPU after sunlight extraction.
379 * Sunlight is disabled if power is zero. */
380 ::Light la = blender::dna::shallow_copy(
382 la.type = LA_SUN;
383 /* Set on the GPU. */
384 la.r = la.g = la.b = -1.0f; /* Tag as world sun light. */
385 la.energy = 1.0f;
386 la.sun_angle = inst_.world.sun_angle();
387 la.shadow_filter_radius = inst_.world.sun_shadow_filter_radius();
388 la.shadow_jitter_overblur = inst_.world.sun_shadow_jitter_overblur();
389 la.shadow_maximum_resolution = inst_.world.sun_shadow_max_resolution();
390 SET_FLAG_FROM_TEST(la.mode, inst_.world.use_sun_shadow(), LA_SHADOW);
391 SET_FLAG_FROM_TEST(la.mode, inst_.world.use_sun_shadow_jitter(), LA_SHADOW_JITTER);
392
393 Light &light = light_map_.lookup_or_add_default(world_sunlight_key);
394 light.used = true;
395 light.sync(inst_.shadows, float4x4::identity(), 0, &la, nullptr, light_threshold_);
396
397 sun_lights_len_ += 1;
398 }
399}
400
402{
403 const ::Light &la = DRW_object_get_data_for_drawing<const ::Light>(*ob);
404 if (use_scene_lights_ == false) {
405 return;
406 }
407
408 if (use_sun_lights_ == false) {
409 if (la.type == LA_SUN) {
410 return;
411 }
412 }
413
414 Light &light = light_map_.lookup_or_add_default(handle.object_key);
415 light.used = true;
416 if (handle.recalc != 0 || !light.initialized) {
417 light.initialized = true;
418 light.sync(inst_.shadows,
419 ob->object_to_world(),
420 ob->visibility_flag,
421 &la,
422 ob->light_linking,
423 light_threshold_);
424 }
425 sun_lights_len_ += int(is_sun_light(light.type));
426 local_lights_len_ += int(!is_sun_light(light.type));
427}
428
430{
431 /* NOTE: We resize this buffer before removing deleted lights. */
432 int lights_allocated = ceil_to_multiple_u(max_ii(light_map_.size(), 1), LIGHT_CHUNK);
433 light_buf_.resize(lights_allocated);
434
435 /* Track light deletion. */
436 /* Indices inside GPU data array. */
437 int sun_lights_idx = 0;
438 int local_lights_idx = sun_lights_len_;
439
440 /* Fill GPU data with scene data. */
441 auto it_end = light_map_.items().end();
442 for (auto it = light_map_.items().begin(); it != it_end; ++it) {
443 Light &light = (*it).value;
444 /* Do not discard casters in baking mode. See WORKAROUND in `surfels_create`. */
445 if (!light.used && !inst_.is_baking()) {
446 light_map_.remove(it);
447 continue;
448 }
449
450 int dst_idx = is_sun_light(light.type) ? sun_lights_idx++ : local_lights_idx++;
451 /* Put all light data into global data SSBO. */
452 light_buf_[dst_idx] = light;
453
454 /* Untag for next sync. */
455 light.used = false;
456 }
457 /* This scene data buffer is then immutable after this point. */
458 light_buf_.push_update();
459
460 /* If exceeding the limit, just trim off the excess to avoid glitchy rendering. */
461 if (sun_lights_len_ + local_lights_len_ > CULLING_MAX_ITEM) {
462 sun_lights_len_ = min_ii(sun_lights_len_, CULLING_MAX_ITEM);
463 local_lights_len_ = min_ii(local_lights_len_, CULLING_MAX_ITEM - sun_lights_len_);
464 inst_.info_append_i18n("Error: Too many lights in the scene.");
465 }
466 lights_len_ = sun_lights_len_ + local_lights_len_;
467
468 /* Resize to the actual number of lights after pruning. */
469 lights_allocated = ceil_to_multiple_u(max_ii(lights_len_, 1), LIGHT_CHUNK);
470 culling_key_buf_.resize(lights_allocated);
471 culling_zdist_buf_.resize(lights_allocated);
472 culling_light_buf_.resize(lights_allocated);
473
474 {
475
476 int2 render_extent = inst_.film.render_extent_get();
477 int2 probe_extent = int2(inst_.sphere_probes.probe_render_extent());
478 int2 max_extent = math::max(render_extent, probe_extent);
479 /* Compute tile size and total word count. */
480 uint word_per_tile = divide_ceil_u(max_ii(lights_len_, 1), 32);
481 int2 tiles_extent;
482 /* Default to 32 as this is likely to be the maximum
483 * tile size used by hardware or compute shading. */
484 uint tile_size = 16;
485 bool tile_size_valid = false;
486 do {
487 tile_size *= 2;
488 tiles_extent = math::divide_ceil(max_extent, int2(tile_size));
489 uint tile_count = tiles_extent.x * tiles_extent.y;
490 if (tile_count > max_tile_count_threshold) {
491 continue;
492 }
493 total_word_count_ = tile_count * word_per_tile;
494 tile_size_valid = true;
495
496 } while (total_word_count_ > max_word_count_threshold || !tile_size_valid);
497 /* Keep aligned with storage buffer requirements. */
498 total_word_count_ = ceil_to_multiple_u(total_word_count_, 32);
499
500 culling_data_buf_.tile_word_len = word_per_tile;
501 culling_data_buf_.tile_size = tile_size;
502 culling_data_buf_.tile_x_len = tiles_extent.x;
503 culling_data_buf_.tile_y_len = tiles_extent.y;
504 culling_data_buf_.items_count = lights_len_;
505 culling_data_buf_.local_lights_len = local_lights_len_;
506 culling_data_buf_.sun_lights_len = sun_lights_len_;
507 }
508 culling_tile_buf_.resize(total_word_count_);
509
510 culling_pass_sync();
511 update_pass_sync();
512 debug_pass_sync();
513}
514
515void LightModule::culling_pass_sync()
516{
517 uint safe_lights_len = max_ii(lights_len_, 1);
518 uint culling_select_dispatch_size = divide_ceil_u(safe_lights_len, CULLING_SELECT_GROUP_SIZE);
519 uint culling_sort_dispatch_size = divide_ceil_u(safe_lights_len, CULLING_SORT_GROUP_SIZE);
520 uint culling_tile_dispatch_size = divide_ceil_u(total_word_count_, CULLING_TILE_GROUP_SIZE);
521
522 /* NOTE: We reference the buffers that may be resized or updated later. */
523
524 culling_ps_.init();
525 {
526 auto &sub = culling_ps_.sub("Select");
527 sub.shader_set(inst_.shaders.static_shader_get(LIGHT_CULLING_SELECT));
528 sub.bind_ubo("sunlight_buf", &inst_.world.sunlight);
529 sub.bind_ssbo("light_cull_buf", &culling_data_buf_);
530 sub.bind_ssbo("in_light_buf", light_buf_);
531 sub.bind_ssbo("out_light_buf", culling_light_buf_);
532 sub.bind_ssbo("out_zdist_buf", culling_zdist_buf_);
533 sub.bind_ssbo("out_key_buf", culling_key_buf_);
534 sub.dispatch(int3(culling_select_dispatch_size, 1, 1));
535 sub.barrier(GPU_BARRIER_SHADER_STORAGE);
536 }
537 {
538 auto &sub = culling_ps_.sub("Sort");
539 sub.shader_set(inst_.shaders.static_shader_get(LIGHT_CULLING_SORT));
540 sub.bind_ssbo("light_cull_buf", &culling_data_buf_);
541 sub.bind_ssbo("in_light_buf", light_buf_);
542 sub.bind_ssbo("out_light_buf", culling_light_buf_);
543 sub.bind_ssbo("in_zdist_buf", culling_zdist_buf_);
544 sub.bind_ssbo("in_key_buf", culling_key_buf_);
545 sub.dispatch(int3(culling_sort_dispatch_size, 1, 1));
546 sub.barrier(GPU_BARRIER_SHADER_STORAGE);
547 }
548 {
549 auto &sub = culling_ps_.sub("Zbin");
550 sub.shader_set(inst_.shaders.static_shader_get(LIGHT_CULLING_ZBIN));
551 sub.bind_ssbo("light_cull_buf", &culling_data_buf_);
552 sub.bind_ssbo("light_buf", culling_light_buf_);
553 sub.bind_ssbo("out_zbin_buf", culling_zbin_buf_);
554 sub.dispatch(int3(1, 1, 1));
555 sub.barrier(GPU_BARRIER_SHADER_STORAGE);
556 }
557 {
558 auto &sub = culling_ps_.sub("Tiles");
559 sub.shader_set(inst_.shaders.static_shader_get(LIGHT_CULLING_TILE));
560 sub.bind_ssbo("light_cull_buf", &culling_data_buf_);
561 sub.bind_ssbo("light_buf", culling_light_buf_);
562 sub.bind_ssbo("out_light_tile_buf", culling_tile_buf_);
563 sub.dispatch(int3(culling_tile_dispatch_size, 1, 1));
564 sub.barrier(GPU_BARRIER_SHADER_STORAGE);
565 }
566}
567
568void LightModule::update_pass_sync()
569{
570 /* TODO(fclem): This dispatch for all light before culling. This could be made better by
571 * only running on lights that survive culling using an indirect dispatch. */
572 uint safe_lights_len = max_ii(lights_len_, 1);
573 uint shadow_setup_dispatch_size = divide_ceil_u(safe_lights_len, CULLING_SELECT_GROUP_SIZE);
574
575 auto &pass = update_ps_;
576 pass.init();
577 pass.shader_set(inst_.shaders.static_shader_get(LIGHT_SHADOW_SETUP));
578 pass.bind_ssbo("light_buf", &culling_light_buf_);
579 pass.bind_ssbo("light_cull_buf", &culling_data_buf_);
580 pass.bind_ssbo("tilemaps_buf", &inst_.shadows.tilemap_pool.tilemaps_data);
581 pass.bind_ssbo("tilemaps_clip_buf", &inst_.shadows.tilemap_pool.tilemaps_clip);
582 pass.bind_resources(inst_.uniform_data);
583 pass.bind_resources(inst_.sampling);
584 pass.dispatch(int3(shadow_setup_dispatch_size, 1, 1));
585 pass.barrier(GPU_BARRIER_SHADER_STORAGE);
586}
587
588void LightModule::debug_pass_sync()
589{
590 if (inst_.debug_mode == eDebugMode::DEBUG_LIGHT_CULLING) {
591 debug_draw_ps_.init();
592 debug_draw_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
593 debug_draw_ps_.shader_set(inst_.shaders.static_shader_get(LIGHT_CULLING_DEBUG));
594 debug_draw_ps_.bind_resources(inst_.uniform_data);
595 debug_draw_ps_.bind_resources(inst_.hiz_buffer.front);
596 debug_draw_ps_.bind_ssbo("light_buf", &culling_light_buf_);
597 debug_draw_ps_.bind_ssbo("light_cull_buf", &culling_data_buf_);
598 debug_draw_ps_.bind_ssbo("light_zbin_buf", &culling_zbin_buf_);
599 debug_draw_ps_.bind_ssbo("light_tile_buf", &culling_tile_buf_);
600 debug_draw_ps_.bind_texture("depth_tx", &inst_.render_buffers.depth_tx);
601 debug_draw_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
602 }
603}
604
606{
607 float far_z = view.far_clip();
608 float near_z = view.near_clip();
609
610 culling_data_buf_.zbin_scale = -CULLING_ZBIN_COUNT / fabsf(far_z - near_z);
611 culling_data_buf_.zbin_bias = -near_z * culling_data_buf_.zbin_scale;
612 culling_data_buf_.tile_to_uv_fac = (culling_data_buf_.tile_size / float2(extent));
613 culling_data_buf_.visible_count = 0;
614 culling_data_buf_.view_is_flipped = view.is_inverted();
615 culling_data_buf_.push_update();
616
617 inst_.manager->submit(culling_ps_, view);
618 inst_.manager->submit(update_ps_, view);
619}
620
622{
623 if (inst_.debug_mode == eDebugMode::DEBUG_LIGHT_CULLING) {
624 inst_.info_append("Debug Mode: Light Culling Validation");
625 inst_.hiz_buffer.update();
626 GPU_framebuffer_bind(view_fb);
627 inst_.manager->submit(debug_draw_ps_, view);
628 }
629}
630
632
633} // namespace blender::eevee
General operations, lookup, etc. for blender lights.
blender::float3 BKE_light_color(const Light &light)
float BKE_light_area(const Light &light, const blender::float4x4 &object_to_world)
float BKE_light_power(const Light &light)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
MINLINE uint ceil_to_multiple_u(uint a, uint b)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE uint divide_ceil_u(uint a, uint b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE int float_as_int(float f)
#define M_1_PI
#define DEG2RADF(_deg)
#define M_PI_2
#define M_PI
MINLINE void negate_v3(float r[3])
unsigned int uint
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
const void * DNA_default_table[SDNA_TYPE_MAX]
@ LA_AREA
@ LA_LOCAL
@ LA_SPOT
@ LA_SUN
@ LA_SHAD_RES_ABSOLUTE
@ LA_CUSTOM_ATTENUATION
@ LA_UNNORMALIZED
@ LA_SHADOW_JITTER
@ LA_SHADOW
@ LA_USE_SOFT_FALLOFF
@ LA_AREA_ELLIPSE
@ LA_AREA_RECT
@ LA_AREA_DISK
@ OB_HIDE_TRANSMISSION
@ OB_HIDE_GLOSSY
@ OB_HIDE_DIFFUSE
@ OB_HIDE_VOLUME_SCATTER
T & DRW_object_get_data_for_drawing(const Object &object)
static AppView * view
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
@ GPU_PRIM_TRIS
@ GPU_BARRIER_SHADER_STORAGE
Definition GPU_state.hh:48
BMesh const char void * data
unsigned long long int uint64_t
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:690
void sync_light(const Object *ob, ObjectHandle &handle)
void set_view(View &view, const int2 extent)
void debug_draw(View &view, gpu::FrameBuffer *view_fb)
gpu::Shader * static_shader_get(eShaderType shader_type)
const ShadowSceneData & get_data()
Pool< ShadowDirectional > directional_pool
Pool< ShadowPunctual > punctual_pool
UniformBuffer< LightData > sunlight
nullptr float
Simple API to draw debug shapes and log in the viewport.
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_BLEND_CUSTOM
Definition draw_state.hh:63
#define CULLING_SELECT_GROUP_SIZE
#define LIGHT_CHUNK
#define CULLING_SORT_GROUP_SIZE
#define CULLING_TILE_GROUP_SIZE
#define SHADOW_MAP_MAX_RES
#define CULLING_ZBIN_COUNT
#define CULLING_MAX_ITEM
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
ccl_device_inline float2 power(const float2 v, const float e)
int sdna_struct_id_get()
void drw_debug_sphere(const float3 center, float radius, const float4 color, const uint lifetime)
static bool is_area_light(eLightType type)
static uint2 uint64_to_uint2(uint64_t data)
static bool is_sun_light(eLightType type)
static bool is_spot_light(eLightType type)
static eLightType to_light_type(short blender_light_type, short blender_area_type, bool use_soft_falloff)
static bool is_local_light(eLightType type)
static bool is_point_light(eLightType type)
static float3 transform_location(Transform t)
T clamp(const T &a, const T &min, const T &max)
T safe_rcp(const T &a)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
T reduce_max(const VecBase< T, Size > &a)
VecBase< T, Size > divide_ceil(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
MatBase< T, NumCol, NumRow > normalize_and_get_size(const MatBase< T, NumCol, NumRow > &a, VectorT &r_size)
T square(const T &a)
T max(const T &a, const T &b)
VecBase< uint32_t, 2 > uint2
bool assign_if_different(T &old_value, T new_value)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
#define fabsf
#define sqrtf
#define tanf
#define cosf
#define min(a, b)
Definition sort.cc:36
LightLinkingRuntime runtime
float sun_angle
float energy
float shadow_filter_radius
float shadow_jitter_overblur
float area(const Transform &tfm) const
float shadow_maximum_resolution
short type
short visibility_flag
LightLinking * light_linking
const MatView< T, ViewNumCol, ViewNumRow, NumCol, NumRow, SrcStartCol, SrcStartRow, Alignment > view() const
void shadow_discard_safe(ShadowModule &shadows)
ShadowDirectional * directional
void shadow_ensure(ShadowModule &shadows)
void sync(ShadowModule &shadows, float4x4 object_to_world, char visibility_flag, const ::Light *la, const LightLinking *light_linking, float threshold)
ShadowPunctual * punctual
max
Definition text_draw.cc:251