Unravel Engine C++ Reference
Loading...
Searching...
No Matches
shadow.cpp
Go to the documentation of this file.
1#include "shadow.h"
2
6#include <engine/engine.h>
7#include <engine/events.h>
15
19#include <graphics/texture.h>
21
22namespace unravel
23{
24namespace shadow
25{
26
27namespace
28{
29
30// clang-format off
31RenderState render_states[RenderState::Count] =
32 {
33 { // Default
34 0
35 | BGFX_STATE_WRITE_RGB
36 | BGFX_STATE_WRITE_A
37 | BGFX_STATE_DEPTH_TEST_LESS
38 | BGFX_STATE_WRITE_Z
39 | BGFX_STATE_CULL_CCW
40 | BGFX_STATE_MSAA
41 , UINT32_MAX
42 , BGFX_STENCIL_NONE
43 , BGFX_STENCIL_NONE
44 },
45 { // ShadowMap_PackDepth
46 0
47 | BGFX_STATE_WRITE_RGB
48 | BGFX_STATE_WRITE_A
49 | BGFX_STATE_WRITE_Z
50 | BGFX_STATE_DEPTH_TEST_LESS
51 | BGFX_STATE_CULL_CCW
52 | BGFX_STATE_MSAA
53 , UINT32_MAX
54 , BGFX_STENCIL_NONE
55 , BGFX_STENCIL_NONE
56 },
57 { // ShadowMap_PackDepthHoriz
58 0
59 | BGFX_STATE_WRITE_RGB
60 | BGFX_STATE_WRITE_A
61 | BGFX_STATE_WRITE_Z
62 | BGFX_STATE_DEPTH_TEST_LESS
63 | BGFX_STATE_CULL_CCW
64 | BGFX_STATE_MSAA
65 , UINT32_MAX
66 , BGFX_STENCIL_TEST_EQUAL
67 | BGFX_STENCIL_FUNC_REF(1)
68 | BGFX_STENCIL_FUNC_RMASK(0xff)
69 | BGFX_STENCIL_OP_FAIL_S_KEEP
70 | BGFX_STENCIL_OP_FAIL_Z_KEEP
71 | BGFX_STENCIL_OP_PASS_Z_KEEP
72 , BGFX_STENCIL_NONE
73 },
74 { // ShadowMap_PackDepthVert
75 0
76 | BGFX_STATE_WRITE_RGB
77 | BGFX_STATE_WRITE_A
78 | BGFX_STATE_WRITE_Z
79 | BGFX_STATE_DEPTH_TEST_LESS
80 | BGFX_STATE_CULL_CCW
81 | BGFX_STATE_MSAA
82 , UINT32_MAX
83 , BGFX_STENCIL_TEST_EQUAL
84 | BGFX_STENCIL_FUNC_REF(0)
85 | BGFX_STENCIL_FUNC_RMASK(0xff)
86 | BGFX_STENCIL_OP_FAIL_S_KEEP
87 | BGFX_STENCIL_OP_FAIL_Z_KEEP
88 | BGFX_STENCIL_OP_PASS_Z_KEEP
89 , BGFX_STENCIL_NONE
90 },
91 { // Custom_BlendLightTexture
92 BGFX_STATE_WRITE_RGB
93 | BGFX_STATE_WRITE_A
94 | BGFX_STATE_WRITE_Z
95 | BGFX_STATE_DEPTH_TEST_LESS
96 | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_COLOR, BGFX_STATE_BLEND_INV_SRC_COLOR)
97 | BGFX_STATE_CULL_CCW
98 | BGFX_STATE_MSAA
99 , UINT32_MAX
100 , BGFX_STENCIL_NONE
101 , BGFX_STENCIL_NONE
102 },
103 { // Custom_DrawPlaneBottom
104 BGFX_STATE_WRITE_RGB
105 | BGFX_STATE_CULL_CW
106 | BGFX_STATE_MSAA
107 , UINT32_MAX
108 , BGFX_STENCIL_NONE
109 , BGFX_STENCIL_NONE
110 },
111 };
112// clang-format on
113
114auto convert(light_type t) -> LightType::Enum
115{
116 static_assert(std::uint8_t(light_type::count) == std::uint8_t(LightType::Count), "Missing impl");
117
118 switch(t)
119 {
120 case light_type::spot:
124 default:
126 }
127}
128
129auto convert(sm_impl t) -> SmImpl::Enum
130{
131 static_assert(std::uint8_t(sm_impl::count) == std::uint8_t(SmImpl::Count), "Missing impl");
132
133 switch(t)
134 {
135 case sm_impl::hard:
136 return SmImpl::Hard;
137
138 case sm_impl::pcf:
139 return SmImpl::PCF;
140
141 case sm_impl::pcss:
142 return SmImpl::PCSS;
143
144 case sm_impl::esm:
145 return SmImpl::ESM;
146
147 case sm_impl::vsm:
148 return SmImpl::VSM;
149 default:
150 return SmImpl::Count;
151 }
152}
153
154auto convert(sm_depth t) -> DepthImpl::Enum
155{
156 static_assert(std::uint8_t(sm_depth::count) == std::uint8_t(DepthImpl::Count), "Missing impl");
157 switch(t)
158 {
159 case sm_depth::invz:
160 return DepthImpl::InvZ;
161
162 case sm_depth::linear:
163 return DepthImpl::Linear;
164
165 default:
166 return DepthImpl::Count;
167 }
168}
169
170auto convert(sm_resolution t) -> float
171{
172 switch(t)
173 {
175 return 8;
176
178 return 9;
179
181 return 10;
182
184 return 11;
185
186 default:
187 return 10;
188 }
189}
190
191void mtxYawPitchRoll(float* _result, float _yaw, float _pitch, float _roll)
192{
193 float sroll = bx::sin(_roll);
194 float croll = bx::cos(_roll);
195 float spitch = bx::sin(_pitch);
196 float cpitch = bx::cos(_pitch);
197 float syaw = bx::sin(_yaw);
198 float cyaw = bx::cos(_yaw);
199
200 _result[0] = sroll * spitch * syaw + croll * cyaw;
201 _result[1] = sroll * cpitch;
202 _result[2] = sroll * spitch * cyaw - croll * syaw;
203 _result[3] = 0.0f;
204 _result[4] = croll * spitch * syaw - sroll * cyaw;
205 _result[5] = croll * cpitch;
206 _result[6] = croll * spitch * cyaw + sroll * syaw;
207 _result[7] = 0.0f;
208 _result[8] = cpitch * syaw;
209 _result[9] = -spitch;
210 _result[10] = cpitch * cyaw;
211 _result[11] = 0.0f;
212 _result[12] = 0.0f;
213 _result[13] = 0.0f;
214 _result[14] = 0.0f;
215 _result[15] = 1.0f;
216}
217
218void screenSpaceQuad(bool _originBottomLeft = true, float _width = 1.0f, float _height = 1.0f)
219{
220 if(3 == bgfx::getAvailTransientVertexBuffer(3, PosColorTexCoord0Vertex::get_layout()))
221 {
222 bgfx::TransientVertexBuffer vb;
223 bgfx::allocTransientVertexBuffer(&vb, 3, PosColorTexCoord0Vertex::get_layout());
225
226 const float zz = 0.0f;
227
228 const float minx = -_width;
229 const float maxx = _width;
230 const float miny = 0.0f;
231 const float maxy = _height * 2.0f;
232
233 const float minu = -1.0f;
234 const float maxu = 1.0f;
235
236 float minv = 0.0f;
237 float maxv = 2.0f;
238
239 if(_originBottomLeft)
240 {
241 std::swap(minv, maxv);
242 minv -= 1.0f;
243 maxv -= 1.0f;
244 }
245
246 vertex[0].m_x = minx;
247 vertex[0].m_y = miny;
248 vertex[0].m_z = zz;
249 vertex[0].m_rgba = 0xffffffff;
250 vertex[0].m_u = minu;
251 vertex[0].m_v = minv;
252
253 vertex[1].m_x = maxx;
254 vertex[1].m_y = miny;
255 vertex[1].m_z = zz;
256 vertex[1].m_rgba = 0xffffffff;
257 vertex[1].m_u = maxu;
258 vertex[1].m_v = minv;
259
260 vertex[2].m_x = maxx;
261 vertex[2].m_y = maxy;
262 vertex[2].m_z = zz;
263 vertex[2].m_rgba = 0xffffffff;
264 vertex[2].m_u = maxu;
265 vertex[2].m_v = maxv;
266
267 bgfx::setVertexBuffer(0, &vb);
268 }
269}
270
271
272void world_space_frustum_corners_legacy(float* corners24f,
273 float near_plane,
274 float far_plane,
275 float proj_width,
276 float proj_height,
277 const float* inv_view_mtx)
278{
279 // Define frustum corners in view space.
280 const float nw = near_plane * proj_width;
281 const float nh = near_plane * proj_height;
282 const float fw = far_plane * proj_width;
283 const float fh = far_plane * proj_height;
284
285 const uint8_t num_corners = 8;
286 const bx::Vec3 corners[num_corners] = {
287 {-nw, nh, near_plane},
288 {nw, nh, near_plane},
289 {nw, -nh, near_plane},
290 {-nw, -nh, near_plane},
291 {-fw, fh, far_plane},
292 {fw, fh, far_plane},
293 {fw, -fh, far_plane},
294 {-fw, -fh, far_plane},
295 };
296
297 // Convert them to world space.
298 float(*out)[3] = (float(*)[3])corners24f;
299 for(uint8_t ii = 0; ii < num_corners; ++ii)
300 {
301 bx::store(&out[ii], bx::mul(corners[ii], inv_view_mtx));
302 }
303}
304
305void world_space_frustum_corners_adaptive(float* corners24f,
306 float near_plane,
307 float far_plane,
308 float proj_width,
309 float proj_height,
310 const float* inv_view_mtx,
311 float altitude_scale_factor,
312 float min_altitude_boost,
313 float max_altitude_boost)
314{
315 // Extract camera position from inverse view matrix
316 bx::Vec3 camera_pos = {inv_view_mtx[12], inv_view_mtx[13], inv_view_mtx[14]};
317
318 // Compute camera altitude above the ground plane (assuming Y is up)
319 const float altitude = camera_pos.y;
320 const float clamped_altitude = bx::clamp(altitude, 0.0f, max_altitude_boost);
321
322 // Adaptive scaling based on altitude
323 const float altitude_boost = bx::max(min_altitude_boost, clamped_altitude * altitude_scale_factor);
324
325 // Adjust near and far planes based on altitude
326 const float actual_near = bx::max(0.01f, near_plane - altitude_boost * 0.1f); // Pull near plane closer for high cameras
327 const float actual_far = far_plane + altitude_boost; // Push far plane further for high cameras
328
329 // Compute corners in view space using adjusted near/far
330 const float nw = actual_near * proj_width;
331 const float nh = actual_near * proj_height;
332 const float fw = actual_far * proj_width;
333 const float fh = actual_far * proj_height;
334
335 const uint8_t num_corners = 8;
336 const bx::Vec3 corners[num_corners] = {
337 {-nw, nh, actual_near},
338 {nw, nh, actual_near},
339 {nw, -nh, actual_near},
340 {-nw, -nh, actual_near},
341 {-fw, fh, actual_far},
342 {fw, fh, actual_far},
343 {fw, -fh, actual_far},
344 {-fw, -fh, actual_far},
345 };
346
347 // Convert them to world space.
348 float(*out)[3] = (float(*)[3])corners24f;
349 for(uint8_t ii = 0; ii < num_corners; ++ii)
350 {
351 bx::store(&out[ii], bx::mul(corners[ii], inv_view_mtx));
352 }
353}
354
355void world_space_frustum_corners_hybrid(float* corners24f,
356 float near_plane,
357 float far_plane,
358 float proj_width,
359 float proj_height,
360 const float* inv_view_mtx,
361 float blend_factor)
362{
363 // Get both legacy and adaptive results
364 float legacy_corners[8][3];
365 float adaptive_corners[8][3];
366
367 world_space_frustum_corners_legacy((float*)legacy_corners, near_plane, far_plane, proj_width, proj_height, inv_view_mtx);
368 world_space_frustum_corners_adaptive((float*)adaptive_corners, near_plane, far_plane, proj_width, proj_height, inv_view_mtx, 0.5f, 0.05f, 100.0f);
369
370 // Blend between the two approaches
371 float(*out)[3] = (float(*)[3])corners24f;
372 for(uint8_t ii = 0; ii < 8; ++ii)
373 {
374 for(uint8_t jj = 0; jj < 3; ++jj)
375 {
376 out[ii][jj] = bx::lerp(legacy_corners[ii][jj], adaptive_corners[ii][jj], blend_factor);
377 }
378 }
379}
380
381
382
383void worldSpaceFrustumCorners(float* _corners24f,
384 float _near,
385 float _far,
386 float _projWidth,
387 float _projHeight,
388 const float* _invViewMtx)
389{
390 // Original/Legacy implementation
391 world_space_frustum_corners_legacy(_corners24f, _near, _far, _projWidth, _projHeight, _invViewMtx);
392}
393
394
395void compute_world_space_frustum_corners(float* corners24f,
396 float near_plane,
397 float far_plane,
398 float proj_width,
399 float proj_height,
400 const float* inv_view_mtx,
402 const adaptive_shadow_params& params)
403{
404 switch(method)
405 {
407 world_space_frustum_corners_adaptive(corners24f,
408 near_plane,
409 far_plane,
410 proj_width,
411 proj_height,
412 inv_view_mtx,
414 params.min_altitude_boost,
415 params.max_altitude_boost);
416 break;
417
419 world_space_frustum_corners_hybrid(corners24f,
420 near_plane,
421 far_plane,
422 proj_width,
423 proj_height,
424 inv_view_mtx,
425 0.5f); // 50% blend
426 break;
427
429 default:
430 world_space_frustum_corners_legacy(corners24f,
431 near_plane,
432 far_plane,
433 proj_width,
434 proj_height,
435 inv_view_mtx);
436 break;
437 }
438}
439
440void split_frustum_legacy(float* splits, uint8_t num_splits, float near_plane, float far_plane, float split_weight)
441{
442 auto factor = float(num_splits) / 4.0f;
443 far_plane = far_plane * factor;
444
445 const float l = split_weight;
446 const float ratio = far_plane / near_plane;
447 const int8_t num_slices = num_splits * 2;
448 const float num_slices_f = float(num_slices);
449
450 // First slice.
451 splits[0] = near_plane;
452
453 for(uint8_t nn = 2, ff = 1; nn < num_slices; nn += 2, ff += 2)
454 {
455 float si = float(int8_t(ff)) / num_slices_f;
456
457 const float near_p = l * (near_plane * bx::pow(ratio, si)) + (1 - l) * (near_plane + (far_plane - near_plane) * si);
458 splits[nn] = near_p; // near
459 splits[ff] = near_p * 1.005f; // far from previous split
460 }
461
462 // Last slice.
463 splits[num_slices - 1] = far_plane;
464}
465
466void split_frustum_adaptive(float* splits, uint8_t num_splits, float near_plane, float far_plane,
467 float split_weight, float camera_altitude, float altitude_influence = 0.2f)
468{
469 auto factor = float(num_splits) / 4.0f;
470 far_plane = far_plane * factor;
471
472 // Adjust split weight based on camera altitude - higher cameras benefit from more uniform distribution
473 const float altitude_factor = bx::clamp(camera_altitude * altitude_influence, 0.0f, 1.0f);
474 const float adjusted_split_weight = bx::lerp(split_weight, 0.5f, altitude_factor); // Move towards linear distribution
475
476 const float l = adjusted_split_weight;
477 const float ratio = far_plane / near_plane;
478 const int8_t num_slices = num_splits * 2;
479 const float num_slices_f = float(num_slices);
480
481 // First slice.
482 splits[0] = near_plane;
483
484 for(uint8_t nn = 2, ff = 1; nn < num_slices; nn += 2, ff += 2)
485 {
486 float si = float(int8_t(ff)) / num_slices_f;
487
488 // Apply non-linear distribution that favors distant splits for high cameras
489 if(camera_altitude > 10.0f)
490 {
491 si = bx::pow(si, 0.8f); // Slightly favor distant splits
492 }
493
494 const float near_p = l * (near_plane * bx::pow(ratio, si)) + (1 - l) * (near_plane + (far_plane - near_plane) * si);
495 splits[nn] = near_p; // near
496 splits[ff] = near_p * 1.005f; // far from previous split
497 }
498
499 // Last slice.
500 splits[num_slices - 1] = far_plane;
501}
502
507 void splitFrustum(float* _splits, uint8_t _numSplits, float _near, float _far, float _splitWeight = 0.75f)
508 {
509 split_frustum_legacy(_splits, _numSplits, _near, _far, _splitWeight);
510 }
511} // namespace
512
517
522
528
530{
531 if(!valid_)
532 {
533 return;
534 }
535
536 valid_ = false;
537
538 for(int i = 0; i < ShadowMapRenderTargets::Count; ++i)
539 {
540 if(bgfx::isValid(rt_shadow_map_[i]))
541 {
542 bgfx::destroy(rt_shadow_map_[i]);
543 rt_shadow_map_[i] = {bgfx::kInvalidHandle};
544 }
545 }
546
547 if(bgfx::isValid(rt_blur_))
548 {
549 bgfx::destroy(rt_blur_);
550 rt_blur_ = {bgfx::kInvalidHandle};
551 }
552}
553
555{
556 if(bgfx::isValid(tex_color_))
557 {
558 bgfx::destroy(tex_color_);
559 }
560
561 for(int i = 0; i < ShadowMapRenderTargets::Count; ++i)
562 {
563 if(bgfx::isValid(shadow_map_[i]))
564 {
565 bgfx::destroy(shadow_map_[i]);
566 }
567 }
568}
569
571{
572 if(bgfx::isValid(tex_color_))
573 {
574 return;
575 }
576 // Uniforms.
577 uniforms_.init();
578 tex_color_ = bgfx::createUniform("s_texColor", bgfx::UniformType::Sampler);
579 shadow_map_[0] = bgfx::createUniform("s_shadowMap0", bgfx::UniformType::Sampler);
580 shadow_map_[1] = bgfx::createUniform("s_shadowMap1", bgfx::UniformType::Sampler);
581 shadow_map_[2] = bgfx::createUniform("s_shadowMap2", bgfx::UniformType::Sampler);
582 shadow_map_[3] = bgfx::createUniform("s_shadowMap3", bgfx::UniformType::Sampler);
583
584 for(int i = 0; i < ShadowMapRenderTargets::Count; ++i)
585 {
586 rt_shadow_map_[i] = {bgfx::kInvalidHandle};
587 }
588
589 // Programs.
590 programs_.init(ctx);
591
592 // Lights.
593 // clang-format off
594 point_light_ =
595 {
596 { { 0.0f, 0.0f, 0.0f, 1.0f } }, //position
597 { { 0.0f,-0.4f,-0.6f, 0.0f } }, //spotdirection, spotexponent
598 };
599
600 directional_light_ =
601 {
602 { { 0.5f,-1.0f, 0.1f, 0.0f } }, //position
603 { { 0.0f, 0.0f, 0.0f, 1.0f } }, //spotdirection, spotexponent
604 };
605
606 // clang-format on
607
608 // Setup uniforms.
609 color_[0] = color_[1] = color_[2] = color_[3] = 1.0f;
610 uniforms_.setPtrs(&point_light_,
611 color_,
612 light_mtx_,
613 &shadow_map_mtx_[ShadowMapRenderTargets::First][0],
614 &shadow_map_mtx_[ShadowMapRenderTargets::Second][0],
615 &shadow_map_mtx_[ShadowMapRenderTargets::Third][0],
616 &shadow_map_mtx_[ShadowMapRenderTargets::Fourth][0]);
617 uniforms_.submitConstUniforms();
618
619 // clang-format off
620 // Settings.
622 {
623 { //LightType::Spot
624
625 { //DepthImpl::InvZ
626
627 { //SmImpl::Hard
628 10.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
629 , 10.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
630 , 1.0f, 1.0f, 10.0f, 1.0f // m_near
631 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
632 , 0.0035f, 0.0f, 0.01f, 0.00001f // m_bias
633 , 0.0012f, 0.0f, 0.05f, 0.00001f // m_normalOffset
634 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
635 , 500.0f, 1.0f, 1000.0f, 1.0f // m_customParam1
636 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
637 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
638 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
639 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
640 , true // m_doBlur
641 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
642 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPackSkinned
643 },
644 { //SmImpl::PCF
645 10.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
646 , 10.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
647 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
648 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
649 , 0.007f, 0.0f, 0.01f, 0.00001f // m_bias
650 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
651 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
652 , 500.0f, 1.0f, 1000.0f, 1.0f // m_customParam1
653 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
654 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
655 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
656 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
657 , true // m_doBlur
658 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
659 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPackSkinned
660 },
661 { //SmImpl::PCSS
662 10.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
663 , 10.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
664 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
665 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
666 , 0.007f, 0.0f, 0.01f, 0.00001f // m_bias
667 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
668 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
669 , 500.0f, 1.0f, 1000.0f, 1.0f // m_customParam1
670 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
671 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
672 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
673 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
674 , true // m_doBlur
675 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
676 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPackSkinned
677 },
678 { //SmImpl::VSM
679 10.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
680 , 10.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
681 , 8.0f, 1.0f, 10.0f, 1.0f // m_near
682 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
683 , 0.045f, 0.0f, 0.1f, 0.00001f // m_bias
684 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
685 , 0.02f, 0.0f, 0.04f, 0.00001f // m_customParam0
686 , 450.0f, 1.0f, 1000.0f, 1.0f // m_customParam1
687 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
688 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
689 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
690 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
691 , true // m_doBlur
692 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::VSM].get() //m_progPack
693 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::VSM].get() //m_progPackSkinned
694 },
695 { //SmImpl::ESM
696 10.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
697 , 10.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
698 , 3.0f, 1.0f, 10.0f, 0.01f // m_near
699 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
700 , 0.02f, 0.0f, 0.3f, 0.00001f // m_bias
701 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
702 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
703 , 9000.0f, 1.0f, 15000.0f, 1.0f // m_customParam1
704 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
705 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
706 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
707 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
708 , true // m_doBlur
709 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
710 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_packDepthSkinned
711 }
712
713 },
714 { //DepthImpl::Linear
715
716 { //SmImpl::Hard
717 10.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
718 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
719 , 1.0f, 1.0f, 10.0f, 1.0f // m_near
720 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
721 , 0.0025f, 0.0f, 0.01f, 0.00001f // m_bias
722 , 0.0012f, 0.0f, 0.05f, 0.00001f // m_normalOffset
723 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
724 , 500.0f, 1.0f, 1000.0f, 1.0f // m_customParam1
725 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
726 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
727 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
728 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
729 , true // m_doBlur
730 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
731 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_packDepthSkinned
732 },
733 { //SmImpl::PCF
734 10.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
735 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
736 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
737 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
738 , 0.0025f, 0.0f, 0.01f, 0.00001f // m_bias
739 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
740 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
741 , 2000.0f, 1.0f, 2000.0f, 1.0f // m_customParam1
742 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
743 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
744 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
745 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
746 , true // m_doBlur
747 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
748 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPackSkinned
749 },
750 { //SmImpl::PCSS
751 10.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
752 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
753 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
754 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
755 , 0.0025f, 0.0f, 0.01f, 0.00001f // m_bias
756 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
757 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
758 , 2000.0f, 1.0f, 2000.0f, 1.0f // m_customParam1
759 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
760 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
761 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
762 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
763 , true // m_doBlur
764 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
765 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPackSkinned
766 },
767 { //SmImpl::VSM
768 10.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
769 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
770 , 1.0f, 1.0f, 10.0f, 1.0f // m_near
771 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
772 , 0.006f, 0.0f, 0.01f, 0.00001f // m_bias
773 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
774 , 0.02f, 0.0f, 0.1f, 0.00001f // m_customParam0
775 , 300.0f, 1.0f, 1500.0f, 1.0f // m_customParam1
776 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
777 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
778 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
779 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
780 , true // m_doBlur
781 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::VSM].get() //m_progPack
782 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::VSM].get() //m_packDepthSkinned
783 },
784 { //SmImpl::ESM
785 10.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
786 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
787 , 1.0f, 1.0f, 10.0f, 0.01f // m_near
788 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
789 , 0.0055f, 0.0f, 0.01f, 0.00001f // m_bias
790 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
791 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
792 , 2500.0f, 1.0f, 5000.0f, 1.0f // m_customParam1
793 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
794 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
795 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
796 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
797 , true // m_doBlur
798 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
799 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_packDepthSkinned
800 }
801
802 }
803
804 },
805 { //LightType::Point
806
807 { //DepthImpl::InvZ
808
809 { //SmImpl::Hard
810 12.0f, 9.0f, 12.0f, 1.0f // m_sizePwrTwo
811 , 10.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
812 , 1.0f, 1.0f, 10.0f, 1.0f // m_near
813 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
814 , 0.006f, 0.0f, 0.01f, 0.00001f // m_bias
815 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
816 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
817 , 50.0f, 1.0f, 300.0f, 1.0f // m_customParam1
818 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
819 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
820 , 0.25f, 0.0f, 2.0f, 0.001f // m_xOffset
821 , 0.25f, 0.0f, 2.0f, 0.001f // m_yOffset
822 , true // m_doBlur
823 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
824 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_packDepthSkinned
825 },
826 { //SmImpl::PCF
827 12.0f, 9.0f, 12.0f, 1.0f // m_sizePwrTwo
828 , 10.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
829 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
830 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
831 , 0.004f, 0.0f, 0.01f, 0.00001f // m_bias
832 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
833 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
834 , 50.0f, 1.0f, 300.0f, 1.0f // m_customParam1
835 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
836 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
837 , 1.0f, 0.0f, 3.0f, 0.001f // m_xOffset
838 , 1.0f, 0.0f, 3.0f, 0.001f // m_yOffset
839 , true // m_doBlur
840 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
841 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_packDepthSkinned
842 },
843 { //SmImpl::PCSS
844 12.0f, 9.0f, 12.0f, 1.0f // m_sizePwrTwo
845 , 10.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
846 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
847 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
848 , 0.004f, 0.0f, 0.01f, 0.00001f // m_bias
849 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
850 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
851 , 50.0f, 1.0f, 300.0f, 1.0f // m_customParam1
852 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
853 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
854 , 1.0f, 0.0f, 3.0f, 0.001f // m_xOffset
855 , 1.0f, 0.0f, 3.0f, 0.001f // m_yOffset
856 , true // m_doBlur
857 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
858 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_packDepthSkinned
859 },
860 { //SmImpl::VSM
861 12.0f, 9.0f, 12.0f, 1.0f // m_sizePwrTwo
862 , 10.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
863 , 8.0f, 1.0f, 10.0f, 1.0f // m_near
864 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
865 , 0.055f, 0.0f, 0.1f, 0.00001f // m_bias
866 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
867 , 0.02f, 0.0f, 0.04f, 0.00001f // m_customParam0
868 , 450.0f, 1.0f, 900.0f, 1.0f // m_customParam1
869 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
870 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
871 , 0.25f, 0.0f, 2.0f, 0.001f // m_xOffset
872 , 0.25f, 0.0f, 2.0f, 0.001f // m_yOffset
873 , true // m_doBlur
874 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::VSM].get() //m_progPack
875 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::VSM].get() //m_packDepthSkinned
876 },
877 { //SmImpl::ESM
878 12.0f, 9.0f, 12.0f, 1.0f // m_sizePwrTwo
879 , 10.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
880 , 3.0f, 1.0f, 10.0f, 0.01f // m_near
881 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
882 , 0.035f, 0.0f, 0.1f, 0.00001f // m_bias
883 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
884 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
885 , 9000.0f, 1.0f, 15000.0f, 1.0f // m_customParam1
886 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
887 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
888 , 0.25f, 0.0f, 2.0f, 0.001f // m_xOffset
889 , 0.25f, 0.0f, 2.0f, 0.001f // m_yOffset
890 , true // m_doBlur
891 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
892 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_packDepthSkinned
893 }
894
895 },
896 { //DepthImpl::Linear
897
898 { //SmImpl::Hard
899 12.0f, 9.0f, 12.0f, 1.0f // m_sizePwrTwo
900 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
901 , 1.0f, 1.0f, 10.0f, 1.0f // m_near
902 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
903 , 0.003f, 0.0f, 0.01f, 0.00001f // m_bias
904 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
905 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
906 , 120.0f, 1.0f, 300.0f, 1.0f // m_customParam1
907 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
908 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
909 , 0.25f, 0.0f, 2.0f, 0.001f // m_xOffset
910 , 0.25f, 0.0f, 2.0f, 0.001f // m_yOffset
911 , true // m_doBlur
912 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
913 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_packDepthSkinned
914 },
915 { //SmImpl::PCF
916 12.0f, 9.0f, 12.0f, 1.0f // m_sizePwrTwo
917 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
918 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
919 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
920 , 0.0035f, 0.0f, 0.01f, 0.00001f // m_bias
921 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
922 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
923 , 120.0f, 1.0f, 300.0f, 1.0f // m_customParam1
924 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
925 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
926 , 1.0f, 0.0f, 3.0f, 0.001f // m_xOffset
927 , 1.0f, 0.0f, 3.0f, 0.001f // m_yOffset
928 , true // m_doBlur
929 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
930 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPackSkinned
931 },
932 { //SmImpl::PCSS
933 12.0f, 9.0f, 12.0f, 1.0f // m_sizePwrTwo
934 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
935 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
936 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
937 , 0.0035f, 0.0f, 0.01f, 0.00001f // m_bias
938 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
939 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
940 , 120.0f, 1.0f, 300.0f, 1.0f // m_customParam1
941 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
942 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
943 , 1.0f, 0.0f, 3.0f, 0.001f // m_xOffset
944 , 1.0f, 0.0f, 3.0f, 0.001f // m_yOffset
945 , true // m_doBlur
946 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
947 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPackSkinned
948 },
949 { //SmImpl::VSM
950 12.0f, 9.0f, 12.0f, 1.0f // m_sizePwrTwo
951 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
952 , 1.0f, 1.0f, 10.0f, 1.0f // m_near
953 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
954 , 0.006f, 0.0f, 0.1f, 0.00001f // m_bias
955 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
956 , 0.02f, 0.0f, 0.1f, 0.00001f // m_customParam0
957 , 400.0f, 1.0f, 900.0f, 1.0f // m_customParam1
958 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
959 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
960 , 0.25f, 0.0f, 2.0f, 0.001f // m_xOffset
961 , 0.25f, 0.0f, 2.0f, 0.001f // m_yOffset
962 , true // m_doBlur
963 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::VSM].get() //m_progPack
964 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::VSM].get() //m_packDepthSkinned
965 },
966 { //SmImpl::ESM
967 12.0f, 9.0f, 12.0f, 1.0f // m_sizePwrTwo
968 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
969 , 1.0f, 1.0f, 10.0f, 0.01f // m_near
970 , 250.0f, 100.0f, 2000.0f, 50.0f // m_far
971 , 0.007f, 0.0f, 0.01f, 0.00001f // m_bias
972 , 0.001f, 0.0f, 0.05f, 0.00001f // m_normalOffset
973 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
974 , 8000.0f, 1.0f, 15000.0f, 1.0f // m_customParam1
975 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
976 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
977 , 0.25f, 0.0f, 2.0f, 0.001f // m_xOffset
978 , 0.25f, 0.0f, 2.0f, 0.001f // m_yOffset
979 , true // m_doBlur
980 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
981 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_packDepthSkinned
982 }
983
984 }
985
986 },
987 { //LightType::Directional
988
989 { //DepthImpl::InvZ
990
991 { //SmImpl::Hard
992 11.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
993 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
994 , 1.0f, 1.0f, 10.0f, 1.0f // m_near
995 , 550.0f, 100.0f, 2000.0f, 50.0f // m_far
996 , 0.0012f, 0.0f, 0.01f, 0.00001f // m_bias
997 , 0.001f, 0.0f, 0.04f, 0.00001f // m_normalOffset
998 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
999 , 200.0f, 1.0f, 400.0f, 1.0f // m_customParam1
1000 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
1001 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
1002 , 0.2f, 0.0f, 1.0f, 0.01f // m_xOffset
1003 , 0.2f, 0.0f, 1.0f, 0.01f // m_yOffset
1004 , true // m_doBlur
1005 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
1006 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_packDepthSkinned
1007 },
1008 { //SmImpl::PCF
1009 11.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
1010 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
1011 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
1012 , 550.0f, 100.0f, 2000.0f, 50.0f // m_far
1013 , 0.0012f, 0.0f, 0.01f, 0.00001f // m_bias
1014 , 0.001f, 0.0f, 0.04f, 0.00001f // m_normalOffset
1015 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
1016 , 200.0f, 1.0f, 400.0f, 1.0f // m_customParam1
1017 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
1018 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
1019 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
1020 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
1021 , true // m_doBlur
1022 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
1023 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_packDepthSkinned
1024 },
1025 { //SmImpl::PCSS
1026 11.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
1027 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
1028 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
1029 , 550.0f, 100.0f, 2000.0f, 50.0f // m_far
1030 , 0.0012f, 0.0f, 0.01f, 0.00001f // m_bias
1031 , 0.001f, 0.0f, 0.04f, 0.00001f // m_normalOffset
1032 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
1033 , 200.0f, 1.0f, 400.0f, 1.0f // m_customParam1
1034 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
1035 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
1036 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
1037 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
1038 , true // m_doBlur
1039 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
1040 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_packDepthSkinned
1041 },
1042 { //SmImpl::VSM
1043 11.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
1044 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
1045 , 1.0f, 1.0f, 10.0f, 1.0f // m_near
1046 , 550.0f, 100.0f, 2000.0f, 50.0f // m_far
1047 , 0.004f, 0.0f, 0.01f, 0.00001f // m_bias
1048 , 0.001f, 0.0f, 0.04f, 0.00001f // m_normalOffset
1049 , 0.02f, 0.0f, 0.04f, 0.00001f // m_customParam0
1050 , 2500.0f, 1.0f, 5000.0f, 1.0f // m_customParam1
1051 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
1052 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
1053 , 0.2f, 0.0f, 1.0f, 0.01f // m_xOffset
1054 , 0.2f, 0.0f, 1.0f, 0.01f // m_yOffset
1055 , true // m_doBlur
1056 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::VSM].get() //m_progPack
1057 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::VSM].get() //m_packDepthSkinned
1058 },
1059 { //SmImpl::ESM
1060 11.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
1061 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
1062 , 1.0f, 1.0f, 10.0f, 0.01f // m_near
1063 , 550.0f, 100.0f, 2000.0f, 50.0f // m_far
1064 , 0.004f, 0.0f, 0.01f, 0.00001f // m_bias
1065 , 0.001f, 0.0f, 0.04f, 0.00001f // m_normalOffset
1066 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
1067 , 9500.0f, 1.0f, 15000.0f, 1.0f // m_customParam1
1068 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
1069 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
1070 , 0.2f, 0.0f, 1.0f, 0.01f // m_xOffset
1071 , 0.2f, 0.0f, 1.0f, 0.01f // m_yOffset
1072 , true // m_doBlur
1073 , programs_.m_packDepth[DepthImpl::InvZ][PackDepth::RGBA].get() //m_progPack
1074 , programs_.m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA].get() //m_packDepthSkinned
1075 }
1076
1077 },
1078 { //DepthImpl::Linear
1079
1080 { //SmImpl::Hard
1081 11.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
1082 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
1083 , 1.0f, 1.0f, 10.0f, 1.0f // m_near
1084 , 550.0f, 100.0f, 2000.0f, 50.0f // m_far
1085 , 0.0012f, 0.0f, 0.01f, 0.00001f // m_bias
1086 , 0.001f, 0.0f, 0.04f, 0.00001f // m_normalOffset
1087 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
1088 , 500.0f, 1.0f, 1000.0f, 1.0f // m_customParam1
1089 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
1090 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
1091 , 0.2f, 0.0f, 1.0f, 0.01f // m_xOffset
1092 , 0.2f, 0.0f, 1.0f, 0.01f // m_yOffset
1093 , true // m_doBlur
1094 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
1095 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_packDepthSkinned
1096 },
1097 { //SmImpl::PCF
1098 11.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
1099 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
1100 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
1101 , 550.0f, 100.0f, 2000.0f, 50.0f // m_far
1102 , 0.0012f, 0.0f, 0.01f, 0.00001f // m_bias
1103 , 0.001f, 0.0f, 0.04f, 0.00001f // m_normalOffset
1104 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
1105 , 200.0f, 1.0f, 400.0f, 1.0f // m_customParam1
1106 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
1107 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
1108 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
1109 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
1110 , true // m_doBlur
1111 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
1112 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPackSkinned
1113 },
1114 { //SmImpl::PCSS
1115 11.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
1116 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
1117 , 1.0f, 1.0f, 99.0f, 1.0f // m_near
1118 , 550.0f, 100.0f, 2000.0f, 50.0f // m_far
1119 , 0.0012f, 0.0f, 0.01f, 0.00001f // m_bias
1120 , 0.001f, 0.0f, 0.04f, 0.00001f // m_normalOffset
1121 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
1122 , 200.0f, 1.0f, 400.0f, 1.0f // m_customParam1
1123 , 2.0f, 0.0f, 8.0f, 1.0f // m_xNum
1124 , 2.0f, 0.0f, 8.0f, 1.0f // m_yNum
1125 , 1.0f, 0.0f, 3.0f, 0.01f // m_xOffset
1126 , 1.0f, 0.0f, 3.0f, 0.01f // m_yOffset
1127 , true // m_doBlur
1128 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
1129 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPackSkinned
1130 },
1131 { //SmImpl::VSM
1132 11.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
1133 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
1134 , 1.0f, 1.0f, 10.0f, 1.0f // m_near
1135 , 550.0f, 100.0f, 2000.0f, 50.0f // m_far
1136 , 0.004f, 0.0f, 0.01f, 0.00001f // m_bias
1137 , 0.001f, 0.0f, 0.04f, 0.00001f // m_normalOffset
1138 , 0.02f, 0.0f, 0.04f, 0.00001f // m_customParam0
1139 , 2500.0f, 1.0f, 5000.0f, 1.0f // m_customParam1
1140 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
1141 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
1142 , 0.2f, 0.0f, 1.0f, 0.01f // m_xOffset
1143 , 0.2f, 0.0f, 1.0f, 0.01f // m_yOffset
1144 , true // m_doBlur
1145 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::VSM].get() //m_progPack
1146 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::VSM].get() //m_packDepthSkinned
1147 },
1148 { //SmImpl::ESM
1149 11.0f, 7.0f, 12.0f, 1.0f // m_sizePwrTwo
1150 , 1.0f, 1.0f, 20.0f, 1.0f // m_depthValuePow
1151 , 1.0f, 1.0f, 10.0f, 0.01f // m_near
1152 , 550.0f, 100.0f, 2000.0f, 50.0f // m_far
1153 , 0.004f, 0.0f, 0.01f, 0.00001f // m_bias
1154 , 0.001f, 0.0f, 0.04f, 0.00001f // m_normalOffset
1155 , 0.7f, 0.0f, 1.0f, 0.01f // m_customParam0
1156 , 9500.0f, 1.0f, 15000.0f, 1.0f // m_customParam1
1157 , 2.0f, 0.0f, 4.0f, 1.0f // m_xNum
1158 , 2.0f, 0.0f, 4.0f, 1.0f // m_yNum
1159 , 0.2f, 0.0f, 1.0f, 0.01f // m_xOffset
1160 , 0.2f, 0.0f, 1.0f, 0.01f // m_yOffset
1161 , true // m_doBlur
1162 , programs_.m_packDepth[DepthImpl::Linear][PackDepth::RGBA].get() //m_progPack
1163 , programs_.m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA].get() //m_packDepthSkinned
1164 }
1165
1166 }
1167 }
1168 };
1169 // clang-format on
1170 bx::memCopy(sm_settings_, smSettings, sizeof(smSettings));
1171
1173 settings_.m_depthImpl = DepthImpl::InvZ;
1174 settings_.m_smImpl = SmImpl::Hard;
1175 settings_.m_spotOuterAngle = 45.0f;
1176 settings_.m_spotInnerAngle = 30.0f;
1177 settings_.m_fovXAdjust = 0.0f;
1178 settings_.m_fovYAdjust = 0.0f;
1179 settings_.m_coverageSpotL = 90.0f;
1180 settings_.m_splitDistribution = 0.6f;
1181 settings_.m_numSplits = 4;
1182 settings_.m_updateLights = true;
1183 settings_.m_updateScene = true;
1184 settings_.m_drawDepthBuffer = false;
1185 settings_.m_showSmCoverage = false;
1186 settings_.m_stencilPack = true;
1187 settings_.m_stabilize = true;
1188}
1189
1191{
1192 PackDepth::Enum depthType = (SmImpl::VSM == settings_.m_smImpl) ? PackDepth::VSM : PackDepth::RGBA;
1193 return depthType;
1194}
1195
1196auto shadowmap_generator::get_rt_texture(uint8_t split) const -> bgfx::TextureHandle
1197{
1198 if(!bgfx::isValid(rt_shadow_map_[split]))
1199 {
1200 return {bgfx::kInvalidHandle};
1201 }
1202
1203 return bgfx::getTexture(rt_shadow_map_[split]);
1204}
1205
1207{
1208 return programs_.m_drawDepth[depth];
1209}
1210
1212{
1213 if(!bgfx::isValid(tex_color_))
1214 {
1215 return;
1216 }
1217 uniforms_.submitPerFrameUniforms();
1218 uniforms_.submitPerDrawUniforms();
1219
1220 for(uint8_t ii = 0; ii < ShadowMapRenderTargets::Count; ++ii)
1221 {
1222 if(!bgfx::isValid(rt_shadow_map_[ii]))
1223 {
1224 continue;
1225 }
1226
1227 bgfx::setTexture(stage + ii, shadow_map_[ii], bgfx::getTexture(rt_shadow_map_[ii]));
1228 }
1229}
1230
1232{
1233 return last_update_ == gfx::get_render_frame();
1234}
1235
1236void shadowmap_generator::update(const camera& cam, const light& l, const math::transform& ltrans, bool is_active)
1237{
1238 last_update_ = gfx::get_render_frame();
1239
1240 if(!l.casts_shadows)
1241 {
1243 return;
1244 }
1245
1246 bool recreateTextures = false;
1247 recreateTextures |= !valid_;
1248
1249 valid_ = true;
1250
1251 const auto& pos = ltrans.get_position();
1252 const auto& dir = ltrans.z_unit_axis();
1253 point_light_.m_position.m_x = pos.x;
1254 point_light_.m_position.m_y = pos.y;
1255 point_light_.m_position.m_z = pos.z;
1256
1257 point_light_.m_spotDirectionInner.m_x = dir.x;
1258 point_light_.m_spotDirectionInner.m_y = dir.y;
1259 point_light_.m_spotDirectionInner.m_z = dir.z;
1260
1261 directional_light_.m_position.m_x = dir.x;
1262 directional_light_.m_position.m_y = dir.y;
1263 directional_light_.m_position.m_z = dir.z;
1264
1265 auto last_settings = settings_;
1266
1267 settings_.m_lightType = convert(l.type);
1268 settings_.m_smImpl = convert(l.shadow_params.type);
1269 settings_.m_depthImpl = convert(l.shadow_params.depth);
1270
1271 settings_.m_showSmCoverage = l.shadow_params.show_coverage;
1272
1273 switch(l.type)
1274 {
1275 case light_type::spot:
1276 settings_.m_spotOuterAngle = l.spot_data.get_outer_angle();
1277 settings_.m_spotInnerAngle = l.spot_data.get_inner_angle();
1278 settings_.m_coverageSpotL = settings_.m_spotOuterAngle;
1279 break;
1280 case light_type::point:
1281 settings_.m_stencilPack = l.point_shadow_params.stencil_pack;
1282 settings_.m_fovXAdjust = l.point_shadow_params.fov_x_adjust;
1283 settings_.m_fovYAdjust = l.point_shadow_params.fov_y_adjust;
1284
1285 break;
1286 default:
1287 settings_.m_splitDistribution = l.directional_shadow_params.split_distribution;
1288 settings_.m_numSplits = l.directional_shadow_params.num_splits;
1289 settings_.m_stabilize = l.directional_shadow_params.stabilize;
1290
1291 break;
1292 }
1293
1294#define SET_CLAMPED_VAL(x, val) x = val // math::clamp(val, x##Min, x##Max)
1295
1296 ShadowMapSettings* currentSmSettings =
1297 &sm_settings_[settings_.m_lightType][settings_.m_depthImpl][settings_.m_smImpl];
1298
1299 SET_CLAMPED_VAL(currentSmSettings->m_sizePwrTwo, convert(l.shadow_params.resolution));
1300 SET_CLAMPED_VAL(currentSmSettings->m_near, l.shadow_params.near_plane);
1301 SET_CLAMPED_VAL(currentSmSettings->m_bias, l.shadow_params.bias);
1302 SET_CLAMPED_VAL(currentSmSettings->m_normalOffset, l.shadow_params.normal_bias);
1303
1304 // currentSmSettings->m_doBlur = l.shadow_params.impl.do_blur;
1305 // SET_VAL(currentSmSettings->m_xNum, l.shadow_params.impl.blur_x_num);
1306 // SET_VAL(currentSmSettings->m_yNum, l.shadow_params.impl.blur_y_num);
1307 // SET_VAL(currentSmSettings->m_xOffset, l.shadow_params.impl.blur_x_offset);
1308 // SET_VAL(currentSmSettings->m_yOffset, l.shadow_params.impl.blur_y_offset);
1309 // SET_VAL(currentSmSettings->m_customParam0, l.shadow_params.impl.hardness);
1310 // SET_VAL(currentSmSettings->m_customParam1, l.shadow_params.impl.depth_multiplier);
1311
1312 switch(l.type)
1313 {
1314 case light_type::spot:
1315 SET_CLAMPED_VAL(currentSmSettings->m_far, l.spot_data.range);
1316 break;
1317 case light_type::point:
1318 SET_CLAMPED_VAL(currentSmSettings->m_far, l.point_data.range);
1319 break;
1320 default:
1321 SET_CLAMPED_VAL(currentSmSettings->m_far, l.shadow_params.far_plane);
1322 break;
1323 }
1324
1325 if(LightType::SpotLight == settings_.m_lightType)
1326 {
1327 point_light_.m_spotDirectionInner.m_inner = settings_.m_spotInnerAngle;
1328 }
1329
1330 // Update render target size.
1331 uint16_t shadowMapSize = 1 << uint32_t(currentSmSettings->m_sizePwrTwo);
1332 recreateTextures |= current_shadow_map_size_ != shadowMapSize;
1333 recreateTextures |= last_settings.m_smImpl != settings_.m_smImpl;
1334 recreateTextures |= last_settings.m_numSplits != settings_.m_numSplits;
1335 recreateTextures |= last_settings.m_lightType != settings_.m_lightType;
1336
1337 if(recreateTextures)
1338 {
1339 current_shadow_map_size_ = shadowMapSize;
1340
1341 if(bgfx::isValid(rt_shadow_map_[0]))
1342 {
1343 bgfx::destroy(rt_shadow_map_[0]);
1344 rt_shadow_map_[0] = {bgfx::kInvalidHandle};
1345 }
1346
1347 {
1348 bgfx::TextureHandle fbtextures[] = {
1349 bgfx::createTexture2D(current_shadow_map_size_,
1350 current_shadow_map_size_,
1351 false,
1352 1,
1353 bgfx::TextureFormat::BGRA8,
1354 BGFX_TEXTURE_RT),
1355 bgfx::createTexture2D(current_shadow_map_size_,
1356 current_shadow_map_size_,
1357 false,
1358 1,
1359 bgfx::TextureFormat::D24S8,
1360 BGFX_TEXTURE_RT),
1361 };
1362 rt_shadow_map_[0] = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
1363 }
1364
1365 // if(LightType::DirectionalLight == settings_.m_lightType)
1366 {
1367 for(uint8_t ii = 1; ii < ShadowMapRenderTargets::Count; ++ii)
1368 {
1369 if(bgfx::isValid(rt_shadow_map_[ii]))
1370 {
1371 bgfx::destroy(rt_shadow_map_[ii]);
1372 rt_shadow_map_[ii] = {bgfx::kInvalidHandle};
1373 }
1374
1375 if(ii < settings_.m_numSplits)
1376 {
1377 bgfx::TextureHandle fbtextures[] = {
1378 bgfx::createTexture2D(current_shadow_map_size_,
1379 current_shadow_map_size_,
1380 false,
1381 1,
1382 bgfx::TextureFormat::BGRA8,
1383 BGFX_TEXTURE_RT),
1384 bgfx::createTexture2D(current_shadow_map_size_,
1385 current_shadow_map_size_,
1386 false,
1387 1,
1388 bgfx::TextureFormat::D24S8,
1389 BGFX_TEXTURE_RT),
1390 };
1391 rt_shadow_map_[ii] = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
1392 }
1393 }
1394 }
1395
1396 if(bgfx::isValid(rt_blur_))
1397 {
1398 bgfx::destroy(rt_blur_);
1399 rt_blur_ = {bgfx::kInvalidHandle};
1400 }
1401
1402 bool bVsmOrEsm = (SmImpl::VSM == settings_.m_smImpl) || (SmImpl::ESM == settings_.m_smImpl);
1403
1404 // Blur shadow map.
1405 if(bVsmOrEsm && currentSmSettings->m_doBlur)
1406 {
1407 rt_blur_ = bgfx::createFrameBuffer(current_shadow_map_size_, current_shadow_map_size_, bgfx::TextureFormat::BGRA8);
1408 }
1409 }
1410
1411 float currentShadowMapSizef = float(int16_t(current_shadow_map_size_));
1412
1413 // Update uniforms.
1414
1415 uniforms_.m_shadowMapTexelSize = 1.0f / currentShadowMapSizef;
1416 uniforms_.m_shadowMapBias = currentSmSettings->m_bias;
1417 uniforms_.m_shadowMapOffset = currentSmSettings->m_normalOffset;
1418 uniforms_.m_shadowMapParam0 = currentSmSettings->m_customParam0;
1419 uniforms_.m_shadowMapParam1 = currentSmSettings->m_customParam1;
1420 uniforms_.m_depthValuePow = currentSmSettings->m_depthValuePow;
1421 uniforms_.m_XNum = currentSmSettings->m_xNum;
1422 uniforms_.m_YNum = currentSmSettings->m_yNum;
1423 uniforms_.m_XOffset = currentSmSettings->m_xOffset;
1424 uniforms_.m_YOffset = currentSmSettings->m_yOffset;
1425 uniforms_.m_showSmCoverage = float(settings_.m_showSmCoverage);
1426 uniforms_.m_lightPtr = (LightType::DirectionalLight == settings_.m_lightType) ? &directional_light_ : &point_light_;
1427
1429 bool homogeneousDepth = gfx::is_homogeneous_depth();
1430 bool originBottomLeft = gfx::is_origin_bottom_left();
1431
1432 // Compute transform matrices.
1433 auto& lightView = light_view_;
1434 auto& lightProj = light_proj_;
1435 auto& lightFrustums = light_frustums_;
1436
1437 float mtxYpr[TetrahedronFaces::Count][16];
1438
1439 if(LightType::SpotLight == settings_.m_lightType)
1440 {
1441 const float fovy = settings_.m_coverageSpotL;
1442 const float aspect = 1.0f;
1443 bx::mtxProj(lightProj[ProjType::Horizontal],
1444 fovy,
1445 aspect,
1446 currentSmSettings->m_near,
1447 currentSmSettings->m_far,
1448 false);
1449
1450 // For linear depth, prevent depth division by variable w-component in shaders and divide here by far plane
1451 if(DepthImpl::Linear == settings_.m_depthImpl)
1452 {
1453 lightProj[ProjType::Horizontal][10] /= currentSmSettings->m_far;
1454 lightProj[ProjType::Horizontal][14] /= currentSmSettings->m_far;
1455 }
1456
1457 const bx::Vec3 at = bx::add(bx::load<bx::Vec3>(point_light_.m_position.m_v),
1458 bx::load<bx::Vec3>(point_light_.m_spotDirectionInner.m_v));
1459 bx::mtxLookAt(lightView[TetrahedronFaces::Green], bx::load<bx::Vec3>(point_light_.m_position.m_v), at);
1460 }
1461 else if(LightType::PointLight == settings_.m_lightType)
1462 {
1463 float ypr[TetrahedronFaces::Count][3] = {
1464 {bx::toRad(0.0f), bx::toRad(27.36780516f), bx::toRad(0.0f)},
1465 {bx::toRad(180.0f), bx::toRad(27.36780516f), bx::toRad(0.0f)},
1466 {bx::toRad(-90.0f), bx::toRad(-27.36780516f), bx::toRad(0.0f)},
1467 {bx::toRad(90.0f), bx::toRad(-27.36780516f), bx::toRad(0.0f)},
1468 };
1469
1470 if(settings_.m_stencilPack)
1471 {
1472 const float fovx = 143.98570868f + 3.51f + settings_.m_fovXAdjust;
1473 const float fovy = 125.26438968f + 9.85f + settings_.m_fovYAdjust;
1474 const float aspect = bx::tan(bx::toRad(fovx * 0.5f)) / bx::tan(bx::toRad(fovy * 0.5f));
1475
1476 bx::mtxProj(lightProj[ProjType::Vertical],
1477 fovx,
1478 aspect,
1479 currentSmSettings->m_near,
1480 currentSmSettings->m_far,
1481 false);
1482
1483 // For linear depth, prevent depth division by variable w-component in shaders and divide here by far plane
1484 if(DepthImpl::Linear == settings_.m_depthImpl)
1485 {
1486 lightProj[ProjType::Vertical][10] /= currentSmSettings->m_far;
1487 lightProj[ProjType::Vertical][14] /= currentSmSettings->m_far;
1488 }
1489
1490 ypr[TetrahedronFaces::Green][2] = bx::toRad(180.0f);
1491 ypr[TetrahedronFaces::Yellow][2] = bx::toRad(0.0f);
1492 ypr[TetrahedronFaces::Blue][2] = bx::toRad(90.0f);
1493 ypr[TetrahedronFaces::Red][2] = bx::toRad(-90.0f);
1494 }
1495
1496 const float fovx = 143.98570868f + 7.8f + settings_.m_fovXAdjust;
1497 const float fovy = 125.26438968f + 3.0f + settings_.m_fovYAdjust;
1498 const float aspect = bx::tan(bx::toRad(fovx * 0.5f)) / bx::tan(bx::toRad(fovy * 0.5f));
1499
1500 bx::mtxProj(lightProj[ProjType::Horizontal],
1501 fovy,
1502 aspect,
1503 currentSmSettings->m_near,
1504 currentSmSettings->m_far,
1505 homogeneousDepth);
1506
1507 // For linear depth, prevent depth division by variable w component in shaders and divide here by far plane
1508 if(DepthImpl::Linear == settings_.m_depthImpl)
1509 {
1510 lightProj[ProjType::Horizontal][10] /= currentSmSettings->m_far;
1511 lightProj[ProjType::Horizontal][14] /= currentSmSettings->m_far;
1512 }
1513
1514 for(uint8_t ii = 0; ii < TetrahedronFaces::Count; ++ii)
1515 {
1516 float mtxTmp[16];
1517 mtxYawPitchRoll(mtxTmp, ypr[ii][0], ypr[ii][1], ypr[ii][2]);
1518
1519 float tmp[3] = {
1520 -bx::dot(bx::load<bx::Vec3>(point_light_.m_position.m_v), bx::load<bx::Vec3>(&mtxTmp[0])),
1521 -bx::dot(bx::load<bx::Vec3>(point_light_.m_position.m_v), bx::load<bx::Vec3>(&mtxTmp[4])),
1522 -bx::dot(bx::load<bx::Vec3>(point_light_.m_position.m_v), bx::load<bx::Vec3>(&mtxTmp[8])),
1523 };
1524
1525 bx::mtxTranspose(mtxYpr[ii], mtxTmp);
1526
1527 bx::memCopy(lightView[ii], mtxYpr[ii], 12 * sizeof(float));
1528 lightView[ii][12] = tmp[0];
1529 lightView[ii][13] = tmp[1];
1530 lightView[ii][14] = tmp[2];
1531 lightView[ii][15] = 1.0f;
1532 }
1533 }
1534 else // LightType::DirectionalLight == m_settings.m_lightType
1535 {
1536 // Setup light view matrix to look at the camera position
1537 // Get camera position from the view inverse matrix
1538 const auto camera_pos = cam.get_position();
1539 const float camera_pos_x = camera_pos.x;
1540 const float camera_pos_y = camera_pos.y;
1541 const float camera_pos_z = camera_pos.z;
1542
1543 // Create eye position by offsetting from camera position using light direction
1544 const bx::Vec3 eye = {
1545 camera_pos_x - directional_light_.m_position.m_x,
1546 camera_pos_y - directional_light_.m_position.m_y,
1547 camera_pos_z - directional_light_.m_position.m_z,
1548 };
1549
1550
1551 // Look at the camera position
1552 const bx::Vec3 at = {camera_pos_x, camera_pos_y, camera_pos_z};
1553 bx::mtxLookAt(lightView[0], eye, at);
1554
1555 // Compute split distances.
1556 const uint8_t maxNumSplits = 4;
1557 BX_ASSERT(maxNumSplits >= settings_.m_numSplits, "Error! Max num splits.");
1558
1559 // Split distances
1560
1561 std::array<float, maxNumSplits * 2> splitSlices; //[maxNumSplits * 2];
1562 splitFrustum(splitSlices.data(),
1563 uint8_t(settings_.m_numSplits),
1564 currentSmSettings->m_near,
1565 currentSmSettings->m_far,
1566 settings_.m_splitDistribution);
1567
1568 // Create initial orthographic projection with fixed size
1569 // The actual size will be adjusted by the crop matrix based on frustum bounds
1570 float mtxProj[16];
1571 bx::mtxOrtho(mtxProj,
1572 /*left*/ -1.0f,
1573 /*right*/ +1.0f,
1574 /*bottom*/ -1.0f,
1575 /*top*/ +1.0f,
1576 -currentSmSettings->m_far,
1577 currentSmSettings->m_far,
1578 0.0f,
1579 homogeneousDepth);
1580
1581 // Update uniforms.
1582 for(uint8_t ii = 0, ff = 1; ii < settings_.m_numSplits; ++ii, ff += 2)
1583 {
1584 // This lags for 1 frame, but it's not a problem.
1585 uniforms_.m_csmFarDistances[ii] = splitSlices[ff];
1586 }
1587
1588 // Compute camera inverse view mtx.
1589
1590 const auto& mtxViewInv = cam.get_view_inverse();
1591
1592 const uint8_t numCorners = 8;
1593 float frustumCorners[maxNumSplits][numCorners][3];
1594 for(uint8_t ii = 0, nn = 0, ff = 1; ii < settings_.m_numSplits; ++ii, nn += 2, ff += 2)
1595 {
1596 bx::Vec3 min = {9000.0f, 9000.0f, 9000.0f};
1597 bx::Vec3 max = {-9000.0f, -9000.0f, -9000.0f};
1598
1599 float frustum_radius = 0.0f;
1600
1601 // if(cam)
1602 {
1603 const float camFovy = cam.get_fov();
1604 const float camAspect = cam.get_aspect_ratio();
1605 const float projHeight = bx::tan(bx::toRad(camFovy) * 0.5f);
1606 const float projWidth = projHeight * camAspect;
1607
1608 // Compute frustum corners for one split in world space.
1609 // Use configurable method for frustum calculation
1610 compute_world_space_frustum_corners((float*)frustumCorners[ii],
1611 splitSlices[nn],
1612 splitSlices[ff],
1613 projWidth,
1614 projHeight,
1615 mtxViewInv,
1616 frustum_method_,
1617 adaptive_params_);
1618
1619 // Calculate frustum center in world space first
1620 bx::Vec3 frustumCenter = {0.0f, 0.0f, 0.0f};
1621 for(uint8_t jj = 0; jj < numCorners; ++jj)
1622 {
1623 frustumCenter.x += frustumCorners[ii][jj][0];
1624 frustumCenter.y += frustumCorners[ii][jj][1];
1625 frustumCenter.z += frustumCorners[ii][jj][2];
1626 }
1627
1628 // Average to get center
1629 frustumCenter.x /= numCorners;
1630 frustumCenter.y /= numCorners;
1631 frustumCenter.z /= numCorners;
1632
1633 // Transform center to light space
1634 const bx::Vec3 lightSpaceCenter = bx::mul(frustumCenter, lightView[0]);
1635
1636 // Calculate radius and transform corners to light space
1637 for(uint8_t jj = 0; jj < numCorners; ++jj)
1638 {
1639 // Transform to light space
1640 const bx::Vec3 xyz = bx::mul(bx::load<bx::Vec3>(frustumCorners[ii][jj]), lightView[0]);
1641
1642 // Calculate distance from center
1643 const float dx = xyz.x - lightSpaceCenter.x;
1644 const float dy = xyz.y - lightSpaceCenter.y;
1645 const float dz = xyz.z - lightSpaceCenter.z;
1646 const float distance = bx::sqrt(dx*dx + dy*dy + dz*dz);
1647 frustum_radius = bx::max(frustum_radius, distance);
1648
1649 // Update bounding box
1650 min = bx::min(min, xyz);
1651 max = bx::max(max, xyz);
1652 }
1653
1654 // Round radius to reduce flickering (similar to the other engine)
1655 frustum_radius = bx::ceil(frustum_radius * 16.0f) / 16.0f;
1656 }
1657
1658 // Option 1: Use min/max approach (your original approach)
1659 const bx::Vec3 minproj = bx::mulH(min, mtxProj);
1660 const bx::Vec3 maxproj = bx::mulH(max, mtxProj);
1661
1662 // Option 2: Use radius-based approach (like the other engine)
1663 // We'll blend between both approaches for better stability
1664
1665 // Calculate scales using min/max approach
1666 float scalex_minmax = 2.0f / (maxproj.x - minproj.x);
1667 float scaley_minmax = 2.0f / (maxproj.y - minproj.y);
1668
1669 // Use the calculated frustum radius for a more stable approach
1670 float scalex_radius = 1.0f / frustum_radius;
1671 float scaley_radius = 1.0f / frustum_radius;
1672
1673 // Blend between the two approaches (0.7 weight to radius approach)
1674 float scalex = bx::lerp(scalex_minmax, scalex_radius, 0.7f);
1675 float scaley = bx::lerp(scaley_minmax, scaley_radius, 0.7f);
1676
1677 if(settings_.m_stabilize)
1678 {
1679 // Increase quantizer for better stability
1680 const float quantizer = 128.0f;
1681 scalex = quantizer / bx::ceil(quantizer / scalex);
1682 scaley = quantizer / bx::ceil(quantizer / scaley);
1683 }
1684
1685 // Calculate center-based offset for better balance
1686 float offsetx = -1.0f - scalex * minproj.x;
1687 float offsety = -1.0f - scaley * minproj.y;
1688
1689 // Apply texel snapping for stability (similar to the other engine's approach)
1690 if(settings_.m_stabilize)
1691 {
1692 float currentShadowMapSizef = float(int16_t(current_shadow_map_size_));
1693 const float halfSize = currentShadowMapSizef * 0.5f;
1694
1695 // Calculate shadow origin in texel space
1696 float shadowOriginX = offsetx * halfSize;
1697 float shadowOriginY = offsety * halfSize;
1698
1699 // Round to nearest texel
1700 shadowOriginX = bx::round(shadowOriginX);
1701 shadowOriginY = bx::round(shadowOriginY);
1702
1703 // Convert back to normalized space
1704 offsetx = shadowOriginX / halfSize;
1705 offsety = shadowOriginY / halfSize;
1706 }
1707
1708 float mtxCrop[16];
1709 bx::mtxIdentity(mtxCrop);
1710 mtxCrop[0] = scalex; // x-scale
1711 mtxCrop[5] = scaley; // y-scale
1712 mtxCrop[12] = offsetx; // x-offset
1713 mtxCrop[13] = offsety; // y-offset
1714
1715 bx::mtxMul(lightProj[ii], mtxCrop, mtxProj);
1716 }
1717 }
1718
1719 if(LightType::SpotLight == settings_.m_lightType)
1720 {
1721 lightFrustums[0].update(math::make_mat4(lightView[0]),
1722 math::make_mat4(lightProj[ProjType::Horizontal]),
1723 homogeneousDepth);
1724 }
1725 else if(LightType::PointLight == settings_.m_lightType)
1726 {
1727 lightFrustums[TetrahedronFaces::Green].update(math::make_mat4(lightView[TetrahedronFaces::Green]),
1728 math::make_mat4(lightProj[ProjType::Horizontal]),
1729 homogeneousDepth);
1730
1731 lightFrustums[TetrahedronFaces::Yellow].update(math::make_mat4(lightView[TetrahedronFaces::Yellow]),
1732 math::make_mat4(lightProj[ProjType::Horizontal]),
1733 homogeneousDepth);
1734
1735 if(settings_.m_stencilPack)
1736 {
1737 lightFrustums[TetrahedronFaces::Blue].update(math::make_mat4(lightView[TetrahedronFaces::Blue]),
1738 math::make_mat4(lightProj[ProjType::Vertical]),
1739 homogeneousDepth);
1740
1741 lightFrustums[TetrahedronFaces::Red].update(math::make_mat4(lightView[TetrahedronFaces::Red]),
1742 math::make_mat4(lightProj[ProjType::Vertical]),
1743 homogeneousDepth);
1744 }
1745 else
1746 {
1747 lightFrustums[TetrahedronFaces::Blue].update(math::make_mat4(lightView[TetrahedronFaces::Blue]),
1748 math::make_mat4(lightProj[ProjType::Horizontal]),
1749 homogeneousDepth);
1750
1751 lightFrustums[TetrahedronFaces::Red].update(math::make_mat4(lightView[TetrahedronFaces::Red]),
1752 math::make_mat4(lightProj[ProjType::Horizontal]),
1753 homogeneousDepth);
1754 }
1755 }
1756 else // LightType::DirectionalLight == settings.m_lightType
1757 {
1758 lightFrustums[0].update(math::make_mat4(lightView[0]), math::make_mat4(lightProj[0]), homogeneousDepth);
1759 lightFrustums[1].update(math::make_mat4(lightView[0]), math::make_mat4(lightProj[1]), homogeneousDepth);
1760 lightFrustums[2].update(math::make_mat4(lightView[0]), math::make_mat4(lightProj[2]), homogeneousDepth);
1761 lightFrustums[3].update(math::make_mat4(lightView[0]), math::make_mat4(lightProj[3]), homogeneousDepth);
1762 }
1763
1764 // Prepare for scene.
1765 {
1766 // Setup shadow mtx.
1767 float mtxShadow[16];
1768
1769 const float ymul = (originBottomLeft) ? 0.5f : -0.5f;
1770 float zadd = (DepthImpl::Linear == settings_.m_depthImpl) ? 0.0f : 0.5f;
1771
1772 // clang-format off
1773 const float mtxBias[16] =
1774 {
1775 0.5f, 0.0f, 0.0f, 0.0f,
1776 0.0f, ymul, 0.0f, 0.0f,
1777 0.0f, 0.0f, 0.5f, 0.0f,
1778 0.5f, 0.5f, zadd, 1.0f,
1779 };
1780 // clang-format on
1781
1782 if(LightType::SpotLight == settings_.m_lightType)
1783 {
1784 float mtxTmp[16];
1785 bx::mtxMul(mtxTmp, lightProj[ProjType::Horizontal], mtxBias);
1786 bx::mtxMul(mtxShadow, lightView[0], mtxTmp); // lightViewProjBias
1787 }
1788 else if(LightType::PointLight == settings_.m_lightType)
1789 {
1790 const float s = (originBottomLeft) ? 1.0f : -1.0f; // sign
1791 zadd = (DepthImpl::Linear == settings_.m_depthImpl) ? 0.0f : 0.5f;
1792
1793 // clang-format off
1794 const float mtxCropBias[2][TetrahedronFaces::Count][16] =
1795 {
1796 { // settings.m_stencilPack == false
1797
1798 { // D3D: Green, OGL: Blue
1799 0.25f, 0.0f, 0.0f, 0.0f,
1800 0.0f, s*0.25f, 0.0f, 0.0f,
1801 0.0f, 0.0f, 0.5f, 0.0f,
1802 0.25f, 0.25f, zadd, 1.0f,
1803 },
1804 { // D3D: Yellow, OGL: Red
1805 0.25f, 0.0f, 0.0f, 0.0f,
1806 0.0f, s*0.25f, 0.0f, 0.0f,
1807 0.0f, 0.0f, 0.5f, 0.0f,
1808 0.75f, 0.25f, zadd, 1.0f,
1809 },
1810 { // D3D: Blue, OGL: Green
1811 0.25f, 0.0f, 0.0f, 0.0f,
1812 0.0f, s*0.25f, 0.0f, 0.0f,
1813 0.0f, 0.0f, 0.5f, 0.0f,
1814 0.25f, 0.75f, zadd, 1.0f,
1815 },
1816 { // D3D: Red, OGL: Yellow
1817 0.25f, 0.0f, 0.0f, 0.0f,
1818 0.0f, s*0.25f, 0.0f, 0.0f,
1819 0.0f, 0.0f, 0.5f, 0.0f,
1820 0.75f, 0.75f, zadd, 1.0f,
1821 },
1822 },
1823 { // settings.m_stencilPack == true
1824
1825 { // D3D: Red, OGL: Blue
1826 0.25f, 0.0f, 0.0f, 0.0f,
1827 0.0f, s*0.5f, 0.0f, 0.0f,
1828 0.0f, 0.0f, 0.5f, 0.0f,
1829 0.25f, 0.5f, zadd, 1.0f,
1830 },
1831 { // D3D: Blue, OGL: Red
1832 0.25f, 0.0f, 0.0f, 0.0f,
1833 0.0f, s*0.5f, 0.0f, 0.0f,
1834 0.0f, 0.0f, 0.5f, 0.0f,
1835 0.75f, 0.5f, zadd, 1.0f,
1836 },
1837 { // D3D: Green, OGL: Green
1838 0.5f, 0.0f, 0.0f, 0.0f,
1839 0.0f, s*0.25f, 0.0f, 0.0f,
1840 0.0f, 0.0f, 0.5f, 0.0f,
1841 0.5f, 0.75f, zadd, 1.0f,
1842 },
1843 { // D3D: Yellow, OGL: Yellow
1844 0.5f, 0.0f, 0.0f, 0.0f,
1845 0.0f, s*0.25f, 0.0f, 0.0f,
1846 0.0f, 0.0f, 0.5f, 0.0f,
1847 0.5f, 0.25f, zadd, 1.0f,
1848 },
1849 }
1850 };
1851 // clang-format on
1852
1853 // clang-format off
1854 // Use as: [stencilPack][flipV][tetrahedronFace]
1855 static const uint8_t cropBiasIndices[2][2][4] =
1856 {
1857 { // settings.m_stencilPack == false
1858 { 0, 1, 2, 3 }, //flipV == false
1859 { 2, 3, 0, 1 }, //flipV == true
1860 },
1861 { // settings.m_stencilPack == true
1862 { 3, 2, 0, 1 }, //flipV == false
1863 { 2, 3, 0, 1 }, //flipV == true
1864 },
1865 };
1866 // clang-format on
1867
1868 for(uint8_t ii = 0; ii < TetrahedronFaces::Count; ++ii)
1869 {
1870 ProjType::Enum projType = (settings_.m_stencilPack) ? ProjType::Enum(ii > 1) : ProjType::Horizontal;
1871 uint8_t biasIndex = cropBiasIndices[settings_.m_stencilPack][uint8_t(originBottomLeft)][ii];
1872
1873 float mtxTmp[16];
1874 bx::mtxMul(mtxTmp, mtxYpr[ii], lightProj[projType]);
1875 bx::mtxMul(shadow_map_mtx_[ii],
1876 mtxTmp,
1877 mtxCropBias[settings_.m_stencilPack][biasIndex]); // mtxYprProjBias
1878 }
1879
1880 bx::mtxTranslate(mtxShadow // lightInvTranslate
1881 ,
1882 -point_light_.m_position.m_v[0],
1883 -point_light_.m_position.m_v[1],
1884 -point_light_.m_position.m_v[2]);
1885 }
1886 else // LightType::DirectionalLight == settings.m_lightType
1887 {
1888 for(uint8_t ii = 0; ii < settings_.m_numSplits; ++ii)
1889 {
1890 float mtxTmp[16];
1891
1892 bx::mtxMul(mtxTmp, lightProj[ii], mtxBias);
1893 bx::mtxMul(shadow_map_mtx_[ii], lightView[0], mtxTmp); // lViewProjCropBias
1894 }
1895 }
1896
1898 {
1899 float tmp[16];
1900 bx::mtxIdentity(tmp);
1901
1902 bx::mtxMul(light_mtx_, tmp, mtxShadow);
1903 }
1904 }
1905}
1906
1908{
1909 auto& lightView = light_view_;
1910 auto& lightProj = light_proj_;
1911 auto& lightFrustums = light_frustums_;
1912
1913 bool homogeneousDepth = gfx::is_homogeneous_depth();
1914 bool originBottomLeft = gfx::is_origin_bottom_left();
1915
1916 float screenProj[16];
1917 float screenView[16];
1918 bx::mtxIdentity(screenView);
1919
1920 bx::mtxOrtho(screenProj, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f, 0.0f, homogeneousDepth);
1921
1923 gfx::render_pass shadowmap_pass_0("shadowmap_pass_0");
1924 gfx::render_pass shadowmap_pass_1("shadowmap_pass_1");
1925 gfx::render_pass shadowmap_pass_2("shadowmap_pass_2");
1926 gfx::render_pass shadowmap_pass_3("shadowmap_pass_3");
1927 gfx::render_pass shadowmap_pass_4("shadowmap_pass_4");
1928 gfx::render_pass shadowmap_vblur_pass_0("shadowmap_vblur_pass_0");
1929 gfx::render_pass shadowmap_hblur_pass_0("shadowmap_hblur_pass_0");
1930 gfx::render_pass shadowmap_vblur_pass_1("shadowmap_hblur_pass_1");
1931 gfx::render_pass shadowmap_hblur_pass_1("shadowmap_hblur_pass_1");
1932 gfx::render_pass shadowmap_vblur_pass_2("shadowmap_vblur_pass_2");
1933 gfx::render_pass shadowmap_hblur_pass_2("shadowmap_hblur_pass_2");
1934 gfx::render_pass shadowmap_vblur_pass_3("shadowmap_vblur_pass_3");
1935 gfx::render_pass shadowmap_hblur_pass_3("shadowmap_hblur_pass_3");
1936
1937 auto RENDERVIEW_SHADOWMAP_0_ID = shadowmap_pass_0.id;
1938 auto RENDERVIEW_SHADOWMAP_1_ID = shadowmap_pass_1.id;
1939 auto RENDERVIEW_SHADOWMAP_2_ID = shadowmap_pass_2.id;
1940 auto RENDERVIEW_SHADOWMAP_3_ID = shadowmap_pass_3.id;
1941 auto RENDERVIEW_SHADOWMAP_4_ID = shadowmap_pass_4.id;
1942 auto RENDERVIEW_VBLUR_0_ID = shadowmap_vblur_pass_0.id;
1943 auto RENDERVIEW_HBLUR_0_ID = shadowmap_hblur_pass_0.id;
1944 auto RENDERVIEW_VBLUR_1_ID = shadowmap_vblur_pass_1.id;
1945 auto RENDERVIEW_HBLUR_1_ID = shadowmap_hblur_pass_1.id;
1946 auto RENDERVIEW_VBLUR_2_ID = shadowmap_vblur_pass_2.id;
1947 auto RENDERVIEW_HBLUR_2_ID = shadowmap_hblur_pass_2.id;
1948 auto RENDERVIEW_VBLUR_3_ID = shadowmap_vblur_pass_3.id;
1949 auto RENDERVIEW_HBLUR_3_ID = shadowmap_hblur_pass_3.id;
1950
1951 if(LightType::SpotLight == settings_.m_lightType)
1952 {
1960 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_0_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
1961 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_1_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
1962 bgfx::setViewRect(RENDERVIEW_VBLUR_0_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
1963 bgfx::setViewRect(RENDERVIEW_HBLUR_0_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
1964
1965 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_0_ID, screenView, screenProj);
1966 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_1_ID, lightView[0], lightProj[ProjType::Horizontal]);
1967 bgfx::setViewTransform(RENDERVIEW_VBLUR_0_ID, screenView, screenProj);
1968 bgfx::setViewTransform(RENDERVIEW_HBLUR_0_ID, screenView, screenProj);
1969
1970 bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_0_ID, rt_shadow_map_[0]);
1971 bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_1_ID, rt_shadow_map_[0]);
1972 bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_0_ID, rt_blur_);
1973 bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_0_ID, rt_shadow_map_[0]);
1974 }
1975 else if(LightType::PointLight == settings_.m_lightType)
1976 {
1987 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_0_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
1988 if(settings_.m_stencilPack)
1989 {
1990 const uint16_t f = current_shadow_map_size_; // full size
1991 const uint16_t h = current_shadow_map_size_ / 2; // half size
1992 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_1_ID, 0, 0, f, h);
1993 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_2_ID, 0, h, f, h);
1994 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_3_ID, 0, 0, h, f);
1995 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_4_ID, h, 0, h, f);
1996 }
1997 else
1998 {
1999 const uint16_t h = current_shadow_map_size_ / 2; // half size
2000 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_1_ID, 0, 0, h, h);
2001 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_2_ID, h, 0, h, h);
2002 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_3_ID, 0, h, h, h);
2003 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_4_ID, h, h, h, h);
2004 }
2005 bgfx::setViewRect(RENDERVIEW_VBLUR_0_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2006 bgfx::setViewRect(RENDERVIEW_HBLUR_0_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2007
2008 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_0_ID, screenView, screenProj);
2009 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_1_ID,
2010 lightView[TetrahedronFaces::Green],
2011 lightProj[ProjType::Horizontal]);
2012
2013 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_2_ID,
2014 lightView[TetrahedronFaces::Yellow],
2015 lightProj[ProjType::Horizontal]);
2016
2017 if(settings_.m_stencilPack)
2018 {
2019 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_3_ID,
2020 lightView[TetrahedronFaces::Blue],
2021 lightProj[ProjType::Vertical]);
2022
2023 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_4_ID,
2024 lightView[TetrahedronFaces::Red],
2025 lightProj[ProjType::Vertical]);
2026 }
2027 else
2028 {
2029 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_3_ID,
2030 lightView[TetrahedronFaces::Blue],
2031 lightProj[ProjType::Horizontal]);
2032
2033 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_4_ID,
2034 lightView[TetrahedronFaces::Red],
2035 lightProj[ProjType::Horizontal]);
2036 }
2037 bgfx::setViewTransform(RENDERVIEW_VBLUR_0_ID, screenView, screenProj);
2038 bgfx::setViewTransform(RENDERVIEW_HBLUR_0_ID, screenView, screenProj);
2039
2040 bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_0_ID, rt_shadow_map_[0]);
2041 bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_1_ID, rt_shadow_map_[0]);
2042 bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_2_ID, rt_shadow_map_[0]);
2043 bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_3_ID, rt_shadow_map_[0]);
2044 bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_4_ID, rt_shadow_map_[0]);
2045 bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_0_ID, rt_blur_);
2046 bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_0_ID, rt_shadow_map_[0]);
2047 }
2048 else // LightType::DirectionalLight == settings.m_lightType
2049 {
2065 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_1_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2066 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_2_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2067 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_3_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2068 bgfx::setViewRect(RENDERVIEW_SHADOWMAP_4_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2069 bgfx::setViewRect(RENDERVIEW_VBLUR_0_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2070 bgfx::setViewRect(RENDERVIEW_HBLUR_0_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2071 bgfx::setViewRect(RENDERVIEW_VBLUR_1_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2072 bgfx::setViewRect(RENDERVIEW_HBLUR_1_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2073 bgfx::setViewRect(RENDERVIEW_VBLUR_2_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2074 bgfx::setViewRect(RENDERVIEW_HBLUR_2_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2075 bgfx::setViewRect(RENDERVIEW_VBLUR_3_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2076 bgfx::setViewRect(RENDERVIEW_HBLUR_3_ID, 0, 0, current_shadow_map_size_, current_shadow_map_size_);
2077
2078 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_1_ID, lightView[0], lightProj[0]);
2079 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_2_ID, lightView[0], lightProj[1]);
2080 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_3_ID, lightView[0], lightProj[2]);
2081 bgfx::setViewTransform(RENDERVIEW_SHADOWMAP_4_ID, lightView[0], lightProj[3]);
2082
2083 bgfx::setViewTransform(RENDERVIEW_VBLUR_0_ID, screenView, screenProj);
2084 bgfx::setViewTransform(RENDERVIEW_HBLUR_0_ID, screenView, screenProj);
2085 bgfx::setViewTransform(RENDERVIEW_VBLUR_1_ID, screenView, screenProj);
2086 bgfx::setViewTransform(RENDERVIEW_HBLUR_1_ID, screenView, screenProj);
2087 bgfx::setViewTransform(RENDERVIEW_VBLUR_2_ID, screenView, screenProj);
2088 bgfx::setViewTransform(RENDERVIEW_HBLUR_2_ID, screenView, screenProj);
2089 bgfx::setViewTransform(RENDERVIEW_VBLUR_3_ID, screenView, screenProj);
2090 bgfx::setViewTransform(RENDERVIEW_HBLUR_3_ID, screenView, screenProj);
2091
2092 bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_1_ID, rt_shadow_map_[0]);
2093 bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_2_ID, rt_shadow_map_[1]);
2094 bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_3_ID, rt_shadow_map_[2]);
2095 bgfx::setViewFrameBuffer(RENDERVIEW_SHADOWMAP_4_ID, rt_shadow_map_[3]);
2096 bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_0_ID, rt_blur_); // vblur
2097 bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_0_ID, rt_shadow_map_[0]); // hblur
2098 bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_1_ID, rt_blur_); // vblur
2099 bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_1_ID, rt_shadow_map_[1]); // hblur
2100 bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_2_ID, rt_blur_); // vblur
2101 bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_2_ID, rt_shadow_map_[2]); // hblur
2102 bgfx::setViewFrameBuffer(RENDERVIEW_VBLUR_3_ID, rt_blur_); // vblur
2103 bgfx::setViewFrameBuffer(RENDERVIEW_HBLUR_3_ID, rt_shadow_map_[3]); // hblur
2104 }
2105
2106 // Clear shadowmap rendertarget at beginning.
2107 const uint8_t flags0 = (LightType::DirectionalLight == settings_.m_lightType)
2108 ? 0
2109 : BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH | BGFX_CLEAR_STENCIL;
2110
2111 bgfx::setViewClear(RENDERVIEW_SHADOWMAP_0_ID,
2112 flags0,
2113 0xfefefefe // blur fails on completely white regions
2114 ,
2115 clear_values_.clear_depth,
2116 clear_values_.clear_stencil);
2117 bgfx::touch(RENDERVIEW_SHADOWMAP_0_ID);
2118
2119 const uint8_t flags1 =
2120 (LightType::DirectionalLight == settings_.m_lightType) ? BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH : 0;
2121
2122 for(uint8_t ii = 0; ii < 4; ++ii)
2123 {
2124 bgfx::setViewClear(RENDERVIEW_SHADOWMAP_1_ID + ii,
2125 flags1,
2126 0xfefefefe // blur fails on completely white regions
2127 ,
2128 clear_values_.clear_depth,
2129 clear_values_.clear_stencil);
2130 bgfx::touch(RENDERVIEW_SHADOWMAP_1_ID + ii);
2131 }
2132
2133 // Render.
2134
2135 ShadowMapSettings* currentSmSettings =
2136 &sm_settings_[settings_.m_lightType][settings_.m_depthImpl][settings_.m_smImpl];
2137
2138 uniforms_.submitPerFrameUniforms();
2139
2140 bool anythingDrawn = false;
2141 // Craft shadow map.
2142 {
2143 // Craft stencil mask for point light shadow map packing.
2144 if(LightType::PointLight == settings_.m_lightType && settings_.m_stencilPack)
2145 {
2146 if(6 == bgfx::getAvailTransientVertexBuffer(6, PosVertex::get_layout()))
2147 {
2148 bgfx::TransientVertexBuffer vb;
2149 bgfx::allocTransientVertexBuffer(&vb, 6, PosVertex::get_layout());
2150 PosVertex* vertex = (PosVertex*)vb.data;
2151
2152 const float min = 0.0f;
2153 const float max = 1.0f;
2154 const float center = 0.5f;
2155 const float zz = 0.0f;
2156
2157 vertex[0].m_x = min;
2158 vertex[0].m_y = min;
2159 vertex[0].m_z = zz;
2160
2161 vertex[1].m_x = max;
2162 vertex[1].m_y = min;
2163 vertex[1].m_z = zz;
2164
2165 vertex[2].m_x = center;
2166 vertex[2].m_y = center;
2167 vertex[2].m_z = zz;
2168
2169 vertex[3].m_x = center;
2170 vertex[3].m_y = center;
2171 vertex[3].m_z = zz;
2172
2173 vertex[4].m_x = max;
2174 vertex[4].m_y = max;
2175 vertex[4].m_z = zz;
2176
2177 vertex[5].m_x = min;
2178 vertex[5].m_y = max;
2179 vertex[5].m_z = zz;
2180
2181 bgfx::setState(0);
2182 bgfx::setStencil(BGFX_STENCIL_TEST_ALWAYS | BGFX_STENCIL_FUNC_REF(1) | BGFX_STENCIL_FUNC_RMASK(0xff) |
2183 BGFX_STENCIL_OP_FAIL_S_REPLACE | BGFX_STENCIL_OP_FAIL_Z_REPLACE |
2184 BGFX_STENCIL_OP_PASS_Z_REPLACE);
2185 bgfx::setVertexBuffer(0, &vb);
2186
2187 programs_.m_black->begin();
2188 bgfx::submit(RENDERVIEW_SHADOWMAP_0_ID, programs_.m_black->native_handle());
2189 programs_.m_black->end();
2190 }
2191 }
2192
2193 anythingDrawn =
2194 render_scene_into_shadowmap(RENDERVIEW_SHADOWMAP_1_ID, models, lightFrustums, currentSmSettings);
2195 }
2196
2197 if(anythingDrawn)
2198 {
2199 PackDepth::Enum depthType = (SmImpl::VSM == settings_.m_smImpl) ? PackDepth::VSM : PackDepth::RGBA;
2200 bool bVsmOrEsm = (SmImpl::VSM == settings_.m_smImpl) || (SmImpl::ESM == settings_.m_smImpl);
2201
2202 // Blur shadow map.
2203 if(bVsmOrEsm && currentSmSettings->m_doBlur)
2204 {
2205 bgfx::setTexture(4, shadow_map_[0], bgfx::getTexture(rt_shadow_map_[0]));
2206 bgfx::setState(BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A);
2207 screenSpaceQuad(originBottomLeft);
2208 programs_.m_vBlur[depthType]->begin();
2209 bgfx::submit(RENDERVIEW_VBLUR_0_ID, programs_.m_vBlur[depthType]->native_handle());
2210 programs_.m_vBlur[depthType]->end();
2211
2212 bgfx::setTexture(4, shadow_map_[0], bgfx::getTexture(rt_blur_));
2213 bgfx::setState(BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A);
2214 screenSpaceQuad(originBottomLeft);
2215 programs_.m_hBlur[depthType]->begin();
2216 bgfx::submit(RENDERVIEW_HBLUR_0_ID, programs_.m_hBlur[depthType]->native_handle());
2217 programs_.m_hBlur[depthType]->end();
2218
2220 {
2221 for(uint8_t ii = 1, jj = 2; ii < settings_.m_numSplits; ++ii, jj += 2)
2222 {
2223 const uint8_t viewId = RENDERVIEW_VBLUR_0_ID + jj;
2224
2225 bgfx::setTexture(4, shadow_map_[0], bgfx::getTexture(rt_shadow_map_[ii]));
2226 bgfx::setState(BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A);
2227 screenSpaceQuad(originBottomLeft);
2228 bgfx::submit(viewId, programs_.m_vBlur[depthType]->native_handle());
2229
2230 bgfx::setTexture(4, shadow_map_[0], bgfx::getTexture(rt_blur_));
2231 bgfx::setState(BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A);
2232 screenSpaceQuad(originBottomLeft);
2233 bgfx::submit(viewId + 1, programs_.m_hBlur[depthType]->native_handle());
2234 }
2235 }
2236 }
2237 }
2238}
2239
2240auto shadowmap_generator::render_scene_into_shadowmap(uint8_t shadowmap_1_id,
2241 const shadow_map_models_t& models,
2242 const math::frustum lightFrustums[ShadowMapRenderTargets::Count],
2243 ShadowMapSettings* currentSmSettings) -> bool
2244{
2245 bool any_rendered = false;
2246 // Draw scene into shadowmap.
2247 uint8_t drawNum;
2248 if(LightType::SpotLight == settings_.m_lightType)
2249 {
2250 drawNum = 1;
2251 }
2252 else if(LightType::PointLight == settings_.m_lightType)
2253 {
2254 drawNum = 4;
2255 }
2256 else // LightType::DirectionalLight == settings.m_lightType)
2257 {
2258 drawNum = uint8_t(settings_.m_numSplits);
2259 }
2260
2261 for(const auto& e : models)
2262 {
2263 const auto& transform_comp = e.get<transform_component>();
2264 auto& model_comp = e.get<model_component>();
2265
2266 const auto& model = model_comp.get_model();
2267 if(!model.is_valid())
2268 continue;
2269
2270 const auto& world_transform = transform_comp.get_transform_global();
2271
2272 const auto& world_bounds_transform = model_comp.get_world_bounds_transform();
2273 const auto& world_bounds = model_comp.get_world_bounds();
2274 const auto& local_bounds = model_comp.get_local_bounds();
2275
2276 const auto& submesh_transforms = model_comp.get_submesh_transforms();
2277 const auto& bone_transforms = model_comp.get_bone_transforms();
2278 const auto& skinning_matrices = model_comp.get_skinning_transforms();
2279
2280 const auto current_lod_index = 0;
2281 for(uint8_t ii = 0; ii < drawNum; ++ii)
2282 {
2283 auto query = lightFrustums[ii].classify_obb(local_bounds, world_bounds_transform);
2284 if(query == math::volume_query::outside)
2285 {
2286 continue;
2287 }
2288
2289 const uint8_t viewId = shadowmap_1_id + ii;
2290
2291 uint8_t renderStateIndex = RenderState::ShadowMap_PackDepth;
2292 if(LightType::PointLight == settings_.m_lightType && settings_.m_stencilPack)
2293 {
2294 renderStateIndex =
2296 }
2297
2298 const auto& _renderState = render_states[renderStateIndex];
2299
2300 model::submit_callbacks callbacks;
2301 callbacks.setup_begin = [&](const model::submit_callbacks::params& submit_params)
2302 {
2303 auto& prog =
2304 submit_params.skinned ? currentSmSettings->m_progPackSkinned : currentSmSettings->m_progPack;
2305 prog->begin();
2306 };
2307 callbacks.setup_params_per_instance = [&](const model::submit_callbacks::params& submit_params)
2308 {
2309 // Set uniforms.
2310 uniforms_.submitPerDrawUniforms();
2311
2312 // Apply render state.
2313 gfx::set_stencil(_renderState.m_fstencil, _renderState.m_bstencil);
2314 gfx::set_state(_renderState.m_state, _renderState.m_blendFactorRgba);
2315 };
2316 callbacks.setup_params_per_submesh =
2317 [&](const model::submit_callbacks::params& submit_params, const material& mat)
2318 {
2319 auto& prog =
2320 submit_params.skinned ? currentSmSettings->m_progPackSkinned : currentSmSettings->m_progPack;
2321
2322 gfx::submit(viewId, prog->native_handle(), 0, submit_params.preserve_state);
2323 };
2324 callbacks.setup_end = [&](const model::submit_callbacks::params& submit_params)
2325 {
2326 auto& prog =
2327 submit_params.skinned ? currentSmSettings->m_progPackSkinned : currentSmSettings->m_progPack;
2328
2329 prog->end();
2330 };
2331
2332 model_comp.set_last_render_frame(gfx::get_render_frame());
2333 model.submit(world_transform,
2334 submesh_transforms,
2335 bone_transforms,
2336 skinning_matrices,
2337 current_lod_index,
2338 callbacks);
2339
2340 any_rendered = true;
2341
2342 // if bounds are fully inside this split we dont need to render it to the next one
2343 if(query == math::volume_query::inside)
2344 {
2345 break;
2346 }
2347 }
2348 }
2349
2350 return any_rendered;
2351}
2352
2354{
2355 // clang-format off
2356 auto& am = ctx.get_cached<asset_manager>();
2357 // clang-format on
2358
2359 auto loadProgram = [&](const std::string& vs, const std::string& fs)
2360 {
2361 auto vs_shader = am.get_asset<gfx::shader>("engine:/data/shaders/shadowmaps/" + vs + ".sc");
2362 auto fs_shadfer = am.get_asset<gfx::shader>("engine:/data/shaders/shadowmaps/" + fs + ".sc");
2363
2364 return std::make_shared<gpu_program>(vs_shader, fs_shadfer);
2365 };
2366
2367 // clang-format off
2368 // Misc.
2369 m_black = loadProgram("vs_shadowmaps_color", "fs_shadowmaps_color_black");
2370
2371 // Blur.
2372 m_vBlur[PackDepth::RGBA] = loadProgram("vs_shadowmaps_vblur", "fs_shadowmaps_vblur");
2373 m_hBlur[PackDepth::RGBA] = loadProgram("vs_shadowmaps_hblur", "fs_shadowmaps_hblur");
2374 m_vBlur[PackDepth::VSM] = loadProgram("vs_shadowmaps_vblur", "fs_shadowmaps_vblur_vsm");
2375 m_hBlur[PackDepth::VSM] = loadProgram("vs_shadowmaps_hblur", "fs_shadowmaps_hblur_vsm");
2376
2377 // Draw depth.
2378 m_drawDepth[PackDepth::RGBA] = loadProgram("vs_shadowmaps_unpackdepth", "fs_shadowmaps_unpackdepth");
2379 m_drawDepth[PackDepth::VSM] = loadProgram("vs_shadowmaps_unpackdepth", "fs_shadowmaps_unpackdepth_vsm");
2380
2381 // Pack depth.
2382 m_packDepth[DepthImpl::InvZ][PackDepth::RGBA] = loadProgram("vs_shadowmaps_packdepth", "fs_shadowmaps_packdepth");
2383 m_packDepth[DepthImpl::InvZ][PackDepth::VSM] = loadProgram("vs_shadowmaps_packdepth", "fs_shadowmaps_packdepth_vsm");
2384
2385 m_packDepth[DepthImpl::Linear][PackDepth::RGBA] = loadProgram("vs_shadowmaps_packdepth_linear", "fs_shadowmaps_packdepth_linear");
2386 m_packDepth[DepthImpl::Linear][PackDepth::VSM] = loadProgram("vs_shadowmaps_packdepth_linear", "fs_shadowmaps_packdepth_vsm_linear");
2387
2388 m_packDepthSkinned[DepthImpl::InvZ][PackDepth::RGBA] = loadProgram("vs_shadowmaps_packdepth_skinned", "fs_shadowmaps_packdepth");
2389 m_packDepthSkinned[DepthImpl::InvZ][PackDepth::VSM] = loadProgram("vs_shadowmaps_packdepth_skinned", "fs_shadowmaps_packdepth_vsm");
2390
2391 m_packDepthSkinned[DepthImpl::Linear][PackDepth::RGBA] = loadProgram("vs_shadowmaps_packdepth_linear_skinned", "fs_shadowmaps_packdepth_linear");
2392 m_packDepthSkinned[DepthImpl::Linear][PackDepth::VSM] = loadProgram("vs_shadowmaps_packdepth_linear_skinned", "fs_shadowmaps_packdepth_vsm_linear");
2393
2394}
2395
2396}
2397} // namespace unravel
bgfx::ProgramHandle loadProgram(bx::FileReaderI *_reader, const char *_vsName, const char *_fsName)
Storage for frustum planes / values and wraps up common functionality.
Definition frustum.h:18
General purpose transformation class designed to maintain each component of the transformation separa...
Definition transform.hpp:27
auto get_position() const noexcept -> const vec3_t &
Get the position component.
auto z_unit_axis() const noexcept -> vec3_t
Get the unit Z axis of the transform.
Manages assets, including loading, unloading, and storage.
Class representing a camera. Contains functionality for manipulating and updating a camera....
Definition camera.h:35
auto get_fov() const -> float
Retrieves the current field of view angle in degrees.
Definition camera.cpp:57
auto get_view_inverse() const -> const math::transform &
Definition camera.cpp:296
auto get_position() const -> const math::vec3 &
Retrieves the current position of the camera.
Definition camera.cpp:346
auto get_aspect_ratio() const -> float
Retrieves the aspect ratio used to generate the horizontal FOV angle.
Definition camera.cpp:183
std::shared_ptr< gpu_program > ptr
Definition gpu_program.h:19
void generate_shadowmaps(const shadow_map_models_t &model)
Definition shadow.cpp:1907
auto get_depth_type() const -> PackDepth::Enum
Definition shadow.cpp:1190
void submit_uniforms(uint8_t stage) const
Definition shadow.cpp:1211
auto get_rt_texture(uint8_t split) const -> bgfx::TextureHandle
Definition shadow.cpp:1196
void update(const camera &cam, const light &l, const math::transform &ltrans, bool is_active)
Definition shadow.cpp:1236
void init(rtti::context &ctx)
Definition shadow.cpp:570
auto already_updated() const -> bool
Definition shadow.cpp:1231
auto get_depth_render_program(PackDepth::Enum depth) const -> gpu_program::ptr
Definition shadow.cpp:1206
Definition cache.hpp:11
void submit(view_id _id, program_handle _handle, int32_t _depth, bool _preserveState)
Definition graphics.cpp:899
void set_state(uint64_t _state, uint32_t _rgba)
Definition graphics.cpp:763
void set_stencil(uint32_t _fstencil, uint32_t _bstencil)
Definition graphics.cpp:773
auto is_homogeneous_depth() -> bool
auto is_origin_bottom_left() -> bool
uint32_t get_render_frame()
hpp::small_vector< entt::handle > shadow_map_models_t
Definition shadow.h:567
sm_resolution
Enum representing the resolution of shadow maps.
Definition light.h:74
sm_impl
Enum representing the implementation type for shadow mapping.
Definition light.h:48
sm_depth
Enum representing the depth method for shadow mapping.
Definition light.h:26
light_type
Enum representing the type of light.
Definition light.h:14
float distance
#define SET_CLAMPED_VAL(x, val)
gfx::view_id id
Definition render_pass.h:98
static auto get_layout() -> const vertex_layout &
Definition vertex_decl.h:15
auto get_cached() -> T &
Definition context.hpp:49
static auto context() -> rtti::context &
Definition engine.cpp:115
Struct representing a light.
Definition light.h:87
SpotDirectionInner m_spotDirectionInner
Definition shadow.h:156
gpu_program::ptr m_packDepthSkinned[DepthImpl::Count][PackDepth::Count]
Definition shadow.h:471
gpu_program::ptr m_hBlur[PackDepth::Count]
Definition shadow.h:468
gpu_program::ptr m_black
Definition shadow.h:466
gpu_program::ptr m_packDepth[DepthImpl::Count][PackDepth::Count]
Definition shadow.h:470
void init(rtti::context &ctx)
Definition shadow.cpp:2353
gpu_program::ptr m_drawDepth[PackDepth::Count]
Definition shadow.h:469
gpu_program::ptr m_vBlur[PackDepth::Count]
Definition shadow.h:467
DepthImpl::Enum m_depthImpl
Definition shadow.h:501
LightType::Enum m_lightType
Definition shadow.h:500
void submitPerFrameUniforms() const
Definition shadow.h:247
void setPtrs(Light *_lightPtr, float *_colorPtr, float *_lightMtxPtr, float *_shadowMapMtx0, float *_shadowMapMtx1, float *_shadowMapMtx2, float *_shadowMapMtx3)
Definition shadow.h:219
void submitPerDrawUniforms() const
Definition shadow.h:256
void submitConstUniforms() const
Definition shadow.h:238