From 76225451bde727fe28c2035034963444de056d7f Mon Sep 17 00:00:00 2001 From: Anecoz Date: Mon, 18 Dec 2023 18:59:04 +0100 Subject: [PATCH] #13: Crude ability to bake DDGI atlases per tile --- assets/bilateral_filter_comp.spv | Bin 11632 -> 11988 bytes assets/bloom_composite_comp.spv | Bin 15800 -> 16156 bytes assets/bloom_prefilter_comp.spv | Bin 10016 -> 10068 bytes assets/cull_comp.spv | Bin 41612 -> 41968 bytes assets/debug_spheres_frag.spv | Bin 1896 -> 1948 bytes assets/debug_spheres_vert.spv | Bin 12184 -> 12540 bytes assets/deferred_cluster_comp.spv | Bin 18512 -> 18564 bytes assets/deferred_pbr_frag.spv | Bin 13032 -> 13084 bytes assets/deferred_tiled_comp.spv | Bin 52104 -> 59132 bytes assets/grass_frag.spv | Bin 3056 -> 3108 bytes assets/grass_vert.spv | Bin 10104 -> 10156 bytes assets/hiz_comp.spv | Bin 4104 -> 4156 bytes assets/irradiance_probe_update_rchit.spv | Bin 45924 -> 51568 bytes assets/irradiance_probe_update_rgen.spv | Bin 10884 -> 12572 bytes assets/irradiance_probe_update_rmiss.spv | Bin 2120 -> 2172 bytes assets/light_shadow_rchit.spv | Bin 5172 -> 5476 bytes assets/light_shadow_rgen.spv | Bin 10088 -> 10444 bytes assets/light_shadow_sum_comp.spv | Bin 11792 -> 12096 bytes assets/luminance_average_comp.spv | Bin 4640 -> 4692 bytes assets/luminance_histogram_comp.spv | Bin 4868 -> 4920 bytes assets/mirror_reflections_rchit.spv | Bin 46052 -> 51696 bytes assets/mirror_reflections_rgen.spv | Bin 11476 -> 11832 bytes assets/mirror_reflections_rmiss.spv | Bin 2184 -> 2236 bytes assets/particle_update_comp.spv | Bin 13592 -> 13948 bytes assets/pp_fxaa_frag.spv | Bin 10432 -> 10484 bytes assets/probe_conv_comp.spv | Bin 8420 -> 9636 bytes assets/shaders/bindless.glsl | 34 +- assets/shaders/deferred_tiled.comp | 39 ++- assets/shaders/irradiance_probe_update.rchit | 3 - assets/shaders/irradiance_probe_update.rgen | 36 +- assets/shaders/pbr_light.glsl | 105 ++++-- assets/shaders/probe_conv.comp | 32 +- assets/shaders/scene_ubo.glsl | 2 + assets/shadow_rchit.spv | Bin 5080 -> 5384 bytes assets/shadow_rgen.spv | Bin 9900 -> 10272 bytes assets/ssao_blur_comp.spv | Bin 4536 -> 4588 bytes assets/ssao_comp.spv | Bin 9436 -> 9488 bytes assets/ssgi_rchit.spv | Bin 12768 -> 13124 bytes assets/ssgi_rgen.spv | Bin 9832 -> 10188 bytes assets/standard_frag.spv | Bin 12964 -> 13320 bytes assets/standard_shadow_point_vert.spv | Bin 9196 -> 9500 bytes assets/standard_shadow_vert.spv | Bin 9520 -> 9876 bytes assets/standard_vert.spv | Bin 19168 -> 19524 bytes assets/surfel_conv_comp.spv | Bin 8052 -> 8104 bytes assets/surfel_sh_comp.spv | Bin 8968 -> 9020 bytes assets/surfel_update_rchit.spv | Bin 29024 -> 29396 bytes assets/surfel_update_rgen.spv | Bin 19708 -> 20064 bytes assets/surfel_update_rmiss.spv | Bin 2400 -> 2452 bytes assets/tlas_update_comp.spv | Bin 12344 -> 12700 bytes assets/tonemap_comp.spv | Bin 10296 -> 10652 bytes src/anedit/logic/AneditApplication.cpp | 31 +- src/anedit/logic/AneditApplication.h | 3 + src/anerend/render/GpuBuffers.h | 8 +- src/anerend/render/ImageHelpers.h | 6 + src/anerend/render/RenderContext.h | 12 +- src/anerend/render/VulkanRenderer.cpp | 311 +++++++++++++++++- src/anerend/render/VulkanRenderer.h | 41 ++- src/anerend/render/asset/Texture.h | 3 +- src/anerend/render/asset/TileInfo.h | 15 + .../passes/IrradianceProbeTranslationPass.cpp | 1 + src/anerend/render/scene/Scene.cpp | 32 ++ src/anerend/render/scene/Scene.h | 13 +- src/anerend/render/scene/ScenePager.cpp | 18 +- src/anerend/render/scene/Tile.cpp | 4 + src/anerend/render/scene/Tile.h | 4 + .../render/scene/internal/SceneSerializer.cpp | 62 +++- 66 files changed, 724 insertions(+), 91 deletions(-) create mode 100644 src/anerend/render/asset/TileInfo.h diff --git a/assets/bilateral_filter_comp.spv b/assets/bilateral_filter_comp.spv index 11f1af184a0b7c2b5aff75a0a46a4a272e127a64..b199ce82e7f0ea15c9e4f9a4dddc936af0dacb81 100644 GIT binary patch delta 736 zcmY*V%}x_h82x5Cw^iF2`eWl5C;=)fU~LF7u~lemA}fpu2@9aNI00&Gr%4+Yq)V60 zeF8V`&8&@2;KIb6;RSFbZ{RuYG#S3+&OPURKleNH@9_7Lo3g7JaV*J-D{m(5rR7hq z-l^A?NaNctQ0Z)JZL8?wrz77gGPUr*-#z z&<;PKV>Zn*6}4zBm~FLK$+PBs)ar)1+YiFgYzk)M)q?q?o>;}`vudQTUqZP5d`74- z+U>KT7G50p5A={+;i-C}zCP%5bZ@pYbw&s)ecY_2U2Cx{3%ybH{*QiEmh2(cF^e>FoP4wSAn@QIUOhS%%1F_Y;RptuLr7LfVMK>Pzqj29~Q2T6=? z@N*+k4J)-*eC0bI+5F2X~S!;Y`$M4H=zA z!Z5xs`n0EE5x{b2PTjsx-7@!sl#H8t_mkX2f}#Acg*uvV8{(IE{U)A`%+BcWZVBfB*p=R{Yt1|jDiP>@P^`_>aVG$yD%Mm0R zoc&;Pd@cn)T=gYmVb<{Wzz( z&&>dBR?;@UQm5gQ;hCnF0oEKx#r!xYly);fo0X`1r7~cXVM?}_0oEMHyZCX=t#oRV zDnb7#-ABi-e{!Aj< zesi8?(iguIrs;+KkWHK8pV0bK{#~u(ik;Bo77G>N~Sx2)&1p7%hX$M1nYpJ%odRAsv^U3;zB z@-wEOJkn>La`y~K&8cp-?>H{ZF!u!Pwo{iXOT*cawYKf+P!I7L*sZcFW#hiH(cVNn zvV-d(FG;3{8}1q0>omMwBb%Uh(tBp)F43C8j(oh`Y<1lKDrdnfHM`31Pl%Z4caM!% zsmm)OE_lUrz#M@;3!6ns*k@Xf1ZK&<=4{rq0?Nx_(LhP@NI5%YKBST~s^o)&N(kr| zG50b3IztwXJ(M6fzGusYt!jV$7fe3NIgNXzmA#fwYxJo8FY^NKS|Dj|9yb_q_X> BD^~yj delta 276 zcmccOx4>^h5Q{!5g9{@A0~Z4WLrG?CDv)AeV}OWp1KBC5IVFi;F*dL|p2>4r#ASJb zBE`u?si}D$shQ~+B|t7v7du!5-{gxd(v19*-?B(c3IN4ZD+=<9ON&rU7Tm1J`kcx1 z3(#T@sAW7rrOH7314#^I4M^+{k{I7)Mh;;^ey9u!6T$?LWgyiYNMeFeF`ms+IaFDg mMHpNrALNmqe1V5$@*N(Y$!~ak7cPN1anSy4L>OXenKrw#X2aq!hijQ&QyG zUdwzmiJmS#T?#ejls69J9mSW1=YD(GI za4Y@}Pjt5RsS`UZ`qh=49UnkXt+m|nWy5p*R%c5h+&rlM+9P5p=;=Am9Nw~||F5?Q z9HLU$b{GBnrnfE+fK9&YKGt8{uU2KVBN;rxXDc3m(F?o4u-5H0x$*>F9{BrB8Jtgi z2=zAUlpP+L=3{6?rRWXd6r3I7`XbJWas3fD5aaLym>pIkm(GmFDnn7_Q;^BMCl_#8 z*D(eVOJvX;t4wfi@G0?c*WqZ0O}bZ$v*}f^ygQtL-zm-!*Z`d49Fl?IJ6;Dy9r96s z4nEIGP0vtSwewkZnm5#0-Vxu`WqytSFZ0W}Et0|I{FZh&L3${9gGa|Xhgg^Z4@tn2 zyz+s+cv*0T2tyV)%>ClrV*Tj-%{c-bdVwJkG0RU;)QO%Mujr({6$ZsiAPY0w{{UHw BdcObw delta 393 zcmexxoT=w16E8E9GCKncBLg=BFT?qXys3-|6N@Vu&usjd$u7;x5Xr#6zy-u5nYpPz zih+#*BE~&=B8RXf4^X5yxhOR?FFZ4)Bm*eR4%Wdtc`t`FBj4nk9MZD{1{nzA zpWW=Jm&(K}!Vo!mqk;J30|p|KZy5LhU94)jo`aEV^Hs}aCR14kW`U0r~_ge-{e>(X-59Zl}ysI0w6Wnm7aMesd>ejC6y3U*uW+W zPTt5Q&M36`B$GT7F9Q<;g9p?~pz*B2xgg_}ftUkHh7T&ngCxce6%#-b16d2wD}p2@ o2o;k+5)*=o$!tz!Wn^R)We}fS$R<3wfsF-<1sFvq_p;pv0RKBDM*si- delta 241 zcmbQk|AKFW7?VCLgE#{N0~ZjNWag#OsMsGQF_0A?bqtdoS%oJ{u=2EG}gzW|Zt)wHv diff --git a/assets/debug_spheres_vert.spv b/assets/debug_spheres_vert.spv index 30f9f246ad396838150e0404905fdae48caf46df..5db077917215c60f92affeab05b7fee0b8ef5dc5 100644 GIT binary patch delta 755 zcmY*VF;Bu!5WY$aR;eJBh-on@gJCpL5rIJ$b#O2-F%HI{JhV|U(we|T{0EY^IJi1E zn*IQPgM&YST?cmu?<*y#mtNm}-`%_S-94TD){WR$AwjA_lVnh>ZwSTeyC?dFLR4X| zzJ2~AN(uTVq6zl1`jt3zuEk!fdCQREqy@Q2jy>l_M7g9KjGJ=?Q|@_Nh}MzQ@Gkkr zu-lY0bW2IeqHg8WsJZIywLH;s9j`m=5)V30%ep?RWc;pfsl8Q}^#Az;frB*~7tWS< zU3U*f2Uz2$)+6=X_syng4<&<#c|3~CCu%V=Fh(2IYMj9uJkjy)+hPK>Oleg0UyYJ> zKx0I^46&Xhdx2eza2Oukc!Zk@xnzV(g)Oxd@jDIom%r-_8M1z#6T~kF2>5mU{;`u!1FyVdwz7$T1`XV-?XnF!GR(eATbz zYHBP?-}1q>FE8As{s3H;WorNc delta 396 zcmey9I3u2ynMs+QfrXKQn}L_XVj^!UqtwLWSXMJe1_twuH$SpVvogG8U|`?^;*!kV zR3OE`#sCrHp3KN8EXe~DDNZg*P0b6>Oex6#%CduX@J`m{lxF0c?8zxD%MVhMUFn%u zlA2eXSyBlxg$=AuU~(g;IHTa^nVixrq9AKaQY%VIi&Be0idccre6uZ|Ijij#pp*yH zW{{oAK>Pzqj29~Q2T6<%D#kE*qps2I;?Mv?t2s_qOd3?O$X z0fj*T##aQgK?Z{O=9?oWZCRK_7~W1^C@VgBgRIEr6S6MMrm_so3?@LmoItDqRA&mL ZK>#FX4dsK(1_2QNA&@rT+^Sg44*+nOK3M<& diff --git a/assets/deferred_cluster_comp.spv b/assets/deferred_cluster_comp.spv index 53d6cc80b64c30c042780049518adf485e12d453..a1386ab4167a9ca34a401c9920748ebcae265bb5 100644 GIT binary patch delta 292 zcmcaGfw5&G0R=BrzeVn9Sy#0!LXGMJLyb>N3vTyi#F%klxmi%au7^GZ_liZe?pfn1a|H=Scm+$iUzM zHJS&gR2hhWAc^rp#r`0Pfvf)QW=q;?km2 zAQNu3(B@j!*{r+_ObiSjQ0sUmCvpqtf{a!MVh$u3KByQEk{CZ!OaMtt04gSeBnEN- p$UF%oF(Ig!%;t&Qg-pz%4AUnI@(E8?;A4Se0miADb@_Iy002BdEe!ww delta 246 zcmbP}_9At|DHdr~hUp9p3|v55l9`(dq!`#3AY$B;8CiuTd4M9t$wjHDdEuEUB^f|j zcCZfK$-1o4jC_+lS*2z9L29xqJ@ZOZ^NKS|Dj}w@fz=62Ze$f_6x=+MbvCQ*7e)pK z52*1VgO!2!2a*^sRO}Cu7#~!OVR9k2@MI5e9$5jX2nQ3wG(o5s&*p>Ng-pyM4AUn& S@(E84;A4Sefz2s=J5&I-oGO0+ diff --git a/assets/deferred_tiled_comp.spv b/assets/deferred_tiled_comp.spv index 877209acb1d2dbf2970481c05edb91f756575ea7..5c9aac011a16279d0940af7e2bcdacabfbf5b92f 100644 GIT binary patch literal 59132 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 literal 52104 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

