From 68029fcd39c5f750896dc7afb9f7955509bb1343 Mon Sep 17 00:00:00 2001 From: Untold Engine Date: Tue, 14 Jul 2026 15:28:30 -0700 Subject: [PATCH] [Patch] fixed env rendering in full immersion mode [Patch] Fixed ibl dynamic range [Docs] Added documentation for xr immersion mode --- README.md | 1 + .../Shaders/OutputTransformShader.metal | 7 +- .../UntoldEngine/Shaders/preCompShader.metal | 8 + .../Systems/RenderingSystem.swift | 3 +- .../UntoldEngineKernels-ios.air | Bin 155408 -> 155424 bytes .../UntoldEngineKernels-ios.metallib | Bin 516553 -> 516633 bytes .../UntoldEngineKernels-tvos.air | Bin 155376 -> 155408 bytes .../UntoldEngineKernels-tvos.metallib | Bin 514313 -> 514393 bytes .../UntoldEngineKernels-tvossim.air | Bin 155408 -> 155424 bytes .../UntoldEngineKernels-tvossim.metallib | Bin 516841 -> 516921 bytes .../UntoldEngineKernels-xros.air | Bin 155376 -> 155408 bytes .../UntoldEngineKernels-xros.metallib | Bin 514329 -> 514409 bytes .../UntoldEngineKernels-xrossim.air | Bin 155408 -> 155424 bytes .../UntoldEngineKernels-xrossim.metallib | Bin 516857 -> 516937 bytes .../UntoldEngineKernels.metallib | Bin 513545 -> 513641 bytes .../Utils/EngineSettingsAPI.swift | 40 ++++ Sources/UntoldEngine/Utils/FuncUtils.swift | 17 ++ docs/API/UsingXRImmersionMode.md | 183 ++++++++++++++++++ mkdocs.yml | 1 + 19 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 docs/API/UsingXRImmersionMode.md diff --git a/README.md b/README.md index f3c13255..7f486278 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ Untold Engine is well-suited for: - [Geometry Streaming System](docs/API/UsingGeometryStreamingSystem.md) - [LOD-Batching-Streaming](docs/API/UsingLOD-Batching-Streaming.md) - [Spatial Input](docs/API/UsingSpatialInput.md) +- [XR Immersion Modes](docs/API/UsingXRImmersionMode.md) - [Gaussian System](docs/API/UsingGaussianSystem.md) - [Spatial Debugger](docs/API/SpatialDebugger.md) - [Profiler](docs/API/UsingProfiler.md) diff --git a/Sources/UntoldEngine/Shaders/OutputTransformShader.metal b/Sources/UntoldEngine/Shaders/OutputTransformShader.metal index e8206243..c19b3216 100644 --- a/Sources/UntoldEngine/Shaders/OutputTransformShader.metal +++ b/Sources/UntoldEngine/Shaders/OutputTransformShader.metal @@ -51,6 +51,11 @@ fragment OutputTransformFragmentOut fragmentOutputTransformShader( OutputTransformFragmentOut out; out.color = c; - out.depth = depth; + // Reverse-Z: sky pixels carry the clear value 0.0 = infinite distance. The + // visionOS compositor reprojects using view distance (near/depth), so exactly + // 0.0 divides to infinity and those pixels are discarded (rendered black). + // Clamp to a finite far depth (~1km) that is visually indistinguishable from + // infinity but valid for the compositor's reprojection. + out.depth = max(depth, 1e-4); return out; } diff --git a/Sources/UntoldEngine/Shaders/preCompShader.metal b/Sources/UntoldEngine/Shaders/preCompShader.metal index 2f2e97d8..11d6f634 100644 --- a/Sources/UntoldEngine/Shaders/preCompShader.metal +++ b/Sources/UntoldEngine/Shaders/preCompShader.metal @@ -54,6 +54,14 @@ fragment float4 fragmentPreCompositeShader(VertexCompositeOutput vertexOut [[sta baseColor.rgb = gaussianColor.rgb + baseColor.rgb * (1.0 - gaussianColor.a); baseColor.a = gaussianColor.a + baseColor.a * (1.0 - gaussianColor.a); + // Non-passthrough modes (full immersion, macOS, AR) present an opaque layer: + // the environment already fills every background pixel, so alpha must be 1.0 + // regardless of what upstream content (HDR alpha, material alpha, Gaussians) + // produced. Only mixed passthrough is allowed to punch through via alpha. + if (isPassthrough == false) { + baseColor.a = 1.0; + } + // Sample gizmo float3 gizmoColor = gizmoTexture.sample(s, vertexOut.uvCoords).rgb; float gizmoLumen = getLuminance(gizmoColor); diff --git a/Sources/UntoldEngine/Systems/RenderingSystem.swift b/Sources/UntoldEngine/Systems/RenderingSystem.swift index 86677bd2..d920687e 100644 --- a/Sources/UntoldEngine/Systems/RenderingSystem.swift +++ b/Sources/UntoldEngine/Systems/RenderingSystem.swift @@ -1330,7 +1330,8 @@ public let outputTransformRenderPass: RenderPasses.RenderPassExecution = { comma renderPassDescriptor.colorAttachments[0].loadAction = .clear renderPassDescriptor.colorAttachments[0].storeAction = .store - renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0) + // Do not override clearColor here: the XR layer sets it per immersion mode + // (UntoldEngineXR.swift), and the fullscreen quad overwrites every pixel anyway. guard let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else { handleError(.renderPassCreationFailed, "Output Transform Pass: encoder creation failed") diff --git a/Sources/UntoldEngine/UntoldEngineKernels/UntoldEngineKernels-ios.air b/Sources/UntoldEngine/UntoldEngineKernels/UntoldEngineKernels-ios.air index f6c491474f2ba7eee9285e4ece98a391f759b807..cf9f01590c5d218461abfc1cfe469bcdf2a53b4e 100644 GIT binary patch delta 1334 zcmXw13rv#-5bpi_v_D$pM-BY1KEODejcqLbP$%Nt~MF?j-+O{jqf91g3I6l#s z6{15%ccCX(?;KVEXR&9;jZdSbCENJAaBj^ZjaIjdmQ0c+=2fVfqn%}?B$Jq_VZky73jN+}|6S`*F2(@{+DMCmc)wZGg`BMco!OXvpic1N1As>YRFG zBiX8tXDDlY^)nehV{4p&HBoJe))&yfrd=ODsm zbI2|xTE!YBOPyRUx~Hngk6B?DW7f+)p=BSLQlC!i$yQX0j4(=p+a z&YDj-c~S7r3N2IO>RGhXyXaWYNW)`tqVnaGB@b^e51#QpCVYwMLBYw-{CAcIN8+2l z%I!=2i8GsfZf&-`U3d2h(N{|idszwb{&Q;ILSL-yJ*`B-#4vqcz_CEu?mR9Kg@(@3 zcZsR9-ni&$H_nm7_Akv^W{TucYVUfU&vuWaEBo9 z6dR<4dg--}Cr|T#yF=D0Qq=Zgvad8pP4Z;Br0JM~cpfZk6Im1^4q$%gSzI=-1*Y$K zmc^ozTcKd&B^E#UZ5x=U=CNozupMd_zRqIt;CAqg6th^`x&uNBH?UY1azbQXHH)U+ zT43hwVR6;voiM%Q8y44icR|6t78cjt-wo!QAr{U1>!8-w$Kv|K`@mzfJYaD{_kIYa z=5zS@^}`UkS;8Sg^awD_a5IPH@Mi-U8SxQ^Hi&);c1B&t<0d$N8eEK|m&Yn-Y=!_M z-sW*L-19<&(I*M$0Bb8StYfBtTcN)l@>sf9Kqt7*ft?kP3b+#@=fK5U+#UgU!`4m+ zu!dd%>tK5q46+hlf%~942o$GPDsVsaUj_|FpHkpKIMfGu96hMO!*HMNg delta 1331 zcmX|A4NOy46n^JXo^=)|#nt!M_BpexSy(J+R5VJV3T)P-CR^w0#o-Sdnzcg*It2K%Zk}N$;tV0a!&5O-}l|x zmWdTD6JxKpO_@YQVsa!Ot*DHB4d%I%PH%w5#y>Vl8Yb+Iv=c-b&M_qnI@=OR%4tpp zxf2y2-Yvi@HcL9Ojh-pQ+fA-nr*Fm_xTC)yOQ@R&8uKMwD7Jg94O7`A5dGeg8RK0o zTc#P1wvlvCvN-MK2zEJlLB>Z*3tlXGr89pKqDG8r(XCXkR6ii-T-HWWyEd8@1NHK( zU?sJbL$FPu-hcexnsLzKxfwTAEDuBM9GU45#kX5^fk`F}pHyJC>1T^9LQk?}p{C1< z9=1m|`A%ejPWMwCF=PsQ3Oesbhm%SJZLl{@8r~quk(P7`IxUrti-a((52Th#`{4T` zSvYd9FCZ#hEHS&N^|>0a$>rgDlFp>LmBkX^FF|ZkD93|~nwek!iBkDYx>-%%HreaakQIA$WxSuL^mo7W* zf85|-mft!KxV6C?-?`QW@()Juj{`T=^u?n7DFX}S`5#)J8Bc6pd90``yJo1c(0^~o zI1qPQh~M^rVEBO~^P(lhUmAj-oxbUi==Aess%?9ovHkUw_>M!J5fey~MdxRjts$M* zzQyK>-YEK6&;<+;M$#&Gn=q6iH3-fa-F*Jw6bTpki~e#4~bHCXRa5B#3B@IWTT47*LjUF?w?)l}k`Lflucp z?UfRZF;|G5S)z1Tgy$xYf_w{XTVfbAJ*@!xF~^|!Rwc|i@+O11C#%3n&1Z1c-JMXF zk;R~;ZWmOqTEgI(d%K{STFYQw$8P9bwTZ!XSDg?l-NvA`zZ&T5uNYk4w+H52`If>}PP}kps}|v^`^RlkXt(y`g9Ev)hLu^kglI2v`p^ zO|-CRhldSdp{>tZECXx=2d$~$upD~MKs_zJ#^F{taTdI^^*)C?V5Aj7v>}ei3b3~W z&D752u?lWtJDPhZJ}e+&93%){ZIg8|Vl?JuAd1 zu>l5ef|tcaB_4KJ3%@>rAUAANVJlRPf|#$kph6Ec zKL<5$c%Z@#Xc>bn9>Xd;2mTV$!dEO)V;6L9AsxJszCw*Zfxncj=cVh^cmZ0ct!lgs!R=(0!qt>Gm3%Z`6!~<-zpRn{ ALjV8( diff --git a/Sources/UntoldEngine/UntoldEngineKernels/UntoldEngineKernels-ios.metallib b/Sources/UntoldEngine/UntoldEngineKernels/UntoldEngineKernels-ios.metallib index b1083f1d0c1da34bb4fd835c7b67d24e55640aed..ec8101e25a56172c080314baa4da810069bc8786 100644 GIT binary patch delta 1612 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 PYEZ-w_ZCb%?*H;HlJ)<5 delta 1326 zcmX|94NOx95bnK}XVq2P6F4JyRkK zsoDvuJ64|fx&^x&hamNnHF>WFy{g4Gc^J7oV&rb1{VvP#I!Ev1$O$7K8}$U=@Tb zQLhLJI*oN9IVB4Exy!2*#=;f0g!6#6}$~qUBt^Q7}D6g=nQiOnJpo+#4q2Dsa8oE zl{Y2bOJqsTpw4cWnurElijqdtvvQ!$voxBAD`4ryw`k0E9ROqJJ2Y;*e-QG?bQ&!+ zhoEx7Y8p2`I0Q|dn`z8xI}8I0cF_1~zXSZKduX)YtOP3ZD2-chRKZfm_cZ3URD&_{ zB8^}Cbp-O=12pCzKL(YVgEVgcwg#FqZ7*ot(NhZpzprBOtGlPb@7}^7!sKb7sPR9l<=6veK6Jreo8f$!*U3CfTB&y zI6MG@9gt3on>chp!&NAyg)z=AEU+^=<$J^ zk!aLd3xhX7$B0d8JOQqoOQmZK^NHiM?lB6@6})=T+^Zl&b}q*8}H tP*p~Za_!YR?1jd!3AtL*qC+1%+)e1z_u)BJ* z5?+REjvGBYvhoP=ZN;S|RhMk?1!b7wM&zZK7H{=;j?1@tUOx@rs!iN?^=ORS_ybn4 zX@1s{Wdso!=BgnUUIZa>8glKlwPlS1g2B0s4l@Cg$) z`Kaack&o5}cGx7kCDIhd9fzKNYm->Zr72i<`dnI)N9tLmStMo-4}&~BNs@sz0=!RV zlaKnSszSU=_|&ZNwFplzU8IS%=#+0M^^m5kWm_rJMO%=l8f99UrG&Jq+lg}yqL&|VNJXs8oiTDA`^R(u`(y@lUmu@_jMf?H#+g-PPnB3ZXn^g z_jg4UL++jKMRt1WsBh6Tu`b$~c#<#h4N6JoNH)`>zD=2AkVnyJh0V-kGSP!0$p8d? z4}20D*8rO)27jUbvv6*l@Qt>=(;8x&wKjW@9@i_iBgl?cJH{jA!P{Hy(62*#LhCYg zap)wBoACnQ%RT7BWn7LAY6_xKC7s$k3S^^Q=`kLT%c&px6s<2+HkqST0GCZF+)Gmi zGUAdksFgaHFYVM1Fdn8}c{8PVuQto@l!cltL&2mDK*k z2OAM?&re7=cUA-S?XNVj9^uyAgbK1>%U8k=Ox}`t`ZRlrJ9HDqu262Z05YJCuO+cY zhj>7Ux%h}4S8|ce(_5Tr^mqaikSsyeVu$w_g3x?G@BonKa_*kg7ED<91ns!efW}WH z!VO9Qx=;jgq8_M0h<4dk{3Oab_QLpf`5mYgOt0QPo(-6)mUtDx=GM~cZo+f1hF13w zo?hPECOofs<0m|!we&O(;fbrI2^UdCaz(Mi1!i9-+y-X%rgiG_BQ|BF#cd{Ws-%(@cQ7^@ngdgVX*C8+MJ`TPEKrC~G{9A^ zplhy>F&Fpa5j;kXh3j?U25WeZJA45mUtCyxX-#>yYD#%?bb`^b+|&Df`HSx7zxF;E zG>G!JMM{K1^6PZA2)R|h%q`z9np;<%TqmBfW_*K-V^o+NlWo*Z;H-}juX!i`Y++cY zI`DHUp36NTH(#IvCAA=T+C6}wyUNLZ`_~rBw6r3v2Gqy~D`vDQWX(uk4rFgNlb=jGhAD?M`xIN%x-1GaI_LwWxS4IZ{PO-Es zc2Aq)!;VVz!)rq$7gqh_StPx# delta 1595 zcmXw(e@qi+7{}kYJ?@V7DhC$nPkN<_h7@-#r7+{9SBi>MQxGF=x)f0ZZn$Q18`;$M z+FDWTbi#Ji$p+}6!yl_o!Ju(HC@IdWWH6M;wrbq6{o%$EXIMt&t|q?8=brEPx#!*= z_vU>kF6j1N&}FWyb=n~ifph=@Dv$=!Kg=u>CAsr8m-DEMWAPoW9c0P3g~$Gyl%GGV zs8GAVBbM$;?!B$WHwiAYi-9j8s{xD593M`=9}pW%}Koy>^wOnM6NV zY&xP1=Of-IRqkW?R=zq&)lJ76BuvHD&H+!kOX8+ArtN;Ovjl0P5@y0d$2~q?mB^Am zL<_?D+Gcu^IwMjzm%Z*Lr{fC07;8kC>D#7u21o-0t2_ngu+t4R`&40fW5ei*>EmQ; z8A?oNm|Ge37*7T6qwmo1Xf?WfAz?_+Z%#fwk6!HKWwTVrHvP5$f>9~OdALBm^qCW(P7#N`X0owE@%ar zPlZ+nn!y?9miTla%LR8v_yr<2?2(1^K6? zctQkMajV`(=J%OyV~fR$@^?M^0?_^lWx#Wb{gJr_e81TrF&c1bkw0P)oDdcZ&f-tv z2E5ARr+@*s(;RXfuJmd$bW>1XIZ9w_){V@oFTx|Fv}o>*LrrRV<@%EH8tkW&ER>^% z6^YISuQ&vCV~oonf`93aGxwYc8|etE|@Mp@w*3 z$T(szygN{spdYiwEbF<_F1ho*+@;U9TCZ3+%LQ{uf3?4Mc%E_Pt)X+yZ3`dWY;Lz@bJZ-&fpwgz4dx(q zUD@loWB1W{X>xtecGx!cChrXjziBp7ZcOb>p1{Qf7^xK-fa3rdDH#Wdh<%H6`5PND zZIs3m2Bb-48zMkuuibYR*zVxb#%Nu@*#D9Yz3|%;i(&s&pMJD9 zB^qQqjs4Si;@$hbDN!<>d~&|=U;n*$_amudn{I#a3*q9ash&}7##f7e{3|7dd2lDb z$37J$>o{f{vw9;P>__Xf=%4Tton`k9dX z_bur`R$|9#cPy&6lSILiQt{1M-}!Qgn44Jqr)=qLk-L{y`zC||tavNrly|T^$Z^Jb zPzyh6JGWWQZD>LX*-2pmDuDt4EqCoaqT?RrV-{glzpEL*O9r diff --git a/Sources/UntoldEngine/UntoldEngineKernels/UntoldEngineKernels-tvossim.air b/Sources/UntoldEngine/UntoldEngineKernels/UntoldEngineKernels-tvossim.air index 3fdef239a907f465439015c63bcbd9e247fe1194..b332ad163a71a1f570e7210e52d352cc7a00a0d0 100644 GIT binary patch delta 1335 zcmXw13rv#-5bpi_v_A;)qXzz0A7Gr##YO7=;4Jo>mYp(T^0iMnzXbG)O}NHY0J=QUY5 zj7`%=dkE%A7L}t}(S`G`yA=G za8g!=oK480ma|o9*`-)Smq&y)hHT07(+=RoMn?L2)IM zEOp4PCR)X6CR>$UCc3AoCd9AO$D6gX&uQ7Grqt)tdUE7dA|s5^W#WJ`B$*0=L;Y;J z+2}L1>t$t@{OM$!>Pn_y*2G84r5kBFCLy}kr4!Q4ors+wPe9@eh;OFH4zu(KE6n6n zvpC}$eX8ftU_deuXf&ol&A*B3pI;+`j^Y$&vOr9=Xy%)4-w&=SDkQ~h@pw+kjs4P? z_t$;FB@_kjuhK9juI?qPTb7*Y9<6^$PF1{~vh4A_m4WjuPYGXQdQ@=wOW*yKfzjB; zZ}WOnf9A~Q?z>xU@6`@HBibsdem^TAK6**zUF?mveV~y@m?)+%@H-Ys+npx`qEO#q z{D7D?`|Yc)cEemrbpO)q6{c`5RkqpU&f7@-qRI`u`*i{=3hWXSrjs*3+K^zS#pEp! zyKf*VjY=8wr3@G9CrfQ}%2fqn*;2n#loL#z)u+mJqc6j%(Svj@!er_Ar~l-wHrM&G zQ;PM{Lap@Xg=bImf4d{rN>bGHVzSqmt0H-_UD9|$PP`13^@%KsVFxgO@GPzv*akCp zy~twG>FrQ3`WlNL|Gopv({wBv4()`R#c#1#Jh&4)qs1&5TX#Wl@g^2agH8xt%7{(F5SISst;tsp}vF zQ}a3e>ef*R-znh`A#w~DW~7P3GWfF|42<}MLmNbX06U|q<#7vKJ_jyF(!*mVG&F&q z5%2N16&|!en9(K)=m2XgFsx&ifZL(J9ds;RET9wIm%z@7#|7LC;Y;9REpCs1dtrMA z_*s3AfVHr*69!ocFUJGW6#$CUDCBq$`mckUqtD3kFdXRx9Y+t!@hBYX2LtCAlH)OO z-vm47h{*9fXbpjjqmvX^4}AmR=S&$2JOMXu!5|lURe>kr;%%V#&_V^C0!#2WQ1c_z z3T%MNA<*%T#|r!r9u0$mcT-AigvbN1^QM_fJOj;tfr}UOm3S6x|A3$GTBXD$=za); ze8{527TER}C;=}k(FcuBKrLv8mDmPN5zq;yF(sadYvqJNz$I$D02enCc7dL|T#Xmu zS_R<}B&BM+3{5t|FKBAi*a7>t5QD delta 1332 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 PYEZ-w_ZCb%?*H;HlJ)<5 delta 1326 zcmX|94NOx95bnK}XVq2P6F4JyRkK zsoDvuJ64|fx&^x&hamNnHF>WFy{g4Gc^J7oV&rb1{VvP#I!Ev1$O$7K8}$U=@Tb zQLhLJI*oN9IVB4Exy!2*#=;f0g!6#6}$~qUBt^Q7}D6g=nQiOnJpo+#4q2Dsa8oE zl{Y2bOJqsTpw4cWnurElijqdtvvQ!$voxBAD`4ryw`k0E9ROqJJ2Y;*e-QG?bQ&!+ zhoEx7Y8p2`I0Q|dn`z8xI}8I0cF_1~zXSZKduX)YtOP3ZD2-chRKZfm_cZ3URD&_{ zB8^}Cbp-O=12pCzKL(YVgEVgcwg#FqZ7*ot(NhZpzprBOtGlPb@7}^7!sKb7sPR9l<=6veK6Jreo8f$!*U3CfTB&y zI6MG@9gt3on>chp!&NAyg)z=AEU+^=<$J^ zk!aLd3xhX7$B0d8JOQqoOQmZK^NHiM?lB6@6})=T+^Zl&b}q*8}H tP*p~Za_!YR?1jd!3AtL*qC+1%+)e1z9De!DZ@ zp$n>~7gUPO?D+-=FdzY-A{2FxeEcj8Mc`;VgshEU6dAR7KzQw=4S_y|{b*;$zVZm5blYZt07q&!mM0_Tf znYtvG1S7VP#PX0tD1ZrwT0;`?8}ngG>xdOML2A@DtZb(R?HHzbE9{MO{QNWk5~4T8kn~>nYBnBk9Q?zFtTjQz`;g|ls!BOvWZw(5?&98euXV) z%tM#t5uM@(=44N^_ypTYnK+AH{g&2_BzHFNUdwhe78qKoPAIe#Q1*995sjY}lI*Tf zPO&GMKx2OKctJ0bPtFVHOoAX8>xrXaM0Xrs=s^8)D_8ZtuH({r2XWkicGRIQ6gvC< zu24DR+T&VeXO@n67Cn;c!yGY9LV>R^S~gdp{uOLZ`^ubUjMA)vk7@9gdt=`(`CpyH?#`4%Glc5uI1f&_*iw zVw%ro`e2T{%`n8e*;@6@_`Yggs__BU)%5MBbntHkmd%A2>96zfRfjMd(ndPA^@Ru3 zL%!k{7|35sMut|XL$#1EzKN97fKI4H7)2BrxL%&?{Md=*6Y&#~@^cfD`~A+v(UF-Qr7HgaqBVQinxNB?FCW z06H-U_>gXt49QmY_e2xMAFM`EtrL5YPBgvji}7s0mNZ9cNG_|2(RPvU3zdwvn{@XH z=4aCVhhTb1w|^Bg%}u%^s~FNrmQegwm3V>K(}s3~IeiIj`kdfx>BBNi+wPW0R0X$* zIsQXGIR>nMt>-|gHHw%LQ^XPlPP9FXaD=3-Wo-{pzK+j7d)+Glmd1`c^M zoWv#;6>?}ZhbU#*7B(eLdMQiVVv8aU4txBvz%&da~Jp(tH5xu`L0Vp{2Pci-dX&$=G}+IRo1 zQIgFsQbQW%)aY%&LDryLSI~Y*Mom#%jdaF_@eNL1r@@18#a8_U-g*bNoA(IM7J#Q{ zy+5ZBxYP}@azq+XPzAE44FVkdvWVKZe`CHv$0!pjL8apE&KWIAMI+4a2Gr`w_^=N+ zPz5T9%EZowJN+C}QMk}%)n1(?C-UW&bI&~g_{`4Jfbs&G>7WxJQ%lNoKG}YW&?>fjWiAtkwdPcm^Gul({#FvF(Q-N(+nT~8;*KTefi7`;xHz_qDQE1$> zy%a8e*ZYJqv8HyF2)!xS1kN4(>M7|WNAn%(rfd2#?&TVZ-Rff?S+3owHc+y&vvs29 zz5{g{*$s>Ax}UEx0OS5U^bsrtvNd6|vD!_fowHeJ{+~e<36JtlKXEub$KUr8Pm*5| z9yL@TRv?@YK8maOeM3koQ3&x|0R{hpN1BP71=nBTfBQ}tWE22aK?@KVxBQ9@G=tBK gK@4BtAxwG0D2ewO#ufabS`@(h>ctZNSqIMj3!#Y>D*ylh delta 1594 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 delta 1332 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 diff --git a/Sources/UntoldEngine/UntoldEngineKernels/UntoldEngineKernels.metallib b/Sources/UntoldEngine/UntoldEngineKernels/UntoldEngineKernels.metallib index 4f9558b0d973095be017fbf04619d95ca572f737..ab18ecf9f90a09b51fe7034c9c0ef43acf6f9413 100644 GIT binary patch delta 1604 zcmXw(3rtg27{|}Oy}jp_-oh;}FHqo?qB3l<3sN!aq%FwH>8e7e&TJP!K}D>h^Ra1L z3iyD!D!RjPM!+``heLsw#kHjwow88@AMq7@WSNT^+>9d`(cR*9lHd8h?|;8@bH4K> z-`@84r|t2|1qB}(F)I#a0NA1d0Ba5?GjRRk3yXUaxGwvrd(&;FC!H8jGw+ody8hA? z>+HINQX<_P;3K_57LX?S;;bGh-9mFI@|-qL2O< zw;*fDate&vqjbBYbeIS(BI%CO5i|0z%x=>z!i+Ja!7;VltZ?gX#?@P^j(dRo79!HZ zre#r8ZXG;2lIK5>RLVCoKtn2&Rf743JKKs)E~FdC>a+YkW*B4pQz-+#($ApA6t6L#9LM3Jf*s4;SH?6j>?kxE?E&FAO>#wcLNWpci06cmujbUM)j$RVXY zVyus?Dk6Q-hn9@K4(Tc0$Cw4HLH&l+j%4^czAWW^oE3|%SEp52OPK1nDhW%R7n7>p z(SmYM1_{SPQi&2jSxn`}3T9D|jSZwQSX_S!QQ?F`3Y*|~SJz2-i<3O*gj<{8Mh2dL zcUMd`;@;z4RLw0N>s$0#ZisOvoe>Lsg|l=Hy@ea=+nmV+c~reNc$~k_BzZ_IMeLf` zJ@83rLNjcQ3;sg?qG*1C^p$?N*A|jHw>$9>SGFQ*EuVo|uAn^hrDx3Yfh*2@{TyiQzCH&Y!I0SpRm`wnEJj>JL`P;@n{XC=>x1#D)H|$z38)j_ zl7-wF`7J5o5+iOxF=3f)Tb*g#L;@C&tU>JJ8t(}VOsBo-nQ9YD&=vk zpdT=+rV+P;z##{yC+l^-*1JOjS6A_o-KM?#fr2bnTv~qa`N!uj-Psjz(r^0vTI(!3 zwU@_k1)O3iwRb+B;W9USBBt$Fo!t^4+ZaFGt&kVgn9__6))!I9P@z55XB0 ze~bIDuq09ENPjmrG!9lZkE*J%l$A3{;^;^fM~64-Zfb1|J_Fd7)#|B^GOxuul4NAG z;IiI^JZ_n1di|4gy)QY^^|f`qs313nI84bM=zv!NbiO`X?)WB_udI3>W_U>0_)0(5qwS;*IO6YQb)0(aRy2fE`16S{jRr z+)#zK(^6W|BfhIjBv~XD?Q0_9QOz(^$&_N8Bceo)4nfW24Wb(=^1pp6E-F!+{Gt{n rGGWnT51fr+N2DxrcwiDLyaChEj$uNHuqo0obnFIPi>%8r84kd|YVa8A delta 1581 zcmXw(4@?tR9LL|g9(M;^<-n??f9RD88q#go+5%hLY)e5AbOkY@vZV}XP>1O}UEcRk=zVHayrZ?`+!t@uo$cSWi`kKL zWSZ}3UgzAfg#sP^OzYlED@0%j*-)kx&o6}~L#|fb0~wH}Zfj~H-~5)jHrl4oiis0m ze6cqd54YQk0<5y8F(&^}QSpV3=u3v&OB0NqB1EmHSXtG1)3TF0%772ga(9`#P#HB- z_QwTT&83;!#KpzC69s-+dQEO-E7~0Fe|{Qv$<26Kei=(wF%BLY2zk2C?b+v0IU5+_ zq;lH_+F&m34YNhOAhk;s0k%3mR+nNg-q}6kDRQN_IgP2&=PfV5cd$`2?c~Nhyrha| zDDDw?L48#Ncb6T&l;x{maWnBTrB6oI6ZZI5rY<{3_0vM;8Ms)8*KxulrNd2*6Kmsr zO#3Q=j;ER1?dmCs_0JG*aAV;LV$YMb8E^2Ah4@bg?J&`|=ANV};sYZ_yUAt0BC(7b zkD#fc$!*Orbd$YV3*NTM2QY;0CONNvti4-)5HraNmiWx zjFhL)&f0S7-DFv%a%lE5vKum!HuUjm;fq2={r&D9v3s1W_Vpi{I z46Ywq5GCtm&*Zkw7Xr=~VhvQ5)fZZ7p!S=6A)|pxUEvE^kV0W4QWjr~GEij}9}5hW zgA?2P;5x4+O*ab_rIR$daq~n@?FuTyq^?-n+_6KgD6J_dsw96nEkFfvSQ+h(O3DtX zo3dxxwzJ12`W;;mW=`3)T`)jYs-o<)pc)Xgi3+H`Bx$Y)+G~Q==3%c(^mXHe|7`%4pLooVAKIJ&N)f zg-gFEKmTgJX!*okFkIoQ8qYDV`||pQ^4(89xY5vMTO{gF!6mS|vuFJhyt-#mjp+G- z$VpP@mo&mo-YGo*N3b9#^Gn>#3#T0Wl@gz-kEfBw_N8gf7g0>%ee=e5=ouB#W)RyA$LukblGcuj{wSlx)Gmw4}k%)<1L@fotgYt!l$MLc6N1htt7hC_vmx bitmapContext.draw(cgImage, in: CGRect(x: 0, y: 0, width: cgImage.width, height: cgImage.height)) + // Sanitize the half-float pixels. Radiance RGBE can encode values beyond + // Float16 range (e.g. the sun disk in "puresky" HDRIs decodes to Inf). + // A single Inf/NaN poisons mip generation and the IBL pre-filter integral, + // which turns every IBL-lit object black. Inf -> max finite half (65504), + // NaN and negatives -> 0. + let componentCount = cgImage.width * cgImage.height * 4 + let halfBits = bitmapContext.data!.bindMemory(to: UInt16.self, capacity: componentCount) + let maxFiniteHalf: UInt16 = 0x7BFF // 65504.0 + for i in 0 ..< componentCount { + let bits = halfBits[i] + if bits & 0x8000 != 0 { + halfBits[i] = 0 // negative radiance is invalid + } else if bits & 0x7C00 == 0x7C00 { + halfBits[i] = (bits & 0x03FF) == 0 ? maxFiniteHalf : 0 // Inf : NaN + } + } + let descriptor = MTLTextureDescriptor() descriptor.pixelFormat = .rgba16Float descriptor.width = cgImage.width diff --git a/docs/API/UsingXRImmersionMode.md b/docs/API/UsingXRImmersionMode.md new file mode 100644 index 00000000..dedb028c --- /dev/null +++ b/docs/API/UsingXRImmersionMode.md @@ -0,0 +1,183 @@ +# Using XR Immersion Modes + +This guide shows how to run your Vision Pro game in **mixed** (passthrough) or +**full** immersion mode, how to enable the environment (skybox), and how to +load a custom IBL/HDR environment. + +--- + +## Choosing an Immersion Mode + +Two settings control the immersion mode, and **they must match**: + +1. The SwiftUI `ImmersiveSpace` style in your app entry point. +2. The engine's immersion mode, set with `setImmersionMode`. + +If they disagree — for example, the space is `.mixed` but the engine is set to +`.full` — you will see camera passthrough bleeding through your scene or a +black background where content should be. + +### Full Immersion + +Your rendered scene replaces the real world entirely. The environment map is +used as the background. + +```swift +@main +struct MyGameApp: App { + + @State private var immersionStyle: ImmersionStyle = .full + + var body: some Scene { + ImmersiveSpace(id: "ImmersiveSpace") { + CompositorLayer(configuration: UntoldEngineConfiguration(), renderer: { layerRenderer in + if let xr = UntoldEngineXR(layerRenderer: layerRenderer) { + XRHolder.shared.xr = xr + + // Must match the ImmersiveSpace style above + xr.setImmersionMode(xrImmersionMode: .full) + + // ... game scene + callbacks + render thread setup + } + }) + } + .immersionStyle(selection: $immersionStyle, in: .full) + } +} +``` + +### Mixed Immersion (Passthrough) + +Your 3D content is composited over the real world. The environment map is not +shown — the camera passthrough is your background. + +```swift +@State private var immersionStyle: ImmersionStyle = .mixed +``` + +```swift +xr.setImmersionMode(xrImmersionMode: .mixed) +``` + +```swift +.immersionStyle(selection: $immersionStyle, in: .mixed) +``` + +### Supporting Both Modes + +Allow both styles in the space and keep the engine in sync whenever the +selection changes: + +```swift +.immersionStyle(selection: $immersionStyle, in: .mixed, .full) +``` + +```swift +// Whenever you switch immersionStyle at runtime: +XRHolder.shared.xr?.setImmersionMode( + xrImmersionMode: immersionStyle is FullImmersionStyle ? .full : .mixed +) +``` + +--- + +## Enabling the Environment + +Enable environment rendering from your `GameScene` setup: + +```swift +setRendering(.environment(.visible(true))) +``` + +- In **full immersion**, the environment map fills the background behind your + scene. +- In **mixed immersion**, the environment is not composited — passthrough is + the background — but the environment still drives image-based lighting (IBL) + on your objects. + +To control whether the environment contributes IBL lighting to your materials: + +```swift +setRendering(.environment(.ibl(true))) // objects are lit by the environment +setRendering(.environment(.ibl(false))) // disable environment lighting +``` + +### Lighting Mode + +Choose where environment lighting comes from: + +```swift +// Use only your authored HDR environment for lighting +setRendering(.environment(.lightingMode(.authoredOnly))) + +// Blend in the real-world lighting estimate (mixed immersion) +setRendering(.environment(.lightingMode(.realWorldEstimate))) +setRendering(.environment(.realWorldLightingContribution(1.0))) +``` + +--- + +## Setting a Custom IBL Environment + +Load your own HDR environment with the `.asset` property. The engine loads the +image, generates mipmaps, and rebuilds the IBL textures (irradiance, specular, +BRDF) in one call: + +```swift +setRendering(.environment(.asset("suburban_garden_2k.hdr"))) +``` + +### Where to Put the File + +Place the HDR inside your project's `GameData/HDR` folder: + +``` +MyGame/ +└── Sources/ + └── MyGame/ + └── GameData/ + └── HDR/ + └── suburban_garden_2k.hdr +``` + +The name is resolved through the engine's standard asset search +(`assetBasePath`, which the generated project points at `GameData`). The +extension is optional — when omitted, the engine tries `.hdr`, `.exr`, and +`.png` in that order: + +```swift +setRendering(.environment(.asset("suburban_garden_2k"))) +``` + +### Loading From a Custom Location + +Pass an explicit directory (the name must include the extension), or use an +absolute path: + +```swift +setRendering(.environment(.asset("studio.hdr", directory: myAssetsURL))) + +setRendering(.environment(.asset("/Users/me/HDRIs/studio.hdr"))) +``` + +### HDR File Guidelines + +- Use an **equirectangular** image with a **2:1 aspect ratio** (e.g. + 2048×1024). +- **2K is the recommended resolution** — it keeps memory low (~20 MB on the + GPU) and looks sharp as a background. IBL lighting quality does not improve + beyond 2K. +- Load the environment during scene setup (for example in your `GameScene` + init), not every frame — the call blocks briefly while the IBL textures are + generated. + +### Complete Example + +```swift +private func configureEngineSystems() { + setRendering(.environment(.visible(true))) + setRendering(.environment(.ibl(true))) + setRendering(.environment(.lightingMode(.authoredOnly))) + setRendering(.environment(.asset("suburban_garden_2k.hdr"))) +} +``` diff --git a/mkdocs.yml b/mkdocs.yml index 7c145abc..0cb60631 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -55,6 +55,7 @@ nav: - Spatial Input: API/UsingSpatialInput.md - Lighting System: API/UsingLightingSystem.md - XR Lighting: API/UsingXRLighting.md + - XR Immersion Modes: API/UsingXRImmersionMode.md - Scene Channels: API/UsingSceneChannels.md - Light Portals: API/UsingLightPortals.md - Materials: API/UsingMaterials.md