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