framefields 2.14.0 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.md +5 -1
- package/dist/audio/index.d.mts +3 -3
- package/dist/audio/index.mjs +10 -10
- package/dist/{audio-DFwRbID_.mjs → audio-6TfPlfl4.mjs} +3 -3
- package/dist/{audio-DFwRbID_.mjs.map → audio-6TfPlfl4.mjs.map} +1 -1
- package/dist/{audio-CdCuGK5d.d.mts → audio-7oqTUi4G.d.mts} +2 -2
- package/dist/{audio-CdCuGK5d.d.mts.map → audio-7oqTUi4G.d.mts.map} +1 -1
- package/dist/cli/check-worker.mjs +44 -44
- package/dist/cli.mjs +1 -1
- package/dist/cloud/index.d.mts.map +1 -1
- package/dist/cloud/index.mjs +1 -1
- package/dist/{cloud-Cj1TIme8.mjs → cloud-jnk1hPYf.mjs} +2 -2
- package/dist/{cloud-Cj1TIme8.mjs.map → cloud-jnk1hPYf.mjs.map} +1 -1
- package/dist/components/index.d.mts +11 -11
- package/dist/components/index.mjs +43 -43
- package/dist/{dist-Kbf-JTry.mjs → dist-BtI6ukB5.mjs} +2 -2
- package/dist/{dist-Kbf-JTry.mjs.map → dist-BtI6ukB5.mjs.map} +1 -1
- package/dist/{dist-B8Nby2CU.mjs → dist-COOpgG9G.mjs} +4 -3
- package/dist/{dist-B8Nby2CU.mjs.map → dist-COOpgG9G.mjs.map} +1 -1
- package/dist/{dist--Uu5bQ_6.mjs → dist-XqlFM2a8.mjs} +13733 -5323
- package/dist/dist-XqlFM2a8.mjs.map +1 -0
- package/dist/{dist-CiTgmfUw.mjs → dist-f1zkl69f.mjs} +4 -4
- package/dist/dist-f1zkl69f.mjs.map +1 -0
- package/dist/{dist-B_rSWeOz.mjs → dist-umQOWz0a.mjs} +1 -1
- package/dist/effects/index.d.mts +4 -4
- package/dist/effects/index.mjs +35 -35
- package/dist/{effects-WMgv8ZaD.mjs → effects-DlRMovU5.mjs} +2 -2
- package/dist/{effects-WMgv8ZaD.mjs.map → effects-DlRMovU5.mjs.map} +1 -1
- package/dist/fonts/index.d.mts +1 -1
- package/dist/fonts/index.mjs +2 -2
- package/dist/{fonts-OW3yAfO5.mjs → fonts-BWYcXjyK.mjs} +3 -3
- package/dist/fonts-BWYcXjyK.mjs.map +1 -0
- package/dist/{gpu-R4T2Tndu.mjs → gpu-CH1PdM4T.mjs} +2 -2
- package/dist/{gpu-R4T2Tndu.mjs.map → gpu-CH1PdM4T.mjs.map} +1 -1
- package/dist/{index-CEKxvGY-.d.mts → index-BHTycml5.d.mts} +2 -2
- package/dist/{index-CEKxvGY-.d.mts.map → index-BHTycml5.d.mts.map} +1 -1
- package/dist/{index-DoP6EiHj.d.mts → index-BcxxxwhV.d.mts} +4 -4
- package/dist/{index-DoP6EiHj.d.mts.map → index-BcxxxwhV.d.mts.map} +1 -1
- package/dist/{index-Bv7gxGK1.d.mts → index-BnB_Ou2y.d.mts} +2 -2
- package/dist/index-BnB_Ou2y.d.mts.map +1 -0
- package/dist/index-C-V6CAhP.d.mts.map +1 -1
- package/dist/{index-D1FqV1eu.d.mts → index-CMhkkc56.d.mts} +43 -11
- package/dist/index-CMhkkc56.d.mts.map +1 -0
- package/dist/{index-B0Vq8Bwf.d.mts → index-CYVpYGM-.d.mts} +2 -2
- package/dist/{index-B0Vq8Bwf.d.mts.map → index-CYVpYGM-.d.mts.map} +1 -1
- package/dist/{index-C7-p9zwU.d.mts → index-DhL7ckvs.d.mts} +5 -5
- package/dist/index-DhL7ckvs.d.mts.map +1 -0
- package/dist/{index-9xte4JgL.d.mts → index-DkAjKnhW.d.mts} +1464 -559
- package/dist/index-DkAjKnhW.d.mts.map +1 -0
- package/dist/{index-GA9_Z8Fn.d.mts → index-RILu3ULT.d.mts} +2 -2
- package/dist/{index-GA9_Z8Fn.d.mts.map → index-RILu3ULT.d.mts.map} +1 -1
- package/dist/{index-C5sgRLlG.d.mts → index-TCtdSXd7.d.mts} +3 -1
- package/dist/index-TCtdSXd7.d.mts.map +1 -0
- package/dist/{index-CRaydvLi.d.mts → index-s2qQ8ifZ.d.mts} +886 -51
- package/dist/index-s2qQ8ifZ.d.mts.map +1 -0
- package/dist/index.d.mts +13 -13
- package/dist/index.mjs +52 -52
- package/dist/preview/index.d.mts +3 -3
- package/dist/preview/index.mjs +10 -10
- package/dist/preview-BeGF1Bb1.mjs +1002 -0
- package/dist/preview-BeGF1Bb1.mjs.map +1 -0
- package/dist/preview-engine/audio.mjs +1 -1
- package/dist/preview-engine/{chunk-64L4GUOF.mjs → chunk-4F3DG6YB.mjs} +2 -2
- package/dist/preview-engine/chunk-A2OTOW3B.mjs +4694 -0
- package/dist/preview-engine/{chunk-GNDE3OXQ.mjs → chunk-BR56TQBP.mjs} +1 -1
- package/dist/preview-engine/{chunk-ADLIF544.mjs → chunk-H2XKXXAU.mjs} +1 -1
- package/dist/preview-engine/chunk-NDUODAY2.mjs +3 -0
- package/dist/preview-engine/{chunk-FZ4RD7HV.mjs → chunk-QAQJSWUT.mjs} +1 -1
- package/dist/preview-engine/chunk-SWRGQTVC.mjs +138 -0
- package/dist/preview-engine/{chunk-52X7SURQ.mjs → chunk-TEA3GVBJ.mjs} +1 -1
- package/dist/preview-engine/chunk-VM2ZBPLM.mjs +644 -0
- package/dist/preview-engine/{chunk-UBY2UYEL.mjs → chunk-XSHNQJ7L.mjs} +1 -1
- package/dist/preview-engine/components.mjs +1 -1
- package/dist/preview-engine/effects.mjs +1 -1
- package/dist/preview-engine/fonts.mjs +1 -1
- package/dist/preview-engine/framefields.mjs +1 -1
- package/dist/preview-engine/player.mjs +2 -2
- package/dist/preview-engine/{renderers-DU7KPFVV.mjs → renderers-6C7NWWDX.mjs} +1 -1
- package/dist/preview-engine/renderers-HHVGNMSJ.mjs +206 -0
- package/dist/preview-engine/{src-YXNX4MLK.mjs → src-RCNEKIRP.mjs} +1 -1
- package/dist/preview-page/index.html +19 -0
- package/dist/preview-page/main.css +1 -0
- package/dist/preview-page/main.js +327 -0
- package/dist/{program-tFKCWU2j.mjs → program-CMigyfso.mjs} +829 -52
- package/dist/program-CMigyfso.mjs.map +1 -0
- package/dist/renderer/index.d.mts +2 -2
- package/dist/renderer/index.mjs +2 -2
- package/dist/{renderer-DkOuQi84.mjs → renderer-0GMEL_Zi.mjs} +3 -3
- package/dist/{renderer-DkOuQi84.mjs.map → renderer-0GMEL_Zi.mjs.map} +1 -1
- package/dist/{renderer-BGp0An5A.mjs → renderer-3Wv2ZBJG.mjs} +3 -3
- package/dist/{renderer-BGp0An5A.mjs.map → renderer-3Wv2ZBJG.mjs.map} +1 -1
- package/dist/{renderer-BVIXKfbC.mjs → renderer-4nXkaAWu.mjs} +1178 -199
- package/dist/renderer-4nXkaAWu.mjs.map +1 -0
- package/dist/{renderer-Cw6_NL2i.mjs → renderer-6SnfLXeg.mjs} +3 -3
- package/dist/{renderer-Cw6_NL2i.mjs.map → renderer-6SnfLXeg.mjs.map} +1 -1
- package/dist/{renderer-BVU22lBS.mjs → renderer-8gHw3O0P.mjs} +2 -2
- package/dist/{renderer-BVU22lBS.mjs.map → renderer-8gHw3O0P.mjs.map} +1 -1
- package/dist/{renderer-BjDddtw9.mjs → renderer-AOBglZHC.mjs} +2 -2
- package/dist/{renderer-D-KHHWQD.mjs → renderer-B0bSARK3.mjs} +3 -3
- package/dist/{renderer-D-KHHWQD.mjs.map → renderer-B0bSARK3.mjs.map} +1 -1
- package/dist/{renderer-CCxk-RJR.mjs → renderer-B2_tuRfl.mjs} +2 -2
- package/dist/{renderer-CCxk-RJR.mjs.map → renderer-B2_tuRfl.mjs.map} +1 -1
- package/dist/{renderer-k5d7JSbs.mjs → renderer-B82FhkEr.mjs} +3 -3
- package/dist/{renderer-k5d7JSbs.mjs.map → renderer-B82FhkEr.mjs.map} +1 -1
- package/dist/{renderer-I0Hh9cLK.mjs → renderer-B9lzA0PY.mjs} +3 -3
- package/dist/{renderer-I0Hh9cLK.mjs.map → renderer-B9lzA0PY.mjs.map} +1 -1
- package/dist/{renderer-Dwwnx7Dk.mjs → renderer-BBSIWSry.mjs} +2 -2
- package/dist/{renderer-Dwwnx7Dk.mjs.map → renderer-BBSIWSry.mjs.map} +1 -1
- package/dist/{renderer-_pC-jB9O.mjs → renderer-BEKDMxbi.mjs} +2 -2
- package/dist/{renderer-_pC-jB9O.mjs.map → renderer-BEKDMxbi.mjs.map} +1 -1
- package/dist/renderer-BERGAxqA.mjs +5 -0
- package/dist/{renderer-raxwsiGI.mjs → renderer-BF960HY8.mjs} +3 -3
- package/dist/{renderer-raxwsiGI.mjs.map → renderer-BF960HY8.mjs.map} +1 -1
- package/dist/{renderer-Dr0tXA4k.mjs → renderer-BFwyVxCu.mjs} +3 -3
- package/dist/{renderer-Dr0tXA4k.mjs.map → renderer-BFwyVxCu.mjs.map} +1 -1
- package/dist/{renderer-DEjo6dw_.mjs → renderer-BNiwcI3-.mjs} +2 -2
- package/dist/{renderer-DEjo6dw_.mjs.map → renderer-BNiwcI3-.mjs.map} +1 -1
- package/dist/{renderer-DIEeHiQA.mjs → renderer-BPbVb2Q4.mjs} +2 -2
- package/dist/{renderer-DIEeHiQA.mjs.map → renderer-BPbVb2Q4.mjs.map} +1 -1
- package/dist/renderer-BQ_YkBMt.mjs +6 -0
- package/dist/{renderer-BBMtmxks.mjs → renderer-BUWxlA8T.mjs} +3 -3
- package/dist/{renderer-BBMtmxks.mjs.map → renderer-BUWxlA8T.mjs.map} +1 -1
- package/dist/renderer-BW0Tjsv9.mjs +5 -0
- package/dist/{renderer-Dgj46uEU.mjs → renderer-BX8liu-e.mjs} +2 -2
- package/dist/{renderer-ZnrEfkYh.mjs → renderer-BXIwDAr_.mjs} +2 -2
- package/dist/{renderer-ZnrEfkYh.mjs.map → renderer-BXIwDAr_.mjs.map} +1 -1
- package/dist/{renderer-DA8YEo_d.mjs → renderer-B_Hy1W-g.mjs} +3 -3
- package/dist/{renderer-DA8YEo_d.mjs.map → renderer-B_Hy1W-g.mjs.map} +1 -1
- package/dist/{renderer-iMiYStcW.mjs → renderer-Bb6cvSgh.mjs} +2 -2
- package/dist/{renderer-iMiYStcW.mjs.map → renderer-Bb6cvSgh.mjs.map} +1 -1
- package/dist/{renderer-BacY4nh8.mjs → renderer-BdppwWC9.mjs} +2 -2
- package/dist/{renderer-BacY4nh8.mjs.map → renderer-BdppwWC9.mjs.map} +1 -1
- package/dist/{renderer-CrxwW6VQ.mjs → renderer-Bhc24HVe.mjs} +3 -3
- package/dist/{renderer-CrxwW6VQ.mjs.map → renderer-Bhc24HVe.mjs.map} +1 -1
- package/dist/{renderer-BH7UCMPQ.mjs → renderer-BiNA2wF0.mjs} +2 -2
- package/dist/{renderer-BH7UCMPQ.mjs.map → renderer-BiNA2wF0.mjs.map} +1 -1
- package/dist/{renderer-DVPgWHZw.mjs → renderer-BmoBgTp5.mjs} +3 -3
- package/dist/{renderer-DVPgWHZw.mjs.map → renderer-BmoBgTp5.mjs.map} +1 -1
- package/dist/{renderer-C20efMI0.mjs → renderer-BmqFmCWS.mjs} +3 -3
- package/dist/{renderer-C20efMI0.mjs.map → renderer-BmqFmCWS.mjs.map} +1 -1
- package/dist/{renderer-B0yVUOPP.mjs → renderer-BnVwAObV.mjs} +2 -2
- package/dist/{renderer-B0yVUOPP.mjs.map → renderer-BnVwAObV.mjs.map} +1 -1
- package/dist/{renderer-CP8wLzTU.mjs → renderer-BxttZHme.mjs} +2 -2
- package/dist/{renderer-CP8wLzTU.mjs.map → renderer-BxttZHme.mjs.map} +1 -1
- package/dist/renderer-BzyPdUD1.mjs +5 -0
- package/dist/renderer-C0hM-mtY.mjs +5 -0
- package/dist/renderer-C6cyUTvk.mjs +5 -0
- package/dist/{renderer-BOSZAdgF.mjs → renderer-C8E4XsSg.mjs} +2 -2
- package/dist/{renderer-BOSZAdgF.mjs.map → renderer-C8E4XsSg.mjs.map} +1 -1
- package/dist/renderer-C8zY3pzk.mjs +5 -0
- package/dist/{renderer-DWq9gYRw.mjs → renderer-C9U-LY50.mjs} +3 -3
- package/dist/{renderer-DWq9gYRw.mjs.map → renderer-C9U-LY50.mjs.map} +1 -1
- package/dist/{renderer-Dj2H5JPR.mjs → renderer-CB2JVu5x.mjs} +3 -3
- package/dist/{renderer-Dj2H5JPR.mjs.map → renderer-CB2JVu5x.mjs.map} +1 -1
- package/dist/{renderer-Bcu3UrI-.mjs → renderer-CC4YBJ8Z.mjs} +3 -3
- package/dist/{renderer-Bcu3UrI-.mjs.map → renderer-CC4YBJ8Z.mjs.map} +1 -1
- package/dist/renderer-CEkSOyKu.mjs +5 -0
- package/dist/{renderer-DzLrvCB2.mjs → renderer-CIycc5O-.mjs} +2 -2
- package/dist/{renderer-DzLrvCB2.mjs.map → renderer-CIycc5O-.mjs.map} +1 -1
- package/dist/renderer-CJYtfa4x.mjs +5 -0
- package/dist/{renderer-BeNl_6EG.mjs → renderer-CJraQlV-.mjs} +2 -2
- package/dist/{renderer-BeNl_6EG.mjs.map → renderer-CJraQlV-.mjs.map} +1 -1
- package/dist/renderer-CKMtHGZh.mjs +5 -0
- package/dist/renderer-CLzicoiy.mjs +5 -0
- package/dist/renderer-CM2A4BHd.mjs +5 -0
- package/dist/{renderer-DtMVitEF.mjs → renderer-COWGWtob.mjs} +2 -2
- package/dist/{renderer-DtMVitEF.mjs.map → renderer-COWGWtob.mjs.map} +1 -1
- package/dist/{renderer-CT3zkfbf.mjs → renderer-COxG2XGf.mjs} +2 -2
- package/dist/{renderer-CT3zkfbf.mjs.map → renderer-COxG2XGf.mjs.map} +1 -1
- package/dist/{renderer-DNxWOz8Q.mjs → renderer-CQDCIsQm.mjs} +2 -2
- package/dist/{renderer-DNxWOz8Q.mjs.map → renderer-CQDCIsQm.mjs.map} +1 -1
- package/dist/{renderer-C5AoaymD.mjs → renderer-CRUeag8i.mjs} +3 -3
- package/dist/{renderer-C5AoaymD.mjs.map → renderer-CRUeag8i.mjs.map} +1 -1
- package/dist/{renderer-ngmYIIob.mjs → renderer-CWVput06.mjs} +3 -3
- package/dist/{renderer-ngmYIIob.mjs.map → renderer-CWVput06.mjs.map} +1 -1
- package/dist/renderer-CZlHjcxr.mjs +5 -0
- package/dist/{renderer-0rveCDm-.mjs → renderer-CbbnBLOB.mjs} +3 -3
- package/dist/{renderer-0rveCDm-.mjs.map → renderer-CbbnBLOB.mjs.map} +1 -1
- package/dist/renderer-CbimvSU8.mjs +5 -0
- package/dist/renderer-Ccvc63yd.mjs +5 -0
- package/dist/renderer-Cdp-SGfq.mjs +5 -0
- package/dist/renderer-CeTcSs3e.mjs +5 -0
- package/dist/{renderer-Brmbl12Y.mjs → renderer-CfLZein2.mjs} +3 -3
- package/dist/{renderer-Brmbl12Y.mjs.map → renderer-CfLZein2.mjs.map} +1 -1
- package/dist/{renderer-BJ8ea92W.mjs → renderer-Ch-q1O-q.mjs} +3 -3
- package/dist/{renderer-BJ8ea92W.mjs.map → renderer-Ch-q1O-q.mjs.map} +1 -1
- package/dist/{renderer-CP108ABB.mjs → renderer-Ch5JvJWl.mjs} +2 -2
- package/dist/{renderer-CP108ABB.mjs.map → renderer-Ch5JvJWl.mjs.map} +1 -1
- package/dist/{renderer-47y12Z37.mjs → renderer-ChtEzq-R.mjs} +2 -2
- package/dist/{renderer-47y12Z37.mjs.map → renderer-ChtEzq-R.mjs.map} +1 -1
- package/dist/{renderer-DhyMfG1v.mjs → renderer-Cj9nTC5l.mjs} +3 -3
- package/dist/{renderer-DhyMfG1v.mjs.map → renderer-Cj9nTC5l.mjs.map} +1 -1
- package/dist/{renderer-BDzn1AKF.mjs → renderer-CqT8HsSS.mjs} +2 -2
- package/dist/{renderer-BDzn1AKF.mjs.map → renderer-CqT8HsSS.mjs.map} +1 -1
- package/dist/{renderer-B7G1KohJ.mjs → renderer-CuQjMhdV.mjs} +2 -2
- package/dist/renderer-CvNuu52U.mjs +5 -0
- package/dist/renderer-CwciC0oI.mjs +5 -0
- package/dist/renderer-CysLUbIr.mjs +5 -0
- package/dist/{renderer-Cm0tsbQH.mjs → renderer-Cz30EVws.mjs} +2 -2
- package/dist/{renderer-Cm0tsbQH.mjs.map → renderer-Cz30EVws.mjs.map} +1 -1
- package/dist/renderer-D3A22Vxb.mjs +5 -0
- package/dist/renderer-D5SY9EmA.mjs +5 -0
- package/dist/renderer-D8h3ZvaE.mjs +5 -0
- package/dist/renderer-DE-B6N9n.mjs +5 -0
- package/dist/renderer-DETZTI7t.mjs +5 -0
- package/dist/{renderer-nHS3Sius.mjs → renderer-DHoX-5U_.mjs} +3 -3
- package/dist/{renderer-nHS3Sius.mjs.map → renderer-DHoX-5U_.mjs.map} +1 -1
- package/dist/{renderer-BWSRryIA.mjs → renderer-DOkm0Ycd.mjs} +2 -2
- package/dist/{renderer-BWSRryIA.mjs.map → renderer-DOkm0Ycd.mjs.map} +1 -1
- package/dist/{renderer-BHYJlK6H.d.mts → renderer-DU3f6ZrS.d.mts} +2 -2
- package/dist/{renderer-BHYJlK6H.d.mts.map → renderer-DU3f6ZrS.d.mts.map} +1 -1
- package/dist/{renderer-BpVOk9ux.mjs → renderer-DUzv-shq.mjs} +2 -2
- package/dist/{renderer-BpVOk9ux.mjs.map → renderer-DUzv-shq.mjs.map} +1 -1
- package/dist/renderer-DWnDj0IM.mjs +5 -0
- package/dist/renderer-DcGUIbQF.mjs +5 -0
- package/dist/renderer-Dfq6FoNO.mjs +5 -0
- package/dist/renderer-DhasXW6S.mjs +3 -0
- package/dist/{renderer-NRMlYkX6.mjs → renderer-DhnOWnEA.mjs} +3 -3
- package/dist/{renderer-NRMlYkX6.mjs.map → renderer-DhnOWnEA.mjs.map} +1 -1
- package/dist/{renderer-COgwYqev.mjs → renderer-Dhy1XHzz.mjs} +3 -3
- package/dist/{renderer-COgwYqev.mjs.map → renderer-Dhy1XHzz.mjs.map} +1 -1
- package/dist/renderer-DjCvpsV_.mjs +5 -0
- package/dist/{renderer-BfZNIiSv.mjs → renderer-DjJshz9Y.mjs} +2 -2
- package/dist/{renderer-BfZNIiSv.mjs.map → renderer-DjJshz9Y.mjs.map} +1 -1
- package/dist/{renderer-CKo7VR8x.mjs → renderer-DmTUIdus.mjs} +3 -3
- package/dist/{renderer-CKo7VR8x.mjs.map → renderer-DmTUIdus.mjs.map} +1 -1
- package/dist/{renderer-Baw6Utxi.mjs → renderer-Dq7AioJa.mjs} +2 -2
- package/dist/{renderer-Baw6Utxi.mjs.map → renderer-Dq7AioJa.mjs.map} +1 -1
- package/dist/renderer-DrAaM6JD.mjs +5 -0
- package/dist/{renderer-D-GWBoVT.mjs → renderer-Dt4sqNEu.mjs} +2 -2
- package/dist/{renderer-D-GWBoVT.mjs.map → renderer-Dt4sqNEu.mjs.map} +1 -1
- package/dist/{renderer-FYOL5Za6.mjs → renderer-Dtcs4idV.mjs} +3 -3
- package/dist/{renderer-FYOL5Za6.mjs.map → renderer-Dtcs4idV.mjs.map} +1 -1
- package/dist/renderer-Dxlv8LYm.mjs +5 -0
- package/dist/{renderer-D-RhYvVl.mjs → renderer-Gj8SrE2W.mjs} +2 -2
- package/dist/{renderer-D-RhYvVl.mjs.map → renderer-Gj8SrE2W.mjs.map} +1 -1
- package/dist/{renderer-D_j1WKMD.mjs → renderer-KfnXDJS0.mjs} +3 -3
- package/dist/{renderer-D_j1WKMD.mjs.map → renderer-KfnXDJS0.mjs.map} +1 -1
- package/dist/{renderer-Bpm145BW.mjs → renderer-MXVlg4p5.mjs} +3 -3
- package/dist/{renderer-Bpm145BW.mjs.map → renderer-MXVlg4p5.mjs.map} +1 -1
- package/dist/{renderer-Nnmi8Gt6.mjs → renderer-N2b6QZ1E.mjs} +3 -3
- package/dist/{renderer-Nnmi8Gt6.mjs.map → renderer-N2b6QZ1E.mjs.map} +1 -1
- package/dist/renderer-Pb43OO2t.mjs +5 -0
- package/dist/{renderer-Ca1KjNCO.mjs → renderer-Q7gDzm8c.mjs} +2 -2
- package/dist/{renderer-Ca1KjNCO.mjs.map → renderer-Q7gDzm8c.mjs.map} +1 -1
- package/dist/{renderer-D2wNFNRf.mjs → renderer-RCiANtRV.mjs} +2 -2
- package/dist/{renderer-D2wNFNRf.mjs.map → renderer-RCiANtRV.mjs.map} +1 -1
- package/dist/{renderer-Cqb7PGrI.mjs → renderer-Sig9nZcI.mjs} +2 -2
- package/dist/renderer-VQbm-cGr.mjs +5 -0
- package/dist/{renderer-W1bVNVR6.mjs → renderer-fabBgwQX.mjs} +3 -3
- package/dist/{renderer-W1bVNVR6.mjs.map → renderer-fabBgwQX.mjs.map} +1 -1
- package/dist/{renderer-zRq0j6Xy.mjs → renderer-g-0PCNoo.mjs} +3 -3
- package/dist/{renderer-zRq0j6Xy.mjs.map → renderer-g-0PCNoo.mjs.map} +1 -1
- package/dist/{renderer-2PjR3w-q.mjs → renderer-gmHKIbKI.mjs} +3 -3
- package/dist/{renderer-2PjR3w-q.mjs.map → renderer-gmHKIbKI.mjs.map} +1 -1
- package/dist/{renderer-03mYJLgX.mjs → renderer-kVZwiRoK.mjs} +3 -3
- package/dist/{renderer-03mYJLgX.mjs.map → renderer-kVZwiRoK.mjs.map} +1 -1
- package/dist/renderer-oPMypDM1.mjs +5 -0
- package/dist/{renderer-DcAKDAnS.mjs → renderer-p7tgxP-A.mjs} +3 -3
- package/dist/{renderer-DcAKDAnS.mjs.map → renderer-p7tgxP-A.mjs.map} +1 -1
- package/dist/{renderer-jUKdkmG5.mjs → renderer-tvYj306A.mjs} +81 -78
- package/dist/renderer-tvYj306A.mjs.map +1 -0
- package/dist/renderer-xvWGpVyp.mjs +5 -0
- package/dist/renderer-zafZbD6Q.mjs +5 -0
- package/dist/{renderers-CP8CFWDs-CshljORp.mjs → renderers-CP8CFWDs-DLjtjrwx.mjs} +2 -2
- package/dist/{renderers-CP8CFWDs-CshljORp.mjs.map → renderers-CP8CFWDs-DLjtjrwx.mjs.map} +1 -1
- package/dist/sam/index.d.mts +2 -2
- package/dist/sam/index.mjs +1 -1
- package/dist/signals/index.d.mts +4 -4
- package/dist/signals/index.mjs +4 -4
- package/dist/{src-BU6vm9sP-DdTHmCr4.mjs → src-B23p_eh7-Cj6-lvV6.mjs} +293 -6
- package/dist/src-B23p_eh7-Cj6-lvV6.mjs.map +1 -0
- package/dist/{src-Dy4gnc6w.mjs → src-CoHAjviq.mjs} +1349 -177
- package/dist/src-CoHAjviq.mjs.map +1 -0
- package/dist/storage/index.mjs +1 -1
- package/package.json +63 -60
- package/dist/dist--Uu5bQ_6.mjs.map +0 -1
- package/dist/dist-CiTgmfUw.mjs.map +0 -1
- package/dist/fonts-OW3yAfO5.mjs.map +0 -1
- package/dist/index-9xte4JgL.d.mts.map +0 -1
- package/dist/index-Bv7gxGK1.d.mts.map +0 -1
- package/dist/index-C5sgRLlG.d.mts.map +0 -1
- package/dist/index-C7-p9zwU.d.mts.map +0 -1
- package/dist/index-CRaydvLi.d.mts.map +0 -1
- package/dist/index-D1FqV1eu.d.mts.map +0 -1
- package/dist/preview-D7BGmE1E.mjs +0 -2446
- package/dist/preview-D7BGmE1E.mjs.map +0 -1
- package/dist/preview-engine/chunk-5DZTPUMH.mjs +0 -2568
- package/dist/preview-engine/chunk-NCQHOGZK.mjs +0 -3
- package/dist/preview-engine/chunk-PH3UUX6A.mjs +0 -138
- package/dist/preview-engine/chunk-UPZURPJY.mjs +0 -2227
- package/dist/preview-engine/renderers-DLJOA3BM.mjs +0 -228
- package/dist/program-tFKCWU2j.mjs.map +0 -1
- package/dist/renderer-6_bzbbXt.mjs +0 -5
- package/dist/renderer-8M-9G6F_.mjs +0 -5
- package/dist/renderer-B5OzKvF8.mjs +0 -5
- package/dist/renderer-BBCZ2qbE.mjs +0 -5
- package/dist/renderer-BChbxCux.mjs +0 -5
- package/dist/renderer-BGeMPr8C.mjs +0 -5
- package/dist/renderer-BPQ8Pkjb.mjs +0 -5
- package/dist/renderer-BTRpA3HD.mjs +0 -5
- package/dist/renderer-BVIXKfbC.mjs.map +0 -1
- package/dist/renderer-BVsECSn-.mjs +0 -5
- package/dist/renderer-Bgos68gc.mjs +0 -6
- package/dist/renderer-BjHOvoqO.mjs +0 -5
- package/dist/renderer-BjXMPPlV.mjs +0 -5
- package/dist/renderer-Byobxqkv.mjs +0 -5
- package/dist/renderer-CKrsg3EG.mjs +0 -5
- package/dist/renderer-Cj875NuH.mjs +0 -5
- package/dist/renderer-CnmzJoMv.mjs +0 -5
- package/dist/renderer-CtklDaMg.mjs +0 -5
- package/dist/renderer-D1tK3in_.mjs +0 -5
- package/dist/renderer-D2yc9P61.mjs +0 -5
- package/dist/renderer-D4v-JvSr.mjs +0 -5
- package/dist/renderer-D5yp74NL.mjs +0 -3
- package/dist/renderer-D7WRWDwB.mjs +0 -5
- package/dist/renderer-DGvA0tdB.mjs +0 -5
- package/dist/renderer-DO7v5Sdm.mjs +0 -5
- package/dist/renderer-DRVvt7-V.mjs +0 -5
- package/dist/renderer-DYMCd3jL.mjs +0 -5
- package/dist/renderer-DmHKw-MM.mjs +0 -5
- package/dist/renderer-DoDsuZ6G.mjs +0 -5
- package/dist/renderer-EpgclS70.mjs +0 -5
- package/dist/renderer-GroKiYyK.mjs +0 -5
- package/dist/renderer-MQ5K_xIS.mjs +0 -5
- package/dist/renderer-U43SflML.mjs +0 -5
- package/dist/renderer-UqOmBgCv.mjs +0 -5
- package/dist/renderer-XLULgJM0.mjs +0 -5
- package/dist/renderer-jUKdkmG5.mjs.map +0 -1
- package/dist/renderer-lNjxY1GG.mjs +0 -5
- package/dist/renderer-ukufL7pl.mjs +0 -5
- package/dist/renderer-wb0NCKdF.mjs +0 -5
- package/dist/src-BU6vm9sP-DdTHmCr4.mjs.map +0 -1
- package/dist/src-Dy4gnc6w.mjs.map +0 -1
|
@@ -1,83 +1,29 @@
|
|
|
1
1
|
import "./chunk-DOL2i2sR.mjs";
|
|
2
2
|
import { It as getActiveMediaMetadata, _n as reportRenderDiagnostic, p as DEFAULT_DURATION_MS, rn as mediaSourceTime, vn as resolveBoolean, xn as resolveNumber } from "./dist-C8XSqfTx.mjs";
|
|
3
3
|
import { i as effectReach, n as defineRenderer, r as effectMaxPixelScale, s as resolveFrameNumber, t as audioRegistry, u as solveHomography } from "./renderer-BuvKGwk3.mjs";
|
|
4
|
-
import { $ as
|
|
5
|
-
import { a as createFullscreenPipeline, l as fragmentBindGroupLayout, n as PREMULTIPLIED_BLEND, t as FULLSCREEN_QUAD_WGSL } from "./gpu-
|
|
6
|
-
import { i as keyedGain, m as measureText, n as decodeAudioSource, s as resolveLayerDuration } from "./dist-
|
|
4
|
+
import { $ as measureMaxCaptionHeight, B as fractureModel, Dt as resolveMediaSourceUrl, Ft as Light3D, J as jointMatrices, Kt as defaultCubeFaceSize, Lt as Matrix4Math, S as blendClipLayers, Tt as trsMatrix, U as getPrimitiveGeometry, Ut as createRandom, V as generateExtrudedTextGeometry, Vt as cameraBasis, Wt as cubeFaceCameras, Zt as lensCenterDensity, _ as SpringBones, a as FRACTURE_INTERIOR_MATERIAL, b as applyConstraints, bt as srtLoader, f as ScreenSpaceRelightPipeline, ft as resolveTextSpans, gt as seatOnSurface, ht as scatterOnSurface, kt as Camera3D, m as SlugFontCache, mt as sampleMorphWeights, n as AudioLatentTrackCache, nt as parseDashArray, pt as rotateByQuat, st as poseNodes, tt as parseColor, u as Renderer3D, ut as resolveClips, wt as transformScale, x as bakeCrowdPalette, yt as spansText, z as fitSpansToText, zt as Vector3Math } from "./dist-XqlFM2a8.mjs";
|
|
5
|
+
import { a as createFullscreenPipeline, l as fragmentBindGroupLayout, n as PREMULTIPLIED_BLEND, t as FULLSCREEN_QUAD_WGSL } from "./gpu-CH1PdM4T.mjs";
|
|
6
|
+
import { i as keyedGain, m as measureText, n as decodeAudioSource, s as resolveLayerDuration } from "./dist-COOpgG9G.mjs";
|
|
7
7
|
import { o as TemporalDeflickerPipeline } from "./dist-DgZpN6IK.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { B as collectNodeOps, U as computeLayout, Y as initLayout, Z as mappedEase, et as numberAt, it as vec3At, q as evaluateTrackAtFrame, rt as sampleTrack } from "./program-CMigyfso.mjs";
|
|
9
9
|
import gsapModule from "gsap";
|
|
10
10
|
|
|
11
|
-
//#region ../../nodes/node-compositor/dist/renderers-
|
|
12
|
-
/**
|
|
13
|
-
* Solves a cubic bezier curve defined by control points (x1, y1) and (x2, y2)
|
|
14
|
-
* for a given progress parameter t in [0, 1].
|
|
15
|
-
*/
|
|
16
|
-
function solveCubicBezier(x1, y1, x2, y2, t) {
|
|
17
|
-
if (t <= 0) return 0;
|
|
18
|
-
if (t >= 1) return 1;
|
|
19
|
-
if (x1 === y1 && x2 === y2) return t;
|
|
20
|
-
let u = t;
|
|
21
|
-
for (let i = 0; i < 8; i++) {
|
|
22
|
-
const oneMinusU$1 = 1 - u;
|
|
23
|
-
const oneMinusU2 = oneMinusU$1 * oneMinusU$1;
|
|
24
|
-
const u2 = u * u;
|
|
25
|
-
const diff = 3 * oneMinusU2 * u * x1 + 3 * oneMinusU$1 * u2 * x2 + u2 * u - t;
|
|
26
|
-
if (Math.abs(diff) < 1e-6) break;
|
|
27
|
-
const dx = 3 * oneMinusU2 * x1 + 6 * oneMinusU$1 * u * (x2 - x1) + 3 * u2 * (1 - x2);
|
|
28
|
-
if (Math.abs(dx) < 1e-6) break;
|
|
29
|
-
u -= diff / dx;
|
|
30
|
-
u = Math.max(0, Math.min(1, u));
|
|
31
|
-
}
|
|
32
|
-
const oneMinusU = 1 - u;
|
|
33
|
-
const checkX = 3 * oneMinusU * oneMinusU * u * x1 + 3 * oneMinusU * u * u * x2 + u * u * u;
|
|
34
|
-
if (Math.abs(checkX - t) > .001) {
|
|
35
|
-
let low = 0;
|
|
36
|
-
let high = 1;
|
|
37
|
-
u = t;
|
|
38
|
-
for (let i = 0; i < 16; i++) {
|
|
39
|
-
const mid = (low + high) * .5;
|
|
40
|
-
const oMid = 1 - mid;
|
|
41
|
-
const xMid = 3 * oMid * oMid * mid * x1 + 3 * oMid * mid * mid * x2 + mid * mid * mid;
|
|
42
|
-
if (Math.abs(xMid - t) < 1e-5) {
|
|
43
|
-
u = mid;
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
if (xMid < t) low = mid;
|
|
47
|
-
else high = mid;
|
|
48
|
-
u = mid;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
const oU = 1 - u;
|
|
52
|
-
return 3 * oU * oU * u * y1 + 3 * oU * u * u * y2 + u * u * u;
|
|
53
|
-
}
|
|
11
|
+
//#region ../../nodes/node-compositor/dist/renderers-CrRYcARA.mjs
|
|
54
12
|
const gsap = gsapModule.timeline ? gsapModule : gsapModule.default || gsapModule;
|
|
55
|
-
/** GSAP's shaping for a keyframe segment, so draw-time tracks ease like baked ones. */
|
|
56
|
-
function gsapEase(fps) {
|
|
57
|
-
return (ease, deltaFrames, t) => {
|
|
58
|
-
const e = mappedEase(ease, deltaFrames, fps);
|
|
59
|
-
const fn = typeof e === "function" ? e : gsap.parseEase(e);
|
|
60
|
-
return fn ? fn(t) : t;
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
function evaluateLive(live, frame, fps, signals) {
|
|
64
|
-
if ((live.track.source ?? { type: "keyframe" }).type === "keyframe") return evaluateKeyframes(live.track, frame - live.startFrame, gsapEase(fps));
|
|
65
|
-
return evaluateTrackAtFrame(live.track, frame, fps, {
|
|
66
|
-
startFrame: live.startFrame,
|
|
67
|
-
baseValues: live.stub,
|
|
68
|
-
signals
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
13
|
/** Seeks the compiled timeline to a frame and applies its live signal tracks. */
|
|
72
14
|
function seekTimeline(result, frame, fps) {
|
|
73
15
|
result.tl.seek(frame / fps);
|
|
74
16
|
for (const live of result.live) {
|
|
75
17
|
let f = Math.max(live.startFrame, Math.min(live.endFrame, frame));
|
|
76
18
|
if (live.step && live.step > 1) f = live.startFrame + Math.floor((f - live.startFrame) / live.step) * live.step;
|
|
77
|
-
live.stub[live.track.prop] =
|
|
19
|
+
live.stub[live.track.prop] = sampleTrack(live.track, f, fps, {
|
|
20
|
+
startFrame: live.startFrame,
|
|
21
|
+
base: live.stub,
|
|
22
|
+
signals: result.signals
|
|
23
|
+
});
|
|
78
24
|
}
|
|
79
25
|
}
|
|
80
|
-
const cache = /* @__PURE__ */ new Map();
|
|
26
|
+
const cache$1 = /* @__PURE__ */ new Map();
|
|
81
27
|
const nodesHashMemo = /* @__PURE__ */ new WeakMap();
|
|
82
28
|
/** Entries untouched for this long are dropped (and their timeline killed). */
|
|
83
29
|
const CACHE_TTL_MS = 1e4;
|
|
@@ -121,17 +67,17 @@ function release(value) {
|
|
|
121
67
|
* the least-recently-used entry if the cache is at capacity. Every dropped
|
|
122
68
|
* timeline MUST be killed — see `release`.
|
|
123
69
|
*/
|
|
124
|
-
function evictForInsert(cache$
|
|
70
|
+
function evictForInsert(cache$2, maxSize) {
|
|
125
71
|
const now = Date.now();
|
|
126
|
-
for (const [key, entry] of cache$
|
|
127
|
-
cache$
|
|
72
|
+
for (const [key, entry] of cache$2.entries()) if (now - entry.cacheTime > CACHE_TTL_MS) {
|
|
73
|
+
cache$2.delete(key);
|
|
128
74
|
release(entry.value);
|
|
129
75
|
}
|
|
130
|
-
if (cache$
|
|
131
|
-
const oldestKey = cache$
|
|
76
|
+
if (cache$2.size >= maxSize) {
|
|
77
|
+
const oldestKey = cache$2.keys().next().value;
|
|
132
78
|
if (oldestKey !== void 0) {
|
|
133
|
-
const oldest = cache$
|
|
134
|
-
cache$
|
|
79
|
+
const oldest = cache$2.get(oldestKey);
|
|
80
|
+
cache$2.delete(oldestKey);
|
|
135
81
|
if (oldest) release(oldest.value);
|
|
136
82
|
}
|
|
137
83
|
}
|
|
@@ -147,76 +93,26 @@ function stableStringify(obj) {
|
|
|
147
93
|
}).join(",") + "}";
|
|
148
94
|
}
|
|
149
95
|
function getCachedTimeline(cacheKey) {
|
|
150
|
-
const entry = cache.get(cacheKey);
|
|
96
|
+
const entry = cache$1.get(cacheKey);
|
|
151
97
|
if (entry) {
|
|
152
98
|
if (Date.now() - entry.cacheTime > CACHE_TTL_MS) {
|
|
153
|
-
cache.delete(cacheKey);
|
|
99
|
+
cache$1.delete(cacheKey);
|
|
154
100
|
release(entry.value);
|
|
155
101
|
return;
|
|
156
102
|
}
|
|
157
103
|
entry.cacheTime = Date.now();
|
|
158
|
-
cache.delete(cacheKey);
|
|
159
|
-
cache.set(cacheKey, entry);
|
|
104
|
+
cache$1.delete(cacheKey);
|
|
105
|
+
cache$1.set(cacheKey, entry);
|
|
160
106
|
return entry.value;
|
|
161
107
|
}
|
|
162
108
|
}
|
|
163
109
|
function setCachedTimeline(cacheKey, value) {
|
|
164
|
-
evictForInsert(cache, TIMELINE_CACHE_MAX);
|
|
165
|
-
cache.set(cacheKey, {
|
|
110
|
+
evictForInsert(cache$1, TIMELINE_CACHE_MAX);
|
|
111
|
+
cache$1.set(cacheKey, {
|
|
166
112
|
cacheTime: Date.now(),
|
|
167
113
|
value
|
|
168
114
|
});
|
|
169
115
|
}
|
|
170
|
-
function mappedEase(ease, durationFrames, fps = 24) {
|
|
171
|
-
if (!ease) return "none";
|
|
172
|
-
const { name, dir, params } = ease;
|
|
173
|
-
if (name === "none") return "none";
|
|
174
|
-
if (name === "spring") {
|
|
175
|
-
const damping = Math.max(.001, params?.[0] ?? 10);
|
|
176
|
-
const stiffness = Math.max(.001, params?.[1] ?? 100);
|
|
177
|
-
const mass = Math.max(.001, params?.[2] ?? 1);
|
|
178
|
-
return (p) => {
|
|
179
|
-
const t = p * (durationFrames && durationFrames > 0 ? durationFrames / (fps > 0 ? fps : 24) : 1);
|
|
180
|
-
const m = mass;
|
|
181
|
-
const k = stiffness;
|
|
182
|
-
const c = damping;
|
|
183
|
-
const w0 = Math.sqrt(k / m);
|
|
184
|
-
const zeta = c / (2 * Math.sqrt(k * m));
|
|
185
|
-
let x = 0;
|
|
186
|
-
if (zeta < 1) {
|
|
187
|
-
const wd = w0 * Math.sqrt(1 - zeta * zeta);
|
|
188
|
-
const A = -1;
|
|
189
|
-
const B = -zeta * w0 / wd;
|
|
190
|
-
x = Math.exp(-zeta * w0 * t) * (A * Math.cos(wd * t) + B * Math.sin(wd * t));
|
|
191
|
-
} else if (zeta === 1) {
|
|
192
|
-
const A = -1;
|
|
193
|
-
const B = -w0;
|
|
194
|
-
x = Math.exp(-w0 * t) * (A + B * t);
|
|
195
|
-
} else {
|
|
196
|
-
const r1 = -w0 * (zeta - Math.sqrt(zeta * zeta - 1));
|
|
197
|
-
const r2 = -w0 * (zeta + Math.sqrt(zeta * zeta - 1));
|
|
198
|
-
const C1 = -1 / (1 - r1 / r2);
|
|
199
|
-
const C2 = -1 - C1;
|
|
200
|
-
x = C1 * Math.exp(r1 * t) + C2 * Math.exp(r2 * t);
|
|
201
|
-
}
|
|
202
|
-
return 1 + x;
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
if (name === "cubic") {
|
|
206
|
-
const x1 = params?.[0] ?? .25;
|
|
207
|
-
const y1 = params?.[1] ?? .1;
|
|
208
|
-
const x2 = params?.[2] ?? .25;
|
|
209
|
-
const y2 = params?.[3] ?? 1;
|
|
210
|
-
return (p) => solveCubicBezier(x1, y1, x2, y2, p);
|
|
211
|
-
}
|
|
212
|
-
if (name === "hold") return (p) => p >= .9999 ? 1 : 0;
|
|
213
|
-
const easeName = name;
|
|
214
|
-
let suffix = "";
|
|
215
|
-
if (params && params.length > 0) suffix = `(${params.join(", ")})`;
|
|
216
|
-
else if (name === "back") suffix = "(1.7)";
|
|
217
|
-
else if (name === "elastic") suffix = "(1, 0.3)";
|
|
218
|
-
return `${easeName}.${dir}${suffix}`;
|
|
219
|
-
}
|
|
220
116
|
/** Props that switch rather than tween: each key is a set from its frame on. */
|
|
221
117
|
const DISCRETE_PROPS = new Set(["hidden", "muted"]);
|
|
222
118
|
function compileTrackToTimeline(tl, stub, track, startFrame, fps, durationFrames, signals, live, step) {
|
|
@@ -231,7 +127,11 @@ function compileTrackToTimeline(tl, stub, track, startFrame, fps, durationFrames
|
|
|
231
127
|
endFrame: startFrame + (Number.isFinite(durationFrames) ? durationFrames : Math.round(fps * 5)),
|
|
232
128
|
...stepped && { step }
|
|
233
129
|
};
|
|
234
|
-
stub[prop] =
|
|
130
|
+
stub[prop] = sampleTrack(track, startFrame, fps, {
|
|
131
|
+
startFrame,
|
|
132
|
+
base: stub,
|
|
133
|
+
signals
|
|
134
|
+
});
|
|
235
135
|
live.push(entry);
|
|
236
136
|
return {
|
|
237
137
|
dropped: 0,
|
|
@@ -366,6 +266,28 @@ function compileTrackToTimeline(tl, stub, track, startFrame, fps, durationFrames
|
|
|
366
266
|
maxAuthoredFrame
|
|
367
267
|
};
|
|
368
268
|
}
|
|
269
|
+
/** A camera's `x` / `y` / `z` are its eye, the same as `cameraX` / `cameraY` / `cameraZ`. */
|
|
270
|
+
const CAMERA_EYE = {
|
|
271
|
+
x: "cameraX",
|
|
272
|
+
y: "cameraY",
|
|
273
|
+
z: "cameraZ"
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* A layer's tracks, with a camera's `x` / `y` / `z` tracks driving its eye:
|
|
277
|
+
* the eye is read from `cameraX` / `cameraY` / `cameraZ`, which the static
|
|
278
|
+
* `x` / `y` / `z` seed, so a track left on `x` would never move it.
|
|
279
|
+
*/
|
|
280
|
+
function layerTracks(lop) {
|
|
281
|
+
const tracks = lop.animation?.tracks ?? [];
|
|
282
|
+
if (lop.kind !== "camera") return tracks;
|
|
283
|
+
return tracks.map((t) => {
|
|
284
|
+
const eye = CAMERA_EYE[t.prop];
|
|
285
|
+
return eye ? {
|
|
286
|
+
...t,
|
|
287
|
+
prop: eye
|
|
288
|
+
} : t;
|
|
289
|
+
});
|
|
290
|
+
}
|
|
369
291
|
/**
|
|
370
292
|
* Dedupe per compiled cache key — a fresh render of the same broken doc SHOULD
|
|
371
293
|
* re-warn. Single-frame renders are the exception: each `renderFrame` call has
|
|
@@ -434,6 +356,7 @@ function hashNodes(nodeOps, width, height, fps, durationSec) {
|
|
|
434
356
|
maxBlurRadius: lop.maxBlurRadius,
|
|
435
357
|
shakeTranslation: lop.shakeTranslation,
|
|
436
358
|
shakeRotation: lop.shakeRotation,
|
|
359
|
+
relativitySpeed: lop.relativitySpeed,
|
|
437
360
|
orbitRadius: lop.orbitRadius,
|
|
438
361
|
orbitAzimuth: lop.orbitAzimuth,
|
|
439
362
|
orbitElevation: lop.orbitElevation,
|
|
@@ -443,11 +366,35 @@ function hashNodes(nodeOps, width, height, fps, durationSec) {
|
|
|
443
366
|
specularIntensity: lop.specularIntensity,
|
|
444
367
|
ambientIntensity: lop.ambientIntensity,
|
|
445
368
|
metallic: lop.metallic,
|
|
369
|
+
emissive: lop.emissive,
|
|
370
|
+
emissiveIntensity: lop.emissiveIntensity,
|
|
371
|
+
clearcoat: lop.clearcoat,
|
|
372
|
+
clearcoatRoughness: lop.clearcoatRoughness,
|
|
373
|
+
anisotropy: lop.anisotropy,
|
|
374
|
+
anisotropyRotation: lop.anisotropyRotation,
|
|
375
|
+
subsurface: lop.subsurface,
|
|
376
|
+
subsurfaceColor: lop.subsurfaceColor,
|
|
377
|
+
sheen: lop.sheen,
|
|
378
|
+
sheenColor: lop.sheenColor,
|
|
379
|
+
sheenRoughness: lop.sheenRoughness,
|
|
380
|
+
iridescence: lop.iridescence,
|
|
381
|
+
iridescenceThickness: lop.iridescenceThickness,
|
|
382
|
+
iridescenceIor: lop.iridescenceIor,
|
|
383
|
+
triplanar: lop.triplanar,
|
|
384
|
+
triplanarScale: lop.triplanarScale,
|
|
385
|
+
triplanarSharpness: lop.triplanarSharpness,
|
|
446
386
|
lightType: lop.lightType,
|
|
387
|
+
color: lop.color,
|
|
447
388
|
intensity: lop.intensity,
|
|
448
389
|
radius: lop.radius,
|
|
449
390
|
angle: lop.angle,
|
|
450
391
|
penumbra: lop.penumbra,
|
|
392
|
+
exposure: lop.exposure,
|
|
393
|
+
hdri: typeof lop.hdri === "string" ? lop.hdri : Boolean(lop.hdri),
|
|
394
|
+
volumetricFog: lop.volumetricFog,
|
|
395
|
+
volumetricFogDensity: lop.volumetricFogDensity,
|
|
396
|
+
volumetricFogAnisotropy: lop.volumetricFogAnisotropy,
|
|
397
|
+
volumetricFogNoiseStrength: lop.volumetricFogNoiseStrength,
|
|
451
398
|
animationProgress: lop.animationProgress,
|
|
452
399
|
animationTime: lop.animationTime,
|
|
453
400
|
animationSpeed: lop.animationSpeed,
|
|
@@ -540,13 +487,30 @@ function compileTimeline(renderId, virtualMedia, options) {
|
|
|
540
487
|
is3D: lop.is3D ?? (lop.kind === "camera" || lop.kind === "light" || lop.kind === "model3d" ? true : false),
|
|
541
488
|
z: lop.z ?? (lop.kind === "camera" ? lop.z ?? -1500 : 0),
|
|
542
489
|
scaleZ: lop.scaleZ ?? 1,
|
|
543
|
-
twoSided: lop.twoSided ??
|
|
490
|
+
twoSided: lop.twoSided ?? lop.kind !== "light",
|
|
544
491
|
material: lop.material,
|
|
545
492
|
shininess: lop.shininess,
|
|
546
493
|
roughness: lop.roughness,
|
|
547
494
|
specularIntensity: lop.specularIntensity,
|
|
548
495
|
ambientIntensity: lop.ambientIntensity,
|
|
549
496
|
metallic: lop.metallic,
|
|
497
|
+
emissive: lop.emissive,
|
|
498
|
+
emissiveIntensity: lop.emissiveIntensity,
|
|
499
|
+
clearcoat: lop.clearcoat,
|
|
500
|
+
clearcoatRoughness: lop.clearcoatRoughness,
|
|
501
|
+
anisotropy: lop.anisotropy,
|
|
502
|
+
anisotropyRotation: lop.anisotropyRotation,
|
|
503
|
+
subsurface: lop.subsurface,
|
|
504
|
+
subsurfaceColor: lop.subsurfaceColor,
|
|
505
|
+
sheen: lop.sheen,
|
|
506
|
+
sheenColor: lop.sheenColor,
|
|
507
|
+
sheenRoughness: lop.sheenRoughness,
|
|
508
|
+
iridescence: lop.iridescence,
|
|
509
|
+
iridescenceThickness: lop.iridescenceThickness,
|
|
510
|
+
iridescenceIor: lop.iridescenceIor,
|
|
511
|
+
triplanar: lop.triplanar,
|
|
512
|
+
triplanarScale: lop.triplanarScale,
|
|
513
|
+
triplanarSharpness: lop.triplanarSharpness,
|
|
550
514
|
animationProgress: lop.animationProgress ?? 0,
|
|
551
515
|
animationTime: lop.animationTime ?? 0,
|
|
552
516
|
animationSpeed: lop.animationSpeed ?? 1,
|
|
@@ -570,17 +534,23 @@ function compileTimeline(renderId, virtualMedia, options) {
|
|
|
570
534
|
maxBlurRadius: lop.maxBlurRadius ?? lop.dof?.maxBlurRadius ?? 24,
|
|
571
535
|
shakeTranslation: lop.shakeTranslation ?? (lop.shake?.enabled ? lop.shake?.translationAmplitude ?? 0 : 0),
|
|
572
536
|
shakeRotation: lop.shakeRotation ?? (lop.shake?.enabled ? lop.shake?.rotationAmplitude ?? 0 : 0),
|
|
537
|
+
relativitySpeed: lop.relativitySpeed ?? lop.relativity?.speed ?? 0,
|
|
573
538
|
orbitRadius: lop.orbitRadius,
|
|
574
539
|
orbitAzimuth: lop.orbitAzimuth,
|
|
575
540
|
orbitElevation: lop.orbitElevation,
|
|
576
541
|
lightType: lop.lightType,
|
|
542
|
+
color: lop.color,
|
|
577
543
|
intensity: lop.intensity ?? (lop.kind === "light" ? 1 : void 0),
|
|
578
544
|
radius: lop.radius,
|
|
579
545
|
angle: lop.angle,
|
|
580
546
|
penumbra: lop.penumbra,
|
|
581
|
-
decay: lop.decay
|
|
547
|
+
decay: lop.decay,
|
|
548
|
+
exposure: lop.exposure,
|
|
549
|
+
volumetricFogDensity: lop.volumetricFogDensity,
|
|
550
|
+
volumetricFogAnisotropy: lop.volumetricFogAnisotropy,
|
|
551
|
+
volumetricFogNoiseStrength: lop.volumetricFogNoiseStrength
|
|
582
552
|
};
|
|
583
|
-
for (const track of lop
|
|
553
|
+
for (const track of layerTracks(lop)) if ((track.source ?? { type: "keyframe" }).type !== "keyframe") stub[track.prop] = evaluateTrackAtFrame(track, lop.startFrame ?? 0, fps, {
|
|
584
554
|
startFrame: lop.startFrame ?? 0,
|
|
585
555
|
baseValues: stub,
|
|
586
556
|
signals
|
|
@@ -610,7 +580,7 @@ function compileTimeline(renderId, virtualMedia, options) {
|
|
|
610
580
|
const durationMs = resolveLayerDuration(void 0, childMeta?.durationMs ?? void 0, composeDuration, layerType);
|
|
611
581
|
durationFrames = Math.max(1, Math.round(durationMs / 1e3 * fps));
|
|
612
582
|
}
|
|
613
|
-
for (const track of lop
|
|
583
|
+
for (const track of layerTracks(lop)) {
|
|
614
584
|
const { dropped, maxAuthoredFrame } = compileTrackToTimeline(tl, stub, track, startFrame, fps, durationFrames, signals, live, lop.animation?.frameStep);
|
|
615
585
|
if (dropped > 0) truncations.push({
|
|
616
586
|
layerId,
|
|
@@ -633,6 +603,7 @@ function compileTimeline(renderId, virtualMedia, options) {
|
|
|
633
603
|
tl.seek(1e-6);
|
|
634
604
|
tl.seek(0);
|
|
635
605
|
const compileResult = {
|
|
606
|
+
key: cacheKey,
|
|
636
607
|
tl,
|
|
637
608
|
targetsById,
|
|
638
609
|
nodes: nodeOps,
|
|
@@ -687,6 +658,232 @@ function compileLayerTimeline(layerId, animation, baseVolume, baseMuted, fps) {
|
|
|
687
658
|
return result;
|
|
688
659
|
}
|
|
689
660
|
/**
|
|
661
|
+
* Character animation for the compositor: poses a model from its clip
|
|
662
|
+
* layers, look-at and IK constraints (targets in scene coordinates) and
|
|
663
|
+
* spring bones (replayed from frame 0 and cached, so frames render the
|
|
664
|
+
* same in any order); and the per-instance records of skinned crowds.
|
|
665
|
+
*/
|
|
666
|
+
const transformPoint$1 = (m, p) => [
|
|
667
|
+
m[0] * p[0] + m[4] * p[1] + m[8] * p[2] + m[12],
|
|
668
|
+
m[1] * p[0] + m[5] * p[1] + m[9] * p[2] + m[13],
|
|
669
|
+
m[2] * p[0] + m[6] * p[1] + m[10] * p[2] + m[14]
|
|
670
|
+
];
|
|
671
|
+
const transformDir = (m, v) => [
|
|
672
|
+
m[0] * v[0] + m[4] * v[1] + m[8] * v[2],
|
|
673
|
+
m[1] * v[0] + m[5] * v[1] + m[9] * v[2],
|
|
674
|
+
m[2] * v[0] + m[6] * v[1] + m[10] * v[2]
|
|
675
|
+
];
|
|
676
|
+
/**
|
|
677
|
+
* A mesh's morph weights: the clip's (or the file's defaults), with any
|
|
678
|
+
* target the layer names in `morphs` set from its track. Names match
|
|
679
|
+
* case-insensitively against the mesh's `morphTargetNames`.
|
|
680
|
+
*/
|
|
681
|
+
function namedMorphWeights(names, base, morphs, clock) {
|
|
682
|
+
if (!morphs || !names?.length) return base;
|
|
683
|
+
const out = [...base];
|
|
684
|
+
const index = new Map(names.map((n, i) => [n.toLowerCase(), i]));
|
|
685
|
+
for (const [name, track] of Object.entries(morphs)) {
|
|
686
|
+
const i = index.get(name.toLowerCase());
|
|
687
|
+
if (i !== void 0) out[i] = numberAt(track, clock, out[i] ?? 0);
|
|
688
|
+
}
|
|
689
|
+
return out;
|
|
690
|
+
}
|
|
691
|
+
/** Whether a node needs the rig evaluator (anything beyond one plain clip). */
|
|
692
|
+
function hasRig(n) {
|
|
693
|
+
return Boolean(n.animationLayers?.length || n.ik?.length || n.lookAt?.length || n.springBones?.length || n.pose && Object.keys(n.pose).length || n.aim?.length || n.drive?.length);
|
|
694
|
+
}
|
|
695
|
+
/** Local rotation for Euler degrees, applied Z, then Y, then X (R = Rz · Ry · Rx), like layers. */
|
|
696
|
+
function eulerQuat(rx, ry, rz) {
|
|
697
|
+
const h = (d) => d * Math.PI / 360;
|
|
698
|
+
const [sx, cx] = [Math.sin(h(rx)), Math.cos(h(rx))];
|
|
699
|
+
const [sy, cy] = [Math.sin(h(ry)), Math.cos(h(ry))];
|
|
700
|
+
const [sz, cz] = [Math.sin(h(rz)), Math.cos(h(rz))];
|
|
701
|
+
return [
|
|
702
|
+
cz * cy * sx - sz * sy * cx,
|
|
703
|
+
cz * sy * cx + sz * cy * sx,
|
|
704
|
+
sz * cy * cx - cz * sy * sx,
|
|
705
|
+
cz * cy * cx + sz * sy * sx
|
|
706
|
+
];
|
|
707
|
+
}
|
|
708
|
+
function jointPoses(p, clock) {
|
|
709
|
+
return Object.entries(p.node.pose ?? {}).map(([joint, j]) => ({
|
|
710
|
+
joint,
|
|
711
|
+
rotation: eulerQuat(numberAt(j.rotateX, clock, 0), numberAt(j.rotateY, clock, 0), numberAt(j.rotateZ, clock, 0)),
|
|
712
|
+
offset: [
|
|
713
|
+
numberAt(j.x, clock, 0),
|
|
714
|
+
numberAt(j.y, clock, 0),
|
|
715
|
+
numberAt(j.z, clock, 0)
|
|
716
|
+
],
|
|
717
|
+
weight: numberAt(j.weight, clock, 1),
|
|
718
|
+
mode: j.mode ?? "additive"
|
|
719
|
+
}));
|
|
720
|
+
}
|
|
721
|
+
function clipLayers(p, frame) {
|
|
722
|
+
const layers = p.node.animationLayers;
|
|
723
|
+
if (!layers?.length) return p.clip ? [{
|
|
724
|
+
clip: p.clip,
|
|
725
|
+
time: p.clipSec,
|
|
726
|
+
weight: 1
|
|
727
|
+
}] : [];
|
|
728
|
+
const out = [];
|
|
729
|
+
for (const l of layers) {
|
|
730
|
+
const [clip] = resolveClips(p.model, [l.clip]);
|
|
731
|
+
if (!clip) continue;
|
|
732
|
+
let time = (l.timeOffset ?? 0) + frame / p.fps * (l.speed ?? 1);
|
|
733
|
+
if (clip.duration > 0) time = l.loop ?? true ? (time % clip.duration + clip.duration) % clip.duration : Math.min(Math.max(time, 0), clip.duration);
|
|
734
|
+
out.push({
|
|
735
|
+
clip,
|
|
736
|
+
time,
|
|
737
|
+
weight: numberAt(l.weight, {
|
|
738
|
+
frame,
|
|
739
|
+
fps: p.fps
|
|
740
|
+
}, 1),
|
|
741
|
+
mask: l.mask
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
return out;
|
|
745
|
+
}
|
|
746
|
+
function constraintsAt(p, frame, toModel) {
|
|
747
|
+
const clock = {
|
|
748
|
+
frame,
|
|
749
|
+
fps: p.fps
|
|
750
|
+
};
|
|
751
|
+
const point = (t) => transformPoint$1(toModel, vec3At(t, clock));
|
|
752
|
+
const direction = (t) => transformDir(toModel, vec3At(t, clock));
|
|
753
|
+
return {
|
|
754
|
+
pose: jointPoses(p, clock),
|
|
755
|
+
aim: (p.node.aim ?? []).map((a) => ({
|
|
756
|
+
joint: a.joint,
|
|
757
|
+
direction: direction(a.direction),
|
|
758
|
+
weight: numberAt(a.weight, clock, 1),
|
|
759
|
+
...a.axis && { axis: a.axis }
|
|
760
|
+
})),
|
|
761
|
+
ik: (p.node.ik ?? []).map((c) => ({
|
|
762
|
+
chain: c.chain,
|
|
763
|
+
target: point(c.target),
|
|
764
|
+
pole: c.poleTarget ? point(c.poleTarget) : void 0,
|
|
765
|
+
weight: numberAt(c.weight, clock, 1)
|
|
766
|
+
})),
|
|
767
|
+
drive: [...p.model.drivers ?? [], ...p.node.drive ?? []],
|
|
768
|
+
lookAt: (p.node.lookAt ?? []).map((c) => ({
|
|
769
|
+
joint: c.joint,
|
|
770
|
+
target: point(c.target),
|
|
771
|
+
weight: numberAt(c.weight, clock, 1),
|
|
772
|
+
maxAngleDeg: c.maxAngleDeg ?? 70,
|
|
773
|
+
axis: c.axis ?? [
|
|
774
|
+
0,
|
|
775
|
+
0,
|
|
776
|
+
1
|
|
777
|
+
]
|
|
778
|
+
}))
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
/** The pose before springs: blended clips, then constraints. */
|
|
782
|
+
function basePose(p, frame, toModel) {
|
|
783
|
+
const rig = blendClipLayers(p.model, clipLayers(p, frame));
|
|
784
|
+
applyConstraints(rig, constraintsAt(p, frame, toModel));
|
|
785
|
+
return rig;
|
|
786
|
+
}
|
|
787
|
+
const springStates = /* @__PURE__ */ new Map();
|
|
788
|
+
function springsAt(p, toModel, rig) {
|
|
789
|
+
const chains = p.node.springBones;
|
|
790
|
+
if (!chains?.length) return void 0;
|
|
791
|
+
const config = JSON.stringify([
|
|
792
|
+
chains,
|
|
793
|
+
p.node.animationLayers,
|
|
794
|
+
p.node.pose,
|
|
795
|
+
p.node.aim,
|
|
796
|
+
p.fps
|
|
797
|
+
]);
|
|
798
|
+
let s = springStates.get(p.key);
|
|
799
|
+
const frame = Math.max(0, Math.floor(p.frame));
|
|
800
|
+
if (!s || s.model !== p.model || s.config !== config || s.frame > frame) {
|
|
801
|
+
const gravityModel = (g) => transformDir(toModel, g ?? [
|
|
802
|
+
0,
|
|
803
|
+
0,
|
|
804
|
+
0
|
|
805
|
+
]);
|
|
806
|
+
s = {
|
|
807
|
+
model: p.model,
|
|
808
|
+
config,
|
|
809
|
+
springs: new SpringBones(rig, chains.map((c) => ({
|
|
810
|
+
...c,
|
|
811
|
+
gravity: gravityModel(c.gravity)
|
|
812
|
+
}))),
|
|
813
|
+
frame: -1
|
|
814
|
+
};
|
|
815
|
+
if (springStates.size > 256) springStates.clear();
|
|
816
|
+
springStates.set(p.key, s);
|
|
817
|
+
}
|
|
818
|
+
for (let f = s.frame + 1; f <= frame; f++) {
|
|
819
|
+
s.springs.step(basePose(p, f, toModel), 1 / p.fps);
|
|
820
|
+
s.frame = f;
|
|
821
|
+
}
|
|
822
|
+
return s.springs;
|
|
823
|
+
}
|
|
824
|
+
/** Model-space node matrices for this frame. */
|
|
825
|
+
function poseCharacter(p) {
|
|
826
|
+
if (!hasRig(p.node) && !p.model.drivers?.length) return poseNodes(p.model, p.clip, p.clipSec);
|
|
827
|
+
const toModel = Matrix4Math.invert(p.sceneRoot) ?? Matrix4Math.identity();
|
|
828
|
+
const rig = basePose(p, p.frame, toModel);
|
|
829
|
+
springsAt(p, toModel, rig)?.apply(rig);
|
|
830
|
+
return rig.world();
|
|
831
|
+
}
|
|
832
|
+
const bakes = /* @__PURE__ */ new WeakMap();
|
|
833
|
+
const palettes = /* @__PURE__ */ new WeakMap();
|
|
834
|
+
/** A baked palette on the GPU, uploaded once. */
|
|
835
|
+
function paletteBuffer(device, palette) {
|
|
836
|
+
let buffer = palettes.get(palette);
|
|
837
|
+
if (!buffer) {
|
|
838
|
+
buffer = device.createBuffer({
|
|
839
|
+
label: "CrowdPalette",
|
|
840
|
+
size: Math.max(64, palette.byteLength),
|
|
841
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
842
|
+
});
|
|
843
|
+
device.queue.writeBuffer(buffer, 0, palette);
|
|
844
|
+
palettes.set(palette, buffer);
|
|
845
|
+
}
|
|
846
|
+
return buffer;
|
|
847
|
+
}
|
|
848
|
+
/** The model's crowd palette for these clips, baked once. */
|
|
849
|
+
function crowdBake(model, crowd) {
|
|
850
|
+
const key = JSON.stringify([crowd.clips, crowd.fps ?? 30]);
|
|
851
|
+
let byKey = bakes.get(model);
|
|
852
|
+
if (!byKey) {
|
|
853
|
+
byKey = /* @__PURE__ */ new Map();
|
|
854
|
+
bakes.set(model, byKey);
|
|
855
|
+
}
|
|
856
|
+
let bake = byKey.get(key);
|
|
857
|
+
if (!bake) {
|
|
858
|
+
const clips = resolveClips(model, crowd.clips);
|
|
859
|
+
if (!clips.length) return void 0;
|
|
860
|
+
bake = bakeCrowdPalette(model, clips, crowd.fps ?? 30);
|
|
861
|
+
byKey.set(key, bake);
|
|
862
|
+
}
|
|
863
|
+
return bake;
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Instance `i`'s second record: (first baked frame, frames per loop, phase
|
|
867
|
+
* in frames, frames per second of playback). Unset fields come from the seed: clip i % n, a random
|
|
868
|
+
* phase, a speed within `speedRange`.
|
|
869
|
+
*/
|
|
870
|
+
function crowdRecord(bake, crowd, i, anim) {
|
|
871
|
+
const rand = createRandom((crowd.seed ?? 1) * 7919 + i * 104729);
|
|
872
|
+
const pick = rand();
|
|
873
|
+
const speedDraw = rand();
|
|
874
|
+
const clipIndex = (anim.clip ?? i) % bake.clips.length;
|
|
875
|
+
const range = bake.clips[Math.max(0, clipIndex)];
|
|
876
|
+
const [s0, s1] = crowd.speedRange ?? [1, 1];
|
|
877
|
+
const offset = anim.animOffset ?? ((crowd.phase ?? "random") === "random" ? pick * range.duration : 0);
|
|
878
|
+
const rate = range.duration > 0 ? range.count / range.duration : bake.fps;
|
|
879
|
+
return [
|
|
880
|
+
range.base,
|
|
881
|
+
range.count,
|
|
882
|
+
offset * rate,
|
|
883
|
+
(anim.animSpeed ?? s0 + (s1 - s0) * speedDraw) * rate
|
|
884
|
+
];
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
690
887
|
* Which container kinds paint their own background.
|
|
691
888
|
*
|
|
692
889
|
* flex/block/box all accept an optional `background` in the program schema.
|
|
@@ -698,6 +895,110 @@ function shouldPaintContainerBackground(kind, background) {
|
|
|
698
895
|
if (!background) return false;
|
|
699
896
|
return kind === "flex" || kind === "block" || kind === "box";
|
|
700
897
|
}
|
|
898
|
+
/** Largest face a cube camera picks on its own; `lens.cubeSize` may go higher. */
|
|
899
|
+
const DEFAULT_MAX_FACE = 4096;
|
|
900
|
+
/**
|
|
901
|
+
* The cube camera an authored camera asks for, or null for an ordinary
|
|
902
|
+
* perspective view. A camera with `relativity` is always a cube camera, even
|
|
903
|
+
* at speed 0, so a shot that accelerates from rest never switches pipelines.
|
|
904
|
+
*/
|
|
905
|
+
function resolveCubeCamera(authored, camera, speed, width, height, maxTextureSize) {
|
|
906
|
+
const projection = authored?.lens?.projection ?? "perspective";
|
|
907
|
+
const relativity = authored?.relativity;
|
|
908
|
+
if (projection === "perspective" && !relativity) return null;
|
|
909
|
+
const lens = {
|
|
910
|
+
projection,
|
|
911
|
+
fov: camera.fov,
|
|
912
|
+
zoom: camera.zoom
|
|
913
|
+
};
|
|
914
|
+
const requested = authored?.lens?.cubeSize;
|
|
915
|
+
const faceSize = Math.min(maxTextureSize, requested ?? defaultCubeFaceSize(lens, width, height, Math.min(DEFAULT_MAX_FACE, maxTextureSize)));
|
|
916
|
+
const basis = cameraBasis(camera);
|
|
917
|
+
const observer = relativity ? {
|
|
918
|
+
speed,
|
|
919
|
+
direction: relativity.direction ? Vector3Math.normalize(relativity.direction) : basis.forward,
|
|
920
|
+
doppler: relativity.doppler ?? true,
|
|
921
|
+
beaming: relativity.beaming ?? true,
|
|
922
|
+
exposure: relativity.exposure ?? "auto"
|
|
923
|
+
} : null;
|
|
924
|
+
return {
|
|
925
|
+
faceSize,
|
|
926
|
+
remap: {
|
|
927
|
+
...lens,
|
|
928
|
+
basis,
|
|
929
|
+
observer
|
|
930
|
+
},
|
|
931
|
+
centerDensity: lensCenterDensity(lens, width, height)
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* Whether the pieces are all still where they started at `frame` (or there
|
|
936
|
+
* is no track): the layer looks whole, and its cut faces, hidden inside,
|
|
937
|
+
* need not draw (where pieces meet, a cut face can tie the surface's depth).
|
|
938
|
+
*/
|
|
939
|
+
function fractureWhole(model, spec, frame) {
|
|
940
|
+
const track = spec.track;
|
|
941
|
+
const stride = (model.nodes?.length ?? 0) * 7;
|
|
942
|
+
if (!track?.length || !stride) return true;
|
|
943
|
+
const frames = Math.floor(track.length / stride);
|
|
944
|
+
const at = Math.min(Math.max(Math.ceil(frame), 0), frames - 1) * stride;
|
|
945
|
+
for (let i = 0; i < stride; i++) if (track[at + i] !== track[i]) return false;
|
|
946
|
+
return true;
|
|
947
|
+
}
|
|
948
|
+
/** The fractured model for a node's source model (cached per model and spec). */
|
|
949
|
+
function fracturedModel(model, spec) {
|
|
950
|
+
return fractureModel(model, spec).model;
|
|
951
|
+
}
|
|
952
|
+
function poseAt(track, at) {
|
|
953
|
+
return {
|
|
954
|
+
p: [
|
|
955
|
+
track[at],
|
|
956
|
+
track[at + 1],
|
|
957
|
+
track[at + 2]
|
|
958
|
+
],
|
|
959
|
+
q: [
|
|
960
|
+
track[at + 3],
|
|
961
|
+
track[at + 4],
|
|
962
|
+
track[at + 5],
|
|
963
|
+
track[at + 6]
|
|
964
|
+
]
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
function blend(a, b, t) {
|
|
968
|
+
if (t <= 0) return a;
|
|
969
|
+
const sign = a.q.reduce((s, v, i) => s + v * b.q[i], 0) < 0 ? -1 : 1;
|
|
970
|
+
const q = a.q.map((v, i) => v + (b.q[i] * sign - v) * t);
|
|
971
|
+
const len = Math.hypot(...q) || 1;
|
|
972
|
+
return {
|
|
973
|
+
p: a.p.map((v, i) => v + (b.p[i] - v) * t),
|
|
974
|
+
q: q.map((v) => v / len)
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Model-space matrices of the pieces' nodes at `frame`. The track is in the
|
|
979
|
+
* layer's parent space (physics reads the layer's own x/y/z, as for any
|
|
980
|
+
* body), and `layerProps` is the layer's matrix in that space, L. A piece
|
|
981
|
+
* at pose (p, q) has node matrix L⁻¹ · T(p) · R(q) · S, so with its inverse
|
|
982
|
+
* bind T(−centroid) a vertex lands at parent · (p + q · S · (v − centroid)):
|
|
983
|
+
* pieces fly in their group, like other bodies. Undefined without a track.
|
|
984
|
+
*/
|
|
985
|
+
function fracturePose(model, spec, frame, layerProps, scale$1) {
|
|
986
|
+
const track = spec.track;
|
|
987
|
+
const pieces = model.nodes?.length ?? 0;
|
|
988
|
+
const stride = pieces * 7;
|
|
989
|
+
if (!track?.length || !stride || track.length % stride !== 0) return void 0;
|
|
990
|
+
const frames = track.length / stride;
|
|
991
|
+
const f = Math.min(Math.max(frame, 0), frames - 1);
|
|
992
|
+
const f0 = Math.floor(f);
|
|
993
|
+
const f1 = Math.min(frames - 1, f0 + 1);
|
|
994
|
+
const toModel = Matrix4Math.invert(layerProps) ?? Matrix4Math.identity();
|
|
995
|
+
const out = [];
|
|
996
|
+
for (let i = 0; i < pieces; i++) {
|
|
997
|
+
const { p, q } = blend(poseAt(track, f0 * stride + i * 7), poseAt(track, f1 * stride + i * 7), f - f0);
|
|
998
|
+
out.push(Matrix4Math.multiply(toModel, trsMatrix(p, q, scale$1)));
|
|
999
|
+
}
|
|
1000
|
+
return out;
|
|
1001
|
+
}
|
|
701
1002
|
const TRANSFORMS = new Set([
|
|
702
1003
|
"position",
|
|
703
1004
|
"rotation",
|
|
@@ -729,6 +1030,253 @@ function compatibleMeshDraws(a, b) {
|
|
|
729
1030
|
for (const key of keys) if (!TRANSFORMS.has(key) && !sameValue(left[key], right[key])) return false;
|
|
730
1031
|
return true;
|
|
731
1032
|
}
|
|
1033
|
+
/** Two frames of one value: the latest and the one before it. */
|
|
1034
|
+
var Slots = class {
|
|
1035
|
+
frame = NaN;
|
|
1036
|
+
value;
|
|
1037
|
+
prevFrame = NaN;
|
|
1038
|
+
prevValue;
|
|
1039
|
+
write(frame, value) {
|
|
1040
|
+
if (frame !== this.frame) {
|
|
1041
|
+
this.prevFrame = this.frame;
|
|
1042
|
+
this.prevValue = this.value;
|
|
1043
|
+
}
|
|
1044
|
+
this.frame = frame;
|
|
1045
|
+
this.value = value;
|
|
1046
|
+
}
|
|
1047
|
+
/** The value at `frame`, if it is one of the two held. */
|
|
1048
|
+
at(frame) {
|
|
1049
|
+
if (frame === this.frame) return this.value;
|
|
1050
|
+
if (frame === this.prevFrame) return this.prevValue;
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
var MotionHistory = class {
|
|
1054
|
+
states = /* @__PURE__ */ new Map();
|
|
1055
|
+
instances;
|
|
1056
|
+
vertices;
|
|
1057
|
+
camera = new Slots();
|
|
1058
|
+
/** Frames recorded, latest last (two kept). */
|
|
1059
|
+
frames = new Slots();
|
|
1060
|
+
constructor(device) {
|
|
1061
|
+
this.instances = new GpuPairs(device, "Instances");
|
|
1062
|
+
this.vertices = new GpuPairs(device, "Vertices");
|
|
1063
|
+
}
|
|
1064
|
+
/** Whether rendering `frame` must render `frame - 1` first to know its motion. */
|
|
1065
|
+
needsPrevious(frame) {
|
|
1066
|
+
return frame > 0 && this.frames.at(frame - 1) === void 0;
|
|
1067
|
+
}
|
|
1068
|
+
previousCamera(frame) {
|
|
1069
|
+
return this.camera.at(frame - 1);
|
|
1070
|
+
}
|
|
1071
|
+
/** A mesh's state at `frame - 1`, shaped for the velocity pass. */
|
|
1072
|
+
previousMesh(key, frame, now) {
|
|
1073
|
+
const prev = this.states.get(key)?.at(frame - 1);
|
|
1074
|
+
if (prev?.kind !== "mesh") return void 0;
|
|
1075
|
+
const out = { modelMatrix: prev.modelMatrix };
|
|
1076
|
+
if (now.skinning && prev.skinning?.length === now.skinning.length) out.skinningMatrices = prev.skinning;
|
|
1077
|
+
const copy = this.instances.at(key, frame - 1);
|
|
1078
|
+
if (now.instanceBuffer && copy && prev.instanceBytes === now.instanceBuffer.size) out.instanceBuffer = copy;
|
|
1079
|
+
const vertices = this.vertices.at(key, frame - 1);
|
|
1080
|
+
if (now.vertexBytes && vertices && prev.vertexBytes === now.vertexBytes) out.vertexBuffer = vertices;
|
|
1081
|
+
if (now.wind && prev.windTime !== void 0) out.wind = {
|
|
1082
|
+
...now.wind,
|
|
1083
|
+
time: prev.windTime
|
|
1084
|
+
};
|
|
1085
|
+
if (now.crowd && prev.crowdTime !== void 0) out.crowd = {
|
|
1086
|
+
...now.crowd,
|
|
1087
|
+
time: prev.crowdTime
|
|
1088
|
+
};
|
|
1089
|
+
return out;
|
|
1090
|
+
}
|
|
1091
|
+
previousQuad(key, frame) {
|
|
1092
|
+
const prev = this.states.get(key)?.at(frame - 1);
|
|
1093
|
+
return prev?.kind === "quad" ? prev.modelMatrix : void 0;
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Records a mesh at `frame`; its instance records and deformed vertices
|
|
1097
|
+
* (when the GPU deforms it) are copied in `encoder`.
|
|
1098
|
+
*/
|
|
1099
|
+
recordMesh(encoder, key, frame, state, buffers) {
|
|
1100
|
+
const { instanceBuffer, vertices } = buffers;
|
|
1101
|
+
if (instanceBuffer) this.instances.copy(encoder, key, frame, instanceBuffer, instanceBuffer.size, GPUBufferUsage.STORAGE);
|
|
1102
|
+
if (vertices) this.vertices.copy(encoder, key, frame, vertices.buffer, vertices.bytes, GPUBufferUsage.VERTEX);
|
|
1103
|
+
this.slots(key).write(frame, {
|
|
1104
|
+
kind: "mesh",
|
|
1105
|
+
...state,
|
|
1106
|
+
...state.skinning && { skinning: state.skinning.slice() },
|
|
1107
|
+
instanceBytes: instanceBuffer?.size,
|
|
1108
|
+
vertexBytes: vertices?.bytes
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
previousSlug(key, frame) {
|
|
1112
|
+
const prev = this.states.get(key)?.at(frame - 1);
|
|
1113
|
+
return prev?.kind === "slug" ? prev : void 0;
|
|
1114
|
+
}
|
|
1115
|
+
/** Records a text plane at `frame`; glyph records are copied (batches are rebuilt each frame). */
|
|
1116
|
+
recordSlug(key, frame, modelMatrix, batches) {
|
|
1117
|
+
this.slots(key).write(frame, {
|
|
1118
|
+
kind: "slug",
|
|
1119
|
+
modelMatrix,
|
|
1120
|
+
batches: batches.map((b) => ({
|
|
1121
|
+
...b,
|
|
1122
|
+
instances: b.instances.slice(0, b.instanceCount * 24)
|
|
1123
|
+
}))
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
recordQuad(key, frame, modelMatrix) {
|
|
1127
|
+
this.slots(key).write(frame, {
|
|
1128
|
+
kind: "quad",
|
|
1129
|
+
modelMatrix
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
recordFrame(frame, camera) {
|
|
1133
|
+
this.camera.write(frame, camera);
|
|
1134
|
+
this.frames.write(frame, true);
|
|
1135
|
+
}
|
|
1136
|
+
slots(key) {
|
|
1137
|
+
let s = this.states.get(key);
|
|
1138
|
+
if (!s) {
|
|
1139
|
+
s = new Slots();
|
|
1140
|
+
this.states.set(key, s);
|
|
1141
|
+
}
|
|
1142
|
+
return s;
|
|
1143
|
+
}
|
|
1144
|
+
};
|
|
1145
|
+
/** GPU copies of a buffer per key, one per frame parity. */
|
|
1146
|
+
var GpuPairs = class {
|
|
1147
|
+
pairs = /* @__PURE__ */ new Map();
|
|
1148
|
+
constructor(device, label) {
|
|
1149
|
+
this.device = device;
|
|
1150
|
+
this.label = label;
|
|
1151
|
+
}
|
|
1152
|
+
at(key, frame) {
|
|
1153
|
+
return this.pairs.get(key)?.[frame & 1];
|
|
1154
|
+
}
|
|
1155
|
+
copy(encoder, key, frame, source, bytes, usage) {
|
|
1156
|
+
const pair = this.pairs.get(key) ?? [];
|
|
1157
|
+
const slot = frame & 1;
|
|
1158
|
+
let copy = pair[slot];
|
|
1159
|
+
if (!copy || copy.size !== bytes) {
|
|
1160
|
+
copy?.destroy();
|
|
1161
|
+
copy = this.device.createBuffer({
|
|
1162
|
+
label: `MotionHistory${this.label}:${key}`,
|
|
1163
|
+
size: bytes,
|
|
1164
|
+
usage: usage | GPUBufferUsage.COPY_DST
|
|
1165
|
+
});
|
|
1166
|
+
pair[slot] = copy;
|
|
1167
|
+
this.pairs.set(key, pair);
|
|
1168
|
+
}
|
|
1169
|
+
encoder.copyBufferToBuffer(source, 0, copy, 0, bytes);
|
|
1170
|
+
}
|
|
1171
|
+
};
|
|
1172
|
+
const histories = /* @__PURE__ */ new Map();
|
|
1173
|
+
/** The motion history of one composition render (by render id). */
|
|
1174
|
+
function motionHistory(device, renderId) {
|
|
1175
|
+
let h = histories.get(renderId);
|
|
1176
|
+
if (!h) {
|
|
1177
|
+
if (histories.size > 64) histories.clear();
|
|
1178
|
+
h = new MotionHistory(device);
|
|
1179
|
+
histories.set(renderId, h);
|
|
1180
|
+
}
|
|
1181
|
+
return h;
|
|
1182
|
+
}
|
|
1183
|
+
/** T · Rz · Ry · Rx · S: the transform the compositor draws a model with. */
|
|
1184
|
+
function nodeMatrix(n) {
|
|
1185
|
+
const rad = Math.PI / 180;
|
|
1186
|
+
const s = n.scale ?? 1;
|
|
1187
|
+
let m = Matrix4Math.translate(n.x ?? 0, n.y ?? 0, n.z ?? 0);
|
|
1188
|
+
if (n.rotateZ) m = Matrix4Math.multiply(m, Matrix4Math.rotateZ(n.rotateZ * rad));
|
|
1189
|
+
if (n.rotateY) m = Matrix4Math.multiply(m, Matrix4Math.rotateY(n.rotateY * rad));
|
|
1190
|
+
if (n.rotateX) m = Matrix4Math.multiply(m, Matrix4Math.rotateX(n.rotateX * rad));
|
|
1191
|
+
return Matrix4Math.multiply(m, Matrix4Math.scale(s * (n.scaleX ?? 1), s * (n.scaleY ?? 1), s * (n.scaleZ ?? 1)));
|
|
1192
|
+
}
|
|
1193
|
+
const isModel = (v) => typeof v === "object" && v !== null && "meshes" in v;
|
|
1194
|
+
/** The surface's mesh: in memory, rebuilt from its primitive spec, or loaded. */
|
|
1195
|
+
async function surfaceModel(n, load) {
|
|
1196
|
+
if (isModel(n.modelData)) return n.modelData;
|
|
1197
|
+
if (n.primitive3d) return getPrimitiveGeometry(n.primitive3d);
|
|
1198
|
+
if (n.src) return load(n.src, n);
|
|
1199
|
+
}
|
|
1200
|
+
const NO_PRE = {
|
|
1201
|
+
q: [
|
|
1202
|
+
0,
|
|
1203
|
+
0,
|
|
1204
|
+
0,
|
|
1205
|
+
1
|
|
1206
|
+
],
|
|
1207
|
+
s: 1
|
|
1208
|
+
};
|
|
1209
|
+
function composeQuat(a, b) {
|
|
1210
|
+
return [
|
|
1211
|
+
a[3] * b[0] + a[0] * b[3] + a[1] * b[2] - a[2] * b[1],
|
|
1212
|
+
a[3] * b[1] - a[0] * b[2] + a[1] * b[3] + a[2] * b[0],
|
|
1213
|
+
a[3] * b[2] + a[0] * b[1] - a[1] * b[0] + a[2] * b[3],
|
|
1214
|
+
a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2]
|
|
1215
|
+
];
|
|
1216
|
+
}
|
|
1217
|
+
/** The variant's lowest point after its own rotation and scale: the largest y (up is -y). */
|
|
1218
|
+
function variantBottom(model, pre) {
|
|
1219
|
+
const b = model.bounds;
|
|
1220
|
+
if (!b) return 0;
|
|
1221
|
+
let bottom = Number.NEGATIVE_INFINITY;
|
|
1222
|
+
for (let k = 0; k < 8; k++) {
|
|
1223
|
+
const corner = [
|
|
1224
|
+
k & 1 ? b.max[0] : b.min[0],
|
|
1225
|
+
k & 2 ? b.max[1] : b.min[1],
|
|
1226
|
+
k & 4 ? b.max[2] : b.min[2]
|
|
1227
|
+
];
|
|
1228
|
+
bottom = Math.max(bottom, rotateByQuat(pre.q, corner)[1] * pre.s);
|
|
1229
|
+
}
|
|
1230
|
+
return bottom;
|
|
1231
|
+
}
|
|
1232
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
1233
|
+
/**
|
|
1234
|
+
* Instance transforms for a scatter: points on the surface, each seated on
|
|
1235
|
+
* its variant's base (instance i draws variant i % bottoms.length; bottoms
|
|
1236
|
+
* already include the variant's own rotation and scale).
|
|
1237
|
+
*/
|
|
1238
|
+
function scatterTransforms(scatter, surface, bottoms) {
|
|
1239
|
+
const surfaceNode = scatter.surface;
|
|
1240
|
+
const key = JSON.stringify([bottoms, surface.bounds?.size]);
|
|
1241
|
+
const hit = cache.get(scatter);
|
|
1242
|
+
if (hit && hit.key === key) return hit.out;
|
|
1243
|
+
const { points } = scatterOnSurface({
|
|
1244
|
+
model: surface,
|
|
1245
|
+
matrix: nodeMatrix(surfaceNode)
|
|
1246
|
+
}, scatter);
|
|
1247
|
+
const n = Math.max(1, bottoms.length);
|
|
1248
|
+
const out = points.map((p, i) => {
|
|
1249
|
+
const [x, y, z] = seatOnSurface(p, bottoms[i % n] ?? 0, scatter.sink ?? 0);
|
|
1250
|
+
return {
|
|
1251
|
+
x,
|
|
1252
|
+
y,
|
|
1253
|
+
z,
|
|
1254
|
+
rotation: p.rotation,
|
|
1255
|
+
scale: p.scale
|
|
1256
|
+
};
|
|
1257
|
+
});
|
|
1258
|
+
cache.set(scatter, {
|
|
1259
|
+
key,
|
|
1260
|
+
out
|
|
1261
|
+
});
|
|
1262
|
+
return out;
|
|
1263
|
+
}
|
|
1264
|
+
/** The wind a mesh of `model` sways in at `seconds`, or undefined when calm. */
|
|
1265
|
+
function meshWind(wind, model, seconds) {
|
|
1266
|
+
if (!wind) return void 0;
|
|
1267
|
+
const b = model.bounds;
|
|
1268
|
+
const height = b ? b.size[1] : 0;
|
|
1269
|
+
if (!b || height <= 0) return void 0;
|
|
1270
|
+
return {
|
|
1271
|
+
amplitudeDeg: wind.amplitudeDeg ?? 8,
|
|
1272
|
+
frequency: wind.frequency ?? .4,
|
|
1273
|
+
direction: wind.direction ?? [1, 0],
|
|
1274
|
+
waveScale: wind.waveScale ?? 600,
|
|
1275
|
+
time: seconds,
|
|
1276
|
+
baseY: b.max[1],
|
|
1277
|
+
height
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
732
1280
|
function translate(tx, ty) {
|
|
733
1281
|
return {
|
|
734
1282
|
a: 1,
|
|
@@ -855,16 +1403,20 @@ const MAX_RASTER_SCALE = 4;
|
|
|
855
1403
|
* Pixels per layout px to rasterize a 2D layer at, so it stays sharp when its
|
|
856
1404
|
* transform onto the canvas scales it up by `axisScale` (the transform's
|
|
857
1405
|
* larger axis scale). Rounded up to a quarter, so an animated zoom reuses a
|
|
858
|
-
* few texture sizes instead of allocating new ones every frame;
|
|
1406
|
+
* few texture sizes instead of allocating new ones every frame; not below 1
|
|
859
1407
|
* (a shrunk layer keeps its layout raster). Capped, rounded down to a quarter,
|
|
860
1408
|
* by MAX_RASTER_SCALE, by `limits.maxDimension` (the GPU's texture side), by
|
|
861
1409
|
* `limits.maxPixels` (a pixel budget for one texture) and by
|
|
862
1410
|
* `limits.effects`, the highest scale the layer's effects keep their look at.
|
|
1411
|
+
* The texture side is a hard limit: a layer longer than it at layout scale
|
|
1412
|
+
* (a tall reel strip, a long scroll) rasterizes just under it, below 1.
|
|
863
1413
|
*/
|
|
864
1414
|
function layerRasterScale(axisScale, size, limits) {
|
|
865
1415
|
const w = Math.max(1, size.width);
|
|
866
1416
|
const h = Math.max(1, size.height);
|
|
867
1417
|
const cap = Math.min(MAX_RASTER_SCALE, limits.maxDimension / Math.max(w, h), Math.sqrt(limits.maxPixels / (w * h)), limits.effects);
|
|
1418
|
+
const fits = limits.maxDimension / Math.max(w, h);
|
|
1419
|
+
if (fits < 1) return Math.floor(fits * 1024) / 1024;
|
|
868
1420
|
const wanted = Math.ceil(axisScale * 4 - 1e-6) / 4;
|
|
869
1421
|
return Math.max(1, Math.min(wanted, Math.floor(cap * 4 + 1e-6) / 4));
|
|
870
1422
|
}
|
|
@@ -1099,6 +1651,10 @@ function textInkOutset(target, lop) {
|
|
|
1099
1651
|
const reach = stroke + shadow;
|
|
1100
1652
|
return reach > 0 ? Math.ceil(reach) + 1 : 0;
|
|
1101
1653
|
}
|
|
1654
|
+
/** Bytes of a mesh's vertex buffer: 16 floats per vertex. */
|
|
1655
|
+
function deformedBytes(mesh) {
|
|
1656
|
+
return mesh.positions.length / 3 * 64;
|
|
1657
|
+
}
|
|
1102
1658
|
function hasVertexAlpha(mesh) {
|
|
1103
1659
|
const cached = meshHasAlpha.get(mesh);
|
|
1104
1660
|
if (cached !== void 0) return cached;
|
|
@@ -1348,8 +1904,35 @@ function surfaceProps(target, lop, mat) {
|
|
|
1348
1904
|
if (lop.castShadow !== void 0) out.castShadow = lop.castShadow;
|
|
1349
1905
|
out.toon = target?.toon ?? lop.toon;
|
|
1350
1906
|
out.outline = target?.outline ?? lop.outline;
|
|
1907
|
+
const file = mat?.surface;
|
|
1908
|
+
const lobes = {
|
|
1909
|
+
clearcoat: target?.clearcoat ?? lop.clearcoat ?? file?.clearcoat,
|
|
1910
|
+
clearcoatRoughness: target?.clearcoatRoughness ?? lop.clearcoatRoughness ?? file?.clearcoatRoughness,
|
|
1911
|
+
anisotropy: target?.anisotropy ?? lop.anisotropy ?? file?.anisotropy,
|
|
1912
|
+
anisotropyRotation: target?.anisotropyRotation ?? lop.anisotropyRotation ?? file?.anisotropyRotation,
|
|
1913
|
+
subsurface: target?.subsurface ?? lop.subsurface ?? file?.subsurface,
|
|
1914
|
+
subsurfaceColor: target?.subsurfaceColor ?? lop.subsurfaceColor ?? file?.subsurfaceColor,
|
|
1915
|
+
sheen: target?.sheen ?? lop.sheen ?? file?.sheen,
|
|
1916
|
+
sheenColor: target?.sheenColor ?? lop.sheenColor ?? file?.sheenColor,
|
|
1917
|
+
sheenRoughness: target?.sheenRoughness ?? lop.sheenRoughness ?? file?.sheenRoughness,
|
|
1918
|
+
iridescence: target?.iridescence ?? lop.iridescence ?? file?.iridescence,
|
|
1919
|
+
iridescenceThickness: target?.iridescenceThickness ?? lop.iridescenceThickness ?? file?.iridescenceThickness,
|
|
1920
|
+
iridescenceIor: target?.iridescenceIor ?? lop.iridescenceIor ?? file?.iridescenceIor
|
|
1921
|
+
};
|
|
1922
|
+
for (const [key, value] of Object.entries(lobes)) if (value !== void 0) out[key] = value;
|
|
1923
|
+
const triplanar = target?.triplanar ?? lop.triplanar;
|
|
1924
|
+
if (triplanar !== void 0) out.triplanar = triplanar;
|
|
1925
|
+
const triplanarScale = target?.triplanarScale ?? lop.triplanarScale;
|
|
1926
|
+
if (triplanarScale !== void 0) out.triplanarScale = triplanarScale;
|
|
1927
|
+
const triplanarSharpness = target?.triplanarSharpness ?? lop.triplanarSharpness;
|
|
1928
|
+
if (triplanarSharpness !== void 0) out.triplanarSharpness = triplanarSharpness;
|
|
1351
1929
|
return out;
|
|
1352
1930
|
}
|
|
1931
|
+
/** A transform's mean scale: the average length of its basis columns. */
|
|
1932
|
+
function matrixScale(m) {
|
|
1933
|
+
const c = (i) => Math.hypot(m[i], m[i + 1], m[i + 2]);
|
|
1934
|
+
return (c(0) + c(4) + c(8)) / 3;
|
|
1935
|
+
}
|
|
1353
1936
|
function computeContainerScissor(matrix, width, height) {
|
|
1354
1937
|
const corners = [
|
|
1355
1938
|
matrix.transformPoint(new DOMPoint(0, 0)),
|
|
@@ -1661,6 +2244,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1661
2244
|
const inheritedSeekOffset = props.inheritedSeekOffset ?? 0;
|
|
1662
2245
|
const shiftedFrame = Math.max(0, frame != null && fps != null ? frame + Math.round(inheritedSeekOffset * fps) : frame ?? 0);
|
|
1663
2246
|
const compositionFrame = props.compositionFrame ?? shiftedFrame;
|
|
2247
|
+
const historyOnly = props.motionHistoryOnly === true;
|
|
1664
2248
|
const compTex = ctx.renderer.getTemporaryTexture(nativeWidth, nativeHeight, [...props.excludeTextures || [], targetTexture]);
|
|
1665
2249
|
const compView = compTex.createView();
|
|
1666
2250
|
const composeDuration = virtualMedia?.metadata?.durationMs ?? DEFAULT_DURATION_MS;
|
|
@@ -1670,6 +2254,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1670
2254
|
durationSec
|
|
1671
2255
|
});
|
|
1672
2256
|
const { targetsById } = compiled;
|
|
2257
|
+
if (!historyOnly && frame != null && sceneMotionBlur(virtualMedia) && motionHistory(ctx.device, compiled.key).needsPrevious(shiftedFrame)) await renderMotionHistory(args, frame - 1);
|
|
1673
2258
|
seekTimeline(compiled, shiftedFrame, fps ?? 24);
|
|
1674
2259
|
const r3d = getRenderer3D(ctx.device, ctx.renderer.format ?? "rgba8unorm", sampleCount3d);
|
|
1675
2260
|
const relightPipe = getScreenSpaceRelightPipeline(ctx.device, ctx.renderer.format ?? "rgba8unorm");
|
|
@@ -1748,6 +2333,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1748
2333
|
const textStyle = {
|
|
1749
2334
|
fontSize: node.fontSize ?? 48,
|
|
1750
2335
|
fontWeight: node.fontWeight,
|
|
2336
|
+
fontVariations: node.fontVariations,
|
|
1751
2337
|
fontFamily: node.fontFamily,
|
|
1752
2338
|
letterSpacing: node.letterSpacing,
|
|
1753
2339
|
lineHeight: node.lineHeight,
|
|
@@ -1811,6 +2397,11 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1811
2397
|
0
|
|
1812
2398
|
];
|
|
1813
2399
|
let dofEnabled = false;
|
|
2400
|
+
/** Shutter motion blur of the 3D scene, and what its draws looked like a frame ago. */
|
|
2401
|
+
let motionBlur = null;
|
|
2402
|
+
let history = null;
|
|
2403
|
+
/** Set when the camera draws a cube map and remaps it through its lens. */
|
|
2404
|
+
let cubeCamera = null;
|
|
1814
2405
|
const sceneLights = [];
|
|
1815
2406
|
let sceneEnvironment = null;
|
|
1816
2407
|
let sceneBloom = null;
|
|
@@ -1873,6 +2464,13 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1873
2464
|
camera.fStop = camStub?.fStop ?? camOp?.dof?.fStop ?? 2.8;
|
|
1874
2465
|
camera.maxBlurRadius = camStub?.maxBlurRadius ?? camOp?.dof?.maxBlurRadius ?? 24;
|
|
1875
2466
|
}
|
|
2467
|
+
const blur = camOp?.motionBlur;
|
|
2468
|
+
if (blur && fps) {
|
|
2469
|
+
motionBlur = blur === true ? {} : blur;
|
|
2470
|
+
history = motionHistory(ctx.device, compiled.key);
|
|
2471
|
+
}
|
|
2472
|
+
cubeCamera = resolveCubeCamera(camOp, camera, camStub?.relativitySpeed ?? camOp?.relativity?.speed ?? 0, nativeWidth, nativeHeight, ctx.device.limits.maxTextureDimension2D);
|
|
2473
|
+
if (cubeCamera && dofEnabled) throw new Error(`Camera '${camOp?.id}' is a cube camera (${camOp?.relativity ? "relativity" : camOp?.lens?.projection}) with depth of field: depth of field needs a single perspective view.`);
|
|
1876
2474
|
for (const lvm of lightVMs) {
|
|
1877
2475
|
const lop = lvm.operation;
|
|
1878
2476
|
const targetId = lop.id || lop.inputHandleId;
|
|
@@ -1887,8 +2485,23 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1887
2485
|
const lightType = target?.lightType ?? lop.lightType ?? "point";
|
|
1888
2486
|
if (lightType === "environment") {
|
|
1889
2487
|
const intensity$1 = target?.intensity ?? lop.intensity;
|
|
2488
|
+
const vfDensity = target?.volumetricFogDensity ?? lop.volumetricFogDensity;
|
|
2489
|
+
const vfAnisotropy = target?.volumetricFogAnisotropy ?? lop.volumetricFogAnisotropy;
|
|
2490
|
+
const vfNoiseStrength = target?.volumetricFogNoiseStrength ?? lop.volumetricFogNoiseStrength;
|
|
2491
|
+
const rawVf = lop.volumetricFog;
|
|
2492
|
+
const baseVf = rawVf === true ? {} : rawVf && typeof rawVf === "object" ? { ...rawVf } : void 0;
|
|
2493
|
+
const volumetricFog = baseVf ? {
|
|
2494
|
+
...baseVf,
|
|
2495
|
+
...vfDensity !== void 0 && { density: vfDensity },
|
|
2496
|
+
...vfAnisotropy !== void 0 && { anisotropy: vfAnisotropy },
|
|
2497
|
+
...vfNoiseStrength !== void 0 && { noise: {
|
|
2498
|
+
...typeof baseVf.noise === "object" ? baseVf.noise : {},
|
|
2499
|
+
strength: vfNoiseStrength
|
|
2500
|
+
} }
|
|
2501
|
+
} : void 0;
|
|
1890
2502
|
sceneEnvironment = {
|
|
1891
2503
|
preset: lop.preset,
|
|
2504
|
+
hdri: lop.hdri,
|
|
1892
2505
|
top: lop.top,
|
|
1893
2506
|
horizon: lop.horizon,
|
|
1894
2507
|
bottom: lop.bottom,
|
|
@@ -1899,6 +2512,9 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1899
2512
|
fog: lop.fog,
|
|
1900
2513
|
floor: lop.floor,
|
|
1901
2514
|
outlines: lop.outlines,
|
|
2515
|
+
ssr: lop.ssr,
|
|
2516
|
+
gi: lop.gi,
|
|
2517
|
+
...volumetricFog && { volumetricFog },
|
|
1902
2518
|
...intensity$1 !== void 0 && { intensity: intensity$1 }
|
|
1903
2519
|
};
|
|
1904
2520
|
sceneBloom = lop.bloom === true ? {} : lop.bloom && typeof lop.bloom === "object" ? { ...lop.bloom } : null;
|
|
@@ -1916,6 +2532,10 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1916
2532
|
const angle = target?.angle ?? lop.angle ?? 45;
|
|
1917
2533
|
const penumbra = target?.penumbra ?? lop.penumbra ?? .2;
|
|
1918
2534
|
const decay = target?.decay ?? lop.decay ?? 1;
|
|
2535
|
+
const width = typeof (target?.width ?? lop.width) === "number" ? target?.width ?? lop.width : void 0;
|
|
2536
|
+
const height = typeof (target?.height ?? lop.height) === "number" ? target?.height ?? lop.height : void 0;
|
|
2537
|
+
const twoSided = Boolean(target?.twoSided ?? lop.twoSided);
|
|
2538
|
+
const rotation = target?.rotation ?? lop.rotation ?? 0;
|
|
1919
2539
|
sceneLights.push({
|
|
1920
2540
|
type: lightType,
|
|
1921
2541
|
color,
|
|
@@ -1930,10 +2550,15 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1930
2550
|
targetY,
|
|
1931
2551
|
targetZ
|
|
1932
2552
|
],
|
|
2553
|
+
...Array.isArray(lop.direction) && { direction: lop.direction },
|
|
1933
2554
|
radius,
|
|
1934
2555
|
angle,
|
|
1935
2556
|
penumbra,
|
|
1936
2557
|
decay,
|
|
2558
|
+
...width !== void 0 && { width },
|
|
2559
|
+
...height !== void 0 && { height },
|
|
2560
|
+
twoSided,
|
|
2561
|
+
rotation,
|
|
1937
2562
|
castShadow: Boolean(lop.castShadow),
|
|
1938
2563
|
shadowSoftness: target?.shadowSoftness ?? lop.shadowSoftness,
|
|
1939
2564
|
shadowDarkness: target?.shadowDarkness ?? lop.shadowDarkness
|
|
@@ -1967,6 +2592,61 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1967
2592
|
eye: reliefEye
|
|
1968
2593
|
} };
|
|
1969
2594
|
};
|
|
2595
|
+
/** Each queued item with its motion key: owner id and its index among the owner's items. */
|
|
2596
|
+
const motionItems = () => {
|
|
2597
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2598
|
+
return pending3DItems.map((item) => {
|
|
2599
|
+
if (item.owner === void 0) return [item, void 0];
|
|
2600
|
+
const n = seen.get(item.owner) ?? 0;
|
|
2601
|
+
seen.set(item.owner, n + 1);
|
|
2602
|
+
return [item, `${item.owner}#${n}`];
|
|
2603
|
+
});
|
|
2604
|
+
};
|
|
2605
|
+
/** Writes this frame's draws (and camera) into the motion history. */
|
|
2606
|
+
const recordMotion = (h, cam) => {
|
|
2607
|
+
const r3d$1 = getRenderer3D(ctx.device, ctx.renderer.format ?? "rgba8unorm", sampleCount3d);
|
|
2608
|
+
for (const [item, key] of motionItems()) {
|
|
2609
|
+
if (!key) continue;
|
|
2610
|
+
if (item.kind === "mesh") h.recordMesh(encoder, key, shiftedFrame, {
|
|
2611
|
+
modelMatrix: r3d$1.meshModelMatrix(item.opts),
|
|
2612
|
+
skinning: item.opts.skinningMatrices,
|
|
2613
|
+
windTime: item.opts.wind?.time,
|
|
2614
|
+
crowdTime: item.opts.crowd?.time
|
|
2615
|
+
}, {
|
|
2616
|
+
instanceBuffer: item.opts.instanceBuffer,
|
|
2617
|
+
vertices: item.meshBuffers && {
|
|
2618
|
+
buffer: item.meshBuffers.vertexBuffer,
|
|
2619
|
+
bytes: deformedBytes(item.mesh)
|
|
2620
|
+
}
|
|
2621
|
+
});
|
|
2622
|
+
else if (item.kind === "quad") h.recordQuad(key, shiftedFrame, r3d$1.quadModelMatrix(item.opts));
|
|
2623
|
+
else h.recordSlug(key, shiftedFrame, r3d$1.quadModelMatrix(item.opts), item.batches);
|
|
2624
|
+
}
|
|
2625
|
+
h.recordFrame(shiftedFrame, cam);
|
|
2626
|
+
};
|
|
2627
|
+
/** Draws the queued items' screen motion since the last frame, then blurs `color` by it into `into`. */
|
|
2628
|
+
const blurScene = (h, cam, color, into, blur, floor) => {
|
|
2629
|
+
const r3d$1 = getRenderer3D(ctx.device, ctx.renderer.format ?? "rgba8unorm", sampleCount3d);
|
|
2630
|
+
const vel = r3d$1.beginVelocityPass(encoder, nativeWidth, nativeHeight, cam, h.previousCamera(shiftedFrame) ?? cam);
|
|
2631
|
+
if (floor) r3d$1.drawFloorVelocity(vel.pass, vel.cameraBindGroup, floor);
|
|
2632
|
+
for (const [item, key] of motionItems()) if (item.kind === "mesh") {
|
|
2633
|
+
const prev = key ? h.previousMesh(key, shiftedFrame, {
|
|
2634
|
+
skinning: item.opts.skinningMatrices,
|
|
2635
|
+
instanceBuffer: item.opts.instanceBuffer,
|
|
2636
|
+
vertexBytes: item.meshBuffers && deformedBytes(item.mesh),
|
|
2637
|
+
wind: item.opts.wind,
|
|
2638
|
+
crowd: item.opts.crowd
|
|
2639
|
+
}) : void 0;
|
|
2640
|
+
r3d$1.drawMeshVelocity(vel.pass, vel.cameraBindGroup, item.meshBuffers ?? item.mesh, item.texture, item.opts, prev);
|
|
2641
|
+
} else if (item.kind === "quad") r3d$1.drawQuadVelocity(vel.pass, vel.cameraBindGroup, item.texture, item.opts, key ? h.previousQuad(key, shiftedFrame) : void 0);
|
|
2642
|
+
else r3d$1.drawSlugVelocity(vel.pass, vel.cameraBindGroup, item.batches, item.opts, item.stackBase, key ? h.previousSlug(key, shiftedFrame) : void 0);
|
|
2643
|
+
vel.pass.end();
|
|
2644
|
+
r3d$1.applyMotionBlur(encoder, color, vel.velocity, into.createView(), {
|
|
2645
|
+
shutterAngle: blur.shutter,
|
|
2646
|
+
sampleCount: blur.samples,
|
|
2647
|
+
maxBlur: blur.maxBlur
|
|
2648
|
+
});
|
|
2649
|
+
};
|
|
1970
2650
|
const flush3DPass = (curTex, curView, curExcludes) => {
|
|
1971
2651
|
if (pending3DItems.length === 0 || !camera) return {
|
|
1972
2652
|
finalTex: curTex,
|
|
@@ -1978,6 +2658,14 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1978
2658
|
if (item.opts.morphWeights?.length) item.meshBuffers = r3d$1.morphMesh(encoder, item.mesh, item.opts.morphWeights, item.opts.wireframe);
|
|
1979
2659
|
if (item.opts.audioDeform) item.meshBuffers = r3d$1.deformMesh(encoder, item.mesh, item.opts.audioDeform, item.opts.wireframe, item.meshBuffers);
|
|
1980
2660
|
}
|
|
2661
|
+
if (historyOnly) {
|
|
2662
|
+
if (history) recordMotion(history, camera);
|
|
2663
|
+
pending3DItems.length = 0;
|
|
2664
|
+
return {
|
|
2665
|
+
finalTex: curTex,
|
|
2666
|
+
finalView: curView
|
|
2667
|
+
};
|
|
2668
|
+
}
|
|
1981
2669
|
const itemTextures = pendingTextures();
|
|
1982
2670
|
const scene3dTex = ctx.renderer.getTemporaryTexture(nativeWidth, nativeHeight, [
|
|
1983
2671
|
curTex,
|
|
@@ -1988,7 +2676,9 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1988
2676
|
const scene3dView = scene3dTex.createView();
|
|
1989
2677
|
const outlineSetting = sceneEnvironment?.outlines;
|
|
1990
2678
|
const outlines = outlineSetting === true ? {} : outlineSetting || null;
|
|
1991
|
-
const
|
|
2679
|
+
const volumetricFogEnabled = Boolean(sceneEnvironment?.volumetricFog);
|
|
2680
|
+
const screenIndirectEnabled = Boolean(sceneEnvironment?.ssr || sceneEnvironment?.gi);
|
|
2681
|
+
const geometryEnabled = dofEnabled || Boolean(outlines) || volumetricFogEnabled || screenIndirectEnabled;
|
|
1992
2682
|
let linearDepthTex;
|
|
1993
2683
|
let linearDepthView;
|
|
1994
2684
|
if (geometryEnabled) {
|
|
@@ -1999,7 +2689,10 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
1999
2689
|
const shadowLights = sceneLights.filter((light) => (light.lightType ?? light.type) !== "ambient").map((light, index) => ({
|
|
2000
2690
|
light,
|
|
2001
2691
|
index
|
|
2002
|
-
})).filter(({ light }) =>
|
|
2692
|
+
})).filter(({ light }) => {
|
|
2693
|
+
const k = light.lightType ?? light.type;
|
|
2694
|
+
return light.castShadow && (k === "directional" || k === "spot" || k === "rect" || k === "point");
|
|
2695
|
+
});
|
|
2003
2696
|
if (shadowLights.length > 0) {
|
|
2004
2697
|
const casters = [];
|
|
2005
2698
|
const receivers = [];
|
|
@@ -2021,13 +2714,23 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2021
2714
|
receivers.push(r3d$1.worldBounds(caster));
|
|
2022
2715
|
if (item.opts.castShadow === true) casters.push(caster);
|
|
2023
2716
|
}
|
|
2024
|
-
if (casters.length > 0)
|
|
2025
|
-
const
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
})
|
|
2030
|
-
|
|
2717
|
+
if (casters.length > 0) {
|
|
2718
|
+
const totalShadowLayers = shadowLights.reduce((sum, { light }) => sum + ((light.lightType ?? light.type) === "point" ? 6 : 1), 0);
|
|
2719
|
+
const allPointShadows = shadowLights.every(({ light }) => (light.lightType ?? light.type) === "point");
|
|
2720
|
+
const resolvedShadowMapSize = shadowMapSize ?? (allPointShadows ? 1024 : 2048);
|
|
2721
|
+
let currentLayer = 0;
|
|
2722
|
+
for (const { light, index } of shadowLights) {
|
|
2723
|
+
const needed = (light.lightType ?? light.type) === "point" ? 6 : 1;
|
|
2724
|
+
const result = r3d$1.renderShadowMap(encoder, light, index, casters, receivers, {
|
|
2725
|
+
mapSize: resolvedShadowMapSize,
|
|
2726
|
+
layer: currentLayer,
|
|
2727
|
+
layerCount: totalShadowLayers
|
|
2728
|
+
});
|
|
2729
|
+
if (result) {
|
|
2730
|
+
shadow.push(result);
|
|
2731
|
+
currentLayer += result.layerCount ?? needed;
|
|
2732
|
+
}
|
|
2733
|
+
}
|
|
2031
2734
|
}
|
|
2032
2735
|
}
|
|
2033
2736
|
const isGlass = (item) => item.kind === "mesh" && (item.opts.material === "glass" || item.opts.material === "acrylic" || item.opts.material === "frosted");
|
|
@@ -2094,28 +2797,34 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2094
2797
|
...transparent.map(({ item }) => item),
|
|
2095
2798
|
...glass
|
|
2096
2799
|
];
|
|
2800
|
+
if (cubeCamera) {
|
|
2801
|
+
const single = [screenIndirectEnabled && "screen-space reflections and GI (ssr, gi)", motionBlur && "motion blur"].filter(Boolean);
|
|
2802
|
+
if (single.length) throw new Error(`A cube camera (${cubeCamera.remap.projection ?? "lens"}) cannot draw ${single.join(" or ")}: they need a single perspective view.`);
|
|
2803
|
+
}
|
|
2097
2804
|
const floorSpec = sceneEnvironment?.floor;
|
|
2098
|
-
|
|
2099
|
-
|
|
2805
|
+
const sceneShadow = shadow.length ? shadow : null;
|
|
2806
|
+
/** The floor's mirror image from `view`, blurred by its roughness, when the eye is above it. */
|
|
2807
|
+
const floorReflection = (view, width, height) => {
|
|
2808
|
+
if (!floorSpec || typeof floorSpec.y !== "number" || view.eye[1] >= floorSpec.y) return null;
|
|
2100
2809
|
const reflectedCamera = {
|
|
2101
|
-
...
|
|
2810
|
+
...view,
|
|
2102
2811
|
eye: [
|
|
2103
|
-
|
|
2104
|
-
2 * floorSpec.y -
|
|
2105
|
-
|
|
2812
|
+
view.eye[0],
|
|
2813
|
+
2 * floorSpec.y - view.eye[1],
|
|
2814
|
+
view.eye[2]
|
|
2106
2815
|
],
|
|
2107
2816
|
target: [
|
|
2108
|
-
|
|
2109
|
-
2 * floorSpec.y -
|
|
2110
|
-
|
|
2817
|
+
view.target[0],
|
|
2818
|
+
2 * floorSpec.y - view.target[1],
|
|
2819
|
+
view.target[2]
|
|
2111
2820
|
],
|
|
2112
2821
|
up: [
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2822
|
+
view.up[0],
|
|
2823
|
+
view.up[1],
|
|
2824
|
+
view.up[2]
|
|
2116
2825
|
]
|
|
2117
2826
|
};
|
|
2118
|
-
const { pass: reflPass, cameraBindGroup: reflCamBind, lightsBindGroup: reflLightsBind, reflectionTexture: reflTex } = r3d$1.beginReflectionPass(encoder,
|
|
2827
|
+
const { pass: reflPass, cameraBindGroup: reflCamBind, lightsBindGroup: reflLightsBind, reflectionTexture: reflTex } = r3d$1.beginReflectionPass(encoder, width, height, reflectedCamera, sceneLights, {
|
|
2119
2828
|
environment: sceneEnvironment,
|
|
2120
2829
|
shadow: null
|
|
2121
2830
|
});
|
|
@@ -2123,28 +2832,112 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2123
2832
|
else if (item.kind === "slug") r3d$1.drawSlugText(reflPass, reflCamBind, reflLightsBind, item.batches, item.opts, item.stackBase, false);
|
|
2124
2833
|
else if (item.kind === "mesh") r3d$1.drawMesh3D(reflPass, reflCamBind, reflLightsBind, item.meshBuffers ?? item.mesh, item.texture, item.opts, false);
|
|
2125
2834
|
reflPass.end();
|
|
2126
|
-
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2835
|
+
return r3d$1.blurReflection(encoder, reflTex, floorSpec.roughness ?? .35);
|
|
2836
|
+
};
|
|
2837
|
+
/**
|
|
2838
|
+
* One forward pass over the batch: floor, then the sorted draws.
|
|
2839
|
+
* `glassBackdrop` is the 2D picture glass refracts: undefined draws
|
|
2840
|
+
* glass over the 3D scene alone (a cube face), null leaves the glass
|
|
2841
|
+
* out (the pre-pass that makes that picture).
|
|
2842
|
+
*/
|
|
2843
|
+
const drawView = (target, screenIndirect, writeHdr, glassBackdrop) => {
|
|
2844
|
+
const begun = r3d$1.beginPass(encoder, target.color, target.width, target.height, target.view, "clear", {
|
|
2845
|
+
r: 0,
|
|
2846
|
+
g: 0,
|
|
2847
|
+
b: 0,
|
|
2848
|
+
a: 0
|
|
2849
|
+
}, target.geometry, sceneLights, {
|
|
2850
|
+
environment: sceneEnvironment,
|
|
2851
|
+
shadow: sceneShadow,
|
|
2852
|
+
screenIndirect
|
|
2853
|
+
}, writeHdr, target.hdr);
|
|
2854
|
+
const { pass: pass$1, cameraBindGroup, lightsBindGroup } = begun;
|
|
2855
|
+
if (floorSpec && target.reflection) r3d$1.drawFloor(pass$1, cameraBindGroup, lightsBindGroup, target.reflection, floorSpec, geometryEnabled, writeHdr);
|
|
2856
|
+
for (const item of ordered) {
|
|
2857
|
+
if (glassBackdrop === null && isGlass(item)) continue;
|
|
2858
|
+
if (item.kind === "quad") r3d$1.drawTextureQuad(pass$1, cameraBindGroup, lightsBindGroup, item.texture, item.opts, geometryEnabled);
|
|
2859
|
+
else if (item.kind === "slug") r3d$1.drawSlugText(pass$1, cameraBindGroup, lightsBindGroup, item.batches, item.opts, item.stackBase, geometryEnabled);
|
|
2860
|
+
else if (item.kind === "mesh") r3d$1.drawMesh3D(pass$1, cameraBindGroup, lightsBindGroup, item.meshBuffers ?? item.mesh, item.texture, isGlass(item) ? {
|
|
2861
|
+
...item.opts,
|
|
2862
|
+
backdrop: glassBackdrop ?? void 0
|
|
2863
|
+
} : item.opts, geometryEnabled);
|
|
2864
|
+
}
|
|
2865
|
+
pass$1.end();
|
|
2866
|
+
return begun;
|
|
2867
|
+
};
|
|
2868
|
+
const sceneSeconds = shiftedFrame / Math.max(1, fps ?? 24);
|
|
2145
2869
|
let final3dTex = scene3dTex;
|
|
2146
|
-
|
|
2147
|
-
|
|
2870
|
+
let mainReflection = null;
|
|
2871
|
+
let mainPass = null;
|
|
2872
|
+
if (cubeCamera) {
|
|
2873
|
+
const size = cubeCamera.faceSize;
|
|
2874
|
+
const cube = r3d$1.getOrCreateCubeTexture(size, false);
|
|
2875
|
+
const hdrCube = sceneBloom ? r3d$1.getOrCreateCubeTexture(size, true) : null;
|
|
2876
|
+
const faceOutlines = outlines && {
|
|
2877
|
+
...outlines,
|
|
2878
|
+
referenceHeight: (outlines.referenceHeight ?? 1080) * 2 * cubeCamera.centerDensity / nativeHeight
|
|
2879
|
+
};
|
|
2880
|
+
const post = Boolean(faceOutlines) || volumetricFogEnabled;
|
|
2881
|
+
const faceExcludes = [
|
|
2882
|
+
curTex,
|
|
2883
|
+
targetTexture,
|
|
2884
|
+
scene3dTex,
|
|
2885
|
+
...curExcludes,
|
|
2886
|
+
...itemTextures
|
|
2887
|
+
];
|
|
2888
|
+
const faceTex = post ? ctx.renderer.getTemporaryTexture(size, size, faceExcludes) : null;
|
|
2889
|
+
const fogTex = faceOutlines && volumetricFogEnabled ? ctx.renderer.getTemporaryTexture(size, size, [...faceExcludes, ...faceTex ? [faceTex] : []]) : null;
|
|
2890
|
+
const faceGeometry = geometryEnabled ? r3d$1.getOrCreateLinearDepthTexture(size, size) : null;
|
|
2891
|
+
cubeFaceCameras(camera.eye, camera.near, camera.far).forEach((face, i) => {
|
|
2892
|
+
const faceView = r3d$1.cubeFaceView(cube, i);
|
|
2893
|
+
const { cameraBindGroup, lightsBindGroup } = drawView({
|
|
2894
|
+
view: face,
|
|
2895
|
+
width: size,
|
|
2896
|
+
height: size,
|
|
2897
|
+
color: faceTex ? faceTex.createView() : faceView,
|
|
2898
|
+
geometry: faceGeometry?.createView(),
|
|
2899
|
+
hdr: hdrCube ? r3d$1.cubeFaceView(hdrCube, i) : void 0,
|
|
2900
|
+
reflection: floorReflection(face, size, size)
|
|
2901
|
+
}, void 0, Boolean(sceneBloom), void 0);
|
|
2902
|
+
if (!faceTex || !faceGeometry) return;
|
|
2903
|
+
if (volumetricFogEnabled) r3d$1.resolveGeometry(encoder, faceGeometry);
|
|
2904
|
+
let source = faceTex;
|
|
2905
|
+
if (faceOutlines) {
|
|
2906
|
+
const inked = fogTex ?? null;
|
|
2907
|
+
r3d$1.applyOutlines(encoder, faceTex, faceGeometry, inked ? inked.createView() : faceView, face, faceOutlines, sceneEnvironment?.fog);
|
|
2908
|
+
if (!inked) return;
|
|
2909
|
+
source = inked;
|
|
2910
|
+
}
|
|
2911
|
+
if (volumetricFogEnabled && sceneEnvironment) r3d$1.applyVolumetricFog(encoder, source, faceGeometry, faceView, cameraBindGroup, lightsBindGroup, sceneEnvironment, sceneSeconds, shiftedFrame);
|
|
2912
|
+
});
|
|
2913
|
+
r3d$1.remapLens(encoder, cube, hdrCube, scene3dView, nativeWidth, nativeHeight, cubeCamera.remap);
|
|
2914
|
+
} else {
|
|
2915
|
+
mainReflection = floorReflection(camera, nativeWidth, nativeHeight);
|
|
2916
|
+
const target = {
|
|
2917
|
+
view: camera,
|
|
2918
|
+
width: nativeWidth,
|
|
2919
|
+
height: nativeHeight,
|
|
2920
|
+
color: scene3dView,
|
|
2921
|
+
geometry: linearDepthView,
|
|
2922
|
+
reflection: mainReflection
|
|
2923
|
+
};
|
|
2924
|
+
if (screenIndirectEnabled && sceneEnvironment) {
|
|
2925
|
+
const { cameraBuffer: radianceCamera } = drawView(target, "radiance", true, curTex);
|
|
2926
|
+
r3d$1.traceScreenIndirect(encoder, radianceCamera, sceneEnvironment);
|
|
2927
|
+
}
|
|
2928
|
+
let glassBackdrop = curTex;
|
|
2929
|
+
if (glass.length) {
|
|
2930
|
+
drawView(target, screenIndirectEnabled ? "apply" : void 0, false, null);
|
|
2931
|
+
glassBackdrop = ctx.renderer.composite(encoder, curTex, scene3dTex, "normal", [
|
|
2932
|
+
targetTexture,
|
|
2933
|
+
scene3dTex,
|
|
2934
|
+
...curExcludes
|
|
2935
|
+
]);
|
|
2936
|
+
}
|
|
2937
|
+
mainPass = drawView(target, screenIndirectEnabled ? "apply" : void 0, Boolean(sceneBloom), glassBackdrop);
|
|
2938
|
+
}
|
|
2939
|
+
if (mainPass && outlines && linearDepthTex) {
|
|
2940
|
+
if (dofEnabled || volumetricFogEnabled) r3d$1.resolveGeometry(encoder, linearDepthTex);
|
|
2148
2941
|
const outlinedTex = ctx.renderer.getTemporaryTexture(nativeWidth, nativeHeight, [
|
|
2149
2942
|
curTex,
|
|
2150
2943
|
targetTexture,
|
|
@@ -2155,7 +2948,19 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2155
2948
|
r3d$1.applyOutlines(encoder, scene3dTex, linearDepthTex, outlinedTex.createView(), camera, outlines, sceneEnvironment?.fog);
|
|
2156
2949
|
final3dTex = outlinedTex;
|
|
2157
2950
|
}
|
|
2158
|
-
if (
|
|
2951
|
+
if (mainPass && volumetricFogEnabled && sceneEnvironment && linearDepthTex) {
|
|
2952
|
+
const vfogTex = ctx.renderer.getTemporaryTexture(nativeWidth, nativeHeight, [
|
|
2953
|
+
curTex,
|
|
2954
|
+
targetTexture,
|
|
2955
|
+
scene3dTex,
|
|
2956
|
+
final3dTex,
|
|
2957
|
+
linearDepthTex,
|
|
2958
|
+
...curExcludes
|
|
2959
|
+
]);
|
|
2960
|
+
r3d$1.applyVolumetricFog(encoder, final3dTex, linearDepthTex, vfogTex.createView(), mainPass.cameraBindGroup, mainPass.lightsBindGroup, sceneEnvironment, sceneSeconds, shiftedFrame);
|
|
2961
|
+
final3dTex = vfogTex;
|
|
2962
|
+
}
|
|
2963
|
+
if (mainPass && dofEnabled && linearDepthTex) {
|
|
2159
2964
|
const dofResultTex = ctx.renderer.getTemporaryTexture(nativeWidth, nativeHeight, [
|
|
2160
2965
|
curTex,
|
|
2161
2966
|
targetTexture,
|
|
@@ -2163,9 +2968,21 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2163
2968
|
final3dTex,
|
|
2164
2969
|
...curExcludes
|
|
2165
2970
|
]);
|
|
2166
|
-
r3d$1.applyDepthOfField(encoder, final3dTex, linearDepthTex, dofResultTex.createView(), cameraBuffer);
|
|
2971
|
+
r3d$1.applyDepthOfField(encoder, final3dTex, linearDepthTex, dofResultTex.createView(), mainPass.cameraBuffer);
|
|
2167
2972
|
final3dTex = dofResultTex;
|
|
2168
2973
|
}
|
|
2974
|
+
if (motionBlur && history) {
|
|
2975
|
+
const blurredTex = ctx.renderer.getTemporaryTexture(nativeWidth, nativeHeight, [
|
|
2976
|
+
curTex,
|
|
2977
|
+
targetTexture,
|
|
2978
|
+
scene3dTex,
|
|
2979
|
+
final3dTex,
|
|
2980
|
+
...curExcludes
|
|
2981
|
+
]);
|
|
2982
|
+
blurScene(history, camera, final3dTex, blurredTex, motionBlur, floorSpec && mainReflection ? floorSpec : void 0);
|
|
2983
|
+
final3dTex = blurredTex;
|
|
2984
|
+
}
|
|
2985
|
+
if (history) recordMotion(history, camera);
|
|
2169
2986
|
if (sceneBloom) {
|
|
2170
2987
|
const bloomTex = ctx.renderer.getTemporaryTexture(nativeWidth, nativeHeight, [
|
|
2171
2988
|
curTex,
|
|
@@ -2226,15 +3043,17 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2226
3043
|
let activeExcludes = excludes;
|
|
2227
3044
|
const mattesByOwner = /* @__PURE__ */ new Map();
|
|
2228
3045
|
const reliefsByOwner = /* @__PURE__ */ new Map();
|
|
3046
|
+
const texturesByOwner = /* @__PURE__ */ new Map();
|
|
2229
3047
|
for (const vm of vms) {
|
|
2230
3048
|
const op$1 = vm.operation;
|
|
2231
3049
|
if (op$1?.matteOf) mattesByOwner.set(op$1.matteOf, vm);
|
|
2232
3050
|
if (op$1?.reliefOf) reliefsByOwner.set(op$1.reliefOf, vm);
|
|
3051
|
+
if (op$1?.textureOf) texturesByOwner.set(op$1.textureOf, vm);
|
|
2233
3052
|
}
|
|
2234
3053
|
for (const child of sorted) {
|
|
2235
3054
|
const lop = child.operation;
|
|
2236
3055
|
if (lop.kind === "camera" || lop.kind === "light") continue;
|
|
2237
|
-
if (lop.matteOf || lop.reliefOf) continue;
|
|
3056
|
+
if (lop.matteOf || lop.reliefOf || lop.textureOf) continue;
|
|
2238
3057
|
const targetId = lop.id || lop.inputHandleId;
|
|
2239
3058
|
const target = targetId ? targetsById[targetId] : void 0;
|
|
2240
3059
|
const isChild3D = Boolean(target?.is3D ?? lop.is3D) || Boolean(camera && ((target?.z ?? lop.z ?? 0) !== 0 || lop.is3D)) || Boolean(parent3DMatrix);
|
|
@@ -2293,10 +3112,37 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2293
3112
|
amount: lop.reliefAmount ?? 0
|
|
2294
3113
|
});
|
|
2295
3114
|
}
|
|
3115
|
+
const textureVM = lop.textureLayerId ? texturesByOwner.get(lop.id) : void 0;
|
|
3116
|
+
let wrapTexture;
|
|
3117
|
+
if (textureVM) {
|
|
3118
|
+
const texture = await isolate(textureVM, nodeIndex);
|
|
3119
|
+
activeExcludes = [...activeExcludes, texture];
|
|
3120
|
+
nodeIndex += 1;
|
|
3121
|
+
const r = rects[lop.textureLayerId];
|
|
3122
|
+
const uvRect = r ? [
|
|
3123
|
+
r.x / targetW,
|
|
3124
|
+
r.y / targetH,
|
|
3125
|
+
r.width / targetW,
|
|
3126
|
+
r.height / targetH
|
|
3127
|
+
] : [
|
|
3128
|
+
0,
|
|
3129
|
+
0,
|
|
3130
|
+
1,
|
|
3131
|
+
1
|
|
3132
|
+
];
|
|
3133
|
+
const from = pending3DItems.length;
|
|
3134
|
+
wrapTexture = () => {
|
|
3135
|
+
for (const item of pending3DItems.slice(from)) {
|
|
3136
|
+
if (item.kind !== "mesh") continue;
|
|
3137
|
+
item.texture = texture;
|
|
3138
|
+
item.opts.uvRect = uvRect;
|
|
3139
|
+
}
|
|
3140
|
+
};
|
|
3141
|
+
}
|
|
2296
3142
|
const matteVM = lop.matteId ? mattesByOwner.get(lop.id) : void 0;
|
|
2297
3143
|
if (matteVM) {
|
|
2298
3144
|
const mode = matteVM.operation.matteMode ?? "alpha";
|
|
2299
|
-
const blend = mode === "luma" ? "luma-in" : mode === "luma-inverted" ? "luma-out" : mode === "alpha-inverted" ? "destination-out" : "destination-in";
|
|
3145
|
+
const blend$1 = mode === "luma" ? "luma-in" : mode === "luma-inverted" ? "luma-out" : mode === "alpha-inverted" ? "destination-out" : "destination-in";
|
|
2300
3146
|
if (isChild3D) {
|
|
2301
3147
|
let coverage = await isolate(matteVM, nodeIndex);
|
|
2302
3148
|
activeExcludes = [...activeExcludes, coverage];
|
|
@@ -2314,7 +3160,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2314
3160
|
b: 1,
|
|
2315
3161
|
a: 1
|
|
2316
3162
|
}, targetW, targetH, "clear").end();
|
|
2317
|
-
coverage = ctx.renderer.composite(encoder, white, coverage, blend, [
|
|
3163
|
+
coverage = ctx.renderer.composite(encoder, white, coverage, blend$1, [
|
|
2318
3164
|
targetTexture,
|
|
2319
3165
|
activeTex,
|
|
2320
3166
|
...activeExcludes,
|
|
@@ -2326,6 +3172,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2326
3172
|
const before = pending3DItems.length;
|
|
2327
3173
|
const res$1 = await renderLayerVM(child, nodeIndex, activeTex, activeView, activeExcludes, accumulatedOpacity, parentMatrix, parentRect, targetW, targetH, parent3DMatrix, isRootScene);
|
|
2328
3174
|
for (const item of pending3DItems.slice(before)) item.opts.matte = coverage;
|
|
3175
|
+
wrapTexture?.();
|
|
2329
3176
|
if (res$1) {
|
|
2330
3177
|
if (res$1.finalTex !== activeTex) activeExcludes = [...activeExcludes, res$1.finalTex];
|
|
2331
3178
|
activeTex = res$1.finalTex;
|
|
@@ -2337,7 +3184,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2337
3184
|
activeExcludes = [...activeExcludes, contentTex];
|
|
2338
3185
|
nodeIndex += 1;
|
|
2339
3186
|
const matteTex = await isolate(matteVM, nodeIndex);
|
|
2340
|
-
const masked = ctx.renderer.composite(encoder, contentTex, matteTex, blend, [
|
|
3187
|
+
const masked = ctx.renderer.composite(encoder, contentTex, matteTex, blend$1, [
|
|
2341
3188
|
targetTexture,
|
|
2342
3189
|
activeTex,
|
|
2343
3190
|
...activeExcludes,
|
|
@@ -2354,6 +3201,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2354
3201
|
continue;
|
|
2355
3202
|
}
|
|
2356
3203
|
const res = await renderLayerVM(child, nodeIndex, activeTex, activeView, activeExcludes, accumulatedOpacity, parentMatrix, parentRect, targetW, targetH, parent3DMatrix, isRootScene);
|
|
3204
|
+
wrapTexture?.();
|
|
2357
3205
|
if (res) {
|
|
2358
3206
|
if (res.finalTex !== activeTex) activeExcludes = [...activeExcludes, res.finalTex];
|
|
2359
3207
|
activeTex = res.finalTex;
|
|
@@ -2386,6 +3234,8 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2386
3234
|
if (shiftedFrame < startFrame) return;
|
|
2387
3235
|
if (durationFrames !== void 0 && shiftedFrame >= startFrame + durationFrames) return;
|
|
2388
3236
|
}
|
|
3237
|
+
const isTrue3D = Boolean(target?.is3D ?? lop.is3D) || Boolean(camera && ((target?.z ?? lop.z ?? 0) !== 0 || lop.is3D));
|
|
3238
|
+
if (historyOnly && !isContainer && kind !== "model3d" && !isTrue3D && !has3DTransform(target, lop)) return;
|
|
2389
3239
|
if (kind === "model3d") {
|
|
2390
3240
|
const r3d$1 = getRenderer3D(ctx.device, ctx.renderer.format ?? "rgba8unorm", sampleCount3d);
|
|
2391
3241
|
let modelSrc = lop.modelData ?? lop.src;
|
|
@@ -2414,6 +3264,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2414
3264
|
} catch (err) {
|
|
2415
3265
|
throw new Error(`Failed to load 3D model ${lop.id ?? "(unnamed)"}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
2416
3266
|
}
|
|
3267
|
+
if (model && lop.fracture3d) model = fracturedModel(model, lop.fracture3d);
|
|
2417
3268
|
if (!model || model.meshes.length === 0) return;
|
|
2418
3269
|
const baseX$1 = lop.x ?? 0;
|
|
2419
3270
|
const baseY$1 = lop.y ?? 0;
|
|
@@ -2469,6 +3320,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2469
3320
|
const instOpt = lop.instances3d;
|
|
2470
3321
|
const rawMeshes = Array.isArray(instOpt.mesh) ? instOpt.mesh : instOpt.mesh ? [instOpt.mesh] : lop.modelData ? [lop.modelData] : lop.primitive3d ? [getPrimitiveGeometry(lop.primitive3d)] : [];
|
|
2471
3322
|
const variants = [];
|
|
3323
|
+
const variantPres = [];
|
|
2472
3324
|
for (const m of rawMeshes) {
|
|
2473
3325
|
let vModel;
|
|
2474
3326
|
if (typeof m === "object" && m !== null) {
|
|
@@ -2482,19 +3334,50 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2482
3334
|
});
|
|
2483
3335
|
} catch {}
|
|
2484
3336
|
}
|
|
2485
|
-
if (vModel && vModel.meshes && vModel.meshes.length > 0)
|
|
3337
|
+
if (vModel && vModel.meshes && vModel.meshes.length > 0) {
|
|
3338
|
+
variants.push(vModel);
|
|
3339
|
+
const isNode = !("meshes" in m);
|
|
3340
|
+
variantPres.push(isNode ? {
|
|
3341
|
+
q: quatFromEulerAngles(m.rotateX ?? 0, m.rotateY ?? 0, m.rotateZ ?? 0),
|
|
3342
|
+
s: m.scale ?? 1
|
|
3343
|
+
} : NO_PRE);
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
if (variants.length === 0 && model) {
|
|
3347
|
+
variants.push(model);
|
|
3348
|
+
variantPres.push(NO_PRE);
|
|
3349
|
+
}
|
|
3350
|
+
if (lop.scatter3d && variants.length > 0) {
|
|
3351
|
+
const scatter = lop.scatter3d;
|
|
3352
|
+
const surface = await surfaceModel(scatter.surface, (src, n) => r3d$1.loadModelAsync(src, n.modelFormat ?? "auto", {
|
|
3353
|
+
center: n.center,
|
|
3354
|
+
normalizeSize: n.normalizeSize
|
|
3355
|
+
}));
|
|
3356
|
+
instOpt.transforms = surface ? scatterTransforms(scatter, surface, variants.map((v, k) => variantBottom(v, variantPres[k]))) : [];
|
|
3357
|
+
instOpt.count = instOpt.transforms.length;
|
|
2486
3358
|
}
|
|
2487
|
-
if (variants.length === 0 && model) variants.push(model);
|
|
2488
3359
|
if (variants.length > 0) {
|
|
2489
3360
|
const count = instOpt.bodies && Array.isArray(instOpt.bodies) && instOpt.bodies.length > 0 ? instOpt.bodies.length : instOpt.count ?? (Array.isArray(instOpt.transforms) ? instOpt.transforms.length : 0);
|
|
2490
3361
|
if (count > 0) {
|
|
2491
3362
|
const numVariants = variants.length;
|
|
2492
3363
|
const bucketCounts = new Uint32Array(numVariants);
|
|
2493
3364
|
for (let i$1 = 0; i$1 < count; i$1++) bucketCounts[i$1 % numVariants]++;
|
|
3365
|
+
const crowdCfg = lop.crowd;
|
|
3366
|
+
const crowdBakes = variants.map((v) => crowdCfg ? crowdBake(v, crowdCfg) : void 0);
|
|
3367
|
+
const strides = crowdBakes.map((b) => b ? 32 : 16);
|
|
3368
|
+
const crowdOpts = (bake, mesh) => {
|
|
3369
|
+
const baked = bake?.meshes.get(mesh);
|
|
3370
|
+
if (!bake || !baked) return void 0;
|
|
3371
|
+
return {
|
|
3372
|
+
palette: paletteBuffer(ctx.device, baked.palette),
|
|
3373
|
+
jointCount: baked.jointCount,
|
|
3374
|
+
time: (shiftedFrame ?? 0) / (fps || 30)
|
|
3375
|
+
};
|
|
3376
|
+
};
|
|
2494
3377
|
const bucketItems = [];
|
|
2495
3378
|
const bucketBounds = [];
|
|
2496
3379
|
for (let k = 0; k < numVariants; k++) {
|
|
2497
|
-
bucketItems.push(new Float32Array(bucketCounts[k] *
|
|
3380
|
+
bucketItems.push(new Float32Array(bucketCounts[k] * strides[k]));
|
|
2498
3381
|
bucketBounds.push({
|
|
2499
3382
|
min: [
|
|
2500
3383
|
Infinity,
|
|
@@ -2523,7 +3406,8 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2523
3406
|
const cursor = bucketCursors[k];
|
|
2524
3407
|
const bData = bucketItems[k];
|
|
2525
3408
|
const bBox = bucketBounds[k];
|
|
2526
|
-
const off = cursor *
|
|
3409
|
+
const off = cursor * strides[k];
|
|
3410
|
+
let ianim = {};
|
|
2527
3411
|
let ix = 0;
|
|
2528
3412
|
let iy = 0;
|
|
2529
3413
|
let iz = 0;
|
|
@@ -2580,6 +3464,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2580
3464
|
} else if (typeof instOpt.instanceAt === "function") {
|
|
2581
3465
|
const t = instOpt.instanceAt(i$1, shiftedFrame ?? 0, fps || 30);
|
|
2582
3466
|
if (!t) continue;
|
|
3467
|
+
ianim = t;
|
|
2583
3468
|
ix = t.x ?? 0;
|
|
2584
3469
|
iy = t.y ?? 0;
|
|
2585
3470
|
iz = t.z ?? 0;
|
|
@@ -2626,6 +3511,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2626
3511
|
}
|
|
2627
3512
|
} else if (Array.isArray(instOpt.transforms) && instOpt.transforms[i$1]) {
|
|
2628
3513
|
const t = instOpt.transforms[i$1];
|
|
3514
|
+
ianim = t;
|
|
2629
3515
|
ix = t.x ?? 0;
|
|
2630
3516
|
iy = t.y ?? 0;
|
|
2631
3517
|
iz = t.z ?? 0;
|
|
@@ -2672,6 +3558,16 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2672
3558
|
}
|
|
2673
3559
|
} else continue;
|
|
2674
3560
|
bucketCursors[k]++;
|
|
3561
|
+
const pre = variantPres[k];
|
|
3562
|
+
if (pre !== NO_PRE) {
|
|
3563
|
+
[iqx, iqy, iqz, iqw] = composeQuat([
|
|
3564
|
+
iqx,
|
|
3565
|
+
iqy,
|
|
3566
|
+
iqz,
|
|
3567
|
+
iqw
|
|
3568
|
+
], pre.q);
|
|
3569
|
+
iscale *= pre.s;
|
|
3570
|
+
}
|
|
2675
3571
|
bData[off + 0] = ix;
|
|
2676
3572
|
bData[off + 1] = iy;
|
|
2677
3573
|
bData[off + 2] = iz;
|
|
@@ -2688,7 +3584,10 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2688
3584
|
bData[off + 13] = ieg;
|
|
2689
3585
|
bData[off + 14] = ieb;
|
|
2690
3586
|
bData[off + 15] = iew;
|
|
2691
|
-
const
|
|
3587
|
+
const bake = crowdBakes[k];
|
|
3588
|
+
if (bake && crowdCfg) bData.set(crowdRecord(bake, crowdCfg, i$1, ianim), off + 16);
|
|
3589
|
+
const vb = variants[k].bounds;
|
|
3590
|
+
const rad = (vb ? vb.boundingSphereRadius + Math.hypot(...vb.center) : 50) * iscale;
|
|
2692
3591
|
bBox.min[0] = Math.min(bBox.min[0], ix - rad);
|
|
2693
3592
|
bBox.min[1] = Math.min(bBox.min[1], iy - rad);
|
|
2694
3593
|
bBox.min[2] = Math.min(bBox.min[2], iz - rad);
|
|
@@ -2700,15 +3599,26 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2700
3599
|
const bCount = bucketCursors[k];
|
|
2701
3600
|
if (bCount === 0) continue;
|
|
2702
3601
|
const v = variants[k];
|
|
2703
|
-
const activeSlice = bCount === bucketCounts[k] ? bucketItems[k] : bucketItems[k].subarray(0, bCount *
|
|
3602
|
+
const activeSlice = bCount === bucketCounts[k] ? bucketItems[k] : bucketItems[k].subarray(0, bCount * strides[k]);
|
|
2704
3603
|
const instanceBuffer = r3d$1.uploadInstanceData(activeSlice);
|
|
2705
3604
|
const bounds = Number.isFinite(bucketBounds[k].min[0]) ? bucketBounds[k] : void 0;
|
|
2706
3605
|
for (const mesh of v.meshes) {
|
|
2707
3606
|
const mat = mesh.materialName ? v.materials[mesh.materialName] : void 0;
|
|
3607
|
+
const diffuse = mat?.diffuseColor ?? [
|
|
3608
|
+
1,
|
|
3609
|
+
1,
|
|
3610
|
+
1,
|
|
3611
|
+
1
|
|
3612
|
+
];
|
|
2708
3613
|
const meshOpts = {
|
|
2709
3614
|
modelMatrix: finalModelMatrix,
|
|
2710
3615
|
opacity: modelOpacity * (mat?.opacity ?? 1),
|
|
2711
|
-
colorTint
|
|
3616
|
+
colorTint: [
|
|
3617
|
+
colorTint[0] * diffuse[0],
|
|
3618
|
+
colorTint[1] * diffuse[1],
|
|
3619
|
+
colorTint[2] * diffuse[2],
|
|
3620
|
+
colorTint[3] * (diffuse[3] ?? 1)
|
|
3621
|
+
],
|
|
2712
3622
|
transparent: false,
|
|
2713
3623
|
twoSided: target?.twoSided ?? lop.twoSided ?? true,
|
|
2714
3624
|
wireframe: Boolean(target?.wireframe ?? lop.wireframe),
|
|
@@ -2720,9 +3630,12 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
2720
3630
|
...surfaceProps(target, lop, mat),
|
|
2721
3631
|
instanceBuffer,
|
|
2722
3632
|
instanceCount: bCount,
|
|
2723
|
-
bounds
|
|
3633
|
+
bounds,
|
|
3634
|
+
wind: meshWind(lop.wind, v, (shiftedFrame ?? 0) / (fps || 30)),
|
|
3635
|
+
crowd: crowdOpts(crowdBakes[k], mesh)
|
|
2724
3636
|
};
|
|
2725
3637
|
pending3DItems.push({
|
|
3638
|
+
owner: lop.id,
|
|
2726
3639
|
kind: "mesh",
|
|
2727
3640
|
mesh,
|
|
2728
3641
|
texture: mat ? await r3d$1.materialTexture(mat) : void 0,
|
|
@@ -3062,6 +3975,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
3062
3975
|
firstInstance
|
|
3063
3976
|
};
|
|
3064
3977
|
pending3DItems.push({
|
|
3978
|
+
owner: lop.id,
|
|
3065
3979
|
kind: "mesh",
|
|
3066
3980
|
mesh,
|
|
3067
3981
|
texture: mat ? await r3d$1.materialTexture(mat) : void 0,
|
|
@@ -3092,6 +4006,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
3092
4006
|
firstInstance: sparkFirst
|
|
3093
4007
|
};
|
|
3094
4008
|
pending3DItems.push({
|
|
4009
|
+
owner: lop.id,
|
|
3095
4010
|
kind: "mesh",
|
|
3096
4011
|
mesh,
|
|
3097
4012
|
texture: mat ? await r3d$1.materialTexture(mat) : void 0,
|
|
@@ -3116,7 +4031,22 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
3116
4031
|
if (lop.loop ?? true) clipSec %= clip.duration;
|
|
3117
4032
|
}
|
|
3118
4033
|
const sceneRoot = Matrix4Math.multiply(finalModelMatrix, model.rootTransform ?? Matrix4Math.identity());
|
|
3119
|
-
const
|
|
4034
|
+
const layerProps = Matrix4Math.multiply(Matrix4Math.translate(sampledX$1 - posX, sampledY$1 - posY, 0), localM);
|
|
4035
|
+
const wholeFracture = Boolean(lop.fracture3d && fractureWhole(model, lop.fracture3d, shiftedFrame ?? 0));
|
|
4036
|
+
const posed = lop.fracture3d && !wholeFracture && fracturePose(model, lop.fracture3d, shiftedFrame ?? 0, layerProps, [
|
|
4037
|
+
scX,
|
|
4038
|
+
scY,
|
|
4039
|
+
scZ
|
|
4040
|
+
]) || (model.nodes ? poseCharacter({
|
|
4041
|
+
model,
|
|
4042
|
+
node: lop,
|
|
4043
|
+
frame: shiftedFrame ?? 0,
|
|
4044
|
+
fps: fps || 30,
|
|
4045
|
+
clip,
|
|
4046
|
+
clipSec,
|
|
4047
|
+
sceneRoot,
|
|
4048
|
+
key: `${compiled.key}:${lop.id}`
|
|
4049
|
+
}) : void 0);
|
|
3120
4050
|
const skinCache = /* @__PURE__ */ new Map();
|
|
3121
4051
|
const placeMesh = (mesh) => {
|
|
3122
4052
|
if (!posed) return { matrix: sceneRoot };
|
|
@@ -3177,6 +4107,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
3177
4107
|
}
|
|
3178
4108
|
}
|
|
3179
4109
|
for (const mesh of model.meshes) {
|
|
4110
|
+
if (wholeFracture && mesh.materialName === FRACTURE_INTERIOR_MATERIAL) continue;
|
|
3180
4111
|
const mat = mesh.materialName ? model.materials[mesh.materialName] : void 0;
|
|
3181
4112
|
const placed = placeMesh(mesh);
|
|
3182
4113
|
const meshSkin = placed.joints ?? skinningMatrices;
|
|
@@ -3279,7 +4210,10 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
3279
4210
|
}
|
|
3280
4211
|
const meshOpts = {
|
|
3281
4212
|
modelMatrix: placed.matrix,
|
|
3282
|
-
morphWeights: sampleMorphWeights(mesh, clip, clipSec),
|
|
4213
|
+
morphWeights: namedMorphWeights(mesh.morphTargetNames, sampleMorphWeights(mesh, clip, clipSec), target?.morphs ?? lop.morphs, {
|
|
4214
|
+
frame: shiftedFrame ?? 0,
|
|
4215
|
+
fps: fps || 30
|
|
4216
|
+
}),
|
|
3283
4217
|
opacity: modelOpacity * (mat?.opacity ?? 1),
|
|
3284
4218
|
colorTint: meshColorTint,
|
|
3285
4219
|
transparent: mat?.alphaMode === "blend" || modelOpacity * (mat?.opacity ?? 1) < 1 || meshColorTint[3] < 1 || hasVertexAlpha(mesh),
|
|
@@ -3298,13 +4232,16 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
3298
4232
|
ambientIntensity: target?.ambientIntensity ?? lop.ambientIntensity ?? 1,
|
|
3299
4233
|
metallic: target?.metallic ?? lop.metallic ?? mat?.metallic,
|
|
3300
4234
|
...surfaceProps(target, lop, mat),
|
|
3301
|
-
ior: target?.ior ?? lop.ior,
|
|
4235
|
+
ior: target?.ior ?? lop.ior ?? mat?.ior,
|
|
3302
4236
|
dispersion: target?.dispersion ?? lop.dispersion,
|
|
3303
4237
|
thickness: target?.thickness ?? lop.thickness,
|
|
3304
|
-
|
|
4238
|
+
...mat?.thickness !== void 0 ? { worldThickness: mat.thickness * matrixScale(placed.matrix) } : {},
|
|
4239
|
+
audioDeform: meshAudioDeform,
|
|
4240
|
+
wind: meshWind(lop.wind, model, (shiftedFrame ?? 0) / (fps || 30))
|
|
3305
4241
|
};
|
|
3306
4242
|
if (mat) meshOpts.maps = await r3d$1.materialMaps(mat);
|
|
3307
4243
|
pending3DItems.push({
|
|
4244
|
+
owner: lop.id,
|
|
3308
4245
|
kind: "mesh",
|
|
3309
4246
|
mesh,
|
|
3310
4247
|
texture: mat ? await r3d$1.materialTexture(mat) : void 0,
|
|
@@ -3430,7 +4367,6 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
3430
4367
|
if (backfaceVisibility === "hidden" && Transform3DMath.computeSignedArea(q) < 0) return;
|
|
3431
4368
|
quad3D = q;
|
|
3432
4369
|
}
|
|
3433
|
-
const isTrue3D = Boolean(target?.is3D ?? lop.is3D) || Boolean(camera && ((target?.z ?? lop.z ?? 0) !== 0 || lop.is3D));
|
|
3434
4370
|
if (isContainer) {
|
|
3435
4371
|
if (lop.transformStyle === "preserve-3d" && isTrue3D) {
|
|
3436
4372
|
let current3DMatrix = Matrix4Math.identity();
|
|
@@ -3561,6 +4497,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
3561
4497
|
}));
|
|
3562
4498
|
}
|
|
3563
4499
|
pending3DItems.push({
|
|
4500
|
+
owner: lop.id,
|
|
3564
4501
|
kind: "quad",
|
|
3565
4502
|
texture: activeGroupTex$1,
|
|
3566
4503
|
opts: quadOpts
|
|
@@ -4064,6 +5001,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
4064
5001
|
fontFamily: lop.fontFamily,
|
|
4065
5002
|
fontStyle: lop.fontStyle,
|
|
4066
5003
|
fontWeight: lop.fontWeight,
|
|
5004
|
+
fontVariations: lop.fontVariations,
|
|
4067
5005
|
fill: target?.fill ?? target?.color ?? lop.fill,
|
|
4068
5006
|
align: lop.align,
|
|
4069
5007
|
direction: lop.direction,
|
|
@@ -4314,8 +5252,9 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
4314
5252
|
if (Math.hypot(vx, vy) > .5) {
|
|
4315
5253
|
if (!isTrue3D && !(is3D && quad3D)) {
|
|
4316
5254
|
const reach = shutterAngle / 360;
|
|
4317
|
-
const
|
|
4318
|
-
const
|
|
5255
|
+
const side = ctx.device.limits.maxTextureDimension2D;
|
|
5256
|
+
const padX$1 = Math.min(Math.ceil(Math.abs(vx) * rasterScale * reach), Math.max(0, Math.floor((side - texW) / 2)));
|
|
5257
|
+
const padY$1 = Math.min(Math.ceil(Math.abs(vy) * rasterScale * reach), Math.max(0, Math.floor((side - texH) / 2)));
|
|
4319
5258
|
blurPadX = padX$1 / rasterScale;
|
|
4320
5259
|
blurPadY = padY$1 / rasterScale;
|
|
4321
5260
|
const paddedTex = ctx.renderer.getTemporaryTexture(texW + padX$1 * 2, texH + padY$1 * 2, [
|
|
@@ -4427,11 +5366,13 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
4427
5366
|
}
|
|
4428
5367
|
const quadHasContent = layerHasRaster || Boolean(quadOpts.borderWidth && quadOpts.borderWidth > 0 && quadOpts.borderColor);
|
|
4429
5368
|
if (!glyphBatches || quadHasContent) pending3DItems.push({
|
|
5369
|
+
owner: lop.id,
|
|
4430
5370
|
kind: "quad",
|
|
4431
5371
|
texture: renderedTex,
|
|
4432
5372
|
opts: quadOpts
|
|
4433
5373
|
});
|
|
4434
5374
|
if (glyphBatches && glyphBatches.length > 0) pending3DItems.push({
|
|
5375
|
+
owner: lop.id,
|
|
4435
5376
|
kind: "slug",
|
|
4436
5377
|
batches: glyphBatches,
|
|
4437
5378
|
opts: quadOpts,
|
|
@@ -4558,6 +5499,7 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
4558
5499
|
...props.excludeTextures || []
|
|
4559
5500
|
];
|
|
4560
5501
|
currentCompTex = (await renderNodeTree(virtualMedia.children ?? [], compTex, compView, initialExcludes, 1, new DOMMatrix(), null, nativeWidth, nativeHeight, null, true)).finalTex;
|
|
5502
|
+
if (history && camera) history.recordFrame(shiftedFrame, camera);
|
|
4561
5503
|
ctx.renderer.popTransform();
|
|
4562
5504
|
ctx.renderer.popScissor();
|
|
4563
5505
|
const finalPass = ctx.renderer.beginFrame(encoder, targetView, {
|
|
@@ -4575,6 +5517,43 @@ const CompositorWebGPURenderer = async (args) => {
|
|
|
4575
5517
|
args.pass = finalPass;
|
|
4576
5518
|
}
|
|
4577
5519
|
};
|
|
5520
|
+
/** Whether a composition's camera asks for shutter motion blur. */
|
|
5521
|
+
function sceneMotionBlur(virtualMedia) {
|
|
5522
|
+
return collectNodeOps(virtualMedia.children).some((vm) => {
|
|
5523
|
+
const op = vm.operation;
|
|
5524
|
+
return op?.kind === "camera" && Boolean(op.motionBlur);
|
|
5525
|
+
});
|
|
5526
|
+
}
|
|
5527
|
+
/**
|
|
5528
|
+
* Renders `frame` of the composition into a scratch target only to record
|
|
5529
|
+
* its 3D motion history (the frame after it reads it).
|
|
5530
|
+
*/
|
|
5531
|
+
async function renderMotionHistory(args, frame) {
|
|
5532
|
+
const { ctx, encoder, props, targetTexture, targetWidth, targetHeight } = args;
|
|
5533
|
+
const excludeTextures = [...props.excludeTextures ?? [], targetTexture];
|
|
5534
|
+
const scratch = ctx.renderer.getTemporaryTexture(targetWidth, targetHeight, excludeTextures);
|
|
5535
|
+
const view = scratch.createView();
|
|
5536
|
+
const sub = {
|
|
5537
|
+
...args,
|
|
5538
|
+
targetView: view,
|
|
5539
|
+
targetTexture: scratch,
|
|
5540
|
+
pass: ctx.renderer.beginFrame(encoder, view, {
|
|
5541
|
+
r: 0,
|
|
5542
|
+
g: 0,
|
|
5543
|
+
b: 0,
|
|
5544
|
+
a: 0
|
|
5545
|
+
}, targetWidth, targetHeight, "clear"),
|
|
5546
|
+
props: {
|
|
5547
|
+
...props,
|
|
5548
|
+
frame,
|
|
5549
|
+
...props.compositionFrame !== void 0 && { compositionFrame: props.compositionFrame - 1 },
|
|
5550
|
+
motionHistoryOnly: true,
|
|
5551
|
+
excludeTextures
|
|
5552
|
+
}
|
|
5553
|
+
};
|
|
5554
|
+
await CompositorWebGPURenderer(sub);
|
|
5555
|
+
sub.pass.end();
|
|
5556
|
+
}
|
|
4578
5557
|
/** Pixels of room around a border texture for its anti-aliased edge. */
|
|
4579
5558
|
const BORDER_AA_MARGIN = 2;
|
|
4580
5559
|
/**
|
|
@@ -4748,4 +5727,4 @@ var renderers_default = defineRenderer({ WebGPURenderer: CompositorWebGPURendere
|
|
|
4748
5727
|
|
|
4749
5728
|
//#endregion
|
|
4750
5729
|
export { Transform3DMath, renderers_default as default, has3DTransform };
|
|
4751
|
-
//# sourceMappingURL=renderer-
|
|
5730
|
+
//# sourceMappingURL=renderer-4nXkaAWu.mjs.map
|