NoX5@KYR1Sss+IHT ze9GPP&a3-8@m>Zl*S{O?9#PLcZ3!;de=B&_Ut4qiw?;FLe#uF#%)wl=`7ZHB#-8(Z zTe#<`y8C~7Y7h6nw(TftjzgSr>;%sK@O`8_wq3y4AHJKEXKb$kXMgyfQXbpx;Or0I zS;`Z0PjL2!?=R)r{5-ffc)fajzRQ&7`FbDlh4`4Gx!9+%jiK)jlpQJMn(qrQ*L**? znz1s!YR+%w#yaEJAME-i_gBKl;5lCpfUD_eJZ)<6KL~99;RnOZ>;577Qqrio-y_Zfm+ujeg8LpZ@s5TYFYn-v0jqgLn_X+3Q_+sC cHLn@@o^cME?e*8b5}WTU&B1=P=ii$Be}Fk#J^%m! diff --git a/assets/grass_frag.spv b/assets/grass_frag.spv index 2bd407b69ebc8baab106ddf6c4539432f3c94bce..106526fddd7d7036edc00542d39882d9ed6f8530 100644 GIT binary patch delta 310 zcmew$zC>cfIVNv*1}6pv1}-2@O3Y3T$;?Uh%uCA$av9hdSiy4KKz2!HZYr`E50I0R znp2VpR>uZb$2<8ilejD&P^37yC^a?DBQ-NUqXeQ0VhjIdLuP44fyuti(vpHeiPVaM z{NmCg6qAKEH!@cqUY5x*ygZEMn^Sp(r2wfSEM5Qr delta 246 zcmZ4E|HE&C95XvBLj?l^1J`6nW?@}!AS)#`rz8|k-;$&Jj?jC_;l0!jYKJDH^=1%N73D+=<9ON&y0OrT1L*@BzjGM{Hn{ldt=-~kl^ z8LAA#Kaj+Dp<;iK#Q30M3`_{U{7^9#Br%ZHAoDmTD{=`l@@)3xQeN=IlKZ=0JxDR`Tzg` diff --git a/assets/hiz_comp.spv b/assets/hiz_comp.spv index 3237b99b6d0f34cf018e7c73d0bed7dbcf924966..9de46175fb92e88f4a1e018a367bad4c83941bf3 100644 GIT binary patch delta 296 zcmeBB*rTw)iP@W-A&-H9feVO}60=i7GILTr^V0HxTn07;}G^60;yFk@K zo4+#uW(s6rVqoxqS_d*(8Hibs#CV}%97tk(P%$1PF_5(&y#kXR*@ZPlkYog*G7?B) lLQpZ8&6(_m%*>(;d6O4%Nl)Iu#WHyh7Y}3Z=A&HBtN_NjD$@V} delta 264 zcmdm^(4nxwiCLeOA&-H9feVOBGILXb6ayOrM2s8APD#xvNd$|rfz|O$?qwF2C(L@=w0YEG;Pj6i=-v$S*D}LNQrzvmncFrqnNt z3=AGn%XolFm4WyNk{HMukk}t2F+Qjm0~10oKU9nbNepB)NH53aLUv(Bp3O7a4Vjrm Y81g1xr=j8Qop#@2XA@YX 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 F{{y^Mg9!it literal 45924 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
    j4$LBti+I}C*KUG_8tLn9X5NurS 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 diff --git a/assets/irradiance_probe_update_rmiss.spv b/assets/irradiance_probe_update_rmiss.spv index 7cb1cc9bc863990a4def9062e9621279150ce6f1..b9212cf9a966200f96c4204bda9e64c3f95becdc 100644 GIT binary patch delta 302 zcmX>h@JC=n8Iw6XgD3+70~Zh{C1$6FWagxL=B4EWxeRO!tYA5AAiE?pHx*foXYxcQ zVM$(~P;qimYHD71W=cs0PzS^`zR7!;q#5}q-(-@O6#%KpuJp_+NzE(HEUAQ;!Ui^3 zaIzq?IHS;JP3HfMybMeX3?5J`c_tUK3g?21R|aAZBpE)a7!Q&dKU7QrNepByNUsQz um>^V40!d5=DkigeA*(7QvnYe;NhOdA)XNT5$3Iz+S(;H`vM#eYqu^#&=KqYgUlak4)2LLehUOJ)(;|DEN7KUY{JrJJX4d)mehOzd>f-*u zwO*1}wH8=ta73^7+`mc(-BIi&U|-X=YOb%3lf(_#@mD;WRBw$kEiPc*&b7X@9e6iM z$3wTgT>Aoga_(=VBhOz!X z2Qx1(&&qG!?7&K^LpDV1tLFd?gU1GZD4RRgEhStn!&t+ycdxpmMEjshz@Y_WOPuQ` MIGrCk#JG1?KHu=r6tRJ%4&SxjNxi4?VE4tZIVM(slW+f~*Mm|69UGs~%%8a`Xjw^bg z+32sY6bf#coOqo_<7=%-L(5KJ);8L>wCwJ?>;6jFwb6=7Sk)kH51y|AHC8=$jhUt4 zVzTA((xWC9Oxw;yA}unnw0ehNn?AVKkh`lz8oaIbx9zc5HF#D3f3o}K|Fs7<(I;g^ zZ+^kQ>FGLQ5#VjvgWRHPE*!?f6Qu-v@39-@It21=(a&i%XGzPiJS@9z>7JMO7sTtX z;yOb4^MMipis=shox_^ zYP*N2TZ!>0mCwB9D0+=amFJ7*HW`JQ(w|pl49Lhi2&OxnIoMM&GI+}o8N=XV`CJ3c zn?~bc;$1R!;9`upj2)`MlTJrZ@XT>~i1EPxW4W|5ZrFq(l*FvUiJD6JVD7dh3s*jJ zoH?>-ji?fga!*!QYKA+x167IUfyv{L;SRapa0gUTB|gdtqin=a?m+FMd0_IkOkVJ= z*SW$S$Rx67BJ$fC+}j983#0pJxL~-?sW&%`N`yk0Thpj;tr3n!g=>#+ye?cvgyTiw zx+5I#1J@hj)T&qOu)tMY;7Bs%ajPF=(mU?uWh`iOnI&=;2GUjC^_* z3{QuG&q@AOGxvhK+`x1#9C?SDcVuY4Yi7Wq1=F#NA*-)`te5g-!Tro|>~*k_8Jj&4 o!(llzSzrzgcR`pF{*=jW;$MQi7jfoe+54{Sgu%aek296zKh`I>*7(>#i2{lGVlWJVJsAUR6`T^6ax-sI~ z6`5baPiXoFbnicK!x9*)U|eY8!gFT&#%CWnynD_)_ub*W%jd_(4|9pBrL;(D!Vo#} z;~@7|yL9lOrk@HSMuQV8qn-MDS!*ExuXUVe*KObKH=DNm=;e;x@I*@JBJdBh)*2le zuwfiHkD3Zee6U`z64Z&arKP#g4KKw)k#k0 zJ`g&wQ=9C-M^o#_S@#i$I+SOl4oN7glblX|lI>xN4$U6UU)_TCdAvNJ7 zr*mIA$DV&3Fs9JR!*7;8Uz@Yyabo63W)O3fsGTXAG1h)68b^t~Uy8;tqV`A8__EY^ zz49LNLOcn@q$2WRX`EIxP7*Z}+BzmlJ|#zI1bq?U3iDw3ZM JpI_}|{sKh7tIPlZ diff --git a/assets/light_shadow_sum_comp.spv b/assets/light_shadow_sum_comp.spv index 3903fe4418aeed4ab4f1eeb8e541d77c156ae648..3009d7467a166a438b2de38fadf1e1aa100d374a 100644 GIT binary patch delta 486 zcmYk2O-jRX5XC2L()d*syQm0?S`dm}Km?&~Y!@zsE=3TUNTDkB!?v~>y@AD(NER;K zcmeScUc~ncDRf{m^WMDqzaeiI-ApTmY`G-}JQ_~W!C{E3_2MKfPU1e2Y%!zd+JN@_9)xsHUMhqKR?jli4@s9fC z6k|O*2Qyzu=TTf<`}CtN%O(dEMQ^I-5DtXL4!kY9f$EYpa7QWT1UU8{)gLR-j#LRa lv|#LsePO(wz^?5jL|Of_h&j~*{fB$iNEj~3xU%tE_y-%}K^p)7 delta 185 zcmX>QHz9_XnMs+QfrXKQn}L_1dLnNwqu9jiK*sWo7awynmT%VN4rW(%XJBC{XJlYd zVt@b`UlGXV17Z-rYO|>DcJ@SB24;p*pi(;^Rsaf@0cj8biCIJWAfrG)8^{+2(iI>+ h3xux;WL5(C96(x!fsLUMNLK;*ATcoBTqu2B7ytz17!?2j diff --git a/assets/luminance_average_comp.spv b/assets/luminance_average_comp.spv index eaffe3ceb4509f4b111d51e4b3349e57f2548386..a656780a6eb6c125ced990e7f7a16c61e6a7e470 100644 GIT binary patch delta 303 zcmZ3Waz$lB5R*4MgBSw?0~Zh{C1$6FWagxL=B4EWxeRO!tYA5AAiE?pHx*fo2gpfD z%_&I)t78MJi3vc(L?$0(6Bd;~ zk`aQ+$ZWpKc94--ltFCrLJslC8#qK5MJFHR@Mq+mEXXO($hX;$b2%d;&*qz4?(6^< C5-NcJ delta 279 zcmcbjvOr}+5R*PDgBSw?0~ZjNWag#joF-?p@4ybfeVO}60=i7GILTr^V0HxTn07ejC6y3U*uW+W zPJYNN&M36`C-Z+MUIr!x1`nu}Jd+*Sg>ym1D+4hHk_;bIj0Z`KA1Wq*BnGk;q*nw< wOb{w2fg~mb6_eRq$ll1zEXq(YnUPy~vH&*=6bmrsPnPBOXB6C=%RQYP01CA&m;e9( delta 248 zcmdm?)}pq-jai?Sp@4ybfeVOBGILXb6ayOrM2s8APD#xvNd$|rfz|O$p2#fD$UAu@ zv$QN9P`tP_&oi$iHLp0cq!P#l>SYJ3KG;mvI|evVCRt)fQoQ1Axsm5it%h-$ll1zEW%JQ*^pa! WvI92@6bnoa;r3w^*u0Q?Iy(U8&L{N% diff --git a/assets/mirror_reflections_rchit.spv b/assets/mirror_reflections_rchit.spv index b62ab17d68521c939fd034ebecca9448da6530c6..673241fdeaa7775b6362445d8c479e2d12d4abf1 100644 GIT binary patch literal 51696 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 G^Zx)9E0yX1 literal 46052 zcmaK#2Y_8w)wWMEB_Z_QLqaH#DxFZ%Lm)s%p+lI=+)0K^X2O(^P$VJrUZuAnprBv@ zX@V#yNKq+*R6!I00Tn?I5dP;m_pF&cN5B7=?S9{Pt-bcz<&=Bw4XNorY(Q4qFIzTS zKD)6#%a4__{_rfb-nOVuTDi*aTCH0DxTx=^9+VBtrcOR^#<+v0&1kB0Hg>ek>uT?q z(bCpbSOqx1rtIn>bt+wCc>n5;5R%4ah zR?LQGkI+Xgd~QQaoBHLH>nS%=RwY2c{#mv~U6$=e8Bdu=nL{~;@;%D^l*cJAP-+27FkX>O@>V6P8*I#l%KL+_m3&{XM|QCTprwWYD8YeqvyOV{kVm9Cb?8C?tKRXUlt zt{u0hzglLFz9#Iy|Aa~7W;D*5H>0y_VQXbZYfD>YMpH{irLn7Jex)a;!mp*Rv9-G? zb*Lj!I)8QKIEeU@8ye?SnhvaVbX68WQSGsMG_exFU8AOLdbxAa#Ks7_tJSn!FSoBI z1`u|pJ!{$_%gkd1aP+8M?lG^u6aTuL+h1dQYkLQEX!hC0R5!HtYWCaJ&^D{m)`eev z-qya4Zf6E3Hgy6~2jsdr;g>XDboI2CU(uXEke-aTt}8yzOP^PT2bm#x7Wn`N^qT}c|_JKEKnsYUgHyDlc|S)n`bqG3)F$*Ju-XSNkN+u!fG|th1fl_r}znQzne2%KbK% zx6Go)u0tyw?ZcZ{d~@0ieNOH(Altg+5eSB-ftl{16)@u8a)XivBzDza&Ft&w_-!ikiix3kg9GqumW--pO_*Cb$CL0Id zi(=p7sndN@mo1Y`LYq)&XIphFoZ2{>oi)dhgfdz+hrOxyYijR0Fz0pIKGc2V49cdW z^~9OWMYAWX$jn$Z+5X1Lq-QK#p2UA9WrhSu27+L*WRnYZc^I6_NtsmopBwA^Ob zmTh*O*}GRN#EI*$d#@SZ&^oiy#MR7kxrx&2huUnkzGJD&TF}zGjde8I{FchG4n^*H z)LM+!I9&SK*ZFO)y^R}z+FZ2m&dStzmB#MY2G8L^*+R6=hPm@vD^q#QXst}{XrEab z-nlJn*-{;8HCNBAdD^B`?|;TSHZ(4(s^;O%v3JbNXG`G6=C_d~axsVbTo%398?MBt z%TAy!_jRIilC{(C8{t>1r~RLV*4uwwwkUj(92cWCw9cFD#YV&{&Y1A2%TA*%=Xg3=-yCbRGtheTSuwj9?%wh~Mjs{=Zv|#mMtKr%$Zf z>|A)dpU#7q_tW`k<^6O4S~<@P(R%k&U3L+?@AwAh&yrK8PZ>XM(u}bar_7i*Wy*}n z6Azv-b>gAp$ge)To;HPj+Khcid5OsNoBQY!z1-yExt+SbyX(NNV()xd<@vqXIsOlv z@#GhViA@Vo>hhDdI%bvXTJT6-%yF+a5H0St)wZ?SN@%Vt&GJ}25A!(J)y;LRs?}zD z_VKCBE`~RDcdh6; zTib5q?x^~{0w2iuTK)@#(8lX*;N;scSavt9>rtqwkepwW@KdwiUE>w@qy8@^PWdOJ`5J6}8P- zSh7{ew-Po!!L)a>(W-5#Yvc2?&k}Av@5O#L>z>)3Po9zYfeb%VW z_APkz*`PL?0-rT&0lioAn+i|&|MU_+xaz-6_#aZTA6DXv;PLs!^M5fsU-#-`Xg*hG zpm|Yo4$lI|GtBwmDTRJ9xccl-lU)U#RNRBF1~+uEpxq5VzU48l(Vn-f&u#_h{T`nOiBG%h|Y_-`teRxgw9(>N!>YRQc<{{P`J_frVV*NiW zcsz@K1!wlWw zoq@T7I|ok%Kcvc^3w~%d-`C)N9?t{!Jd4$3@1l2h&#k^iDAxF|RV^7=HRgNhz0YKI z*@y5vhn{#f*+*#Js?F&$?a5fbDDf{#oF;wz`;~Z2iLX=Q>y`N65+73HLrZ*EiSJV4 zyOsDJB|fsmN0s=P5k;5Bt^i-UA1KtJnA1Y&mdxE-hc;EB4_v*($aj>v>z3tpjf9 zy-elj=DL0SYqRxBdIaDGbF*5W1G=At%+>D)oY(MkFO5cP$=~19Wn;nloEHwx zgPI5P)ANqi?-=s=D*Rk;zjI(+CwH{)Vv2XQ6Z5@PlTFc=Cqw%>T+CCYxEVY@@3%gi z1y0{D+n?{o)ji@}yxcjAcky!PFW$w=owIlsFL$ouUA&w>#k=_WtOZhi%N;Xfzf~Q# ze81#_20KQ-Q>pHuUVraf^U!M?uCsbRx4ie%9-8y(7dGvD0(B1jE~(0U!sdNF*rQiJyxIRFXnYCe>(-vJ{1UBe z-|F{R&fTLqZ}4M3Eo$@csk%7lfYCMN%klxc_p?!LwjsQCZ`EZR!}-kFoWD@XbEwTW?c-CMeXYbdFYzr)e5(@Q zy2Smya9**Ad}j5#!^nS1!@~VLT4uGhRWIMnNnJJ)dsFw^xeN0*VAXXUU5Yub#P=%k zeM)@45}#b+Q%ZbViBB)_L;CQ6`FEi`=TT`;j>+#y^Jmwdccr!2j6N}HvzaAcDe>7Q zKBvUz_TlyU_p--wp&j4e(U`uYJs!U)6>eA^4KrIS)$>}-gYTBxI{i)-?4DJ3|Icji zZu1+#(A@i7d`(D&R-gNM?VQV3Fs(iJ!K&^xl+S8xNnjM{S3%Xqds&9Ia!yT9Bqq``l)&3?-iJ5 z_l)1C=e+Rq+&LX>vft0iv6QcGmyVcKYc38ADxe zw{2q)&;I;Af8PJ-&o<7(x!A|F@)X9~PGiVDcy>9^Yg}l~0nb#q=5_D<-gZ3`>poKV z;5&F@8iJ_x`ELpet;gTz!HeHBmYi4U+?<-w-Rwagzp6A*mu$!R^55;Q{_Y9 zzI&X&y<&Cjcdk~&Yb1Eh1dmGa=md{R@WBZ_B*BL!xGll$37%Kry~r=#J9~cb#aM$6 zE5?v&p3}Yyjdp~gMQ=N~?M9Zgayzd_X*;>?7Ez)O+NqV>xn0tBa@#FR+Nt%ntIoSzzlRb(uajzi*ATh-?p*El zMDxA5+TRn+_vUIJC7SQe)jmx$-d*+8Yt{W&^|KHChET$Wk?4vtC9{%r4Ot#nLs$K*J)k168Yukqt^R>TjU z##f8@eg;e9%Z=|oFutG1?92V*xc%(o5%EGR&zXMqq2CZn_|+6zbv~-`V$Mb;es*Kq z$rSULjo>^UMKPA2xjgjoaNg8nTzalf3lGjam+(4^6+=4X&!R(aQu$zA~=7Fy!c*U!V&R< zr}5PyzQ1uzg^rL9^exs&+Fv#n)ZOTQzA$WN`)25&8y-pk7{^jN+HhU#vaU^tV$jIN55P`b4{ChtX^yZlCsJY};E~jOQ9gj*elYf~#vEUU1`T{~EPeUA`r?xf@^Zm+x}pJCFR_IA0g% z(Re#j+n@SS=4dBs{nah5?QYaVC?2-io!U0)tFa<`P}|p@)MD*J$!ZL>x!Jd+nj_!6 z7P`Eu4amRKPkmGW>G(N^`l=h7uOs_t+6I%uQPeSi=Gstjb@|MK4=i|N!K-6fF8`k2 zzS5kdUp3d?&h zGPvVc-?iYE7h1Hx0`3@tUkUbJ5d13ekc3|i9!c4PR>r-CVhoFI_1DLIuBEnrb2Ojp z3a)NG^6LxD{`9?p!l$26!I$QI(VoF?%y~94__uPt*J$%G?oAY9*iK*Vmgw(hu>C~) zTfk2}`Q+}wzYV|giYxXA{+--Dsi*&2;aT=j55Fzvi$+HO--R2~IJVVaAIJYaYWIcL zJ>xs?cThZn-wEzlaM$uKiu*6@KLz(Mxb}xB9$|kRocjL`?*0h-i{RRXzX5hW%M;^~m{~;J0qyc=yQhGPqil@VgrA_6ZF= ze%HX&qJ-adXuA(Oeb0z@JzOnH_$@`d@`|`{JxDg<(~aUh2MAJYEi=P zUbHM*^i%J3UxFQ{YdM%Jy`Rn1{;v}2YVA5&To+65(40pX$MrF;^DgOEXy)UZ^@p!a zt$$5nGhXDo0b2ViOLhsqDg5OXCyorhGn}L6Tt7PJ*XMTQpA7e0G5!*;W^;^rIt^hd zJW9m91bxs8!+O^7Qn*?a{fxg9E%y42VE*KD8gT}(sn)#v>7B!WOSsQK!MBAkqEYZY z;Ktp8GtT?;bof$gOT;_~jicxMIT8NUlaqR`H;ds9>~z`=;eU4S|5!dp#=Z^i8ixJ8 z+@6h&9G-xCua7x;3vT~6QmoazfBhTXYfqHW*Ji1`21SWD+n`4r&+YIZk@y=c{0}Jn z<2n%j2N(Wnzg{=yq3c`Da{;=(<$Nwk{L_3cOZ?M(?kN2AP3Pgqg@5!B`TrVSzq0@H z=;l)P|0lY+M~U_M1pOuUynA?aF2tNp`5y6{lKY-a&1bpo!6U&QKCkWocdadPuIgi~ z9SfU2`ucwDfBAYn^}U$(!C>Ea$&IlqwR5j#K62lAscGM%z_vAx@4w8$IKJ1C>o<lr z|1kx&t^Q|Izr0%Y8Crk2-_xsUKexbMW4y-R1~(QpQfgLMBz)tXQ`U}K0gYg?V!SzwmkyPw#M=q*>`Oo!F{*p zF_=%C$AjY@>O95yRj%ECzN^yTdGno=+#J3^ZU1WaA@{wMnxA(TfnyDfWV zZk#35wox;V-1kaqv9_ne`IA3a`;N)n)r{r)Ben271MHsl8Qk|s+ST;+ospXTo=x2! zKQ;T6``$>+{C#JX=I^^9HRJfsM{b-8sLfT)IC9_ns5x%m`BcyKn*4o_+;*1~KEB_v zo!s|1(av`{(av`?a@$>A_^8=V?t7YO=Q|qb$2@(nBDdYug^!x;!cyRm8K1Jb_%5(8^`DPI3 z+uY>-rY^YG`<)W5-QR(QUGDF;Qhs>C{p``4aNoQ58>sNtK0o2wk59PvMG4n_YQoom zpH<>ll(@e)ivG;^k%SM2|FXm%O*og4%-2a=p@~yyXK7aWJYsAEPGf8f zSF^pJF(SrxXxfb7xhFS<@plKSjUo@9i}s}WtYjYA^z%7sBt_c={kWe|k18}{dj85s zan?KE6ToVIW{-aMf~!aFdxIxZPN9wC-v_L}dgMI`tiA{zbKMtg9QDxl1FJub-7)wK zHksmcnq$x&IUG>f%-L&_CoM(X3oR5N=vwGy*09KFuW`d2Q9$F(< z-S-=ja}zvr)*d-mz}n2&YqdObZUvjO?|Z_3E?hl$8`$-UzT3h2sN453)E$&L6xUe0 zZG9f@q-b-W4#L(|Xy)R5K|X^0XGXS;K)^bn zM?G>q4IH^@k6cd&Yl~dZ0IQjc_e*)?dM4Oh)wM68Rx{Ugsn4UFL-Cw7K9|qz{6b%X zkNg7o(n61R7Z&Y2Z=&5rXzJ1KVz6!1qunLoa(|bisfW)u3!gOhWoYV?$;fA^%fZIC ztv1Kzvw^yCyf<74b|2-}PsV1utKjPTcz?MXY`b*)*TB`!!^bw)f^DZBv9ANW?rH4n z;p!3l2C%WyaV&+aN9-HHwo_kR^!F{WeQJyTZUQf&r2X9tSC9T~0o$L~g;+V9U_Ep_8_n_Hcf9)|=b?5LW z)DKYZr+7`&E;lFbzQ6k^+;^0|*K>Xx!$bO0_UG>D{QL~8X7MmD-1+YnRQKS|(e+u5 z+0*}Fus-7`+U)m1YIX4=)W0b3FR5?APyJEwx4`D{82Aaw;}p5~=qJIpmD|s+!LFO! zb^8t2cwzr7*nY$QG}u0lSb4cTw(*{#c&X#|nyq@_z>??)l7@q;loqwN~UjsK&-T>R)cNl+wtLx)A{W|z8N_tMe0ay1t zu+1OAwo{MTZ-PCi)7XE4t4HiVgN>b@({I7mBlcgwwo_kR^!GN{KD9-E?|>Ik(*E9s zt4Du-1>0YGPQM3NkN(~V+fF_D`v7d8+MLH%snv|@wejy@=P~a6?vH=K)uZnZ!S-mZ*%+%Y@gbqzt6$W zW7^*raP{c#Kj88_eu<_Y{e1)jdKRP-ylS+Q35dniBWJWzcM|zxK#=5IAzxCvsJf`CAU` zUbvHZk^k~&>M?&SfXjPfMKtx8zm>qYQ;*mygWU^h>{ZazBlfD`@?KaCO+8|-4z`{8 z;$knX0k%(V(chY2_d?p=T4?Ig-`e2vURVcBJ^EW0Y&-SnZ#}SmYI7d_?5`Gcwmw)b z)@d+U%_Fo83N2mFA%#|5&+2_~D4Ol{*S?e(_PHTgo6mRdqha7psMX{Cvk_R`;$dIL zj-0idv)9_;V6U;-d^aK2<~4FNu-6T3zNe7KShoPXzqM@+mWzE~u}Oh_SK+(bX!CWr z^P`{dE#xEkWZ-wd+kl5sn}dBB(^$sP*ESnd>lg912gm))b8aX2j+Et?8LDh&{?D#zMMjB8i0_p-RAK(pQWKlOX?@%!N2!D@cr_6afe1bckO z{At^RqUJj|v9Z1OjsZKC^jU5!T-{toQ_I7DJXrs9PfviW>pzZKuD|!ciD3QH-1mm7 z>%SMZJp3nt_4l)=a|_J&<^R<6--lWr^S(dWdDpfdSRS?mz^;L|$<%UfM-g)>cw}Mo zy^&nMY1FX}zAqX@8Nm*8O%DXOQ9CD&)7;I+evNM&+vn{V|3Tn`DXy*aYkawJ{>?hX zdRS}oebklsc|N(Ohr&lutGlL$Q+v3k+76?rxu)V+qocsiVY;RbaCQ5cK`jseMzH?r znl{1J^`A*Ck2Pur>z}UaEV#P<6>53-w}ACe*Ys$(y8g4N<*{z9;8@c+V0qZuz(-JQ zHySuPOF836Eu}972UW)quWbHlTzCu&?FqgR3 z-4E985!z3{YWl^q%L8Eh)?a&!<3X_Fh--sf-^lMFu;WPc`x#t4^7}bh&Eh?fOLfmY zJOZ}8=hVZLn1^40wMEXq1RKXAv`4{e={O#P>#NNeF^*q>9f$q6XXN_EIGzAU9_HXY zKS@!KHGitm)a|o8mS3Y8!}C2I%WvS?BJbaVjpY&A(_l5@hW1RM*-v~{e->%*V2Dbe@OA%kvr!9l(>_a+G|UEV8VydcBK;Ev*3=`d(}TF=IZ>I z_eT_Si0iIgAML}bKc;Ap>wx?gO4vUs>~Rjs|3!)ZJ_Qemk=C>|cPj z$9l;>&+XMc@g>+bFrRc!dknWW8K_&Nu+8HBFQHm;XEY|Db}`!?o#58(1(HGlW%v)qc*9zM%yTY<7U z#eF1>IIDq;Gqvc`zlW>lymnyn@8bIVP<7iJgXZ7KRhN5?t_5~aAIy$(&#evDN4-D% zGm2wyk7hH&+WKMZU;^@zU_IO4}z8-HVTZ4rMHu<=u$P2uVhe>m87>hY}bHL&Bd zZ|%nO+}jMCo(pn)eMWTMU1Qfe^4tO(d8Tu?CAzlo+bZ!(=VEJgZHtS!{yNyU>d|%^ zaP*Omb6a$6(RMqq?bYuio_lwDu)5a=_wJ5h5BILN9Vlv!OYA%h!@d(Z`gAY4_jX28 zkNfNhu$slg$~_r#xeG!%mvY-Um(iznI=9YooIksQy>7&LxEow8&ci*x9*#xZ?i4l0 zB91sC!N!U6a1>n4JUtIbgFO$`ZR2@32COdkJRA#7&%<$Webm$Q&}+LkV|%S04^~Up zZ30|9eD(r6PjNk$>l5~gU}L2FW^cH9`0N8VMqKmd`Z%{SC)P11lfbo0+K^$W_2<%v5eGdk!IXABFAz;^6-8Qc8pw6eDUEjmu`l!eH z#=buSO}oXzN}qV=cO-&7H=@P$W(IsIJc{3KI)6u@>#sfDwKjnHlYft+-EnwrnhAD| z)Y52VB%I~uGOd#n}g;reQuLphz|`idjYT(EIsecQllvA*qK*H_&(uJ1gsy4>|W z2Ar;M2V5WZ^7?k7X}5S-=@awNh2T8I^N`#&alP&ad+qdjD!nJnN7oj9$ATkH>bC%0 zTim}Eg4JvvZI1(|ZG8q%(>HvM2S*<1wc`YIZQ*w!IAW!K-$2(Ed7K1RvwgH(1WwzU zhnl|OvltwCq}Rcd(Y1x&5^%&y{Z2vG7I~ZsR;C>|S8{9NStHl{e{O{x7Xa}jMWrsyyCnsP;n-&F9J zk4xajiTSt`u4eJDaz1>Q?e+h1iawW79FzU2MZ7D)X}qi8Y8DSG<1H?(PuC*oa}DK; zLc0O1em%u^^j_D#1?ErwxlsF!6#I94+M@rP!D;`uz||}sR`wr#-HM>kcPPele$J}2A(Hm`IKeIHFdKEwY2YqmFSt3|2RWeaa)oBVc2w$2*l@fQ_xq@ygTj zZim0eHWbI}Ik+vw@orBY=jCIxOUL`$ggZyCl=yoEkA3(nxN*(fSn?R><6yNqN{sUf zuzL7B3AVj+VGOxGVSfs2jC8Jk4Ob7J-++x_KgN*j6ZWSId%9-NpsD*T;yOJG<`27o zcZGmx`y4p(i!uBTO+DH^59UwaR@>rY?Oy;JS9`?!JvefWcrT)jnj7O#Sh9q;a5gR5CQtfJ39Ky2^z$ML@o_WV)zUgA0P2G|(d?9aWR7GwD% zxIC6O(bVHR$3KD9JYPQ{##>+ypT)HOnWE;t6q}!Y{{?J+F_yQ%Y8L+Fhx4WHJB8-j z=@;k7yI{v;@i|!EzoMzzCi;3GY+sJi{Vn(0)Bgjo*A8``3)KDwHjcKK7d7vvF&68H z|97zQJx|5ydAbYnJa)4eGFE+5#N}L zf5Bre+)s|<6EuCbMeI+(_8GDN4OffUpMlkk?cOoY=Wt_bbByvBqu1G10Qk&0i*y;*Bcs<;NzZ>!a>|G#|C_Um2_xe3gPn`&HrksN3HB)%5pSVs)_d5qu4} zb8-puYkq6O^-+)CGOPt=8|3#??eYH5xzHB5tOHgHzHY%IxAoxqsGFN}rxyN$!R8y+ z$RS`g|DLt}&aGPbZwNL<@L^!v$8Uf)0;?@0_sC&mxb3t>KbwHnm*QtXu9;fI9S&BD z7+(YXcfHlaXESi>vpHNp^@yn!{#$?@Pw*|lwvTK0R$zV9-RJUjpHCuJkBJobx%+wV z1n&cOZ|_STd)t4PCEc6bm-sFvzFWZ~$8F)pjd|M+uC^4-F&bYj{C5DW1>dpYF^@aJ z^-+&;j{vLtcjt|1j%pEOSFq#MX1?;U?Oxb|?*X@c?1w$UOKnRXIgA9`PFu7a1-4y` zb2L~#b^CQ*)WUxZ*j$2-1?v-I8VA-#-L;gbYdMviJocl+HEaI_PfqXw1$MosP+a3_ z)Un2U5j$PueM@{wiBB!@=_P(}i62tphZWqhdwrP*H}~Ls!_7agFZ;mtQIG4(Bye0` zw8!se`%p*h1Hchmd&G8Lw8ffD1KXeL>zv5Lb|Bcf*5>@k zM{u?DdU+7obI~^1^l^^Wqy3>^`_tz9$-{OyIAS}O@`!x|*x0twW_#B|J=z}$Rtr7@ zZ2z&pj{@tX?%tEf-gCVUrg%)J#C7Dr0{c1RAc}kJ5Ni9dO(QYXgEtjC-dk4SOR-0Z z_m<7*+VqcnXMyc6&e7TMrEvA-cq8Z>w}4$kKR0Q24fTmNo>SP@LDTnWO1wj91>3Ja zp3mk#7wj0cIVbXTPL9OK<4{V>$zcU{P7Y7>Bf!qj4CSnN)U5?>q@GK0-P)<+^YbF|ifgCqytu^ADDksO+uUP0kN-B9>*aOTwf`JEifhCY@F|pjl#?lO?wnfa zacwyrei}vH815IfI3LdhyN|WGcjRF^8|*#}eh%C{9Ov%2aDCMMZ0xyz9@z8J=XLGI zbq}gXoD0Be!7l{ccU(U%0vlrjMPKd4aqnsqyKgV0M2v5O)q-CJ_MDV^eZCw%i#o1l zSHRVxcwI67E79!R_hrU3j=s^ScCqJ)Ya#X=@%kh7{7|>wfz;Q+J*VTd;dO8|zeD*1 z{~N#_zMs%`J>@$T&wFviUy6_Gek0nqD6acbiv74hZYuP6pM5i2&Enyhgz-KGMtedtNi@NU_%+s9A%{+z?>o&00t~)4^$9K`xBaiQa)hr&7hw;63Xt%9%e+O7C z`1ir?x44J?0B-v+g|GJbp5%w%$mK5V#&F$#gsv@O+zB?u#uVdeHy5v4+M?ZEV6}+< zWAOiqe>b|ec#ggYY+LoXf87gSN`KlS{(ayy{{8U(75^vb+9Lh~VB4xk{0G5HiLWi5 zseTH!Uu~g11Xe$q68lOm=KE*hbpC%1PtW&<;rgh@zIg;3`$l{08}-;HzW_Tn_q=_% zUw?_F9{c1`u$sjq-6xCDw5R*f{TO-w3Vc?=9|wCLE@q#)ubu$wqaJxb368wAoA+bX z>Jj(XVEdN4mwp5GT#sw(Z^8Pg+x{tPwP^n=*z20MXQ<_2`yJT+w0Vz{M?WusXVagy z=fUz3%$hm;9_)3|c(&87-_z9EBL2(Z==&wGJZ!ImoiE$HLM;#5AHdF?w%4fTk=GmG z$m?~md_?j5`$w>!5$(&Ew$;ZtFH&odKK=xD?7{yGHlO&6^cGkj^*C?;0(QN;M{1Aj z?b~2&5$j#>#T5H}hg$Au75Bkk!G4yojW&JWq*jmi?}OE}y+T z{vS}Q>F-+o1MEE~&eIR!OA9?>{u9l1v8O%)tLYmt)x!T@VAnPHCt%kr=I&FlKI$=d z{|3k0X^*-47_2Q~eGX1ze*sU|B;wK@P2UjMO>Tu z!}U>*d}_e1Ma)etTuoo+<|}M!5wjj_zY%i){5Ha>htEK;;|`x?;QFb1y)f5h!Rr3E z2kpmaGPTHSd9Zy)%oX7J#IwbUV6`Y-yWM{)q1je@_^u3g&Z30A3i?v?DDix{S5K#g0Bu&^SNV9Y7d_~)YqV>d5;%IJfCH}?uN}e=3yiW2zL&2_j?4u3g`l&~pVc@IqiM}?1tLf`pXj2RSjlpVuRure76&KQ{M>oaKiXGJR z3*1G0Y=M3LUqErrkE8Z8-j3A%+rQo;gKtsd{#(CcUmd?O3Ag>&5+9#%{r$InqrLun zm-wWF>+iqo8~)}zCE?l+DY$dvZk$NBe!i_NUE#CJ)=b;E3&>lSl0Rz{a+XHru;z)ot(fWir_FC!XmJ zfO~E9v!^!OxL4KV`_-vnf2*Lb-My`5Ovf}0tmbtqaU+QDG;gD4S0En*xB zb{>Ks1~&KLhZlCA3ygOJTp#uDITCChUf1-Q0oG4FaytraU)s#W^H9wgo`(%!&%=m0 z6RuDE=DrcEk2;sK{2mm~<4tJVEgsIRK3?y%#r4kX!V-$d@szmUolsz}7bhn88wozC zz+Kdf5`A%^pA7c;cnWpA1Di$vaXlK2-kxy#n^)q;B;3BPNVxu272J7pU(JS_L)^1k z;7j3A;`#4rbZz=a+c{v{$~&oB;f}%Yw~aj)t`_(6Hn4N+`v&9LULV)facUPkM*9~# zzIexA%nrEo8aZ^ro%6`E3$BlPoGaa6`}JJWZd~U{J>tvh4MJ zwF|-O<{Hmf$HCP-U*fs(c(DDueuKdJgzbdFwhlJ^ZlsR*-+*gBkz!ucmqC50m+ z!{&o=a~fUR;OuzboN0;Xg0&r%L>} zgxmhLgu6fAO}O^ImiT)m{$aw0;r~&>ZU0$`e^KIJCfxf3OVek3{O6Z?xb~Wa8-JY= zU$4XmC*1Z!5^npU3D-U>;o5g8@!d*%kA&NPWWsGfD&gA4BwYI;C4N|mACYj|&q%oK zk4m`qnF-gvu*8oq@e>nn`;!uG`$Y-YesaRKUtZ!@miW~PxBayVxBYbq*M397wclOh z_m=qm3Agdcw88UvS@PFX4jmUG{rF z>f5Lv#va$A@4>ajJLlWMYD@8H%c`Hp?trUDtnY&(R(j3<0lKz`^+T{)8tX@J_4o{P zC)oJvUOT6_gSK=&y)SBa{hj+ifSu#mf3Jhp!u|%>afkhnV70Kn2{vZf{{&WxefejwF>R;K zeeLtXU%=Ylq8Ll$^i{4TY7UF^L({mk+{+;xe#AHZ!JpIQC} z)<@m>w(q}#)y*e9Km7yjeEU9ByM6dh-ag-hYmYwu3APVyA5zO>jy?uE$HD&vc20wT z0(K6aGoL#@1=~hHZPCZ)V8>-2pMm9J`w!TDwS7S?58GGZGm3U!g5~-#?Rj6}*B|b< zwD~+D7yB&oZ*>2=Lj#CY3tvKg8pS;9&$!03o&L7_2uT+Wb zD172w!9cj0#l!Vr33}eQE`zR*abg^U!0w6IN6W(1^ffPSYLVA+;BsEeqp3%pD}dc| z#x(C0;cEIBQ=3}kuoBq)5IL+2S95>q?^>zp?|HZi*gdj{`0`cZYIlOeXEnI{CVW+j6m8T+QN9-d|rs*T*<9j?KX7{@NU_rmuNvQ;WQ|0GIRH5>4Hh?x(H5>HgXpuBM+c zwW&o8Uk9iAYg@RQ|BjRXu9cep?x*d*>HgXtu9ohd9pLHy+7Ygn`s@UEf5l$f8E!0n zwMBlrf@3fF*+L$+-NCV!{G1^V+n(UqOM8Ijj%OsbeTCm>aO|Z~V7Y!{s7F|eYt>lr z62|XdG7tMRuJLTAzwKNfePhkWfy-+)9!=dG+)EP*pV&)#!PP7t<-If!T_5AbIQ9mo zduboIn!e_xO)c`81TN>bFPgeB-Ans{)4jAmTunb?YEz3GCWF(xGzG5azwxENYo(^Y zdub{--AmKpYUw_i4o~lK2g1{Ra}eBi`e}Z+u`8YH-~}cVLK8W`{oF+ z+}vkS+gJECfMeer1(xeKllovv?3+gL62|JjF%SDQuJLTAzwKNLePex^z~%L+psAaK z`=+_@iG4E*u4eHl@0;1^`WPq1(E?8Q&Czf*ea%aoTI4kcT+XW%P2HI8o4Me0-?YKi z^fRV5waB3zobH=r;A-FnwgM2HI<4@Dy>vQU&EiqsOJ|_#W1JYr znc#FUods9Z*Sxf;MP6rv%XyuHrfy94(z)PtFP#Th)6baN)FOxT!RcPQ5UzFsMSs^y zO@H^&Mc{NVT?|k6(j{=UbT3^BcQ3`h`6k>r`f7_@t^mirxg0DH+g0G$H&=q?VY>z# z`{rt}+}y9Fwy*HJ9vu7TI78>la%#J*VyUcy-2H|Ak~#xM3ujo|Y7 zd<#w89NafI6+W?VZicH_Jj(m#7Ib}#6XWUgM zyWn)+d=IXspE0$mMGm)v(|z-OxY`{Q{aq_H{oOY|0H^!rhw$`1^&_}@B(67i!qw92 z&0TQg*j9Vwat}E6&D~&m*zNuYoTwf&(Fc-^?4Xg-5lIEj}$(!Z+-z+vv`#E%`egQ zF;0x*QE<9%9)qjtYhK#aBClV8%XvMHrfy94%@g2s-#iId)6baN)FOwc!0EpE4P5Ql z6#ZQ*HT~T;zXhkyJWs>b((B7J@N_Rd3s3jbb8xkEFZ~W~EZb_2{C*FPz4QWD9=4aj zv6o&1%ft2xIQG)ZV7cRYmD;|-?+@VEORs_D`n^v5JSFzh8{j33-@RlW_Get<*-n4k zxjy>Fn*9-6Ub8pR)Xl-Y^ryln_R^o>Y8H?3UU~~%ALGP0{sK<-(%Wz~ea%aoTIBT( zxSZF!XzIpvFZ~sq?xpwOxkhbFZEBIj2ino1{ommFc%RANEy2~I#5<>dpxO5C6yv^6 ztrl@V1grU7vT;5FJ12g3t?i$bXs0dOeGIl;{3h*RV6}tDDYQ@F>Yq^j{!X5Le|Ir` zc$`h~`#az9pOfHo3p||qyab=0_*{_S3k&S;)h?p=ecvV2@wEAsO{EHIrSJ&4* zAmQe)T*A$D`GjjPx%`W zV;V=_=u><2F%aw?2)+#59OE||gW&q8$L}AO1smTr&>rt>T`z4BYX$u%_UqcoV=OCy z-B;RNM|phLzB1UquV_5mY1hyFp)KOC3Ra8xSPksE^(e76tD|ev-#G3Qwa8@+u=5)4 z?$?AHLp}Oh3v9bM*VYEB=^HWC!hb!m`$L=iP9CYuW6n&4r0a_TQ6qU*_g(-ePYg`)B7^@qLJCi1cq{g5;bkY_hGfmossaxZU zyp_MexHPkI=bvz6{28uXn0U@GnDHf-d(XKa@4U-=AACKqmvWtgP*RkHEw*O%TiKd@ zI9}e6Lin)Wmp{LAw+rHt5Ml-Pe0Zq$gCpIaj9&ways(m732_u0>nv9`RaLueg9=|v zwVpf)M$s#D%%@e%UFAy043z7wvgYutKZ*1t45G97lzcL|YG$e~*W%CWS@FC9N&jD8 z5af79qnE+`=x7-3>r-M2S2Z*B4^GBoJ)KJ?&lBM(Av|mOWMV#TQEMT?HAMO}I+^Mf z)`C)^7klzH*aN}!lwlp1%5Z!j}0*)4aJSIVZNxm}SW8TuJX^rLYZG`ESN$V8Ac{zABhBqzF}`0P zUS%6>(RK|nKUHEb@jCE3_-*ty;BNqX@GV#y#ypMn%fMa4Kb`(AW$_#D#UK5h(qFnW BV!{9b delta 582 zcmYjOO-lk%6unQ!k8;M3EHa(piorn+Q|D6tz|YY z`UCCTM5}&7EeZ-cS4Z-};klDc}3PeNDq)P^veeyZ!cG096w4D~RVMULbE9QLZN=G}bOq5WVJx;CTJ z&_U=jste!@bP2o$F!NjjoaG!~nv)Z>OZ@%QhCGV5&}GCW!3Ag&oB^@`*BRVD2fd2> RTclp&hw?8hI=}g9=noHcMbH2M diff --git a/assets/mirror_reflections_rmiss.spv b/assets/mirror_reflections_rmiss.spv index 89eb4df14300858884c444373b8a0a4d39b0fb44..6fb9fadf0bcb2b9f97ac2a802482994686dbde1c 100644 GIT binary patch delta 301 zcmeAW+#|T5jLDpxL4tvSfeVO}60=i7GILTr^V0HxTn07U0r~_ge-{iea(v19*Z!$^C3V_sPS9<1^q~;Z8mQ+GaVFQ~i zI9ZTcoKa}ACi8zrUIr!x1`nu}Jd+Dqg>ym1D+4hHk_;bIj0Z`KA1Wq*BnGk;q*nw< tOb{w2fg~mb6_eS#kkyruS(HIy@<%rDN$etwVv_~g{TT%|C$g(E0sz2WCm8?$ delta 240 zcmdlZ*de%~j7guBL4tvSfeVOBGILXb6ayOrM2s8APD#xvNd$|rfz|O$KFB1_$UFHa zle8=!P`tP_&oi$iHLp0cq!P#l>SYJ3^M6L$FN_Qf9#Ers zfJ&8t_y>|0FI4Ogk{HMekUECRjjY0xBUpK41)w4vObF8ip<+CnFS5EaGK(-sOjcwU UpKQP`GTDROhmn8tRCaYn0KU5+rvLx| diff --git a/assets/particle_update_comp.spv b/assets/particle_update_comp.spv index e17f379a93da38a222a50124b5773caca7537518..6c226baed1e95923b6de3c124c765fdf10160cb9 100644 GIT binary patch delta 765 zcmY*V%Syvg5S_Gn_-M2-J}Rc-V^!3ph`7>?c2PtST&um+*cdfQp)N%HgmO3jfolma zEVyvtM-)H7m1|u%Cru#^OzxaBbLXCu$BSRj%;%O3QWY8{lcJ6(l<7`b(|m>K=K1|a z+c2n0L?fIh$4znQdZOw#t{9R|TGAWkI&v>XmMh4PZqJ%bg{OfK{*hac&iO`v+n9XQ z=ag~T)91=X%rtMSekAdKIEex#+6bppP!aP5IBJ?j zaktDhl)?dc=mB2feV2UVw}RVBF*Je0y(_NQIWc?9CjuO1 dfuRqv!g!d^fbkIQtn!aJWg=uEh|7yV_8;)hZ7u)+ delta 392 zcmey9Gb4+anMs+QfrXKQn}L@herU|`?^;*!kVR3OE` z#sCrHp1hGwSds@QQk-0rnwl4$nNpGglw}9&;GKMzO`4H!@=rEtS$>e3>`KqPlGME7 z%#uooDQsYM0+S8d#Tf-Rd$KQQW6ar{%6Fd0_6s8eg9p?Wkon3$`~yjh7b^A#NsJFF z#xS{1PGVVWRRjA!#f!Pji6?hGspIY2{{fWjaE<0}H$AOk`Cyv?qX zH<=klCdau|}2!O<_p?r|pAfOH8a{}pH YAfE$B>i~l(8A#^=`MH}Lm3|8Y0J8!Q_$6?|HD+^m1|tRr1}-2@O3Y3T$;?Uh%uCA$av9hdSiy4KKz2!HZYr`E&*YEH z!jil|q2lDC)YQE2%#@N0pbm&>e3NBaq#5}qTe3*Y3V_sPS9<1^q~;Z8mQ+GaVFQ~i zIJuBToKa|VCyP64AOjNvg9p?~9-t~^AZ9@l16c+V<3JMQgNpGWiSa|l1STtT32TZV n$p}JaB#^{}pkgwcJ-MzjGKx-?=h0;}ob1Wt4|LZ|9(5T2JccLM delta 242 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 EKN5XV6#xJL diff --git a/assets/shaders/bindless.glsl b/assets/shaders/bindless.glsl index fa1fe73..b8c26d4 100644 --- a/assets/shaders/bindless.glsl +++ b/assets/shaders/bindless.glsl @@ -1,6 +1,9 @@ #extension GL_EXT_nonuniform_qualifier : enable #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable +#define TILE_PAGE_RADIUS 0 +#define TILE_SIZE 32 + struct Renderable { mat4 transform; @@ -20,6 +23,11 @@ struct Light vec4 color; // w is enabled or not }; +struct TileInfo +{ + int ddgiAtlasTex; +}; + struct PointLightShadowCube { mat4 shadowMatrices[6]; // Front, back, up, down, right, left where "front" is +x @@ -160,7 +168,11 @@ layout(std430, set = 0, binding = 13) readonly buffer SkeletonBuffer { mat4 joints[]; } skeletonBuffer; -layout(set = 0, binding = 14) uniform sampler2D textures[]; +layout(std430, set = 0, binding = 14) readonly buffer TileInfoBuffer { + TileInfo tiles[]; +} tileInfoBuffer; + +layout(set = 0, binding = 15) uniform sampler2D textures[]; SurfaceData getSurfaceDataFromMat(MaterialInfo matInfo, vec2 uv, vec3 inNormal, mat3 inTBN, vec3 inTangent, vec3 inColor) { @@ -262,4 +274,24 @@ vec4 constructBoundingSphere(MeshInfo meshInfo) float radius = distance(meshInfo.minPos.xyz, meshInfo.maxPos.xyz) / 2.0; return vec4(center, radius); +} + +// Returns -1 if there is no tile info for this pos, else an index into the tileinfo buffer +int worldPosToTileInfo(vec3 worldPos, vec3 camPos, out ivec2 idx) +{ + const int w = TILE_PAGE_RADIUS * 2 + 1; + idx = ivec2(int(floor(worldPos.x/TILE_SIZE)), int(floor(worldPos.z/TILE_SIZE))); + ivec2 cameraIdx = ivec2(int(floor(camPos.x/TILE_SIZE)), int(floor(camPos.z/TILE_SIZE))); + + // Are we outside of radius? + if (idx.x - cameraIdx.x > TILE_PAGE_RADIUS || + idx.y - cameraIdx.y > TILE_PAGE_RADIUS) { + return -1; + } + + // Else convert to cam-relative index + ivec2 camRelativeIdx = idx - cameraIdx; + ivec2 fixedIdx = camRelativeIdx + TILE_PAGE_RADIUS; // from 0 instead of -r + + return fixedIdx.y * w + fixedIdx.x; } \ No newline at end of file diff --git a/assets/shaders/deferred_tiled.comp b/assets/shaders/deferred_tiled.comp index 688c6f8..55834b1 100644 --- a/assets/shaders/deferred_tiled.comp +++ b/assets/shaders/deferred_tiled.comp @@ -1,6 +1,7 @@ #version 450 #extension GL_GOOGLE_include_directive : enable +#extension GL_EXT_nonuniform_qualifier : enable layout (local_size_x = 32, local_size_y = 32) in; @@ -258,19 +259,37 @@ void doLight(ivec2 pixel) } } - if (checkUboFlag(UBO_DDGI_FLAG)) { - if (distance(ubo.cameraPos.xyz, fragWorldPos) > NUM_PROBES_PER_PLANE * PROBE_STEP.x / 2.0) { + // Check if we have a DDGI atlas + ivec2 tIdx = ivec2(0, 0); + int tileBufIdx = worldPosToTileInfo(fragWorldPos, ubo.cameraPos.xyz, tIdx); + int atlasIdx = tileInfoBuffer.tiles[tileBufIdx].ddgiAtlasTex; + bool ddgiAtlas = tileBufIdx >= 0 && atlasIdx >= 0; + + if (checkUboFlag(UBO_DDGI_FLAG) || ddgiAtlas) { + if (!ddgiAtlas && distance(ubo.cameraPos.xyz, fragWorldPos) > NUM_PROBES_PER_PLANE * PROBE_STEP.x / 2.0) { ambient += ubo.skyIntensity * vec3(0.3) * albedo * clamp(shadow, 0.3, 1.0); } else { - ambient += calcIndirectDiffuseLight( - normal, - albedo, - metallic, - roughness, - fragWorldPos, - ubo.cameraPos.xyz, - probeTex); + if (ddgiAtlas) { + ambient += calcIndirectDiffuseLight( + normal, + albedo, + metallic, + roughness, + fragWorldPos, + ubo.cameraPos.xyz, + textures[nonuniformEXT(atlasIdx)]); + } + else { + ambient += calcIndirectDiffuseLight( + normal, + albedo, + metallic, + roughness, + fragWorldPos, + ubo.cameraPos.xyz, + probeTex); + } } } else { diff --git a/assets/shaders/irradiance_probe_update.rchit b/assets/shaders/irradiance_probe_update.rchit index fcef662..81f761e 100644 --- a/assets/shaders/irradiance_probe_update.rchit +++ b/assets/shaders/irradiance_probe_update.rchit @@ -65,15 +65,12 @@ void main() 1 // payload (location = 1) ); - //payload.irradiance = shadowPayload.shadow < 0.5 ? vec3(0.0) : vec3(1.0); - // proceed to calculate our radiance MaterialInfo matInfo = materialBuffer.infos[materialIndex]; vec2 uv = v0.uv.xy * barycentrics.x + v1.uv.xy * barycentrics.y + v2.uv.xy * barycentrics.z; vec3 normal = normalize(v0.normal.xyz * barycentrics.x + v1.normal.xyz * barycentrics.y + v2.normal.xyz * barycentrics.z); normal = normalize(vec3(normal.xyz * gl_WorldToObjectEXT)); vec3 color = v0.color.xyz * barycentrics.x + v1.color.xyz * barycentrics.y + v2.color.xyz * barycentrics.z; - //vec3 tangent = v0.tangent.xyz * barycentrics.x + v1.tangent.xyz * barycentrics.y + v2.tangent.xyz * barycentrics.z; color = toLinear(vec4(color, 1.0)).rgb; SurfaceData surfData = getSurfaceDataFromMat(matInfo, uv, normal, mat3(0.0), vec3(0.0), color); diff --git a/assets/shaders/irradiance_probe_update.rgen b/assets/shaders/irradiance_probe_update.rgen index 6ec5ef9..f91b88a 100644 --- a/assets/shaders/irradiance_probe_update.rgen +++ b/assets/shaders/irradiance_probe_update.rgen @@ -51,21 +51,37 @@ void main() ivec2 pixel = ivec2(gl_LaunchIDEXT.xy); int probeX = pixel.x / PROBE_IRR_DIR_PIX_SIZE; - int probeY = int(pc.probeLayer);//pixel.y / (PROBE_IRR_DIR_PIX_SIZE * NUM_PROBES_PER_PLANE); // THIS IS THE HEIGHT, AKA PLANE! - int probeZ = pixel.y / PROBE_IRR_DIR_PIX_SIZE;//(pixel.y - (probeY * PROBE_IRR_DIR_PIX_SIZE * NUM_PROBES_PER_PLANE)) / PROBE_IRR_DIR_PIX_SIZE; + int probeY = int(pc.probeLayer); + int probeZ = pixel.y / PROBE_IRR_DIR_PIX_SIZE; ivec2 pixelWithinProbe = ivec2(pixel.x - probeX * PROBE_IRR_DIR_PIX_SIZE, pixel.y - probeZ * PROBE_IRR_DIR_PIX_SIZE); int rayIndex = pixelWithinProbe.y * PROBE_IRR_DIR_PIX_SIZE + pixelWithinProbe.x; - ivec2 camProbeIdx = - ivec2(int(ubo.cameraPos.x / PROBE_STEP.x), int(ubo.cameraPos.z / PROBE_STEP.z)); + vec3 origin = vec3(0.0); + if (checkUboFlag(UBO_BAKE_MODE_ON_FLAG)) { + // If we're baking, use the tile info to figure out where the current probe is located + const int tSize = ubo.bakeTileInfo.z; + const ivec2 tIdx = ubo.bakeTileInfo.xy; + const vec3 scale = vec3( + float(tSize) / float(NUM_PROBES_PER_PLANE), + 1.0, + float(tSize) / float(NUM_PROBES_PER_PLANE)); - vec3 camOffset = vec3( - float(camProbeIdx.x) * PROBE_STEP.x - PROBE_STEP.x * float(NUM_PROBES_PER_PLANE)/2.0, - 0.0, - float(camProbeIdx.y) * PROBE_STEP.z - PROBE_STEP.z * float(NUM_PROBES_PER_PLANE)/2.0); + const vec3 tileOffset = vec3(float(tIdx.x) * float(tSize), 0.0, float(tIdx.y) * float(tSize)); - vec3 origin = vec3(float(probeX), float(probeY), float(probeZ)) * PROBE_STEP + camOffset; + origin = vec3(float(probeX), float(probeY), float(probeZ)) * scale + tileOffset; + } + else { + ivec2 camProbeIdx = + ivec2(int(ubo.cameraPos.x / PROBE_STEP.x), int(ubo.cameraPos.z / PROBE_STEP.z)); + + vec3 camOffset = vec3( + float(camProbeIdx.x) * PROBE_STEP.x - PROBE_STEP.x * float(NUM_PROBES_PER_PLANE)/2.0, + 0.0, + float(camProbeIdx.y) * PROBE_STEP.z - PROBE_STEP.z * float(NUM_PROBES_PER_PLANE)/2.0); + + origin = vec3(float(probeX), float(probeY), float(probeZ)) * PROBE_STEP + camOffset; + } // Create a directional vector from the "ray index" vec3 worldDir = worldDirFromFibonacciIndex(rayIndex); @@ -89,8 +105,6 @@ void main() tMax, // ray max range 0); // payload (location = 0) - //vec3 packedDir = (worldDir.xyz + 1.0) * 0.5; - //imageStore(dirIm, pixel, vec4(packedDir, 1.0)); imageStore(dirIm, pixel, vec4(worldDir.xyz, 1.0)); imageStore(irradianceIm, pixel, vec4(payload.irradiance.rgb, 1.0)); diff --git a/assets/shaders/pbr_light.glsl b/assets/shaders/pbr_light.glsl index 9bd9f01..f52cf66 100644 --- a/assets/shaders/pbr_light.glsl +++ b/assets/shaders/pbr_light.glsl @@ -177,27 +177,15 @@ vec3 sampleSingleProbe(sampler2D probeTex, ivec3 probeIndex, vec3 normal) ivec2 probePixelEnd = probePixelStart + PROBE_CONV_PIX_SIZE - 1; - /*vec2 probeTexStart = vec2( - (float(probePixelStart.x) + 0.5) / float(probeTexSize.x), - (float(probePixelStart.y) + 0.5) / float(probeTexSize.y));*/ - vec2 probeTexStart = pixelToUv(probePixelStart, probeTexSize); - - /*vec2 probeTexEnd = vec2( - (float(probePixelEnd.x) + 0.5) / float(probeTexSize.x), - (float(probePixelEnd.y) + 0.5) / float(probeTexSize.y));*/ - vec2 probeTexEnd = pixelToUv(probePixelEnd, probeTexSize); // This returns on -1 to 1, so change to 0 to 1 vec2 oct = octEncode(normalize(normal)); oct = (oct + vec2(1.0)) * 0.5; - //oct = clamp(oct, vec2(0.05), vec2(0.95)); vec2 octTexCoord = probeTexStart + (probeTexEnd - probeTexStart) * oct; - //vec4 irr = texture(probeTex, octTexCoord); - //return irr.rgb / irr.w; return texture(probeTex, octTexCoord).rgb; } @@ -254,29 +242,78 @@ vec4 weightProbe(sampler2D probeTex, vec3 worldPos, vec3 probePos, vec3 normal, vec3 sampleProbe(sampler2D probeTex, vec3 worldPos, vec3 normal) { // Find closest probe to worldPos - ivec2 camProbeIdx = - ivec2(int(ubo.cameraPos.x / PROBE_STEP.x), int(ubo.cameraPos.z / PROBE_STEP.z)); + int probeX = 0; + int probeY = 0; + int probeZ = 0; + + vec3 baseProbePos = vec3(0.0); + + vec3 probeStep = PROBE_STEP; + + // Do we have a baked atlas? + ivec2 tIdx = ivec2(0, 0); + int tileBufIdx = worldPosToTileInfo(worldPos, ubo.cameraPos.xyz, tIdx); + int atlasIdx = -1; + if (tileBufIdx >= 0) { + atlasIdx = tileInfoBuffer.tiles[tileBufIdx].ddgiAtlasTex; + } + bool ddgiAtlas = tileBufIdx >= 0 && atlasIdx >= 0; + + if (ddgiAtlas) { + const int tSize = TILE_SIZE; + const vec3 tileOffset = vec3(float(tIdx.x) * float(tSize), 0.0, float(tIdx.y) * float(tSize)); - vec3 camOffset = vec3( - float(camProbeIdx.x) * PROBE_STEP.x - PROBE_STEP.x * float(NUM_PROBES_PER_PLANE) / 2.0, - 0.0, - float(camProbeIdx.y) * PROBE_STEP.z - PROBE_STEP.z * float(NUM_PROBES_PER_PLANE) / 2.0); - //vec3 camOffset = vec3(ubo.cameraGridPos.x - PROBE_STEP.x * float(NUM_PROBES_PER_PLANE) / 2.0, 0.0, ubo.cameraGridPos.z - PROBE_STEP.z * float(NUM_PROBES_PER_PLANE) / 2.0); - //vec3 camOffset = vec3(0.0); - //vec3 camOffset = vec3(floor(ubo.cameraPos.x) - float(NUM_PROBES_PER_PLANE) / 2.0, 0.0, floor(ubo.cameraPos.z) - float(NUM_PROBES_PER_PLANE) / 2.0); + probeStep = vec3( + float(tSize) / float(NUM_PROBES_PER_PLANE), + 1.0, + float(tSize) / float(NUM_PROBES_PER_PLANE)); - int probeX = clamp(int(floor((worldPos.x - camOffset.x) / PROBE_STEP.x)), 0, NUM_PROBES_PER_PLANE - 1); - int probeY = clamp(int(floor(worldPos.y / PROBE_STEP.y)), 0, NUM_PROBE_PLANES - 1); - int probeZ = clamp(int(floor((worldPos.z - camOffset.z) / PROBE_STEP.z)), 0, NUM_PROBES_PER_PLANE - 1); + vec3 posInTile = worldPos - tileOffset; + probeX = clamp(int(floor(posInTile.x / probeStep.x)), 0, NUM_PROBES_PER_PLANE - 1); + probeY = clamp(int(floor(posInTile.y / probeStep.y)), 0, NUM_PROBE_PLANES - 1); + probeZ = clamp(int(floor(posInTile.z / probeStep.z)), 0, NUM_PROBES_PER_PLANE - 1); - //vec3 baseProbePos = vec3(probeX + camOffset.x, probeY * 2.0, probeZ + camOffset.z); - vec3 baseProbePos = vec3(probeX, probeY, probeZ) * PROBE_STEP + camOffset; + baseProbePos = vec3(probeX, probeY, probeZ) * probeStep + tileOffset; + } + else if (checkUboFlag(UBO_BAKE_MODE_ON_FLAG)) { + // If we're baking, use the tile information to find the closest probe + const int tSize = ubo.bakeTileInfo.z; + const ivec2 tIdx = ubo.bakeTileInfo.xy; + const vec3 tileOffset = vec3(float(tIdx.x) * float(tSize), 0.0, float(tIdx.y) * float(tSize)); + + probeStep = vec3( + float(tSize) / float(NUM_PROBES_PER_PLANE), + 1.0, + float(tSize) / float(NUM_PROBES_PER_PLANE)); + + vec3 posInTile = worldPos - tileOffset; + probeX = clamp(int(floor(posInTile.x / probeStep.x)), 0, NUM_PROBES_PER_PLANE - 1); + probeY = clamp(int(floor(posInTile.y / probeStep.y)), 0, NUM_PROBE_PLANES - 1); + probeZ = clamp(int(floor(posInTile.z / probeStep.z)), 0, NUM_PROBES_PER_PLANE - 1); + + baseProbePos = vec3(probeX, probeY, probeZ) * probeStep + tileOffset; + } + else { + ivec2 camProbeIdx = + ivec2(int(ubo.cameraPos.x / PROBE_STEP.x), int(ubo.cameraPos.z / PROBE_STEP.z)); + + vec3 camOffset = vec3( + float(camProbeIdx.x) * PROBE_STEP.x - PROBE_STEP.x * float(NUM_PROBES_PER_PLANE) / 2.0, + 0.0, + float(camProbeIdx.y) * PROBE_STEP.z - PROBE_STEP.z * float(NUM_PROBES_PER_PLANE) / 2.0); + + probeX = clamp(int(floor((worldPos.x - camOffset.x) / PROBE_STEP.x)), 0, NUM_PROBES_PER_PLANE - 1); + probeY = clamp(int(floor(worldPos.y / PROBE_STEP.y)), 0, NUM_PROBE_PLANES - 1); + probeZ = clamp(int(floor((worldPos.z - camOffset.z) / PROBE_STEP.z)), 0, NUM_PROBES_PER_PLANE - 1); + + baseProbePos = vec3(probeX, probeY, probeZ) * PROBE_STEP + camOffset; + } float sumWeight = 0.0; vec3 sumIrradiance = vec3(0.0); // alpha is how far from the floor(currentVertex) position. on [0, 1] for each axis. - vec3 alpha = clamp((worldPos - baseProbePos) / PROBE_STEP, vec3(0.0), vec3(1.0)); + vec3 alpha = clamp((worldPos - baseProbePos) / probeStep, vec3(0.0), vec3(1.0)); vec3 probePos = baseProbePos; @@ -284,37 +321,37 @@ vec3 sampleProbe(sampler2D probeTex, vec3 worldPos, vec3 normal) sumIrradiance += res.w * res.rgb; sumWeight += res.w; - probePos = baseProbePos + vec3(1.0, 1.0, 1.0) * PROBE_STEP; + probePos = baseProbePos + vec3(1.0, 1.0, 1.0) * probeStep; res = weightProbe(probeTex, worldPos, probePos, normal, ivec3(probeX + 1, probeY + 1, probeZ + 1), alpha, ivec3(1, 1, 1)); sumIrradiance += res.w * res.rgb; sumWeight += res.w; - probePos = baseProbePos + vec3(1.0, 1.0, 0.0) * PROBE_STEP; + probePos = baseProbePos + vec3(1.0, 1.0, 0.0) * probeStep; res = weightProbe(probeTex, worldPos, probePos, normal, ivec3(probeX + 1, probeY + 1, probeZ), alpha, ivec3(1, 1, 0)); sumIrradiance += res.w * res.rgb; sumWeight += res.w; - probePos = baseProbePos + vec3(1.0, 0.0, 0.0) * PROBE_STEP; + probePos = baseProbePos + vec3(1.0, 0.0, 0.0) * probeStep; res = weightProbe(probeTex, worldPos, probePos, normal, ivec3(probeX + 1, probeY, probeZ), alpha, ivec3(1, 0, 0)); sumIrradiance += res.w * res.rgb; sumWeight += res.w; - probePos = baseProbePos + vec3(0.0, 1.0, 1.0) * PROBE_STEP; + probePos = baseProbePos + vec3(0.0, 1.0, 1.0) * probeStep; res = weightProbe(probeTex, worldPos, probePos, normal, ivec3(probeX, probeY + 1, probeZ + 1), alpha, ivec3(0, 1, 1)); sumIrradiance += res.w * res.rgb; sumWeight += res.w; - probePos = baseProbePos + vec3(0.0, 1.0, 0.0) * PROBE_STEP; + probePos = baseProbePos + vec3(0.0, 1.0, 0.0) * probeStep; res = weightProbe(probeTex, worldPos, probePos, normal, ivec3(probeX, probeY + 1, probeZ), alpha, ivec3(0, 1, 0)); sumIrradiance += res.w * res.rgb; sumWeight += res.w; - probePos = baseProbePos + vec3(0.0, 0.0, 1.0) * PROBE_STEP; + probePos = baseProbePos + vec3(0.0, 0.0, 1.0) * probeStep; res = weightProbe(probeTex, worldPos, probePos, normal, ivec3(probeX, probeY, probeZ + 1), alpha, ivec3(0, 0, 1)); sumIrradiance += res.w * res.rgb; sumWeight += res.w; - probePos = baseProbePos + vec3(1.0, 0.0, 1.0) * PROBE_STEP; + probePos = baseProbePos + vec3(1.0, 0.0, 1.0) * probeStep; res = weightProbe(probeTex, worldPos, probePos, normal, ivec3(probeX + 1, probeY, probeZ + 1), alpha, ivec3(1, 0, 1)); sumIrradiance += res.w * res.rgb; sumWeight += res.w; diff --git a/assets/shaders/probe_conv.comp b/assets/shaders/probe_conv.comp index ab37d8d..140b11d 100644 --- a/assets/shaders/probe_conv.comp +++ b/assets/shaders/probe_conv.comp @@ -21,7 +21,7 @@ layout(push_constant) uniform constants { void main() { const int xs = NUM_PROBES_PER_PLANE * PROBE_CONV_PIX_SIZE; - const int ys = NUM_PROBES_PER_PLANE * PROBE_CONV_PIX_SIZE;//* NUM_PROBE_PLANES; + const int ys = NUM_PROBES_PER_PLANE * PROBE_CONV_PIX_SIZE;; if (gl_GlobalInvocationID.x > xs || gl_GlobalInvocationID.y > ys) { return; @@ -36,11 +36,10 @@ void main() ivec2 probeStartPixel = (pixelPreLayer / PROBE_CONV_PIX_SIZE) * PROBE_IRR_DIR_PIX_SIZE; // in input image pixels ivec2 pixelWithinProbe = pixel - probeIdx * PROBE_CONV_PIX_SIZE; - // 16x16 kernel + // 8x8 kernel int kernelSize = PROBE_IRR_DIR_PIX_SIZE; ivec2 pixOffset = 2 * probeIdx + 1; - //vec2 octUv = vec2(float(pixelWithinProbe.x) + 0.5, float(pixelWithinProbe.y) + 0.5) / float(PROBE_CONV_PIX_SIZE); vec2 octUv = pixelToUv(pixelWithinProbe, ivec2(PROBE_CONV_PIX_SIZE)); octUv = octUv * 2.0 - 1.0; @@ -54,8 +53,6 @@ void main() vec3 irradiance = imageLoad(irrIm, currPix).rgb; vec3 dir = imageLoad(dirIm, currPix).rgb; - /*vec3 packedDir = imageLoad(dirIm, currPix).rgb; - vec3 dir = (packedDir * 2.0) - 1.0;*/ float weight = max(0.0, dot(dir, octDir)); if (weight > 1e-6) { result += vec4(weight * irradiance, weight); @@ -65,14 +62,29 @@ void main() // Add old value vec4 oldVal = imageLoad(outputIm, pixOffset + pixel); + vec4 outRes = vec4(0.0); - if (result.w > 1e-6) { - result.rgb /= result.w; + if (checkUboFlag(UBO_BAKE_MODE_ON_FLAG)) { + vec3 preWeightOldVal = oldVal.rgb * oldVal.w; + + float totalWeight = oldVal.w + result.w; + + vec3 totalResult = result.rgb + preWeightOldVal; + + if (totalWeight > 1e-6) { + totalResult /= totalWeight; + } + + outRes = vec4(totalResult, totalWeight); } + else { + if (result.w > 1e-6) { + result.rgb /= result.w; + } - float hysteresis = 0.96; - vec4 outRes = result * (1.0 - hysteresis) + oldVal * hysteresis; - //vec4 outRes = result; + float hysteresis = 0.96; + outRes = result * (1.0 - hysteresis) + oldVal * hysteresis; + } imageStore(outputIm, pixOffset + pixel, outRes); } \ No newline at end of file diff --git a/assets/shaders/scene_ubo.glsl b/assets/shaders/scene_ubo.glsl index 5886354..bec2703 100644 --- a/assets/shaders/scene_ubo.glsl +++ b/assets/shaders/scene_ubo.glsl @@ -9,6 +9,7 @@ #define UBO_BS_VIS_FLAG 1 << 8 #define UBO_HACK_FLAG 1 << 9 #define UBO_RT_ON_FLAG 1 << 10 +#define UBO_BAKE_MODE_ON_FLAG 1 << 11 layout(set = 0, binding = 0) uniform UniformBufferObject { mat4 view; @@ -21,6 +22,7 @@ layout(set = 0, binding = 0) uniform UniformBufferObject { vec4 cameraPos; ivec4 cameraGridPos; vec4 lightDir; + ivec4 bakeTileInfo; // x, y: tile idx, z: tile size float time; float delta; uint screenWidth; diff --git a/assets/shadow_rchit.spv b/assets/shadow_rchit.spv index 642415bb345f92c2fbd420873b52b7299d1ab967..3aee58c1a4f44535700e35896f2a891f22b3baa4 100644 GIT binary patch delta 416 zcmYk0%}T>?5X84_KKx1*D(FQ~dk}mB=}Dnj5wvRJUFbg&C<;vqy@*#qJd{33=@a+} z-h2`7&aWik!en=5XEXnwx;q+0b1+ zr!N{Uu+Y$`!Qd%7D~6AG>?Uwu+rE0`KOd*58*$?=bv%Xsm6u*p;QYJt`tl~|Zc>a# zZn3lS6`b}YR-tVzsSES$Mm-Qbp{Fn5)ULoye>Pujby4dA7epQjRK*W9H%m_R|2>@j z=Hj=Rd)dAjk|mGEdg(=PNCt2C$rDi)gRQ$ BHKqUn delta 116 zcmeCsx}na?%%sfDz{1GD&A`hLIFYxOQFvmvD`UXMtJds{0h?PnPP56nGq5lOFfcGE u0Wk=`_=-R_-{yz>#Vo3_49pCEK&}7~D*%=I18EQdiCIJW0h9NNcmn`(V-Xer diff --git a/assets/shadow_rgen.spv b/assets/shadow_rgen.spv index 074b81ab898727490bcb4974252c16b81976fded..5e4e7ae3b6ecc537b51c12e93bfaa597ded86244 100644 GIT binary patch literal 10272 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 diff --git a/assets/ssao_blur_comp.spv b/assets/ssao_blur_comp.spv index 182befd0df5e317410601e99988503c43b403b5d..9fb65e55aa822c3625075cbdbc814b057837ce24 100644 GIT binary patch delta 312 zcmdm?{6=|07LzhNgC+w50~Zh{C1$6FWagxL=B4EWxeRO!tYA6r$%Rb9x;#LUl+>J( zM6e7SScVtKE>12=P0b6>Oex6#>VTNWH+dtIG$a4yvp`Z{@=GRZNkO2>)QW=q;?km2 zAQNu3&}LcY!%Tq;ObiSjQ0qVzDFZPJk{HM$kQfJ&7#~!O2T6<{Dkd=5kWE-q1W5+u z0FVh1NMb@zF`3PgY&#j5MHw_FD{=@=HsD}^VgW{t$+jH+jJ%V3IrJI%Ht*&5%>e+_ C{VO8? delta 266 zcmaE(yhC|I7Lzn9gC+w50~ZjNWag#e3N;Zr5X7rYcfmA3V_sPS9<1^q~;Z8mQ+GaVFQ~i zI60A7oKa|VCG%vK$sQa$kvu?IWguo@VqoxqS`V@WB*uXx#s?MSK@#JKiU}Zzfh-5< x6`5SfAuK9^BqIcsk=fkJk;%j;I{7`9E~C+8N$%^6ypun2>of9gR^-_&0RSa0D*ONd delta 248 zcmbQ>b;onVF(!Rh1``Gb1}-2j$;?d!QVeVi5HW5bJ0&%zBoQpe23E&2S&&(rk$18t zv$QN9P`tP_&oi$iHLp0cq!P#l>SYJ3OsMsGQF}}%)9KweDP#G2`gb4yrF%Bd#L8utd=B*r=OpGFv<+*hy2XJ3u RqtD2@Ih1F&1OOg8BM<-p diff --git a/assets/ssgi_rchit.spv b/assets/ssgi_rchit.spv index db41d3897c24653d6ac88f1e06f606721eca0863..a42f23582ae673b28770fcedfd6099f14138d491 100644 GIT binary patch delta 893 zcmY*WJ8#oq6uoY2$7$oZIEnfQ38a-+C^M?M6eL75LeqCk$>R&PQi7DYQae=XUNJ=e z1q}QEYUg>tIb6G%d<{L^~WQV=ku}30GhE}nV74^u?9RmgRjp0v%Z>UEGS)? zVL9jM!HJvQ%Ys^l=u;vaaPm}Knw*v3auY6_;G79Jo8Wj1<`#mHn=j5MJnqEvF#PI1 zGFI6vUY-ejuQA(O3}C|6AshI{%g#sGkj+3V!1fj!euGB>lwn zJK^s++tiA|-|{mp6E0M`sbNJ@(Nq@vW!RjCQ<7&-;>W02hvw?aV$ z?m+XAV=OUe;Cl+pUVFgnBEx%P9|RpMI0lOz09T>82sIP)(1+j!5*Ipx&3_R4-vM6% sub^5H`WTp}T!fS$^ivpb^3S~oxOHmloV)@1X8}>roSe8BHkO9Y9YvpJiU0rr delta 552 zcmYjNF;Bu!5Wdm^tx!rW1QZEs6B8q|i<;o13=XJ>sJLJa#7H94L>WB23E?pVLvz^p&W$W95R`EzIOS79n$t`2y;gH%RLtIYFv0b8})j zXL#$mhFs2)OeJ`hkn`~G0y$V)^Euziu>!6F_rVJjybR8I9$&~0JP;dp>aM~rqOL zd!?=(zkTBT6p``A^C0)gl?KjNkWbss^={D9Tm9}!K*@^}_X;?N!3&+`iU1wm3)`_S zAL~5x+Nvtwyt9_-v)~8A{#HNK{Xq~OPG_fYmCQG5NzIuF)aA&rKe$ID^#6a_6>^MD z=UK2G_S%D8eL(DBu~XDk|6thd>iy}u50HIKBBoA^x~)?)0)saY@2KO~F0;|cn0AQ`-Ycm>IoiRnArCuV;(`cm^%&6K@eza1%?HpYfE8g=4Ch9nIKkiMQTM#efl`~ZSndI&zn46H} z+%MEUB(=X$8RV!X=2na~VER8tem&W~b3Y~iuq)C^@dZG$*=*f{oL}=Ll0(#8M4#*L GXZ`^$czbjJ delta 454 zcmX@(|H6ltnMs+QfrXKQn}L_%#YEm(M#+iYv5b#5zRhIPXJt@gU|`?^;*!kVR3OE` z#sCrH2C`F9b4n7yVr*b_Jd+nPi!<_0-pMR2%Lf!MF3t1ID@n~O&Mc_}a)El;!Rq)Y ze`J#6;OOR?IJtYiQj&U-_MY!|&)@rQzg!uinSw@&pa>asF*1fCH+sHP&jnF^{QDN( z)2PV)91&eMuI*~4Ygc-$Tb2|i)w_$Z?{seLAd9kS+FhsN#f7~%LyonSn3rE##)>f? z411NHWA_Ff=V6jN=@pkk&xi$S=_z5l8+t{3ROy6=_}^Uf7!sS!c4y1!HU?Gu9$Mwm zYJvFeVXI~LCj*1S9A0F=Ct|TIG!~o2s-#ezd8^-OAIMiDCt~i0QBb6AMvt*wfj?!2 zsO-Oj;WItJ=6x0oFl>(8c!0%ywkX%lL^2(?G5wpYyJP;SB{aiJz)%FX%afim3$w5A zSLXk8%e1Fes>!EBVhxmQdl}eyg?$(*Krge8k)i8uDgCL0l2nw!%E-8-$gC9=v+k-@ r2<Ubt!WEW@To&1trT9yweUR;{znOBmUSDaZ=3FHFxvV+y} zPgdlRW)zrg%OTDvxH*)=la-l;A!@QHpE@JoW?MdGmcTDSTRosQ@c?xy1Mv?eF~5U2MdqeW4T+X{_NiJ{ddjxGm=n87c9u`8>dqx>QOO3DM@k~chw8U8jP?IH zn0YNp>$PCku+sVv{Vaq&yP delta 117 zcmbQ^^~Rl-nMs+QfrXKQn}L_%<3!$EM%jtgxr`q+zHR1Y{IK~cS2l;NI|B>D2L=WP wB_IX?7+(>{=G**Gn4eu$mVue!9guqzh!ud!-ven70Et;c`5!h%N+0F~03D$i(f|Me diff --git a/assets/standard_shadow_vert.spv b/assets/standard_shadow_vert.spv index cef40a282278ee6d80aaa3439dd07c9247aeb76b..8c618f728647aee7fcdfbc6bc6929df6f2b30970 100644 GIT binary patch delta 696 zcmY*V%Syvg5S=uSs%>mE78+Z{>Z%LDtw@my;sabMxay+XTP>C)QnJinOP(27XN)^V=j7OJw*(*mW{>+l<3YQ4V(S0XaRP^^RuAeWuTgP#LNmlj4i<7-aFS@PV|0oMSw#uaNqCewugQIZ+LLP delta 346 zcmbQ@yTOZ>nMs+QfrXKQn}L_%=0x69M#+iAv5Yr1Ue#n}XJwecz`(#YS&>axmmA1R zNzExq1k!9k2$JCe;^O3@)YQE2%#@N0peQ?7oOf~}n=~We!AOa8Lr$#AF|Wg2I3mSlrPQu3pPy$~|QSl<FqD_0?wCRrVZ!6$>QT$q5`motYpa>x1?S1TiN3zbzm8j($3KU4yX z1+bKlB?4I5$MgWE``EU6HnO>VfH8b#*L^eIV|5JMD8?|@1=CoYN+RTIbei()SXU~Ds=T$)OKKU?oKwKdoDygYm&sMqXwnWp)M@Mh0#MUWSy3ys3<86N@J@CU53soXX73%Aml&z`!;6Ad9dr zH;|Q*np2Vpq}hNFB*O#5#mPmfsd?diL8u7N=33#~9J1~VEDXs&4N5>^5PJ(M6fzGusYt!jV$7fe3NIgNXzmA#fwYxJo8FY^NKS|Dj|9yb_q4r#ASJb zBE`u?si}D$shQ~+B|t7v7du!5-{gxd(v19*-?B(c3IN4ZD+=<9ON&rU7Tm1Jn$BeU z1!%Dc)G{8RQe`0ifg}d91|;?eNsMoDBfGF6KU9W=31I@rGLUKxBr!p#7|&)=jgBC|B3z~r~g(vpHeiPVaM z{NmCg6qAKEE3&w=@G>wlFnB;6z%zLxhj1=0P=hiMb0EopECY%0Ac^rq#RQPV1fXIf zNMaxdfb>cri3vf)WHvwKaAjo{WpJKs$R|G8flq|dX>uT+KO^ttg?#ahe482h*+l@3 C9V<5g delta 246 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 delta 10189 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 diff --git a/assets/surfel_update_rgen.spv b/assets/surfel_update_rgen.spv index d59c40e3cc69616cf143c73c34bd96b01b3afdec..938a6b7945514108e340d1338aa2e01152ab8dc7 100644 GIT binary patch delta 744 zcmY*Xxk>|36ur;POT=W7m?$Vw<3ccv*a>2#B1SAE5U`YJUNo4fBqO8~3-<-Ws|2mA zEG%RSYfB5k53sPYw6It3p2SuO~MOAH%gpRP-MvdR7g;#LcYSl{4TtHWKi#M_tqo2Yg7Ba5q zklv5QEAThMce^JOcD0a4i?~|UqeWe<%cJ2GFt5j>#ayk=euyo#Phx?VbCe?H$)F={ z@iR8~&hWG4w8!C+j&-&>J_nUArvtu+86z+Oe26g&fWyBx4~~4q?oZqpzHUnEr({CE zCJp_T42eV)6;f1pjd9P2z`!-RkX2Zh zn}LBLB{ioc5lFKEAxMS?$SzJUN=?lR&rB)F0E)7M#d#-hWR+&*n|u~X@=t!rDlI7h zRGC^)kY8L{lnP`5RYJ@b+$_uH%muXXs=#-~)Gt6YJ)klmvz3AP2a*^sRO}Cu7#~!O zfeE3PA1cOzBnEN;$UKh8hQh*(Jewnh{W)aa8CV!PfQpoW5+DHMD+1Ykn=NJLvM`G< zXiR>nAU^qng2-kLMGi(rp2>nr@r=Bi3zZhLs>(7jGqeE>Xa%}R0ccn|kPQMLF>5Hl KV{@&>V^sjm>o~yx diff --git a/assets/surfel_update_rmiss.spv b/assets/surfel_update_rmiss.spv index fa2fd7b50d56504e9b82610ad538385e8289ee3b..17c9555155c19b35859691144819401a983e2b5d 100644 GIT binary patch delta 310 zcmaDLG(~trACosbgCYY10~Zh{C1$6FWagxL=B4EWxeRO!tYA5AAiE?pHx*fo2gpfD z%_&I)t78MJC{mnUl$x67k(!yFQ3BBgv4wx~MPDvt=W&=Wy3=a?&Cl{rr=7ndblw<%! z*}>wxlRq*^GxAO5WtL{-pRCC&Ehzw0nOaehUtC(03SfQ5-B1XmiE`R&^d#qEIwc|FN?PmSh&=@kZ28>aw9k}aWquSna&hax^olEF9 zPV052MNB5(XguxJ?rAv*pS>e(Mp{nyoOAEA<&2^g${H2_M{a7a(mVRhb>6eW)-do% z>-bH~{FG@evN9;-HqV~3IHV6O9kN|*(&MArf88vnD!v>gujW(-{fP7p_u$Zb z>MEVE2=Gzaud7GS{{;%)XiRIK`_>8dAXY?+n?Dl@kahfmPns+F!T(x&T zumh1__zf^6sf6jte6lzP~+$y7_Nz9yIu&h1kfCv%XjFHjggo^*pvhGAQD@xjt67iMNE?Rpiq5VqUFIGx`Po^I+|LKDN%2}Tpch7(LT-w9wY0l9936A8w}!X^`p zK8BSNj2?#F6x-DAnsUhu+G|<%jBEz&hHvYSEe5NX?u|~iGp#rpeo_m!WYg&QaM~IF zw&L&WNusdFJ)ahb5w{?lenY#6tpP)ePkS?_jqAaCatWG#*)I4?cG`br=LRNI{)T;b kZAntnARWT-d41TteC}#RK3gp4?#p_v%3rzsVt>s418S{~&;S4c delta 1137 zcmZ9LJ#W)c6o#)GI|(FqsDcP7Dk2V2Xqps(#DEY|K}gL6?Ep+jnDnM~m5<7CfQe4* zM0bFJg^d+ufsH?a1QR3T2Ou#pFfj1G{=)bsH$LY%?>Q&FK7QSQ|Io}WH48%5L`j(9 z;@p&4Z9d&G)-)kH?>>DiX=|!sR#)5b?~dKU#2ek54F=M?^XNeKeUTT2XsaEwdYuY< z#i2Jjz$J_TEWviikMFtiNy2g=+om*+Pg}h)Yg$`l#Y#J*mPLy!yH?cRdgY1Z9^Z0m@Jms7Y zJCJ6Td}xUh)#$UsN9?!*SvF4xOY+p0r~_$MNmZgm2iokg2|MmUmd(qj^VE%cIE(yYyI7(Fij3c;ml*oRi7)OchcZzY0$o`}lpDY>QiTHjh z5z|u)&-Hd7ET$kQiOFTKEgU{?2WBuj9oRN(E{+oYM(76q#^U+PQQ`6`(pm^{IL<+K zfi@P|waDjGa-9_?(Lz15SJVqzSFh}{dTXD*x{ffrvO81gvm4nue7==k_&n4O-kTP# M8}PdeqxsVM3mau}xc~qF diff --git a/assets/tonemap_comp.spv b/assets/tonemap_comp.spv index cb26071b14de99f0cdf66e9f1ac9faa2fbd82d7c..9d40987542fa3e825f67c7d5ce10f3966e14b046 100644 GIT binary patch delta 887 zcmY*XJx|+E6umEgwi6QP3n(;h5G`du1$FGurE~$NwgRbBhm^cf3z|x?k;oL5vLml7 z{DUGdT|0KFI(6=kU_|OUjvd@9UEh1o{eJTIw^#d~Ra$dJE2)Yn?Mu(7&Sm()c9clv z=J##sg)0{#G6((GJ2nTwiP;+tz5t3Nb{ea~kAlyp$kpP%*8D>cRCqWtX81nnN1sqJ z?N*OH?W;z-q5W=?ImhF@VPuA35RIo@oV0T*?&&4fPR9C|Gbv%E|Hr#Rj?(WR1>4a{ zFFY`3#5P9Zrdj^$)4{-urYn=DL^vgcWiHPp=4pAZjYx&OIg3t5CfTpvsdrKm+0E{* zp?D3d3mh*dS1xe%jH?y6M#eScYj1vIp%7_hk>vu{&bUX(PjAPaaDn`C4x{Xd77N=t z@HKQ7-~7_$6x%a=Ut^^lCZ+X!g(vVS>__| _sceneFut; render::scene::ScenePager _scenePager; + + // Test bake + bool _baking = false; }; \ No newline at end of file diff --git a/src/anerend/render/GpuBuffers.h b/src/anerend/render/GpuBuffers.h index 2d6c845..42c529c 100644 --- a/src/anerend/render/GpuBuffers.h +++ b/src/anerend/render/GpuBuffers.h @@ -67,6 +67,10 @@ struct GPULight { glm::vec4 _color; // w is enabled or not }; +struct GPUTileInfo { + int _ddgiAtlasTex; +}; + struct GPUPointLightShadowCube { glm::mat4 _shadowMatrices[6]; @@ -102,7 +106,8 @@ enum SceneUboFlags : std::uint32_t UBO_SS_PROBES_FLAG = 1 << 7, UBO_BS_VIS_FLAG = 1 << 8, UBO_HACK_FLAG = 1 << 9, - UBO_RT_ON_FLAG = 1 << 10 + UBO_RT_ON_FLAG = 1 << 10, + UBO_BAKE_MODE_ON_FLAG = 1 << 11 }; // This is used as a UBO and has follows std140 rules (use 4-byte things basically...) @@ -117,6 +122,7 @@ struct GPUSceneData { glm::vec4 cameraPos; glm::ivec4 cameraGridPos; glm::vec4 lightDir; + glm::ivec4 bakeTileInfo; // x, y: tile idx, z: tile size float time; float delta; uint32_t screenWidth; diff --git a/src/anerend/render/ImageHelpers.h b/src/anerend/render/ImageHelpers.h index 5770fef..d521e38 100644 --- a/src/anerend/render/ImageHelpers.h +++ b/src/anerend/render/ImageHelpers.h @@ -362,6 +362,12 @@ static void transitionImageLayout( barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; sourceStage = VK_PIPELINE_STAGE_HOST_BIT; destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; + } + else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + barrier.srcAccessMask = VK_ACCESS_HOST_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + sourceStage = VK_PIPELINE_STAGE_HOST_BIT; + destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; } else { printf("unsupported layout transition!\n"); diff --git a/src/anerend/render/RenderContext.h b/src/anerend/render/RenderContext.h index acdd7b8..1674b5e 100644 --- a/src/anerend/render/RenderContext.h +++ b/src/anerend/render/RenderContext.h @@ -10,6 +10,7 @@ #include "asset/Texture.h" #include "asset/Animator.h" #include "asset/Light.h" +#include "asset/TileInfo.h" #include "animation/Animation.h" #include "animation/Skeleton.h" #include "internal/InternalMesh.h" @@ -50,7 +51,10 @@ struct AssetUpdate !_removedRenderables.empty() || !_addedLights.empty() || !_updatedLights.empty() || - !_removedLights.empty(); + !_removedLights.empty() || + !_addedTileInfos.empty() || + !_updatedTileInfos.empty() || + !_removedTileInfos.empty(); } std::vector _addedModels; @@ -80,6 +84,10 @@ struct AssetUpdate std::vector _addedLights; std::vector _updatedLights; std::vector _removedLights; + + std::vector _addedTileInfos; + std::vector _updatedTileInfos; + std::vector _removedTileInfos; }; class RenderContext @@ -87,6 +95,8 @@ class RenderContext public: virtual ~RenderContext() {} + virtual bool isBaking() = 0; + virtual VkDevice& device() = 0; virtual VkDescriptorPool& descriptorPool() = 0; virtual VmaAllocator vmaAllocator() = 0; diff --git a/src/anerend/render/VulkanRenderer.cpp b/src/anerend/render/VulkanRenderer.cpp index 3d52bc1..ae4213c 100644 --- a/src/anerend/render/VulkanRenderer.cpp +++ b/src/anerend/render/VulkanRenderer.cpp @@ -6,6 +6,7 @@ #include "GpuBuffers.h" #include "RenderResource.h" #include "VulkanExtensions.h" +#include "scene/Tile.h" #include "passes/CullRenderPass.h" #include "passes/GeometryRenderPass.h" #include "passes/PresentationRenderPass.h" @@ -254,6 +255,7 @@ VulkanRenderer::~VulkanRenderer() vmaDestroyBuffer(_vmaAllocator, _gpuStagingBuffer[i]._buffer, _gpuStagingBuffer[i]._allocation); vmaDestroyBuffer(_vmaAllocator, _gpuSceneDataBuffer[i]._buffer, _gpuSceneDataBuffer[i]._allocation); vmaDestroyBuffer(_vmaAllocator, _gpuLightBuffer[i]._buffer, _gpuLightBuffer[i]._allocation); + vmaDestroyBuffer(_vmaAllocator, _gpuTileBuffer[i]._buffer, _gpuTileBuffer[i]._allocation); vmaDestroyBuffer(_vmaAllocator, _gpuPointLightShadowBuffer[i]._buffer, _gpuPointLightShadowBuffer[i]._allocation); vmaDestroyBuffer(_vmaAllocator, _gpuViewClusterBuffer[i]._buffer, _gpuViewClusterBuffer[i]._allocation); vmaDestroyBuffer(_vmaAllocator, _gpuSkeletonBuffer[i]._buffer, _gpuSkeletonBuffer[i]._allocation); @@ -284,6 +286,8 @@ bool VulkanRenderer::init() _lightsChanged.resize(MAX_FRAMES_IN_FLIGHT); _modelsChanged.resize(MAX_FRAMES_IN_FLIGHT); _materialsChanged.resize(MAX_FRAMES_IN_FLIGHT); + _texturesChanged.resize(MAX_FRAMES_IN_FLIGHT); + _tileInfosChanged.resize(MAX_FRAMES_IN_FLIGHT); uint32_t extensionCount = 0; vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); @@ -408,6 +412,12 @@ bool VulkanRenderer::init() for (auto& val : _materialsChanged) { val = false; } + for (auto& val : _texturesChanged) { + val = false; + } + for (auto& val : _tileInfosChanged) { + val = true; + } std::vector vert; std::vector inds; @@ -522,6 +532,38 @@ void VulkanRenderer::assetUpdate(AssetUpdate&& update) bool textureIdMapUpdate = !update._removedTextures.empty(); bool forceModelChange = false; + // Start with tile infos + bool tileInfosChanged = false; + + // Added tile infos + for (auto& ti : update._addedTileInfos) { + _currentTileInfos.emplace_back(std::move(ti)); + + tileInfosChanged = true; + } + + // Updated tile infos + for (auto& ti : update._updatedTileInfos) { + for (auto& oldTi : _currentTileInfos) { + if (oldTi._index == ti._index) { + oldTi = ti; + tileInfosChanged = true; + break; + } + } + } + + // Removed tile infos + for (auto& removedIdx : update._removedTileInfos) { + for (auto it = _currentTileInfos.begin(); it != _currentTileInfos.end(); ++it) { + if (it->_index == removedIdx) { + _currentTileInfos.erase(it); + tileInfosChanged = true; + break; + } + } + } + // Removed models (forces id map to update, could be expensive) for (auto& removedModel : update._removedModels) { // Find internal model and use memory interface to "free" memory @@ -1075,6 +1117,7 @@ void VulkanRenderer::assetUpdate(AssetUpdate&& update) bool renderableChange = !update._addedRenderables.empty() || !update._removedRenderables.empty() || !update._updatedRenderables.empty(); bool materialChange = !update._addedMaterials.empty() || !update._removedMaterials.empty() || !update._updatedMaterials.empty(); bool lightChange = !update._addedLights.empty() || !update._updatedLights.empty() || !update._removedLights.empty(); + bool texChange = textureIdMapUpdate; if (modelChange) { for (std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { @@ -1100,6 +1143,18 @@ void VulkanRenderer::assetUpdate(AssetUpdate&& update) } } + if (texChange) { + for (std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { + _texturesChanged[i] = true; + } + } + + if (tileInfosChanged) { + for (std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { + _tileInfosChanged[i] = true; + } + } + printAssetUpdateInfo( modelBytes, materialBytes, @@ -1307,6 +1362,9 @@ void VulkanRenderer::uploadPendingTextures(VkCommandBuffer cmdBuffer) if (tex._format == asset::Texture::Format::RGBA8_SRGB) { format = VK_FORMAT_R8G8B8A8_SRGB; } + else if (tex._format == asset::Texture::Format::RGBA16F_SFLOAT) { + format = VK_FORMAT_R16G16B16A16_SFLOAT; + } internal::InternalTexture internalTex{}; internalTex._id = tex._id; @@ -1498,7 +1556,7 @@ void VulkanRenderer::copyDynamicModels(VkCommandBuffer cmdBuffer) } void VulkanRenderer::update( - const Camera& camera, + Camera& camera, const Camera& shadowCamera, const glm::vec4& lightDir, double delta, @@ -1543,6 +1601,16 @@ void VulkanRenderer::update( shadowProj[1][1] *= -1; proj[1][1] *= -1; + // If we are baking, lock camera to middle of baking tile + if (_bakeInfo._bakingIndex) { + const auto ts = scene::Tile::_tileSize; + glm::vec3 pos{ + (float)(_bakeInfo._bakingIndex._idx.x * ts + ts / 2), + 5.0f, + (float)(_bakeInfo._bakingIndex._idx.y * ts + ts / 2) }; + camera.setPosition(pos); + } + auto invView = glm::inverse(camera.getCamMatrix()); auto invProj = glm::inverse(proj); @@ -1576,6 +1644,12 @@ void VulkanRenderer::update( if (_renderOptions.hack) ubo.flags |= gpu::UBO_HACK_FLAG; if (_enableRayTracing) ubo.flags |= gpu::UBO_RT_ON_FLAG; + // Are we baking? + if (_bakeInfo._bakingIndex) { + ubo.flags |= gpu::UBO_BAKE_MODE_ON_FLAG; + ubo.bakeTileInfo = glm::ivec4(_bakeInfo._bakingIndex._idx.x, _bakeInfo._bakingIndex._idx.y, (int)scene::Tile::_tileSize, 0); + } + void* data; vmaMapMemory(_vmaAllocator, _gpuSceneDataBuffer[_currentFrame]._allocation, &data); memcpy(data, &ubo, sizeof(gpu::GPUSceneData)); @@ -1584,6 +1658,21 @@ void VulkanRenderer::update( if (!lockCulling) { _latestCamera = camera; } + + // Should we download a baked DDGI texture? + if (_bakeInfo._stopNextFrame) { + _bakeInfo._stopNextFrame = false; + + // Wait for device idle + vkDeviceWaitIdle(_device); + + auto tex = downloadDDGIAtlas(); + + assert(_bakeInfo._callback && "No callback in baking info!"); + _bakeInfo._callback(tex); + _bakeInfo._callback = nullptr; + _bakeInfo._bakingIndex = scene::TileIndex(); + } } AccelerationStructure VulkanRenderer::registerBottomLevelAS( @@ -2408,6 +2497,72 @@ VkPhysicalDeviceRayTracingPipelinePropertiesKHR VulkanRenderer::getRtPipeProps() return _rtPipeProps; } +asset::Texture VulkanRenderer::downloadDDGIAtlas() +{ + // NOTE: This HAS to be called with the device idle! + auto* imRes = (ImageRenderResource*)_vault.getResource("ProbeRaysConvTex"); + assert(imRes && "The DDGI atlas texture could not be retrieved!"); + + // Create a temporary staging buffer that is host visible + uint32_t width = (8 + 2) * (uint32_t)getNumIrradianceProbesXZ(); + uint32_t height = (8 + 2) * (uint32_t)getNumIrradianceProbesXZ() * (uint32_t)getNumIrradianceProbesY(); + size_t totalSize = width * height * 4 * 2; // 4 channels at 16 bits each + AllocatedBuffer stagingBuf; + + bufferutil::createBuffer( + _vmaAllocator, + totalSize, + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, + stagingBuf); + + auto cmdBuf = beginSingleTimeCommands(); + + // Transition atlas to transfer src optimal + imageutil::transitionImageLayout( + cmdBuf, + imRes->_image._image, + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + + // Copy atlas into staging buf + VkBufferImageCopy imCopy{}; + imCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imCopy.imageSubresource.layerCount = 1; + imCopy.imageExtent.depth = 1; + imCopy.imageExtent.height = height; + imCopy.imageExtent.width = width; + + vkCmdCopyImageToBuffer(cmdBuf, imRes->_image._image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stagingBuf._buffer, 1, &imCopy); + + // Transition back + imageutil::transitionImageLayout( + cmdBuf, + imRes->_image._image, + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + endSingleTimeCommands(cmdBuf); + + // Map staging buffer and download data + asset::Texture outTex; + outTex._width = width; + outTex._height = height; + outTex._format = asset::Texture::Format::RGBA16F_SFLOAT; + outTex._data.resize(totalSize); + + void* data = nullptr; + vmaMapMemory(_vmaAllocator, stagingBuf._allocation, &data); + std::memcpy(outTex._data.data(), data, totalSize); + vmaUnmapMemory(_vmaAllocator, stagingBuf._allocation); + + vmaDestroyBuffer(_vmaAllocator, stagingBuf._buffer, stagingBuf._allocation); + + return outTex; +} + void VulkanRenderer::checkWorldPosCallback() { if (!_worldPosRequest._callback || !_worldPosRequest._recorded) return; @@ -3182,6 +3337,76 @@ void VulkanRenderer::prefillGPUPointLightShadowCubeBuffer(VkCommandBuffer& comma _currentStagingOffset += dataSize; } +void VulkanRenderer::prefillGPUTileInfoBuffer(VkCommandBuffer& commandBuffer) +{ + // This should fill the GPU buffer with the current available tile infos. + // The indices in the buffer need to be relative to the camera position. + + std::size_t dataSize = (MAX_PAGE_TILE_RADIUS * 2 + 1) * sizeof(gpu::GPUTileInfo); + uint8_t* data; + vmaMapMemory(_vmaAllocator, _gpuStagingBuffer[_currentFrame]._allocation, (void**)&data); + + // Offset according to current staging buffer usage + data = data + _currentStagingOffset; + + gpu::GPUTileInfo* mappedData = reinterpret_cast(data); + + // Figure out the camera index + const auto cameraIndex = scene::Tile::posToIdx(_latestCamera.getPosition()); + + // This is a weird loop, it is like this to guarantee sequential read/write access + const auto r = MAX_PAGE_TILE_RADIUS; + const auto w = 2 * r + 1; + for (int x = 0; x < w; ++x) { + for (int y = 0; y < w; ++y) { + + bool valueWritten = false; + for (auto& ti : _currentTileInfos) { + const auto& idx = ti._index._idx - cameraIndex._idx; + if (idx.x + r == x && idx.y + r == y) { + mappedData[y * w + x]._ddgiAtlasTex = (int)_textureIdMap[ti._ddgiAtlas]; + valueWritten = true; + break; + } + } + + if (!valueWritten) { + mappedData[y * w + x]._ddgiAtlasTex = -1; + } + + } + } + + VkBufferCopy copyRegion{}; + copyRegion.dstOffset = 0; + copyRegion.srcOffset = _currentStagingOffset; + copyRegion.size = dataSize; + vkCmdCopyBuffer(commandBuffer, _gpuStagingBuffer[_currentFrame]._buffer, _gpuTileBuffer[_currentFrame]._buffer, 1, ©Region); + + VkBufferMemoryBarrier memBarr{}; + memBarr.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + memBarr.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + memBarr.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + memBarr.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + memBarr.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + memBarr.buffer = _gpuTileBuffer[_currentFrame]._buffer; + memBarr.offset = 0; + memBarr.size = VK_WHOLE_SIZE; + + vkCmdPipelineBarrier( + commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + 0, 0, nullptr, + 1, &memBarr, + 0, nullptr); + + vmaUnmapMemory(_vmaAllocator, _gpuStagingBuffer[_currentFrame]._allocation); + + // Update staging offset + _currentStagingOffset += dataSize; +} + void VulkanRenderer::updateWindForceImage(VkCommandBuffer& commandBuffer) { /*std::size_t dataSize = _currentWindMap.height * _currentWindMap.width * 4; @@ -3427,6 +3652,13 @@ bool VulkanRenderer::initBindless() skeletonLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; bindings.emplace_back(std::move(skeletonLayoutBinding)); + VkDescriptorSetLayoutBinding tileLayoutBinding{}; + tileLayoutBinding.binding = _tileBinding; + tileLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + tileLayoutBinding.descriptorCount = 1; + tileLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT; + bindings.emplace_back(std::move(tileLayoutBinding)); + VkDescriptorSetLayoutBinding texLayoutBinding{}; texLayoutBinding.binding = _bindlessTextureBinding; texLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; @@ -3566,6 +3798,24 @@ bool VulkanRenderer::initBindless() descriptorWrites.emplace_back(std::move(lightBufWrite)); + // Tile Info SSBO + VkDescriptorBufferInfo tileBufferInfo{}; + VkWriteDescriptorSet tileBufWrite{}; + + tileBufferInfo.buffer = _gpuTileBuffer[i]._buffer; + tileBufferInfo.offset = 0; + tileBufferInfo.range = VK_WHOLE_SIZE; + + tileBufWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + tileBufWrite.dstSet = _bindlessDescriptorSets[i]; + tileBufWrite.dstBinding = _tileBinding; + tileBufWrite.dstArrayElement = 0; + tileBufWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + tileBufWrite.descriptorCount = 1; + tileBufWrite.pBufferInfo = &tileBufferInfo; + + descriptorWrites.emplace_back(std::move(tileBufWrite)); + // Point light shadow cube views UBO VkDescriptorBufferInfo pointLightShadowBufferInfo{}; VkWriteDescriptorSet pointLightShadowBufWrite{}; @@ -3841,6 +4091,7 @@ bool VulkanRenderer::initGpuBuffers() _gpuWindForceImage.resize(MAX_FRAMES_IN_FLIGHT); _gpuWindForceView.resize(MAX_FRAMES_IN_FLIGHT); _gpuLightBuffer.resize(MAX_FRAMES_IN_FLIGHT); + _gpuTileBuffer.resize(MAX_FRAMES_IN_FLIGHT); _gpuPointLightShadowBuffer.resize(MAX_FRAMES_IN_FLIGHT); _gpuViewClusterBuffer.resize(MAX_FRAMES_IN_FLIGHT); _gpuSkeletonBuffer.resize(MAX_FRAMES_IN_FLIGHT); @@ -3923,6 +4174,15 @@ bool VulkanRenderer::initGpuBuffers() name = "_gpuLightBuffer" + std::to_string(i); setDebugName(VK_OBJECT_TYPE_BUFFER, (uint64_t)_gpuLightBuffer[i]._buffer, name.c_str()); + bufferutil::createBuffer( + _vmaAllocator, + (2 * MAX_PAGE_TILE_RADIUS + 1) * sizeof(gpu::GPUTileInfo), + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + 0, + _gpuTileBuffer[i]); + name = "_gpuTileBuffer" + std::to_string(i); + setDebugName(VK_OBJECT_TYPE_BUFFER, (uint64_t)_gpuTileBuffer[i]._buffer, name.c_str()); + bufferutil::createBuffer( _vmaAllocator, MAX_NUM_POINT_LIGHT_SHADOWS * sizeof(gpu::GPUPointLightShadowCube), @@ -4098,7 +4358,7 @@ void VulkanRenderer::prepare() ImGuizmo::BeginFrame(); } -void VulkanRenderer::drawFrame(bool applyPostProcessing, bool debug) +void VulkanRenderer::drawFrame() { // At the start of the frame, we want to wait until the previous frame has finished, so that the command buffer and semaphores are available to use. vkWaitForFences(_device, 1, &_inFlightFences[_currentFrame], VK_TRUE, UINT64_MAX); @@ -4123,7 +4383,7 @@ void VulkanRenderer::drawFrame(bool applyPostProcessing, bool debug) return; } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { - printf("Failed to require swap chain image!\n"); + printf("Failed to acquire swap chain image!\n"); return; } @@ -4428,6 +4688,24 @@ void VulkanRenderer::executeFrameGraph(VkCommandBuffer commandBuffer, int imageI } } + // If textures changed, we need to re-do everything that depends on the texture indices + if (_texturesChanged[_currentFrame]) { + // Materials depend on texture indices + _materialsChanged[_currentFrame] = true; + + // TODO: Tile-information (baked textures have new indices) + _tileInfosChanged[_currentFrame] = true; + + _texturesChanged[_currentFrame] = false; + } + + // Tile infos + if (_tileInfosChanged[_currentFrame]) { + prefillGPUTileInfoBuffer(commandBuffer); + + _tileInfosChanged[_currentFrame] = false; + } + // Models, i.e. meshes that need to be uploaded to giga buffers if (_modelsChanged[_currentFrame]) { // Upload to the giga vertex and index buffers. This will be a no-op if there is nothing to upload. @@ -4455,7 +4733,6 @@ void VulkanRenderer::executeFrameGraph(VkCommandBuffer commandBuffer, int imageI if (forceRenderableUpdate) { for (std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { - // renderables changed because there might be a new dynamicMeshId in the renderable _renderablesChanged[i] = true; } } @@ -4561,6 +4838,32 @@ void VulkanRenderer::requestWorldPosition(glm::ivec2 viewportPos, WorldPosCallba _worldPosRequest._viewportPos = viewportPos; } +void VulkanRenderer::startBakeDDGI(scene::TileIndex tileIdx) +{ + // Start baking at the given idx. + // This means: + // - setting the camera at the middle of the tile at tileIdx + // - setting ubo params that will allow ddgi generation to accumulate instead of using hysteresis + _bakeInfo._bakingIndex = tileIdx; + _bakeInfo._originalCamPos = _latestCamera.getPosition(); + _bakeInfo._stopNextFrame = false; +} + +glm::vec3 VulkanRenderer::stopBake(BakeTextureCallback callback) +{ + // Stop baking means that we have to download the current DDGI probe atlas + // from the GPU and return it as a asset::Texture object. + // We can't really do that synchronously here, so we have to defer it. + _bakeInfo._stopNextFrame = true; + _bakeInfo._callback = callback; + return _bakeInfo._originalCamPos; +} + +bool VulkanRenderer::isBaking() +{ + return !!_bakeInfo._bakingIndex; +} + VkDevice& VulkanRenderer::device() { return _device; diff --git a/src/anerend/render/VulkanRenderer.h b/src/anerend/render/VulkanRenderer.h index 7708ca7..b0354dd 100644 --- a/src/anerend/render/VulkanRenderer.h +++ b/src/anerend/render/VulkanRenderer.h @@ -33,6 +33,7 @@ #include "internal/DeletionQueue.h" #include "internal/InternalTexture.h" #include "AccelerationStructure.h" +#include "scene/TileIndex.h" //#include "../logic/WindSystem.h" @@ -45,6 +46,7 @@ namespace render { typedef std::function WorldPosCallback; +typedef std::function BakeTextureCallback; struct PerFrameTimer { @@ -81,7 +83,7 @@ class VulkanRenderer : public RenderContext void assetUpdate(AssetUpdate&& update) override final; void update( - const Camera& camera, + Camera& camera, const Camera& shadowCamera, const glm::vec4& lightDir, double delta, @@ -97,7 +99,7 @@ class VulkanRenderer : public RenderContext // Goes through all registered renderables, updates any resource descriptor sets (like UBOs), // updates push constants, renders and queues for presentation. - void drawFrame(bool applyPostProcessing, bool debug); + void drawFrame(); // Will recreate swapchain to accomodate the new window size. void notifyFramebufferResized(); @@ -105,7 +107,15 @@ class VulkanRenderer : public RenderContext // Request a world position for a given viewport 2D position. void requestWorldPosition(glm::ivec2 viewportPos, WorldPosCallback callback); + // Sets the renderer in "baking" mode, baking diffuse GI at the given tile index. + void startBakeDDGI(scene::TileIndex tileIdx); + + // Immediately returns the original camera position. Callback will be called after next update() has finished. + glm::vec3 stopBake(BakeTextureCallback callback); + // Render Context interface + bool isBaking() override final; + VkDevice& device() override final; VkDescriptorPool& descriptorPool() override final; VmaAllocator vmaAllocator() override final; @@ -205,9 +215,21 @@ class VulkanRenderer : public RenderContext static const std::size_t MAX_NUM_JOINTS = 50; static const std::size_t MAX_NUM_SKINNED_MODELS = 1000; static const std::size_t MAX_NUM_POINT_LIGHT_SHADOWS = 4; + static const std::size_t MAX_PAGE_TILE_RADIUS = 0; std::unordered_map _blackboard; + // Baking stuff + struct DDGIBakeInfo + { + bool _stopNextFrame = false; + scene::TileIndex _bakingIndex; + glm::vec3 _originalCamPos; + BakeTextureCallback _callback; + } _bakeInfo; + + asset::Texture downloadDDGIAtlas(); + // Pending world position request struct WorldPosRequest { @@ -276,6 +298,8 @@ class VulkanRenderer : public RenderContext std::vector _renderablesChanged; std::vector _lightsChanged; std::vector _materialsChanged; + std::vector _texturesChanged; + std::vector _tileInfosChanged; std::vector _modelsToUpload; std::vector _materialsToUpload; @@ -333,11 +357,11 @@ class VulkanRenderer : public RenderContext uint32_t _meshBinding = _gigaVtxBinding + 1; uint32_t _tlasBinding = _meshBinding + 1; uint32_t _skeletonBinding = _tlasBinding + 1; - uint32_t _bindlessTextureBinding = _skeletonBinding + 1; + uint32_t _tileBinding = _skeletonBinding + 1; + uint32_t _bindlessTextureBinding = _tileBinding + 1; // Use a mem interface to select empty bindless indices. internal::BufferMemoryInterface _bindlessTextureMemIf; - //uint32_t _currentBindlessTextureIndex = 0; void createTexture( VkCommandBuffer cmdBuffer, @@ -401,6 +425,9 @@ class VulkanRenderer : public RenderContext // SSBO for light information. std::vector _gpuLightBuffer; + // SSBO for per-tile information. + std::vector _gpuTileBuffer; + // UBO for point light shadow cube views, used in multiview rendering. std::vector _gpuPointLightShadowBuffer; @@ -440,9 +467,15 @@ class VulkanRenderer : public RenderContext // Fills GPU buffer containing current point light shadow cube views. void prefillGPUPointLightShadowCubeBuffer(VkCommandBuffer& commandBuffer); + // Fills GPU tile info buffer with the current tile infos (camera relative). + void prefillGPUTileInfoBuffer(VkCommandBuffer& commandBuffer); + // Update wind force image void updateWindForceImage(VkCommandBuffer& commandBuffer); + // Current tile infos + std::vector _currentTileInfos; + // View space clusters for the light assignment struct ViewCluster { diff --git a/src/anerend/render/asset/Texture.h b/src/anerend/render/asset/Texture.h index 70d8331..8594c7c 100644 --- a/src/anerend/render/asset/Texture.h +++ b/src/anerend/render/asset/Texture.h @@ -18,7 +18,8 @@ struct Texture enum class Format : std::uint8_t { RGBA8_UNORM, - RGBA8_SRGB + RGBA8_SRGB, + RGBA16F_SFLOAT } _format; std::vector _data; diff --git a/src/anerend/render/asset/TileInfo.h b/src/anerend/render/asset/TileInfo.h new file mode 100644 index 0000000..e9a0ba3 --- /dev/null +++ b/src/anerend/render/asset/TileInfo.h @@ -0,0 +1,15 @@ +#pragma once + +#include "../../util/Uuid.h" +#include "../scene/TileIndex.h" + +namespace render::asset { + +struct TileInfo +{ + scene::TileIndex _index; + + util::Uuid _ddgiAtlas; +}; + +} \ No newline at end of file diff --git a/src/anerend/render/passes/IrradianceProbeTranslationPass.cpp b/src/anerend/render/passes/IrradianceProbeTranslationPass.cpp index 2d5f87a..4693d2f 100644 --- a/src/anerend/render/passes/IrradianceProbeTranslationPass.cpp +++ b/src/anerend/render/passes/IrradianceProbeTranslationPass.cpp @@ -56,6 +56,7 @@ void IrradianceProbeTranslationPass::registerToGraph(FrameGraphBuilder& fgb, Ren fgb.registerRenderPassExe("IrradianceProbeTrans", [this, width, height, numProbesPlane, numProbesHeight, octPixelSize](RenderExeParams exeParams) { if (!exeParams.rc->getRenderOptions().ddgiEnabled) return; + if (exeParams.rc->isBaking()) return; const glm::vec3 probeStep = { 1.0, 2.0, 1.0 }; diff --git a/src/anerend/render/scene/Scene.cpp b/src/anerend/render/scene/Scene.cpp index e3e3ce7..7b2d4fd 100644 --- a/src/anerend/render/scene/Scene.cpp +++ b/src/anerend/render/scene/Scene.cpp @@ -459,6 +459,38 @@ const asset::Renderable* Scene::getRenderable(util::Uuid id) return rend; } +void Scene::setDDGIAtlas(util::Uuid texId, scene::TileIndex idx) +{ + if (_tiles.find(idx) != _tiles.end()) { + _tiles[idx].setDDGIAtlas(texId); + } + else { + // Add a new tile here + Tile tile(idx); + tile.setDDGIAtlas(texId); + _tiles[idx] = std::move(tile); + } + + // add to tile infos (could be more in here in the future) + bool found = false; + for (auto& ti : _tileInfos) { + if (ti._idx == idx) { + ti._ddgiAtlas = texId; + found = true; + break; + } + } + + if (!found) { + TileInfo ti{}; + ti._ddgiAtlas = texId; + ti._idx = idx; + _tileInfos.emplace_back(std::move(ti)); + } + + addEvent(SceneEventType::DDGIAtlasAdded, util::Uuid(), idx); +} + void Scene::setRenderableTint(util::Uuid id, const glm::vec3& tint) { for (auto it = _renderables.begin(); it != _renderables.end(); ++it) { diff --git a/src/anerend/render/scene/Scene.h b/src/anerend/render/scene/Scene.h index f220b31..ab42415 100644 --- a/src/anerend/render/scene/Scene.h +++ b/src/anerend/render/scene/Scene.h @@ -49,7 +49,8 @@ enum class SceneEventType RenderableRemoved, LightAdded, LightUpdated, - LightRemoved + LightRemoved, + DDGIAtlasAdded }; struct SceneEvent @@ -164,6 +165,8 @@ class Scene void removeRenderable(util::Uuid id); const asset::Renderable* getRenderable(util::Uuid id); + void setDDGIAtlas(util::Uuid texId, scene::TileIndex idx); + // TODO: Decide if the Scene class really is the correct place to access/modify renderables. void setRenderableTint(util::Uuid id, const glm::vec3& tint); void setRenderableTransform(util::Uuid id, const glm::mat4& transform); @@ -171,6 +174,12 @@ class Scene void setRenderableBoundingSphere(util::Uuid id, const glm::vec4& boundingSphere); void setRenderableVisible(util::Uuid id, bool val); + struct TileInfo + { + TileIndex _idx; + util::Uuid _ddgiAtlas; + }; + private: friend struct internal::SceneSerializer; @@ -192,6 +201,8 @@ class Scene std::vector _renderables; std::vector _lights; + std::vector _tileInfos; + SceneEventLog _eventLog; internal::SceneSerializer _serialiser; diff --git a/src/anerend/render/scene/ScenePager.cpp b/src/anerend/render/scene/ScenePager.cpp index 9634f47..5cb3eff 100644 --- a/src/anerend/render/scene/ScenePager.cpp +++ b/src/anerend/render/scene/ScenePager.cpp @@ -89,7 +89,6 @@ void ScenePager::update(const glm::vec3& pos) if (std::find(_pagedTiles.begin(), _pagedTiles.end(), currIdx) != _pagedTiles.end()) { // Go through events to see if anything changed on this already paged tile - // (currently only renderables, but could be lots more) for (const auto& event : log._events) { if (event._tileIdx && event._tileIdx == currIdx) { if (event._type == SceneEventType::RenderableAdded) { @@ -114,6 +113,12 @@ void ScenePager::update(const glm::vec3& pos) else if (event._type == SceneEventType::LightRemoved) { upd._removedLights.emplace_back(event._id); } + else if (event._type == SceneEventType::DDGIAtlasAdded) { + asset::TileInfo ti{}; + ti._index = currIdx; + ti._ddgiAtlas = tile->getDDGIAtlas(); + upd._addedTileInfos.emplace_back(std::move(ti)); + } } } @@ -131,6 +136,14 @@ void ScenePager::update(const glm::vec3& pos) upd._addedLights.emplace_back(std::move(copy)); } + // Do DDGI Atlas if present + if (auto atlasId = tile->getDDGIAtlas()) { + asset::TileInfo ti{}; + ti._index = currIdx; + ti._ddgiAtlas = atlasId; + upd._addedTileInfos.emplace_back(std::move(ti)); + } + pagedTiles.emplace_back(currIdx); } } @@ -155,6 +168,9 @@ void ScenePager::update(const glm::vec3& pos) for (const auto& lightId : tile->getLightIds()) { upd._removedLights.emplace_back(lightId); } + + // Remove tile info + upd._removedTileInfos.emplace_back(idx); } _pagedTiles = std::move(pagedTiles); diff --git a/src/anerend/render/scene/Tile.cpp b/src/anerend/render/scene/Tile.cpp index 60897b3..bfd4d22 100644 --- a/src/anerend/render/scene/Tile.cpp +++ b/src/anerend/render/scene/Tile.cpp @@ -18,6 +18,8 @@ Tile::~Tile() Tile::Tile(Tile&& rhs) { std::swap(_renderables, rhs._renderables); + std::swap(_lights, rhs._lights); + std::swap(_ddgiAtlas, rhs._ddgiAtlas); std::swap(_index, rhs._index); _initialized = true; rhs._initialized = false; @@ -27,6 +29,8 @@ Tile& Tile::operator=(Tile&& rhs) { if (this != &rhs) { std::swap(_renderables, rhs._renderables); + std::swap(_lights, rhs._lights); + std::swap(_ddgiAtlas, rhs._ddgiAtlas); std::swap(_index, rhs._index); _initialized = true; rhs._initialized = false; diff --git a/src/anerend/render/scene/Tile.h b/src/anerend/render/scene/Tile.h index 4ec638c..0ee3617 100644 --- a/src/anerend/render/scene/Tile.h +++ b/src/anerend/render/scene/Tile.h @@ -33,6 +33,9 @@ class Tile void removeLight(util::Uuid id); const std::vector& getLightIds() const { return _lights; } + void setDDGIAtlas(util::Uuid id) { _ddgiAtlas = id; } + util::Uuid getDDGIAtlas() { return _ddgiAtlas; } + static const unsigned _tileSize = 32; // in world space static TileIndex posToIdx(const glm::vec3& pos); @@ -43,6 +46,7 @@ class Tile // TODO: particles std::vector _renderables; std::vector _lights; + util::Uuid _ddgiAtlas; }; diff --git a/src/anerend/render/scene/internal/SceneSerializer.cpp b/src/anerend/render/scene/internal/SceneSerializer.cpp index 440dc1c..52786e2 100644 --- a/src/anerend/render/scene/internal/SceneSerializer.cpp +++ b/src/anerend/render/scene/internal/SceneSerializer.cpp @@ -81,6 +81,13 @@ void serialize(S& s, glm::i16vec4& v) s.value2b(v.w); } +template +void serialize(S& s, glm::ivec2& v) +{ + s.value4b(v.x); + s.value4b(v.y); +} + template void serialize(S& s, render::Vertex& v) { @@ -272,6 +279,26 @@ void serialize(S& s, std::vector& v) s.container(v, 1024); } +template +void serialize(S& s, render::scene::TileIndex& t) +{ + s.object(t._idx); + s.value1b(t._initialized); +} + +template +void serialize(S& s, render::scene::Scene::TileInfo& t) +{ + s.object(t._idx); + s.object(t._ddgiAtlas); +} + +template +void serialize(S& s, std::vector& t) +{ + s.container(t, 1024); +} + } namespace render::scene::internal { @@ -290,7 +317,8 @@ std::uint32_t headerSize() 4 + // skel idx 4 + // animator idx 4 + // rend idx - 4; // light idx + 4 + // light idx + 4; // tile info idx } } @@ -338,6 +366,7 @@ void SceneSerializer::serialize(const Scene& scene, const std::filesystem::path& 4 bytes animator idx (uint32_t) 4 bytes renderable idx (uint32_t) 4 bytes lights idx (uint32_t) + 4 bytes tileInfo idx (uint32_t) -- prefabs -- @@ -357,6 +386,8 @@ void SceneSerializer::serialize(const Scene& scene, const std::filesystem::path& -- lights -- + -- tile infos -- + EOF */ @@ -372,6 +403,7 @@ void SceneSerializer::serialize(const Scene& scene, const std::filesystem::path& auto renderables = scene._renderables; auto animators = scene._animators; auto lights = scene._lights; + auto tileInfos = scene._tileInfos; std::ofstream file(path, std::ios::binary); if (file.bad()) { @@ -392,6 +424,7 @@ void SceneSerializer::serialize(const Scene& scene, const std::filesystem::path& std::vector serialisedAnimators; std::vector serializedRenderables; std::vector serialisedLights; + std::vector serialisedTis; printf("Serialising prefabs...\n"); auto prefabsByteSize = (uint32_t)bitsery::quickSerialization>>(serialisedPrefabs, prefabs); @@ -411,6 +444,8 @@ void SceneSerializer::serialize(const Scene& scene, const std::filesystem::path& auto renderablesByteSize = (uint32_t)bitsery::quickSerialization>>(serializedRenderables, renderables); printf("Serialising lights...\n"); auto lightsByteSize = (uint32_t)bitsery::quickSerialization>>(serialisedLights, lights); + printf("Serialising tile infos...\n"); + auto tisByteSize = (uint32_t)bitsery::quickSerialization>>(serialisedTis, tileInfos); auto headerSz = headerSize(); @@ -425,6 +460,7 @@ void SceneSerializer::serialize(const Scene& scene, const std::filesystem::path& auto animatorIdx = skeletonIdx + skeletonsByteSize; auto renderableIdx = animatorIdx + animatorsByteSize; auto lightsIdx = renderableIdx + renderablesByteSize; + auto tiIdx = lightsIdx + lightsByteSize; file.write((const char*)&version, 1); // prefab idx (where model info starts) @@ -445,6 +481,8 @@ void SceneSerializer::serialize(const Scene& scene, const std::filesystem::path& file.write((const char*)&renderableIdx, 4); // lights idx file.write((const char*)&lightsIdx, 4); + // ti idx + file.write((const char*)&tiIdx, 4); // write the data file.write((const char*)serialisedPrefabs.data(), prefabsByteSize); @@ -456,6 +494,7 @@ void SceneSerializer::serialize(const Scene& scene, const std::filesystem::path& file.write((const char*)serialisedAnimators.data(), animatorsByteSize); file.write((const char*)serializedRenderables.data(), renderablesByteSize); file.write((const char*)serialisedLights.data(), lightsByteSize); + file.write((const char*)serialisedTis.data(), tisByteSize); file.close(); @@ -520,6 +559,7 @@ std::future SceneSerializer::deserialize(const std::files 4 bytes animator idx (uint32_t) 4 bytes renderable idx (uint32_t) 4 bytes lights idx (uint32_t) + 4 bytes tile info idx (uint32_t) -- prefabs -- @@ -539,6 +579,8 @@ std::future SceneSerializer::deserialize(const std::files -- lights -- + -- tile infos -- + EOF */ @@ -571,6 +613,7 @@ std::future SceneSerializer::deserialize(const std::files uint32_t animatorIdx = header4BytePtr[6]; uint32_t rendIdx = header4BytePtr[7]; uint32_t lightIdx = header4BytePtr[8]; + uint32_t tiIdx = header4BytePtr[9]; std::vector serialisedPrefabs(textureIdx - prefabIdx); std::vector serialisedTextures(modelIdx - textureIdx); @@ -580,7 +623,8 @@ std::future SceneSerializer::deserialize(const std::files std::vector serialisedSkeletons(animatorIdx - skeletonIdx); std::vector serialisedAnimators(rendIdx - animatorIdx); std::vector serialisedRenderables(lightIdx - rendIdx); - std::vector serialisedLights(fileSize - lightIdx); + std::vector serialisedLights(tiIdx - lightIdx); + std::vector serialisedTis(fileSize - tiIdx); // We need these here so that we can add them properly to the scene. std::vector prefabs; @@ -592,6 +636,7 @@ std::future SceneSerializer::deserialize(const std::files std::vector animators; std::vector rends; std::vector lights; + std::vector tis; // Read prefabs if (!desHelper(file, prefabIdx, serialisedPrefabs, prefabs)) { @@ -641,12 +686,18 @@ std::future SceneSerializer::deserialize(const std::files return; } - // Read renderables + // Read lights if (!desHelper(file, lightIdx, serialisedLights, lights)) { p.set_value(DeserialisedSceneData()); return; } + // Read tile infos + if (!desHelper(file, tiIdx, serialisedTis, tis)) { + p.set_value(DeserialisedSceneData()); + return; + } + for (auto& p : prefabs) { outputData._scene->addPrefab(std::move(p)); } @@ -674,6 +725,11 @@ std::future SceneSerializer::deserialize(const std::files for (auto& l : lights) { outputData._scene->addLight(std::move(l)); } + for (auto& ti : tis) { + if (ti._ddgiAtlas) { + outputData._scene->setDDGIAtlas(ti._ddgiAtlas, ti._idx); + } + } p.set_value(std::move(outputData)); }