Unravel Engine C++ Reference
Loading...
Searching...
No Matches
assao_pass.cpp
Go to the documentation of this file.
1#include "assao_pass.h"
2#include "graphics/graphics.h"
5#include <graphics/texture.h>
6
7namespace unravel
8{
9
10#define SAMPLER_POINT_CLAMP (BGFX_SAMPLER_POINT | BGFX_SAMPLER_UVW_CLAMP)
11#define SAMPLER_POINT_MIRROR (BGFX_SAMPLER_POINT | BGFX_SAMPLER_UVW_MIRROR)
12#define SAMPLER_LINEAR_CLAMP (BGFX_SAMPLER_UVW_CLAMP)
13
14#define SSAO_DEPTH_MIP_LEVELS 4
15
16void vec2Set(float* _v, float _x, float _y)
17{
18 _v[0] = _x;
19 _v[1] = _y;
20}
21
22void vec4Set(float* _v, float _x, float _y, float _z, float _w)
23{
24 _v[0] = _x;
25 _v[1] = _y;
26 _v[2] = _z;
27 _v[3] = _w;
28}
29
30void vec4iSet(int32_t* _v, int32_t _x, int32_t _y, int32_t _z, int32_t _w)
31{
32 _v[0] = _x;
33 _v[1] = _y;
34 _v[2] = _z;
35 _v[3] = _w;
36}
37
38static const int32_t cMaxBlurPassCount = 6;
39
41{
42 auto& am = ctx.get_cached<asset_manager>();
43
44 auto loadProgram = [&](const std::string& cs)
45 {
46 auto cs_shader = am.get_asset<gfx::shader>("engine:/data/shaders/assao/" + cs + ".sc");
47
48 auto prog = std::make_shared<gpu_program>(cs_shader);
49 m_programs.emplace_back(prog);
50 return prog->native_handle();
51 };
52
53 // Create uniforms
54 u_rect = bgfx::createUniform("u_rect", bgfx::UniformType::Vec4); // viewport/scissor rect for compute
55 m_uniforms.init();
56
57 // Create texture sampler uniforms (used when we bind textures)
58 s_normal = bgfx::createUniform("s_normal", bgfx::UniformType::Sampler); // Normal gbuffer
59 s_depth = bgfx::createUniform("s_depth", bgfx::UniformType::Sampler); // Depth gbuffer
60
61 // clang-format off
62 s_ao = bgfx::createUniform("s_ao", bgfx::UniformType::Sampler);
63 s_blurInput = bgfx::createUniform("s_blurInput", bgfx::UniformType::Sampler);
64 s_finalSSAO = bgfx::createUniform("s_finalSSAO", bgfx::UniformType::Sampler);
65 s_depthSource = bgfx::createUniform("s_depthSource", bgfx::UniformType::Sampler);
66 s_viewspaceDepthSource = bgfx::createUniform("s_viewspaceDepthSource", bgfx::UniformType::Sampler);
67 s_viewspaceDepthSourceMirror = bgfx::createUniform("s_viewspaceDepthSourceMirror", bgfx::UniformType::Sampler);
68 s_importanceMap = bgfx::createUniform("s_importanceMap", bgfx::UniformType::Sampler);
69 // clang-format on
70
71 // Create program from shaders.
72
73 // clang-format off
74 m_prepareDepthsProgram = loadProgram("cs_assao_prepare_depths");
75 m_prepareDepthsAndNormalsProgram = loadProgram("cs_assao_prepare_depths_and_normals");
76 m_prepareDepthsHalfProgram = loadProgram("cs_assao_prepare_depths_half");
77 m_prepareDepthsAndNormalsHalfProgram = loadProgram("cs_assao_prepare_depths_and_normals_half");
78 m_prepareDepthMipProgram = loadProgram("cs_assao_prepare_depth_mip");
79 m_generateQ0Program = loadProgram("cs_assao_generate_q0");
80 m_generateQ1Program = loadProgram("cs_assao_generate_q1");
81 m_generateQ2Program = loadProgram("cs_assao_generate_q2");
82 m_generateQ3Program = loadProgram("cs_assao_generate_q3");
83 m_generateQ3BaseProgram = loadProgram("cs_assao_generate_q3base");
84 m_generateQ0ProgramRgba16f = loadProgram("cs_assao_generate_q0_normal_rgba16f");
85 m_generateQ1ProgramRgba16f = loadProgram("cs_assao_generate_q1_normal_rgba16f");
86 m_generateQ2ProgramRgba16f = loadProgram("cs_assao_generate_q2_normal_rgba16f");
87 m_generateQ3ProgramRgba16f = loadProgram("cs_assao_generate_q3_normal_rgba16f");
88 m_generateQ3BaseProgramRgba16f = loadProgram("cs_assao_generate_q3base_normal_rgba16f");
89 m_smartBlurProgram = loadProgram("cs_assao_smart_blur");
90 m_smartBlurWideProgram = loadProgram("cs_assao_smart_blur_wide");
91 m_nonSmartBlurProgram = loadProgram("cs_assao_non_smart_blur");
92 m_applyProgram = loadProgram("cs_assao_apply");
93 m_nonSmartApplyProgram = loadProgram("cs_assao_non_smart_apply");
94 m_nonSmartHalfApplyProgram = loadProgram("cs_assao_non_smart_half_apply");
95 m_generateImportanceMapProgram = loadProgram("cs_assao_generate_importance_map");
96 m_postprocessImportanceMapAProgram = loadProgram("cs_assao_postprocess_importance_map_a");
97 m_postprocessImportanceMapBProgram = loadProgram("cs_assao_postprocess_importance_map_b");
98 m_loadCounterClearProgram = loadProgram("cs_assao_load_counter_clear");
99 m_updateGBufferProgram = loadProgram("cs_assao_update_g_buffer");
100 // clang-format on
101
102 m_loadCounter = bgfx::createDynamicIndexBuffer(1, BGFX_BUFFER_COMPUTE_READ_WRITE | BGFX_BUFFER_INDEX32);
103
104 return true;
105}
106
107void assao_pass::run(const camera& cam, gfx::render_view& rview, const run_params& params)
108{
109 m_settings = params.params;
110
111 const auto size = params.depth->get_size();
112
113 m_width = size.width;
114 m_height = size.height;
115
116 if(m_size[0] != (int32_t)m_width - 2 * m_border || m_size[1] != (int32_t)m_height - 2 * m_border)
117 {
118 destroy_frame_buffers();
119 create_frame_buffers();
120 }
121
122 const float* viewMtx = cam.get_view();
123 float projMtx[16];
124
125 float n = cam.get_near_clip();
126 float f = cam.get_far_clip();
127
129 {
130 auto fovy = cam.get_fov();
131 bx::mtxProj(projMtx, fovy, float(m_size[0]) / float(m_size[1]), n, f, false);
132 }
133 else
134 {
135 float zoom = cam.get_zoom_factor();
136 const frect_t rect = {-(float(m_size[0]) / 2.0f) * zoom,
137 (float(m_size[1]) / 2.0f) * zoom,
138 (float(m_size[0]) / 2.0f) * zoom,
139 -(float(m_size[1]) / 2.0f) * zoom};
140
141 bx::mtxOrtho(projMtx, rect.left, rect.right, rect.bottom, rect.top, n, f, 0, false);
142 }
143
144 // ASSAO passes
145#if USE_ASSAO == 0
146 update_uniforms(0, viewMtx, projMtx);
147
148 gfx::render_pass pass("assao_pass");
149 auto view = pass.id;
150
151 {
152 bgfx::setTexture(0, s_depthSource, params.depth->native_handle(), SAMPLER_POINT_CLAMP);
153 m_uniforms.submit();
154
155 if(m_settings.generate_normals)
156 {
157 bgfx::setImage(5, m_normals, 0, bgfx::Access::Write);
158 }
159
160 if(m_settings.quality_level < 0)
161 {
162 for(int32_t j = 0; j < 2; ++j)
163 {
164 bgfx::setImage((uint8_t)(j + 1), m_halfDepths[j == 0 ? 0 : 3], 0, bgfx::Access::Write);
165 }
166
167 bgfx::dispatch(view,
168 m_settings.generate_normals ? m_prepareDepthsAndNormalsHalfProgram
169 : m_prepareDepthsHalfProgram,
170 (m_halfSize[0] + 7) / 8,
171 (m_halfSize[1] + 7) / 8);
172 }
173 else
174 {
175 for(int32_t j = 0; j < 4; ++j)
176 {
177 bgfx::setImage((uint8_t)(j + 1), m_halfDepths[j], 0, bgfx::Access::Write);
178 }
179
180 bgfx::dispatch(view,
181 m_settings.generate_normals ? m_prepareDepthsAndNormalsProgram : m_prepareDepthsProgram,
182 (m_halfSize[0] + 7) / 8,
183 (m_halfSize[1] + 7) / 8);
184 }
185 }
186
187 // only do mipmaps for higher quality levels (not beneficial on quality level 1, and detrimental on quality level 0)
188 if(m_settings.quality_level > 1)
189 {
190 uint16_t mipWidth = (uint16_t)m_halfSize[0];
191 uint16_t mipHeight = (uint16_t)m_halfSize[1];
192
193 for(uint8_t i = 1; i < SSAO_DEPTH_MIP_LEVELS; i++)
194 {
195 mipWidth = (uint16_t)bx::max(1, mipWidth >> 1);
196 mipHeight = (uint16_t)bx::max(1, mipHeight >> 1);
197
198 for(uint8_t j = 0; j < 4; ++j)
199 {
200 bgfx::setImage(j, m_halfDepths[j], i - 1, bgfx::Access::Read);
201 bgfx::setImage(j + 4, m_halfDepths[j], i, bgfx::Access::Write);
202 }
203
204 m_uniforms.submit();
205 float rect[4] = {0.0f, 0.0f, (float)mipWidth, (float)mipHeight};
206 bgfx::setUniform(u_rect, rect);
207
208 bgfx::dispatch(view, m_prepareDepthMipProgram, (mipWidth + 7) / 8, (mipHeight + 7) / 8);
209 }
210 }
211
212 // for adaptive quality, importance map pass
213 for(int32_t ssaoPass = 0; ssaoPass < 2; ++ssaoPass)
214 {
215 if(ssaoPass == 0 && m_settings.quality_level < 3)
216 {
217 continue;
218 }
219
220 if(ssaoPass == 1 && m_settings.quality_level == 3)
221 {
222 gfx::render_pass pass(fmt::format("importance map pass {}", ssaoPass).c_str());
223 view = pass.id;
224 }
225
226 bool adaptiveBasePass = (ssaoPass == 0);
227
228 BX_UNUSED(adaptiveBasePass);
229
230 int32_t passCount = 4;
231
232 int32_t halfResNumX = (m_halfResOutScissorRect[2] - m_halfResOutScissorRect[0] + 7) / 8;
233 int32_t halfResNumY = (m_halfResOutScissorRect[3] - m_halfResOutScissorRect[1] + 7) / 8;
234 float halfResRect[4] = {(float)m_halfResOutScissorRect[0],
235 (float)m_halfResOutScissorRect[1],
236 (float)m_halfResOutScissorRect[2],
237 (float)m_halfResOutScissorRect[3]};
238
239 for(int32_t pass = 0; pass < passCount; pass++)
240 {
241 if(m_settings.quality_level < 0 && (pass == 1 || pass == 2))
242 {
243 continue;
244 }
245
246 int32_t blurPasses = m_settings.blur_pass_count;
247 blurPasses = bx::min(blurPasses, cMaxBlurPassCount);
248
249 if(m_settings.quality_level == 3)
250 {
251 // if adaptive, at least one blur pass needed as the first pass needs to read the final texture results
252 // - kind of awkward
253 if(adaptiveBasePass)
254 {
255 blurPasses = 0;
256 }
257 else
258 {
259 blurPasses = bx::max(1, blurPasses);
260 }
261 }
262 else if(m_settings.quality_level <= 0)
263 {
264 // just one blur pass allowed for minimum quality
265 blurPasses = bx::min(1, m_settings.blur_pass_count);
266 }
267
268 update_uniforms(pass, viewMtx, projMtx);
269
270 bgfx::TextureHandle pPingRT = m_pingPongHalfResultA;
271 bgfx::TextureHandle pPongRT = m_pingPongHalfResultB;
272
273 // Generate
274 {
275 bgfx::setImage(6, blurPasses == 0 ? m_finalResults : pPingRT, 0, bgfx::Access::Write);
276
277 bgfx::setUniform(u_rect, halfResRect);
278
279 bgfx::setTexture(0, s_viewspaceDepthSource, m_halfDepths[pass], SAMPLER_POINT_CLAMP);
280 bgfx::setTexture(1, s_viewspaceDepthSourceMirror, m_halfDepths[pass], SAMPLER_POINT_MIRROR);
281 if(m_settings.generate_normals)
282 {
283 bgfx::setImage(2, m_normals, 0, bgfx::Access::Read);
284 }
285 else
286 {
287 bgfx::setImage(2, params.normal->native_handle(), 0, bgfx::Access::Read);
288 }
289
290 if(!adaptiveBasePass && (m_settings.quality_level == 3))
291 {
292 bgfx::setBuffer(3, m_loadCounter, bgfx::Access::Read);
293 bgfx::setTexture(4, s_importanceMap, m_importanceMap, SAMPLER_LINEAR_CLAMP);
294 bgfx::setImage(5, m_finalResults, 0, bgfx::Access::Read);
295 }
296
297 bgfx::ProgramHandle programsNormal[5] = {m_generateQ0Program,
298 m_generateQ1Program,
299 m_generateQ2Program,
300 m_generateQ3Program,
301 m_generateQ3BaseProgram};
302
303 bgfx::ProgramHandle programsRgba16f[5] = {m_generateQ0ProgramRgba16f,
304 m_generateQ1ProgramRgba16f,
305 m_generateQ2ProgramRgba16f,
306 m_generateQ3ProgramRgba16f,
307 m_generateQ3BaseProgramRgba16f};
308
309 bgfx::ProgramHandle* programs = programsNormal;
310
311 if(!m_settings.generate_normals)
312 {
313 programs = programsRgba16f;
314 }
315
316 int32_t programIndex = bx::max(0, (!adaptiveBasePass) ? (m_settings.quality_level) : (4));
317
318 m_uniforms.m_layer = blurPasses == 0 ? (float)pass : 0.0f;
319 m_uniforms.submit();
320 bgfx::dispatch(view, programs[programIndex], halfResNumX, halfResNumY);
321 }
322
323 // Blur
324 if(blurPasses > 0)
325 {
326 int32_t wideBlursRemaining = bx::max(0, blurPasses - 2);
327
328 for(int32_t i = 0; i < blurPasses; i++)
329 {
330 bgfx::setViewFrameBuffer(view, BGFX_INVALID_HANDLE);
331 bgfx::touch(view);
332
333 m_uniforms.m_layer = ((i == (blurPasses - 1)) ? (float)pass : 0.0f);
334 m_uniforms.submit();
335
336 bgfx::setUniform(u_rect, halfResRect);
337
338 bgfx::setImage(0, i == (blurPasses - 1) ? m_finalResults : pPongRT, 0, bgfx::Access::Write);
339 bgfx::setTexture(1,
340 s_blurInput,
341 pPingRT,
343
344 if(m_settings.quality_level > 0)
345 {
346 if(wideBlursRemaining > 0)
347 {
348 bgfx::dispatch(view, m_smartBlurWideProgram, halfResNumX, halfResNumY);
349 wideBlursRemaining--;
350 }
351 else
352 {
353 bgfx::dispatch(view, m_smartBlurProgram, halfResNumX, halfResNumY);
354 }
355 }
356 else
357 {
358 bgfx::dispatch(view,
359 m_nonSmartBlurProgram,
360 halfResNumX,
361 halfResNumY); // just for quality level 0 (and -1)
362 }
363
364 bgfx::TextureHandle temp = pPingRT;
365 pPingRT = pPongRT;
366 pPongRT = temp;
367 }
368 }
369 }
370
371 if(ssaoPass == 0 && m_settings.quality_level == 3)
372 { // Generate importance map
373 m_uniforms.submit();
374 bgfx::setImage(0, m_importanceMap, 0, bgfx::Access::Write);
375 bgfx::setTexture(1, s_finalSSAO, m_finalResults, SAMPLER_POINT_CLAMP);
376 bgfx::dispatch(view,
377 m_generateImportanceMapProgram,
378 (m_quarterSize[0] + 7) / 8,
379 (m_quarterSize[1] + 7) / 8);
380
381 m_uniforms.submit();
382 bgfx::setImage(0, m_importanceMapPong, 0, bgfx::Access::Write);
383 bgfx::setTexture(1, s_importanceMap, m_importanceMap);
384 bgfx::dispatch(view,
385 m_postprocessImportanceMapAProgram,
386 (m_quarterSize[0] + 7) / 8,
387 (m_quarterSize[1] + 7) / 8);
388
389 bgfx::setBuffer(0, m_loadCounter, bgfx::Access::ReadWrite);
390 bgfx::dispatch(view, m_loadCounterClearProgram, 1, 1);
391
392 m_uniforms.submit();
393 bgfx::setImage(0, m_importanceMap, 0, bgfx::Access::Write);
394 bgfx::setTexture(1, s_importanceMap, m_importanceMapPong);
395 bgfx::setBuffer(2, m_loadCounter, bgfx::Access::ReadWrite);
396 bgfx::dispatch(view,
397 m_postprocessImportanceMapBProgram,
398 (m_quarterSize[0] + 7) / 8,
399 (m_quarterSize[1] + 7) / 8);
400 }
401 }
402
403 // Apply
404 {
405 // select 4 deinterleaved AO textures (texture array)
406 bgfx::setImage(0, m_aoMap, 0, bgfx::Access::Write);
407 bgfx::setTexture(1, s_finalSSAO, m_finalResults);
408
409 m_uniforms.submit();
410
411 float rect[4] = {(float)m_fullResOutScissorRect[0],
412 (float)m_fullResOutScissorRect[1],
413 (float)m_fullResOutScissorRect[2],
414 (float)m_fullResOutScissorRect[3]};
415 bgfx::setUniform(u_rect, rect);
416
417 bgfx::ProgramHandle program;
418 if(m_settings.quality_level < 0)
419 program = m_nonSmartHalfApplyProgram;
420 else if(m_settings.quality_level == 0)
421 program = m_nonSmartApplyProgram;
422 else
423 program = m_applyProgram;
424 bgfx::dispatch(view,
425 program,
426 (m_fullResOutScissorRect[2] - m_fullResOutScissorRect[0] + 7) / 8,
427 (m_fullResOutScissorRect[3] - m_fullResOutScissorRect[1] + 7) / 8);
428 }
429
430#endif
431
432 {
433 gfx::render_pass pass("update g_buffer ao pass");
434 bgfx::setImage(0, params.color_ao->native_handle(), 0, bgfx::Access::ReadWrite);
435 bgfx::setImage(1, m_aoMap, 0, bgfx::Access::Read);
436
437 bgfx::dispatch(pass.id, m_updateGBufferProgram, (m_size[0] + 7) / 8, (m_size[1] + 7) / 8);
438 }
439
440 gfx::discard();
441}
442
443auto assao_pass::shutdown() -> int32_t
444{
445 // Cleanup.
446
447 m_uniforms.destroy();
448
449 bgfx::destroy(u_rect);
450
451 bgfx::destroy(s_normal);
452 bgfx::destroy(s_depth);
453 bgfx::destroy(s_ao);
454 bgfx::destroy(s_blurInput);
455 bgfx::destroy(s_finalSSAO);
456 bgfx::destroy(s_depthSource);
457 bgfx::destroy(s_viewspaceDepthSource);
458 bgfx::destroy(s_viewspaceDepthSourceMirror);
459 bgfx::destroy(s_importanceMap);
460
461 bgfx::destroy(m_loadCounter);
462 destroy_frame_buffers();
463
464 m_programs.clear();
465
466 return 0;
467}
468
469void assao_pass::create_frame_buffers()
470{
471 m_border = 0;
472
473 m_size[0] = m_width + 2 * m_border;
474 m_size[1] = m_height + 2 * m_border;
475 m_halfSize[0] = (m_size[0] + 1) / 2;
476 m_halfSize[1] = (m_size[1] + 1) / 2;
477 m_quarterSize[0] = (m_halfSize[0] + 1) / 2;
478 m_quarterSize[1] = (m_halfSize[1] + 1) / 2;
479
480 vec4iSet(m_fullResOutScissorRect, m_border, m_border, m_width + m_border, m_height + m_border);
481 vec4iSet(m_halfResOutScissorRect,
482 m_fullResOutScissorRect[0] / 2,
483 m_fullResOutScissorRect[1] / 2,
484 (m_fullResOutScissorRect[2] + 1) / 2,
485 (m_fullResOutScissorRect[3] + 1) / 2);
486
487 int32_t blurEnlarge =
488 cMaxBlurPassCount + bx::max(0, cMaxBlurPassCount - 2); // +1 for max normal blurs, +2 for wide blurs
489 vec4iSet(m_halfResOutScissorRect,
490 bx::max(0, m_halfResOutScissorRect[0] - blurEnlarge),
491 bx::max(0, m_halfResOutScissorRect[1] - blurEnlarge),
492 bx::min(m_halfSize[0], m_halfResOutScissorRect[2] + blurEnlarge),
493 bx::min(m_halfSize[1], m_halfResOutScissorRect[3] + blurEnlarge));
494
495 // Make gbuffer and related textures
496
497 for(int32_t i = 0; i < 4; i++)
498 {
499 m_halfDepths[i] = bgfx::createTexture2D(uint16_t(m_halfSize[0]),
500 uint16_t(m_halfSize[1]),
501 true,
502 1,
503 bgfx::TextureFormat::R16F,
504 BGFX_TEXTURE_COMPUTE_WRITE | SAMPLER_POINT_CLAMP);
505 }
506
507 m_pingPongHalfResultA = bgfx::createTexture2D(uint16_t(m_halfSize[0]),
508 uint16_t(m_halfSize[1]),
509 false,
510 2,
511 bgfx::TextureFormat::RG8,
512 BGFX_TEXTURE_COMPUTE_WRITE);
513 m_pingPongHalfResultB = bgfx::createTexture2D(uint16_t(m_halfSize[0]),
514 uint16_t(m_halfSize[1]),
515 false,
516 2,
517 bgfx::TextureFormat::RG8,
518 BGFX_TEXTURE_COMPUTE_WRITE);
519
520 m_finalResults = bgfx::createTexture2D(uint16_t(m_halfSize[0]),
521 uint16_t(m_halfSize[1]),
522 false,
523 4,
524 bgfx::TextureFormat::RG8,
525 BGFX_TEXTURE_COMPUTE_WRITE | SAMPLER_LINEAR_CLAMP);
526
527 m_normals = bgfx::createTexture2D(uint16_t(m_size[0]),
528 uint16_t(m_size[1]),
529 false,
530 1,
531 bgfx::TextureFormat::RGBA8,
532 BGFX_TEXTURE_COMPUTE_WRITE);
533
534 m_importanceMap = bgfx::createTexture2D(uint16_t(m_quarterSize[0]),
535 uint16_t(m_quarterSize[1]),
536 false,
537 1,
538 bgfx::TextureFormat::R8,
539 BGFX_TEXTURE_COMPUTE_WRITE | SAMPLER_LINEAR_CLAMP);
540 m_importanceMapPong = bgfx::createTexture2D(uint16_t(m_quarterSize[0]),
541 uint16_t(m_quarterSize[1]),
542 false,
543 1,
544 bgfx::TextureFormat::R8,
545 BGFX_TEXTURE_COMPUTE_WRITE | SAMPLER_LINEAR_CLAMP);
546
547 m_aoMap = bgfx::createTexture2D(uint16_t(m_size[0]),
548 uint16_t(m_size[1]),
549 false,
550 1,
551 bgfx::TextureFormat::R8,
552 BGFX_TEXTURE_COMPUTE_WRITE | SAMPLER_POINT_CLAMP);
553}
554
555void assao_pass::destroy_frame_buffers()
556{
557 if(!bgfx::isValid(m_aoMap))
558 {
559 return;
560 }
561
562 for(uint32_t ii = 0; ii < BX_COUNTOF(m_halfDepths); ++ii)
563 {
564 bgfx::destroy(m_halfDepths[ii]);
565 }
566
567 bgfx::destroy(m_pingPongHalfResultA);
568 bgfx::destroy(m_pingPongHalfResultB);
569 bgfx::destroy(m_finalResults);
570 bgfx::destroy(m_normals);
571 bgfx::destroy(m_aoMap);
572
573 bgfx::destroy(m_importanceMap);
574 bgfx::destroy(m_importanceMapPong);
575}
576
577void assao_pass::update_uniforms(int32_t _pass, const float* view, const float* proj)
578{
579 vec2Set(m_uniforms.m_viewportPixelSize, 1.0f / (float)m_size[0], 1.0f / (float)m_size[1]);
580 vec2Set(m_uniforms.m_halfViewportPixelSize, 1.0f / (float)m_halfSize[0], 1.0f / (float)m_halfSize[1]);
581
582 vec2Set(m_uniforms.m_viewport2xPixelSize,
583 m_uniforms.m_viewportPixelSize[0] * 2.0f,
584 m_uniforms.m_viewportPixelSize[1] * 2.0f);
585 vec2Set(m_uniforms.m_viewport2xPixelSize_x_025,
586 m_uniforms.m_viewport2xPixelSize[0] * 0.25f,
587 m_uniforms.m_viewport2xPixelSize[1] * 0.25f);
588
589 float depthLinearizeMul =
590 -proj[3 * 4 + 2]; // float depthLinearizeMul = ( clipFar * clipNear ) / ( clipFar - clipNear );
591 float depthLinearizeAdd =
592 proj[2 * 4 + 2]; // float depthLinearizeAdd = clipFar / ( clipFar - clipNear );
593 // correct the handedness issue. need to make sure this below is correct, but I think it is.
594
595 if(depthLinearizeMul * depthLinearizeAdd < 0)
596 {
597 depthLinearizeAdd = -depthLinearizeAdd;
598 }
599
600 vec2Set(m_uniforms.m_depthUnpackConsts, depthLinearizeMul, depthLinearizeAdd);
601
602 float tanHalfFOVY = 1.0f / proj[1 * 4 + 1]; // = tanf( drawContext.Camera.GetYFOV( ) * 0.5f );
603 float tanHalfFOVX = 1.0F / proj[0]; // = tanHalfFOVY * drawContext.Camera.GetAspect( );
604
605 if(bgfx::getRendererType() == bgfx::RendererType::OpenGL)
606 {
607 vec2Set(m_uniforms.m_ndcToViewMul, tanHalfFOVX * 2.0f, tanHalfFOVY * 2.0f);
608 vec2Set(m_uniforms.m_ndcToViewAdd, tanHalfFOVX * -1.0f, tanHalfFOVY * -1.0f);
609 }
610 else
611 {
612 vec2Set(m_uniforms.m_ndcToViewMul, tanHalfFOVX * 2.0f, tanHalfFOVY * -2.0f);
613 vec2Set(m_uniforms.m_ndcToViewAdd, tanHalfFOVX * -1.0f, tanHalfFOVY * 1.0f);
614 }
615
616 m_uniforms.m_effectRadius = bx::clamp(m_settings.radius, 0.0f, 100000.0f);
617 m_uniforms.m_effectShadowStrength = bx::clamp(m_settings.shadow_multiplier * 4.3f, 0.0f, 10.0f);
618 m_uniforms.m_effectShadowPow = bx::clamp(m_settings.shadow_power, 0.0f, 10.0f);
619 m_uniforms.m_effectShadowClamp = bx::clamp(m_settings.shadow_clamp, 0.0f, 1.0f);
620 m_uniforms.m_effectFadeOutMul = -1.0f / (m_settings.fade_out_to - m_settings.fade_out_from);
621 m_uniforms.m_effectFadeOutAdd =
622 m_settings.fade_out_from / (m_settings.fade_out_to - m_settings.fade_out_from) + 1.0f;
623 m_uniforms.m_effectHorizonAngleThreshold = bx::clamp(m_settings.horizon_angle_threshold, 0.0f, 1.0f);
624
625 // 1.2 seems to be around the best trade off - 1.0 means on-screen radius will stop/slow growing when the camera is
626 // at 1.0 distance, so, depending on FOV, basically filling up most of the screen This setting is
627 // viewspace-dependent and not screen size dependent intentionally, so that when you change FOV the effect stays
628 // (relatively) similar.
629 float effectSamplingRadiusNearLimit = (m_settings.radius * 1.2f);
630
631 // if the depth precision is switched to 32bit float, this can be set to something closer to 1 (0.9999 is fine)
632 m_uniforms.m_depthPrecisionOffsetMod = 0.9992f;
633
634 // used to get average load per pixel; 9.0 is there to compensate for only doing every 9th InterlockedAdd in
635 // PSPostprocessImportanceMapB for performance reasons
636 m_uniforms.m_loadCounterAvgDiv = 9.0f / (float)(m_quarterSize[0] * m_quarterSize[1] * 255.0);
637
638 // Special settings for lowest quality level - just nerf the effect a tiny bit
639 if(m_settings.quality_level <= 0)
640 {
641 effectSamplingRadiusNearLimit *= 1.50f;
642
643 if(m_settings.quality_level < 0)
644 {
645 m_uniforms.m_effectRadius *= 0.8f;
646 }
647 }
648
649 effectSamplingRadiusNearLimit /= tanHalfFOVY; // to keep the effect same regardless of FOV
650
651 m_uniforms.m_effectSamplingRadiusNearLimitRec = 1.0f / effectSamplingRadiusNearLimit;
652
653 m_uniforms.m_adaptiveSampleCountLimit = m_settings.adaptive_quality_limit;
654
655 m_uniforms.m_negRecEffectRadius = -1.0f / m_uniforms.m_effectRadius;
656
657 if(bgfx::getCaps()->originBottomLeft)
658 {
659 vec2Set(m_uniforms.m_perPassFullResCoordOffset, (float)(_pass % 2), 1.0f - (float)(_pass / 2));
660 vec2Set(m_uniforms.m_perPassFullResUVOffset,
661 ((_pass % 2) - 0.0f) / m_size[0],
662 (1.0f - ((_pass / 2) - 0.0f)) / m_size[1]);
663 }
664 else
665 {
666 vec2Set(m_uniforms.m_perPassFullResCoordOffset, (float)(_pass % 2), (float)(_pass / 2));
667 vec2Set(m_uniforms.m_perPassFullResUVOffset,
668 ((_pass % 2) - 0.0f) / m_size[0],
669 ((_pass / 2) - 0.0f) / m_size[1]);
670 }
671
672 m_uniforms.m_invSharpness = bx::clamp(1.0f - m_settings.sharpness, 0.0f, 1.0f);
673 m_uniforms.m_passIndex = (float)_pass;
674 vec2Set(m_uniforms.m_quarterResPixelSize, 1.0f / (float)m_quarterSize[0], 1.0f / (float)m_quarterSize[1]);
675
676 float additionalAngleOffset =
677 m_settings.temporal_supersampling_angle_offset; // if using temporal supersampling approach (like "Progressive
678 // Rendering Using Multi-frame Sampling" from GPU Pro 7, etc.)
679 float additionalRadiusScale =
680 m_settings.temporal_supersampling_radius_offset; // if using temporal supersampling approach (like "Progressive
681 // Rendering Using Multi-frame Sampling" from GPU Pro 7, etc.)
682 const int32_t subPassCount = 5;
683 for(int32_t subPass = 0; subPass < subPassCount; subPass++)
684 {
685 int32_t a = _pass;
686
687 int32_t spmap[5]{0, 1, 4, 3, 2};
688 int32_t b = spmap[subPass];
689
690 float ca, sa;
691 float angle0 = ((float)a + (float)b / (float)subPassCount) * (3.1415926535897932384626433832795f) * 0.5f;
692 angle0 += additionalAngleOffset;
693
694 ca = bx::cos(angle0);
695 sa = bx::sin(angle0);
696
697 float scale = 1.0f + (a - 1.5f + (b - (subPassCount - 1.0f) * 0.5f) / (float)subPassCount) * 0.07f;
698 scale *= additionalRadiusScale;
699
700 vec4Set(m_uniforms.m_patternRotScaleMatrices[subPass], scale * ca, scale * -sa, -scale * sa, -scale * ca);
701 }
702
703 m_uniforms.m_normalsUnpackMul = 2.0f;
704 m_uniforms.m_normalsUnpackAdd = -1.0f;
705
706 m_uniforms.m_detailAOStrength = m_settings.detail_shadow_strength;
707
708 if(m_settings.generate_normals)
709 {
710 bx::mtxIdentity(m_uniforms.m_normalsWorldToViewspaceMatrix);
711 }
712 else
713 {
714 bx::mtxTranspose(m_uniforms.m_normalsWorldToViewspaceMatrix, view);
715 }
716}
717} // namespace unravel
#define SSAO_DEPTH_MIP_LEVELS
#define SAMPLER_POINT_CLAMP
#define SAMPLER_POINT_MIRROR
#define SAMPLER_LINEAR_CLAMP
bgfx::ProgramHandle loadProgram(bx::FileReaderI *_reader, const char *_vsName, const char *_fsName)
entt::handle b
entt::handle a
auto native_handle() const -> T
Definition handle_impl.h:40
auto init(rtti::context &ctx) -> bool
void run(const camera &camera, gfx::render_view &rview, const run_params &params)
auto shutdown() -> int32_t
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_far_clip() const -> float
Retrieves the distance from the camera to the far clip plane.
Definition camera.cpp:67
auto get_fov() const -> float
Retrieves the current field of view angle in degrees.
Definition camera.cpp:57
auto get_projection_mode() const -> projection_mode
Retrieves the current projection mode for this camera.
Definition camera.cpp:52
auto get_zoom_factor() const -> float
Retrieves the zoom factor.
Definition camera.cpp:9
auto get_view() const -> const math::transform &
Retrieves the current view matrix.
Definition camera.cpp:276
auto get_near_clip() const -> float
Retrieves the distance from the camera to the near clip plane.
Definition camera.cpp:62
float scale
Definition hub.cpp:25
void discard(uint8_t _flags)
Definition graphics.cpp:968
void vec4Set(float *_v, float _x, float _y, float _z, float _w)
void vec4iSet(int32_t *_v, int32_t _x, int32_t _y, int32_t _z, int32_t _w)
void vec2Set(float *_v, float _x, float _y)
gfx::view_id id
Definition render_pass.h:98
auto get_size() const -> usize32_t
Definition texture.cpp:68
T width
Definition basetypes.hpp:55
T height
Definition basetypes.hpp:56