@descix/frqtl-node 0.6.1-p3.2 → 0.6.1-p3.3
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/CLAUDE.md +1 -1
- package/README.md +1 -1
- package/dist/dist-manifest.json +21 -21
- package/dist/frqtl/compat/renderer/providers/godrays-layer.js +301 -12
- package/dist/frqtl/compat/renderer/providers/p5-provider.js +6 -0
- package/dist/frqtl/compat/renderer/providers/three-provider.js +66 -17
- package/dist/frqtl/objects/FrqtlApp.js +17 -1
- package/dist/frqtl/objects/RecipeContext.js +17 -0
- package/dist/frqtl/objects/record/Record.js +4 -9
- package/dist/frqtl/parts/FrqtlVision.js +158 -27
- package/dist/frqtl/parts/LiveChart.js +1 -1
- package/dist/frqtl/parts/SphereEmitter.js +2 -2
- package/dist/frqtl/parts/Tunnel.js +1 -1
- package/dist/frqtl/parts/Wall.js +1 -1
- package/dist/frqtl/scenes/dse-tunnel-rebuild.js +33 -22
- package/dist/frqtl/scenes/mirror-route.js +10 -6
- package/dist/shim/engine/router.js +2 -2
- package/dist/shim/field-descriptor/index.js +5 -5
- package/dist/shim/host/device.js +6 -2
- package/dist/shim/registry/exhibits.js +10 -10
- package/dist/shim/registry/walkthrough.js +38 -90
- package/dist/shim/render/capture-envelope.js +21 -0
- package/dist/shim/render/sun-look.js +6 -11
- package/llms.txt +2 -2
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A discrete cellular-automata physics engine (compiled Rust → WASM) for node: the same modules as
|
|
4
4
|
`@descix/frqtl-web` (one source, built twice), plus the node engine door `bootNode` and the hosted eyes.
|
|
5
|
-
`0.6.1-p3.
|
|
5
|
+
`0.6.1-p3.3` (npm dist-tag `next`). Node ≥ 22.12.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
npm install @descix/frqtl-node
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ FRQTL for node: a discrete cellular-automata physics engine (compiled Rust → W
|
|
|
4
4
|
local per-pixel rules — a frame moves one pixel per tick, single occupancy, momentum — rather than force
|
|
5
5
|
equations. Interference, blackbody spectra and atom-like binding emerge from the automaton.
|
|
6
6
|
|
|
7
|
-
`0.6.1-p3.
|
|
7
|
+
`0.6.1-p3.3` (npm dist-tag `next`). Node ≥ 22.12.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
package/dist/dist-manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@descix/frqtl-node",
|
|
3
|
-
"version": "0.6.1-p3.
|
|
3
|
+
"version": "0.6.1-p3.3",
|
|
4
4
|
"files": {
|
|
5
5
|
"eyes/index.js": "b3563421030bb7fdd277eb697959fbe9107463cbb5478160edc7d887daa67be3",
|
|
6
6
|
"fat/pkg-node/egpt_wasm.js": "5e6af1f6725c93c0e9ad7386f1785cbe639ce596a4caa19ca85729c1f2bea04d",
|
|
@@ -26,21 +26,21 @@
|
|
|
26
26
|
"frqtl/compat/renderer/display-slot.js": "8a2e99836dcc2f95155f2cd8ffeb9267054e3848c2e8f2ce320ebaca22f80a9e",
|
|
27
27
|
"frqtl/compat/renderer/lo-drawn-center.js": "5d285c8e6b0775db336de559855d28d752aed7544610f0430d8a389c530673cc",
|
|
28
28
|
"frqtl/compat/renderer/orbit-bag.js": "b6671d3b35fcf5f79e228934a8032e729309e62b66920602f34c834f3f911681",
|
|
29
|
-
"frqtl/compat/renderer/providers/godrays-layer.js": "
|
|
29
|
+
"frqtl/compat/renderer/providers/godrays-layer.js": "fdfde9469cdeefce87785a648b77ed46ead22de46369b3b70212446ef3cbb850",
|
|
30
30
|
"frqtl/compat/renderer/providers/index.js": "fa669158a082a0081125c81694ca79962639caf86a575ee198a815f3e13a19e7",
|
|
31
|
-
"frqtl/compat/renderer/providers/p5-provider.js": "
|
|
31
|
+
"frqtl/compat/renderer/providers/p5-provider.js": "d247d81c785b1d45b863a9e4081b2b85302106ddc0de75aece0f9a9553dabbc9",
|
|
32
32
|
"frqtl/compat/renderer/providers/three-camera-contract.js": "644c1cc5e381cd2af897e69762216f84716808eeb5948efb989f48c47696bc60",
|
|
33
33
|
"frqtl/compat/renderer/providers/three-camera-geometry.js": "a741f72c34005fc47fb4d53cc7ef2d2df4bfa7e8eecc9a0252b1083b3d5e301a",
|
|
34
|
-
"frqtl/compat/renderer/providers/three-provider.js": "
|
|
34
|
+
"frqtl/compat/renderer/providers/three-provider.js": "30fc893f303144cd6fff66092c2e42e9880f7dc2da4fe6a27878d9b5b0c2e8dc",
|
|
35
35
|
"frqtl/compat/renderer/renderCapabilities-common.js": "4e4bf31a8ab5b4b938fdbd517e30d28e9c8e90251b6fe1dbaafd575bf2d4ccf3",
|
|
36
36
|
"frqtl/compat/renderer/renderer-provider-contract.js": "295574c6b10ce4c335b7c9a83941f3c1723b412c21f0004501add45e533bdb5a",
|
|
37
37
|
"frqtl/compat/renderer/unprojectStill.js": "43c4286c124eaa238d963fe3ae5551a1c87727809d5245a129f368a117863c45",
|
|
38
38
|
"frqtl/compat/vendor.js": "2393ada71cdbe750d409174e1ba9b098148796efdff746b315d706a0b32e58e8",
|
|
39
39
|
"frqtl/experiments/_shared/boot-failure.js": "1a92e85b06acdefede5613f2fac7cd4e61d2aba590820f1bfa92f6829fcbbdd4",
|
|
40
40
|
"frqtl/node-entry.js": "a401039b4fcf53ac620edbd80985aa4448122f2e3caaeaf4d5595f5e9d512b60",
|
|
41
|
-
"frqtl/objects/FrqtlApp.js": "
|
|
41
|
+
"frqtl/objects/FrqtlApp.js": "bc4b4b2206588cd91fc8454b058a11d4b8b797fa3064e32af12be81d2d927d6e",
|
|
42
42
|
"frqtl/objects/ObjectFactory.js": "a8f050ce61b7ab9c9b4f81e9eeaebf05c3cc0b532c741ce93d6e952489772b11",
|
|
43
|
-
"frqtl/objects/RecipeContext.js": "
|
|
43
|
+
"frqtl/objects/RecipeContext.js": "4dafe289b2a5f768529d340e0d3876ddd8c72b4c295a37c00f77efe02912fc7c",
|
|
44
44
|
"frqtl/objects/collectors/DataCollector.js": "8736d6cb77eec36ce2adcf2bc3b0d2436eeb70a73b77182ff053efdc6ca071df",
|
|
45
45
|
"frqtl/objects/constants/WallBehaviors.js": "a05c6e06923962e2cc2cf7204131e5d20bf83c5c8e85fbb13867872040345e40",
|
|
46
46
|
"frqtl/objects/geometry/SlabFace.js": "847921b124d3bc1692e88c363c087d392a1baa7c652a3a61e381d0f8a8342e57",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"frqtl/objects/objects/slitLinerScatter.js": "9413cc7efa2132c68d7b4d5030af28d92e8d085e127d5c8e1568d0028da2fc13",
|
|
74
74
|
"frqtl/objects/objects/sustainedSource.js": "0c324cef1583226d090b4d1014c2576ef8237f1bad47c1511bed3c3f81e04206",
|
|
75
75
|
"frqtl/objects/objects/tagger.js": "e2a5ef9ae68466afb6b157ca6d7ce03a6f126d8c91c9f9d4be6dba8e928535eb",
|
|
76
|
-
"frqtl/objects/record/Record.js": "
|
|
76
|
+
"frqtl/objects/record/Record.js": "fea53f9ae9c72e216f1e9ca7e2035c093e3135ccd132918ff6abd299fac6057b",
|
|
77
77
|
"frqtl/objects/record/open-record.js": "2da2abcccd3ad5bc39eb7fcfb764601cd031dd0afa9b3c9cb96b0669621827df",
|
|
78
78
|
"frqtl/objects/schema/engine-scopes.js": "d9d07914f748f9e7f86cc68e4d49da3b07d2bce37fea5280a88e6862ef3bb619",
|
|
79
79
|
"frqtl/objects/schema/index.js": "74ba0b6a6e057cfd40edf2ce41fcce7206c0204e90eeee4a8db3b711f10ffd33",
|
|
@@ -112,21 +112,21 @@
|
|
|
112
112
|
"frqtl/parts/DetectorWall.js": "d39ab88056fa28c322863430f8bad9704879e5d8149f1ac65adf1add057996f5",
|
|
113
113
|
"frqtl/parts/FrqtlControlOverlay.js": "f862b1529265224aa96878b56b0c1c6e65683ba3fd6b517df86e17e92147f9c4",
|
|
114
114
|
"frqtl/parts/FrqtlControlsPanel.js": "792d03dea218bdc335ba7e04362be620edbfa331bed9de087d61942299728cc1",
|
|
115
|
-
"frqtl/parts/FrqtlVision.js": "
|
|
115
|
+
"frqtl/parts/FrqtlVision.js": "217472e195ccd588cccd8be9fe9419836b66c96c20509fa7d4320a57116bb0b3",
|
|
116
116
|
"frqtl/parts/GraphingDetectorWall.js": "a2fef24c2ef00416792c4b46a09c9544601e45e84593fa2287d2311f27a1bcee",
|
|
117
117
|
"frqtl/parts/LargeObject.js": "d6cae738b30965f3eba4be4399fb4410f17afc3267b51e3ad9e1ba7423e17922",
|
|
118
118
|
"frqtl/parts/LightColor.js": "8637e5a09bbad3a4fdd2034ccb44dfc1fda743e29b12b4c685a64b9e1df28daa",
|
|
119
|
-
"frqtl/parts/LiveChart.js": "
|
|
119
|
+
"frqtl/parts/LiveChart.js": "5d31947db9909e7a85dcbd99560e49b3f24ad60aea13f24b736a04d45998f060",
|
|
120
120
|
"frqtl/parts/LogicGate.js": "05716711db1794ce9e29027ea16af083e5a1cc8b0657dce853cb6d2f6ee1fc02",
|
|
121
121
|
"frqtl/parts/OvenBox.js": "7e393dd736c6ae410d85e5fe3edbea8677e5834bd1fe7b19d4e8f46af13764ac",
|
|
122
122
|
"frqtl/parts/PointSource.js": "57b3b8353cba8c5ebfff6653e39948c9f0ee240449b4af08247687d3d9d9f092",
|
|
123
123
|
"frqtl/parts/Rectangle.js": "8be4cae13135c3cb185d025dfd10d3a03b21d5627bfa92363c2faa021f751571",
|
|
124
124
|
"frqtl/parts/SlitLightSource.js": "89a17aaade03e2e961af4181e6c3fd479d31c2c3298c46abc477a13f26d7a07a",
|
|
125
125
|
"frqtl/parts/SlitScreen.js": "bdcaa761d0aa68c415a06ab2c523a8d4553a4c48cee00fe33d5df994adcf599a",
|
|
126
|
-
"frqtl/parts/SphereEmitter.js": "
|
|
126
|
+
"frqtl/parts/SphereEmitter.js": "bf801404c67ff26dbf61353ea617fcefcff5a546c2e62f4d4afb95e9781c7a5e",
|
|
127
127
|
"frqtl/parts/Trace.js": "f9d91bb9435bc5fabfd7bfdbfbf3f3ae34e2338090251d9e9d6c11abc2ed25fb",
|
|
128
|
-
"frqtl/parts/Tunnel.js": "
|
|
129
|
-
"frqtl/parts/Wall.js": "
|
|
128
|
+
"frqtl/parts/Tunnel.js": "7a7c3e52caa5f018178c596d735e6062c4cac1545d014216d3027ba9f457d07d",
|
|
129
|
+
"frqtl/parts/Wall.js": "7af7a41f7c8348deee1237a20e37e9c0e69cd3669ab315efaa8eeac03fbbccb8",
|
|
130
130
|
"frqtl/parts/index.js": "70b8e227e09663889f4c7942d385f843d977579765723f829880fd6e9868ac53",
|
|
131
131
|
"frqtl/scenes/absorbing-wall-3d.js": "722bb433142833f03150052b95039686aba0d9db510a5ff13fad95b5f17e0cf8",
|
|
132
132
|
"frqtl/scenes/absorbing-wall.js": "0a47ca64e56481841339cd5882cf0e54ec7c14d87a4306d016ead1ff26591197",
|
|
@@ -141,13 +141,13 @@
|
|
|
141
141
|
"frqtl/scenes/dse-one-emitter.js": "619892663838e0f018b9ade83c9994fb0709b9ed9904c92e41470a7b7fdd396f",
|
|
142
142
|
"frqtl/scenes/dse-one-slit.js": "7bf299e3cc64dd3d1f8df805eec63d98d36b8592d55e3ef478d46c38bf674812",
|
|
143
143
|
"frqtl/scenes/dse-photoelectric.js": "e0402c4508a4d97d3d9461f889b10a49da82ef5f232d81455c5e482db8b0bda6",
|
|
144
|
-
"frqtl/scenes/dse-tunnel-rebuild.js": "
|
|
144
|
+
"frqtl/scenes/dse-tunnel-rebuild.js": "c2721b4460dbe2f38e7e3bcff6f8498fd798c3404b807931b288ae2ccd43eec5",
|
|
145
145
|
"frqtl/scenes/dse-two-emitters.js": "74cf1d4b226b0ce4e337697a0327de9b95190159b2554f53e629d89525321877",
|
|
146
146
|
"frqtl/scenes/dse-two-slits.js": "f303a848d9c463a5a9443c380b257795b19127b122bdd2fcb28855841b219939",
|
|
147
147
|
"frqtl/scenes/empty.js": "f3c2161f7bbc1be2d7fba0f117ac16b9e60966d9448877ead4037e3cb4fee678",
|
|
148
148
|
"frqtl/scenes/laser-buildup.js": "f4b29b2eeeca730642f5adf2f499f6594b73f6e51ba6aa9a237f4ee643c5cf23",
|
|
149
149
|
"frqtl/scenes/mirror-3d.js": "79ac794dfbc608037936908a9fe58ca34be93be6263d5940bb38129d55bb7943",
|
|
150
|
-
"frqtl/scenes/mirror-route.js": "
|
|
150
|
+
"frqtl/scenes/mirror-route.js": "1407dd7a39c0efcd5ea0f028d67299c1ca4153c1c0cab2bb36d10416f1129931",
|
|
151
151
|
"frqtl/scenes/mirror.js": "c7bcd440e9a78e333fd81d906b3788a62342910f46cf98de860098fcc1e0ba91",
|
|
152
152
|
"frqtl/scenes/omni-3d.js": "d420a7aae9fdfd394b9288ce1f0256416e1b07f70bc570a928a4592c32a47c27",
|
|
153
153
|
"frqtl/scenes/omni-source.js": "4f9aaa0e0ccbf4d18908d1628688dbeae376b535318f0cf969d61d8ea8f90b83",
|
|
@@ -166,13 +166,13 @@
|
|
|
166
166
|
"shim/engine/artifact-shell.js": "f23c327500f8174b12d464868f6ec9c1701e7a9a5faa1c43a2ddafc3191dc38c",
|
|
167
167
|
"shim/engine/boot-phases.js": "c6e12e12824bcf6f1a289f46e41c898a5416c80c131594525145aae9a3eefbfa",
|
|
168
168
|
"shim/engine/engine-stack-boot.js": "0abf57dcff2ca2bb025c787a17875d49d54d9218ac08c78cb9c678dbb6118d08",
|
|
169
|
-
"shim/engine/router.js": "
|
|
169
|
+
"shim/engine/router.js": "a2582ce456f5cee9ac4d9d2117afdf4dce59e7e3e009f483dbd0f8d0a4c3cb8e",
|
|
170
170
|
"shim/engine/site-graph.js": "b0d2569c67516d08bba17a152d5d3bfa0b036666eda7f11df74b4d68854e1b93",
|
|
171
171
|
"shim/experiment-frame/index.js": "5a0219aaa225d8f808c405b08623ce85ada37d83fb4f55f983db3303e431e47f",
|
|
172
172
|
"shim/expr/ast-schema.js": "4f1133b887639bbd86fab976292323bf4a955cdc873ff7ca8e8a8eb3b416923f",
|
|
173
|
-
"shim/field-descriptor/index.js": "
|
|
173
|
+
"shim/field-descriptor/index.js": "050091a9cab0bd37b32b5d8a52fc9bca3b42a089c188d7e49a11cf88b5c069f7",
|
|
174
174
|
"shim/frame-data/index.js": "df6957b0b4a8e0ee0035bc970647b90089b421ae7f05911cc047d48457164be6",
|
|
175
|
-
"shim/host/device.js": "
|
|
175
|
+
"shim/host/device.js": "7dd8d069463141e4f8bdc8827d747c0a9e27ad7ec1d2c6feaaad6e58f0bed512",
|
|
176
176
|
"shim/host/host-view.js": "feec2f5fdc318e75cd01768c24891f85d2694a269696fcfffd9567d31983cf43",
|
|
177
177
|
"shim/host/index.js": "fade4b171218965570aa2e67e841920ebb3d972ff15e1cfa0394fd3fa123d82c",
|
|
178
178
|
"shim/index.js": "96165c6161ffddbace0be0cde0b3a83943298531537dd2cc9c6e281b8274ff19",
|
|
@@ -210,19 +210,19 @@
|
|
|
210
210
|
"shim/project/register-node.mjs": "9b408da7dc1b11d16237cd62caca281c823ea80173d386ad35e41ea17c34857f",
|
|
211
211
|
"shim/project/specifiers.js": "288e5e06e53b873449190f6f85855177a72e52623bd11eef016acafb8095d829",
|
|
212
212
|
"shim/registry/copy-gate.js": "cfbf52669c849b8837b326f2743458f1ead0720cad51a6c6d409c9bd6c7f9495",
|
|
213
|
-
"shim/registry/exhibits.js": "
|
|
213
|
+
"shim/registry/exhibits.js": "5a2f085c8a6b012114796897ec284f2bdd5081936b4e474d6227318c67dfb48a",
|
|
214
214
|
"shim/registry/index.js": "3a96c6b8790058663bb3157f6daecbcc199c2472d096b413e1766dd279832c05",
|
|
215
215
|
"shim/registry/scene-roster.js": "318fe373f71b1c58d05425693f2fad4bd5368f6095b65817c6d637430a0bfb73",
|
|
216
216
|
"shim/registry/scene-source.js": "c9c4b48c24d4b1ebee1549a7891a1ba708909b94b9403ce28eefbd902cacf49f",
|
|
217
217
|
"shim/registry/showcase-link.js": "daf5c1426aeb3c578bace5e0edea9ba2538cd82336d2cdc944e5fed6decd7551",
|
|
218
218
|
"shim/registry/studio-landing.js": "bd81ad9333332de4a29b3121f963edd354450c75c97f4f43170a98c2dcceb7f3",
|
|
219
|
-
"shim/registry/walkthrough.js": "
|
|
219
|
+
"shim/registry/walkthrough.js": "439e03fc6c85e5982a98049118dc89f33c498778c1f3349bbbe8f60d64761071",
|
|
220
220
|
"shim/render-state/apply.js": "94a9e60cb1722c9a82aa00f2f161fd65e6f438147333856a786e42a4ad5b7064",
|
|
221
221
|
"shim/render-state/index.js": "72a6a3dcd8037893cb8fbd7ef32b126770e7efaec70847f8e4f2915ddb690b43",
|
|
222
|
-
"shim/render/capture-envelope.js": "
|
|
222
|
+
"shim/render/capture-envelope.js": "74db53dbc8c87d1b52452bcb858b1cc5210593062fec0b98609cd59cab63777a",
|
|
223
223
|
"shim/render/heat-colormap.js": "0eadc758179024734c45eaeffd8f5b44e7c4102b7042767a4a5b66541b3bbd7c",
|
|
224
224
|
"shim/render/render-stages.js": "baf674c205df7638af53e51ac77152a448fe6bf6d4ea51d58ac565556cd38da7",
|
|
225
|
-
"shim/render/sun-look.js": "
|
|
225
|
+
"shim/render/sun-look.js": "95cf56ee8a5c8da107323bf0dd33568e68e2a8bb2d9a5d61a3453a1b9d28ba2c",
|
|
226
226
|
"shim/rpc/index.js": "56af3afeed22e8d718cd2f7a8ad70db8745f54dbc139af9d71f1d73e2ca37698",
|
|
227
227
|
"shim/runtime/index.js": "92bb4d8b5f203f949e441781b864efe5c6748df14a3a8f306e4c0bc11c7f6d35",
|
|
228
228
|
"shim/storage/boot.js": "689504e15dc075e32d08abf61c75a45b1d565c09f086b42400dae40d8186c411",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* godrays-layer.js — the three provider's god-rays layer: WHAT the rays are computed from
|
|
5
|
-
* (the source rule),
|
|
5
|
+
* (the source rule, `godraySource`), HOW (`godrayMode`: streak | field | radial), and the passes.
|
|
6
6
|
*
|
|
7
7
|
* God-rays are a render effect computed from the density of the LIGHT particles: by default
|
|
8
8
|
* (`godraySource: 'leaf'`) the frames of the fundamental (lowest) layer. A parent frame at a higher layer is drawn in the scene
|
|
@@ -96,6 +96,140 @@
|
|
|
96
96
|
return out;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/**
|
|
100
|
+
* The `godrayMode` render option — the ONE owner of its values and default. HOW the rays are
|
|
101
|
+
* computed from the source frames:
|
|
102
|
+
* 'streak' (default) — each source frame trails a short streak BEHIND it along its own
|
|
103
|
+
* projected direction of travel (FrameData vx,vy,vz: the mean axis);
|
|
104
|
+
* 'field' — every source frame's projected direction is splatted into a
|
|
105
|
+
* direction grid; each pixel's march steps UPSTREAM along the local
|
|
106
|
+
* direction, so the shafts extend ahead of the light and bend with the flow;
|
|
107
|
+
* 'radial' — every pixel marches toward ONE light point (`lightUV`).
|
|
108
|
+
* `godrayDensity` is the reach in every mode: the march's fraction of the distance to the
|
|
109
|
+
* light (radial), the streak length (streak), the march length (field).
|
|
110
|
+
*/
|
|
111
|
+
var GODRAY_MODES = ['streak', 'field', 'radial'];
|
|
112
|
+
var GODRAY_MODE_DEFAULT = 'streak';
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The effective mode for a bag value: unset → the default; anything not declared THROWS.
|
|
116
|
+
* @param {*} value — opts.godrayMode
|
|
117
|
+
* @returns {'streak'|'field'|'radial'}
|
|
118
|
+
*/
|
|
119
|
+
function resolveGodrayMode(value) {
|
|
120
|
+
if (value === undefined || value === null) { return GODRAY_MODE_DEFAULT; }
|
|
121
|
+
if (GODRAY_MODES.indexOf(value) === -1) {
|
|
122
|
+
throw new Error('GodraysLayer: godrayMode ' + JSON.stringify(value) + ' is not one of [' +
|
|
123
|
+
GODRAY_MODES.join(', ') + '] (default ' + JSON.stringify(GODRAY_MODE_DEFAULT) + ').');
|
|
124
|
+
}
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Screen-fraction scales (of the screen's SHORT side) the density knob multiplies.
|
|
129
|
+
var STREAK_REACH = 0.06; // streak length = godrayDensity × this
|
|
130
|
+
var STREAK_WIDTH = 0.004; // streak width (floor 1.5 physical px)
|
|
131
|
+
var STREAK_GAIN = 0.6; // streak brightness relative to the source pixel at the head
|
|
132
|
+
var FIELD_REACH = 0.25; // field march length = godrayDensity × this
|
|
133
|
+
var FIELD_CELLS = 96; // direction-grid columns along the LONG side
|
|
134
|
+
var FIELD_RADIUS = 3; // splat radius in grid cells (tent weight)
|
|
135
|
+
var MARCH_SAMPLES = 50; // steps per pixel in the radial and field marches
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Each frame's head in screen UV and its projected direction of travel as a UNIT vector in
|
|
139
|
+
* PIXEL space (aspect-corrected). The direction is the projection of (pos + d̂) minus the
|
|
140
|
+
* projection of pos, d̂ = normalize(vx,vy,vz). A frame with no direction, one whose direction
|
|
141
|
+
* projects to under 1e-6 px (along the view axis), or one outside the clip volume yields NO
|
|
142
|
+
* entry: it still draws in the scene as itself, a dot with no streak and no flow.
|
|
143
|
+
* @param {Array<object>} frames — FrameData (rect.x, rect.y, z, vx, vy, vz)
|
|
144
|
+
* @param {Function} project — (x,y,z) → NDC {x,y,z}
|
|
145
|
+
* @param {number} w @param {number} h — the target's pixel size
|
|
146
|
+
* @returns {{count:number, u:Float32Array, v:Float32Array, dx:Float32Array, dy:Float32Array}}
|
|
147
|
+
*/
|
|
148
|
+
function screenDirections(frames, project, w, h) {
|
|
149
|
+
var n = frames.length;
|
|
150
|
+
var out = { count: 0, u: new Float32Array(n), v: new Float32Array(n), dx: new Float32Array(n), dy: new Float32Array(n) };
|
|
151
|
+
for (var i = 0; i < n; i++) {
|
|
152
|
+
var f = frames[i];
|
|
153
|
+
var vx = f.vx || 0, vy = f.vy || 0, vz = f.vz || 0;
|
|
154
|
+
var len = Math.sqrt(vx * vx + vy * vy + vz * vz);
|
|
155
|
+
if (len === 0) { continue; }
|
|
156
|
+
var x = f.rect.x, y = f.rect.y, z = f.z || 0;
|
|
157
|
+
var p0 = project(x, y, z), x0 = p0.x, y0 = p0.y, z0 = p0.z;
|
|
158
|
+
if (!(Math.abs(x0) <= 1 && Math.abs(y0) <= 1 && Math.abs(z0) <= 1)) { continue; }
|
|
159
|
+
var p1 = project(x + vx / len, y + vy / len, z + vz / len);
|
|
160
|
+
var px = (p1.x - x0) * w / 2, py = (p1.y - y0) * h / 2;
|
|
161
|
+
var pl = Math.sqrt(px * px + py * py);
|
|
162
|
+
if (!(pl > 1e-6)) { continue; }
|
|
163
|
+
var k = out.count++;
|
|
164
|
+
out.u[k] = x0 * 0.5 + 0.5; out.v[k] = y0 * 0.5 + 0.5;
|
|
165
|
+
out.dx[k] = px / pl; out.dy[k] = py / pl;
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Screen-space streak quads (two triangles each), in NDC: the head at the frame, the tail
|
|
172
|
+
* `lengthPx` BEHIND it (opposite its direction), `widthPx` wide. Per vertex: `head` (the head's
|
|
173
|
+
* UV, where the colour is sampled) and `fade` (1 at the head, 0 at the tail).
|
|
174
|
+
* @param {object} dirs — screenDirections(...)
|
|
175
|
+
* @returns {{count:number, position:Float32Array, head:Float32Array, fade:Float32Array}}
|
|
176
|
+
*/
|
|
177
|
+
function streakQuads(dirs, lengthPx, widthPx, w, h) {
|
|
178
|
+
var n = dirs.count, pos = new Float32Array(n * 18), head = new Float32Array(n * 12), fade = new Float32Array(n * 6);
|
|
179
|
+
var sx = 2 / w, sy = 2 / h, half = widthPx / 2;
|
|
180
|
+
for (var i = 0; i < n; i++) {
|
|
181
|
+
var hx = dirs.u[i] * 2 - 1, hy = dirs.v[i] * 2 - 1, dx = dirs.dx[i], dy = dirs.dy[i];
|
|
182
|
+
var tx = hx - dx * lengthPx * sx, ty = hy - dy * lengthPx * sy;
|
|
183
|
+
var nx = -dy * half * sx, ny = dx * half * sy;
|
|
184
|
+
// head+n, head-n, tail+n ; tail+n, head-n, tail-n
|
|
185
|
+
var vs = [hx + nx, hy + ny, 1, hx - nx, hy - ny, 1, tx + nx, ty + ny, 0,
|
|
186
|
+
tx + nx, ty + ny, 0, hx - nx, hy - ny, 1, tx - nx, ty - ny, 0];
|
|
187
|
+
for (var j = 0; j < 6; j++) {
|
|
188
|
+
var o = i * 6 + j;
|
|
189
|
+
pos[o * 3] = vs[j * 3]; pos[o * 3 + 1] = vs[j * 3 + 1]; pos[o * 3 + 2] = 0;
|
|
190
|
+
fade[o] = vs[j * 3 + 2];
|
|
191
|
+
head[o * 2] = dirs.u[i]; head[o * 2 + 1] = dirs.v[i];
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return { count: n * 6, position: pos, head: head, fade: fade };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The direction field: a `gw × gh` RGBA grid (row 0 = bottom, UV v = 0). Each direction is
|
|
199
|
+
* splatted with a tent weight over `radius` cells; a cell stores its normalized mean direction
|
|
200
|
+
* in R,G (0.5 + 0.5·d̂) and in B the strength a = coherence × coverage (coherence = |mean|,
|
|
201
|
+
* 0 where opposed flows cancel; coverage = min(1, Σweight)). Decode: d = (RG·2 − 1)·B.
|
|
202
|
+
* @param {object} dirs — screenDirections(...)
|
|
203
|
+
* @returns {{width:number, height:number, data:Uint8Array}}
|
|
204
|
+
*/
|
|
205
|
+
function buildDirectionField(dirs, gw, gh, radius) {
|
|
206
|
+
var cells = gw * gh, sx = new Float32Array(cells), sy = new Float32Array(cells), sw = new Float32Array(cells);
|
|
207
|
+
for (var i = 0; i < dirs.count; i++) {
|
|
208
|
+
var cx = dirs.u[i] * gw - 0.5, cy = dirs.v[i] * gh - 0.5;
|
|
209
|
+
var i0 = Math.max(0, Math.ceil(cx - radius)), i1 = Math.min(gw - 1, Math.floor(cx + radius));
|
|
210
|
+
var j0 = Math.max(0, Math.ceil(cy - radius)), j1 = Math.min(gh - 1, Math.floor(cy + radius));
|
|
211
|
+
for (var j = j0; j <= j1; j++) {
|
|
212
|
+
for (var ii = i0; ii <= i1; ii++) {
|
|
213
|
+
var ex = ii - cx, ey = j - cy, wt = 1 - Math.sqrt(ex * ex + ey * ey) / (radius + 1);
|
|
214
|
+
if (wt <= 0) { continue; }
|
|
215
|
+
var c = j * gw + ii;
|
|
216
|
+
sx[c] += dirs.dx[i] * wt; sy[c] += dirs.dy[i] * wt; sw[c] += wt;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
var data = new Uint8Array(cells * 4);
|
|
221
|
+
for (var k = 0; k < cells; k++) {
|
|
222
|
+
var r = 0.5, g = 0.5, a = 0;
|
|
223
|
+
if (sw[k] > 0) {
|
|
224
|
+
var mx = sx[k] / sw[k], my = sy[k] / sw[k], m = Math.sqrt(mx * mx + my * my);
|
|
225
|
+
if (m > 1e-6) { r = 0.5 + 0.5 * mx / m; g = 0.5 + 0.5 * my / m; a = m * Math.min(1, sw[k]); }
|
|
226
|
+
}
|
|
227
|
+
data[k * 4] = Math.round(r * 255); data[k * 4 + 1] = Math.round(g * 255);
|
|
228
|
+
data[k * 4 + 2] = Math.round(a * 255); data[k * 4 + 3] = 255;
|
|
229
|
+
}
|
|
230
|
+
return { width: gw, height: gh, data: data };
|
|
231
|
+
}
|
|
232
|
+
|
|
99
233
|
// R4-B god-rays — radial light-scattering march (adapted from abberg's
|
|
100
234
|
// VolumetericLightShader / GPU Gems 3). For each pixel it steps TOWARD the
|
|
101
235
|
// projected light position, accumulating SOURCE brightness with exponential
|
|
@@ -110,7 +244,7 @@
|
|
|
110
244
|
'uniform float uWeight;',
|
|
111
245
|
'uniform float uExposure;',
|
|
112
246
|
'varying vec2 vTexCoord;',
|
|
113
|
-
'const int SAMPLES =
|
|
247
|
+
'const int SAMPLES = ' + MARCH_SAMPLES + ';',
|
|
114
248
|
'void main() {',
|
|
115
249
|
' vec2 tc = vTexCoord;',
|
|
116
250
|
' vec2 delta = (tc - uLightPos) * (1.0 / float(SAMPLES)) * uDensity;',
|
|
@@ -126,6 +260,64 @@
|
|
|
126
260
|
'}'
|
|
127
261
|
].join('\n');
|
|
128
262
|
|
|
263
|
+
// The 'field' march: the radial march's accumulation (same decay/weight/exposure), but each
|
|
264
|
+
// step reads the LOCAL direction from the field and steps upstream along it, so a pixel
|
|
265
|
+
// collects the light that flowed into it. An empty cell (strength 0) does not step.
|
|
266
|
+
var GODRAY_FIELD_FRAG = [
|
|
267
|
+
'uniform sampler2D uScene;',
|
|
268
|
+
'uniform sampler2D uField;',
|
|
269
|
+
'uniform vec2 uStepUV;', // one step's length in UV per unit pixel-space direction
|
|
270
|
+
'uniform float uDecay;',
|
|
271
|
+
'uniform float uWeight;',
|
|
272
|
+
'uniform float uExposure;',
|
|
273
|
+
'varying vec2 vTexCoord;',
|
|
274
|
+
'const int SAMPLES = ' + MARCH_SAMPLES + ';',
|
|
275
|
+
'void main() {',
|
|
276
|
+
' vec2 tc = vTexCoord;',
|
|
277
|
+
' vec3 rays = vec3(0.0);',
|
|
278
|
+
' float decay = 1.0;',
|
|
279
|
+
' for (int i = 0; i < SAMPLES; i++) {',
|
|
280
|
+
' vec3 f = texture2D(uField, tc).rgb;',
|
|
281
|
+
' tc -= (f.rg * 2.0 - 1.0) * f.b * uStepUV;',
|
|
282
|
+
' vec3 s = texture2D(uScene, tc).rgb;',
|
|
283
|
+
' rays += s * decay * uWeight;',
|
|
284
|
+
' decay *= uDecay;',
|
|
285
|
+
' }',
|
|
286
|
+
' gl_FragColor = vec4(rays * uExposure, 1.0);',
|
|
287
|
+
'}'
|
|
288
|
+
].join('\n');
|
|
289
|
+
|
|
290
|
+
// The 'streak' quads: positions are NDC already; colour = the source image AT THE HEAD,
|
|
291
|
+
// fading to black at the tail, added (additive blending) into a black rays target.
|
|
292
|
+
var GODRAY_STREAK_VERT = [
|
|
293
|
+
'attribute vec2 aHead;',
|
|
294
|
+
'attribute float aFade;',
|
|
295
|
+
'varying vec2 vHead;',
|
|
296
|
+
'varying float vFade;',
|
|
297
|
+
'void main() {',
|
|
298
|
+
' vHead = aHead; vFade = aFade;',
|
|
299
|
+
' gl_Position = vec4(position.xy, 0.0, 1.0);',
|
|
300
|
+
'}'
|
|
301
|
+
].join('\n');
|
|
302
|
+
// The head colour is the brightest texel of the 3×3 around the head: a sub-pixel quantum lands
|
|
303
|
+
// between texels, so a single tap at its centre reads it dimmed.
|
|
304
|
+
var GODRAY_STREAK_FRAG = [
|
|
305
|
+
'uniform sampler2D uSource;',
|
|
306
|
+
'uniform vec2 uTexel;',
|
|
307
|
+
'uniform float uGain;',
|
|
308
|
+
'varying vec2 vHead;',
|
|
309
|
+
'varying float vFade;',
|
|
310
|
+
'void main() {',
|
|
311
|
+
' vec3 c = vec3(0.0);',
|
|
312
|
+
' for (int i = -1; i <= 1; i++) {',
|
|
313
|
+
' for (int j = -1; j <= 1; j++) {',
|
|
314
|
+
' c = max(c, texture2D(uSource, vHead + vec2(float(i), float(j)) * uTexel).rgb);',
|
|
315
|
+
' }',
|
|
316
|
+
' }',
|
|
317
|
+
' gl_FragColor = vec4(c * vFade * uGain, 1.0);',
|
|
318
|
+
'}'
|
|
319
|
+
].join('\n');
|
|
320
|
+
|
|
129
321
|
// R4-B composite — unblurred scene + additive rays * intensity knob.
|
|
130
322
|
var GODRAY_COMP_FRAG = [
|
|
131
323
|
'uniform sampler2D uScene;',
|
|
@@ -140,17 +332,19 @@
|
|
|
140
332
|
].join('\n');
|
|
141
333
|
|
|
142
334
|
/**
|
|
143
|
-
* The live passes, created lazily by the provider on first activation.
|
|
335
|
+
* The live passes, created lazily by the provider on first activation. Every mode ends in the
|
|
336
|
+
* same composite (sceneRT + rays × intensity → screen); they differ in how rtRays is made.
|
|
144
337
|
* @param {object} THREE
|
|
145
338
|
* @param {string} quadVert — the provider's full-screen-quad vertex shader
|
|
146
339
|
* @param {number} w @param {number} h — the provider's physical size
|
|
147
|
-
* @returns {{rtSource:object, setSize:Function, lightUV:Function, march:Function}}
|
|
340
|
+
* @returns {{rtSource:object, setSize:Function, lightUV:Function, march:Function, streak:Function, field:Function}}
|
|
148
341
|
*/
|
|
149
342
|
function makeGodrayPasses(THREE, quadVert, w, h) {
|
|
150
343
|
var fxScene = new THREE.Scene();
|
|
151
344
|
var fxQuad = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), null);
|
|
152
345
|
fxScene.add(fxQuad);
|
|
153
|
-
var vLight = new THREE.Vector3();
|
|
346
|
+
var vLight = new THREE.Vector3(), vProj = new THREE.Vector3(), clearKeep = new THREE.Color();
|
|
347
|
+
var size = { w: w, h: h };
|
|
154
348
|
var blurMat = new THREE.ShaderMaterial({
|
|
155
349
|
uniforms: {
|
|
156
350
|
uScene: { value: null },
|
|
@@ -166,9 +360,49 @@
|
|
|
166
360
|
uniforms: { uScene: { value: null }, uRays: { value: null }, uIntensity: { value: 1.0 } },
|
|
167
361
|
vertexShader: quadVert, fragmentShader: GODRAY_COMP_FRAG, depthWrite: false, depthTest: false
|
|
168
362
|
});
|
|
363
|
+
var fieldMat = new THREE.ShaderMaterial({
|
|
364
|
+
uniforms: {
|
|
365
|
+
uScene: { value: null },
|
|
366
|
+
uField: { value: null },
|
|
367
|
+
uStepUV: { value: new THREE.Vector2(0, 0) },
|
|
368
|
+
uDecay: blurMat.uniforms.uDecay, // the SAME accumulation as the radial march
|
|
369
|
+
uWeight: blurMat.uniforms.uWeight,
|
|
370
|
+
uExposure: blurMat.uniforms.uExposure
|
|
371
|
+
},
|
|
372
|
+
vertexShader: quadVert, fragmentShader: GODRAY_FIELD_FRAG, depthWrite: false, depthTest: false
|
|
373
|
+
});
|
|
374
|
+
var fieldTex = null;
|
|
375
|
+
|
|
376
|
+
var streakScene = new THREE.Scene();
|
|
377
|
+
var streakGeo = new THREE.BufferGeometry(), streakCap = 0;
|
|
378
|
+
var streakMat = new THREE.ShaderMaterial({
|
|
379
|
+
uniforms: { uSource: { value: null }, uTexel: { value: new THREE.Vector2(1 / w, 1 / h) }, uGain: { value: STREAK_GAIN } },
|
|
380
|
+
vertexShader: GODRAY_STREAK_VERT, fragmentShader: GODRAY_STREAK_FRAG,
|
|
381
|
+
blending: THREE.AdditiveBlending, transparent: true, depthWrite: false, depthTest: false,
|
|
382
|
+
side: THREE.DoubleSide // a quad's winding follows its direction; never cull it
|
|
383
|
+
});
|
|
384
|
+
var streakMesh = new THREE.Mesh(streakGeo, streakMat);
|
|
385
|
+
streakMesh.frustumCulled = false;
|
|
386
|
+
streakScene.add(streakMesh);
|
|
387
|
+
|
|
388
|
+
function composite(renderer, quadCamera, sceneRT, rtRays, intensity) {
|
|
389
|
+
compMat.uniforms.uScene.value = sceneRT.texture;
|
|
390
|
+
compMat.uniforms.uRays.value = rtRays.texture;
|
|
391
|
+
compMat.uniforms.uIntensity.value = intensity;
|
|
392
|
+
fxQuad.material = compMat;
|
|
393
|
+
renderer.setRenderTarget(null);
|
|
394
|
+
renderer.render(fxScene, quadCamera);
|
|
395
|
+
}
|
|
396
|
+
// The reach in every mode is the density knob; unset → the value the radial march holds.
|
|
397
|
+
function densityOf(density) { return (typeof density === 'number') ? density : blurMat.uniforms.uDensity.value; }
|
|
398
|
+
function directionsOf(frames, camera) {
|
|
399
|
+
return screenDirections(frames, function (x, y, z) { return vProj.set(x, y, z).project(camera); }, size.w, size.h);
|
|
400
|
+
}
|
|
401
|
+
function shortSide() { return Math.min(size.w, size.h); }
|
|
402
|
+
|
|
169
403
|
var passes = {
|
|
170
404
|
rtSource: new THREE.WebGLRenderTarget(w, h), // the SOURCE image the provider renders into
|
|
171
|
-
setSize: function (sw, sh) { passes.rtSource.setSize(sw, sh); },
|
|
405
|
+
setSize: function (sw, sh) { size.w = sw; size.h = sh; passes.rtSource.setSize(sw, sh); },
|
|
172
406
|
// Light position in [0,1] screen UV: the fullness-weighted centroid of the SOURCE
|
|
173
407
|
// frames, projected through `camera` (2D ortho + 3D persp); screen centre when none.
|
|
174
408
|
lightUV: function (tickData, camera, source) {
|
|
@@ -183,7 +417,7 @@
|
|
|
183
417
|
vLight.set(sx / sw, sy / sw, sz / sw).project(camera); // → NDC [-1,1]
|
|
184
418
|
return new THREE.Vector2(vLight.x * 0.5 + 0.5, vLight.y * 0.5 + 0.5);
|
|
185
419
|
},
|
|
186
|
-
// Pass 2: march sourceRT → rtRays. Pass 3:
|
|
420
|
+
// 'radial' — Pass 2: march sourceRT toward lightUV → rtRays. Pass 3: composite.
|
|
187
421
|
march: function (renderer, quadCamera, sceneRT, sourceRT, rtRays, lightUV, density, intensity) {
|
|
188
422
|
blurMat.uniforms.uScene.value = sourceRT.texture;
|
|
189
423
|
blurMat.uniforms.uLightPos.value.copy(lightUV);
|
|
@@ -191,12 +425,61 @@
|
|
|
191
425
|
fxQuad.material = blurMat;
|
|
192
426
|
renderer.setRenderTarget(rtRays);
|
|
193
427
|
renderer.render(fxScene, quadCamera);
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
428
|
+
composite(renderer, quadCamera, sceneRT, rtRays, intensity);
|
|
429
|
+
},
|
|
430
|
+
// 'streak' — rtRays cleared to black, one fading quad per moving source frame trailing
|
|
431
|
+
// behind it (colour = sourceRT at its head), then the composite.
|
|
432
|
+
streak: function (renderer, quadCamera, sceneRT, sourceRT, rtRays, frames, camera, density, intensity) {
|
|
433
|
+
var q = streakQuads(directionsOf(frames, camera), densityOf(density) * STREAK_REACH * shortSide(),
|
|
434
|
+
Math.max(1.5, STREAK_WIDTH * shortSide()), size.w, size.h);
|
|
435
|
+
if (q.count > streakCap) {
|
|
436
|
+
streakCap = Math.max(q.count, streakCap * 2, 600);
|
|
437
|
+
streakGeo.setAttribute('position', new THREE.BufferAttribute(new Float32Array(streakCap * 3), 3));
|
|
438
|
+
streakGeo.setAttribute('aHead', new THREE.BufferAttribute(new Float32Array(streakCap * 2), 2));
|
|
439
|
+
streakGeo.setAttribute('aFade', new THREE.BufferAttribute(new Float32Array(streakCap), 1));
|
|
440
|
+
}
|
|
441
|
+
if (q.count > 0) {
|
|
442
|
+
streakGeo.attributes.position.array.set(q.position);
|
|
443
|
+
streakGeo.attributes.aHead.array.set(q.head);
|
|
444
|
+
streakGeo.attributes.aFade.array.set(q.fade);
|
|
445
|
+
streakGeo.attributes.position.needsUpdate = true;
|
|
446
|
+
streakGeo.attributes.aHead.needsUpdate = true;
|
|
447
|
+
streakGeo.attributes.aFade.needsUpdate = true;
|
|
448
|
+
}
|
|
449
|
+
streakGeo.setDrawRange(0, q.count);
|
|
450
|
+
streakMat.uniforms.uSource.value = sourceRT.texture;
|
|
451
|
+
streakMat.uniforms.uTexel.value.set(1 / size.w, 1 / size.h);
|
|
452
|
+
renderer.getClearColor(clearKeep);
|
|
453
|
+
var alphaKeep = renderer.getClearAlpha();
|
|
454
|
+
renderer.setClearColor(0x000000, 1);
|
|
455
|
+
renderer.setRenderTarget(rtRays);
|
|
456
|
+
renderer.clear();
|
|
457
|
+
if (q.count > 0) { renderer.render(streakScene, quadCamera); }
|
|
458
|
+
renderer.setClearColor(clearKeep, alphaKeep);
|
|
459
|
+
composite(renderer, quadCamera, sceneRT, rtRays, intensity);
|
|
460
|
+
},
|
|
461
|
+
// 'field' — the source frames' directions → a grid texture; march sourceRT along it →
|
|
462
|
+
// rtRays; then the composite.
|
|
463
|
+
field: function (renderer, quadCamera, sceneRT, sourceRT, rtRays, frames, camera, density, intensity) {
|
|
464
|
+
var long = Math.max(size.w, size.h);
|
|
465
|
+
var gw = Math.max(8, Math.round(FIELD_CELLS * size.w / long)), gh = Math.max(8, Math.round(FIELD_CELLS * size.h / long));
|
|
466
|
+
var grid = buildDirectionField(directionsOf(frames, camera), gw, gh, FIELD_RADIUS);
|
|
467
|
+
if (!fieldTex || fieldTex.image.width !== gw || fieldTex.image.height !== gh) {
|
|
468
|
+
if (fieldTex) { fieldTex.dispose(); }
|
|
469
|
+
fieldTex = new THREE.DataTexture(grid.data, gw, gh, THREE.RGBAFormat);
|
|
470
|
+
fieldTex.minFilter = THREE.LinearFilter; fieldTex.magFilter = THREE.LinearFilter;
|
|
471
|
+
} else {
|
|
472
|
+
fieldTex.image.data.set(grid.data);
|
|
473
|
+
}
|
|
474
|
+
fieldTex.needsUpdate = true;
|
|
475
|
+
var stepPx = densityOf(density) * FIELD_REACH * shortSide() / MARCH_SAMPLES;
|
|
476
|
+
fieldMat.uniforms.uScene.value = sourceRT.texture;
|
|
477
|
+
fieldMat.uniforms.uField.value = fieldTex;
|
|
478
|
+
fieldMat.uniforms.uStepUV.value.set(stepPx / size.w, stepPx / size.h);
|
|
479
|
+
fxQuad.material = fieldMat;
|
|
480
|
+
renderer.setRenderTarget(rtRays);
|
|
199
481
|
renderer.render(fxScene, quadCamera);
|
|
482
|
+
composite(renderer, quadCamera, sceneRT, rtRays, intensity);
|
|
200
483
|
}
|
|
201
484
|
};
|
|
202
485
|
return passes;
|
|
@@ -209,5 +492,11 @@ export {
|
|
|
209
492
|
GODRAY_SOURCES,
|
|
210
493
|
GODRAY_SOURCE_DEFAULT,
|
|
211
494
|
resolveGodraySource,
|
|
495
|
+
GODRAY_MODES,
|
|
496
|
+
GODRAY_MODE_DEFAULT,
|
|
497
|
+
resolveGodrayMode,
|
|
498
|
+
screenDirections,
|
|
499
|
+
streakQuads,
|
|
500
|
+
buildDirectionField,
|
|
212
501
|
makeGodrayPasses
|
|
213
502
|
};
|
|
@@ -491,6 +491,12 @@ import * as RendererProviderContract from '../renderer-provider-contract.js';
|
|
|
491
491
|
var prog = compileProgram(gl, VERT_SRC, fragSrc);
|
|
492
492
|
if (!prog) return { skip: true };
|
|
493
493
|
|
|
494
|
+
// Both uploads (the scene canvas and FieldBuilder's field) are TOP row first, and
|
|
495
|
+
// vTexCoord has its origin at the BOTTOM-left (Filters.js convention). Flip on upload,
|
|
496
|
+
// once for this context, or the composite draws the whole picture upside down while
|
|
497
|
+
// screenToWorld (and every hand on the canvas) stays right side up.
|
|
498
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
|
|
499
|
+
|
|
494
500
|
var quadBuf = gl.createBuffer();
|
|
495
501
|
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
|
|
496
502
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);
|