mirror of
https://github.com/molstar/molstar.git
synced 2026-06-07 23:34:23 +08:00
Compare commits
422 Commits
safari-deb
...
v3.26.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bdd0b470b | ||
|
|
b7a51f12bf | ||
|
|
e002ac5474 | ||
|
|
211d339ce0 | ||
|
|
509fb14473 | ||
|
|
ef838a1b83 | ||
|
|
f84b5b633d | ||
|
|
8ec8c1170d | ||
|
|
920b98e4d1 | ||
|
|
c80f52d4bc | ||
|
|
0b6aa42daf | ||
|
|
04dc6427ef | ||
|
|
77e366b484 | ||
|
|
add7cfa0f2 | ||
|
|
14d4fa142c | ||
|
|
7fe1617f25 | ||
|
|
cbe4cb521c | ||
|
|
7c394525c1 | ||
|
|
12ed051fea | ||
|
|
014913c635 | ||
|
|
369e45c282 | ||
|
|
26b633618a | ||
|
|
e3054d6ee1 | ||
|
|
0b6294f4ec | ||
|
|
7b130dc0f3 | ||
|
|
d93c128c25 | ||
|
|
e1dd74775e | ||
|
|
e61e706607 | ||
|
|
a57d46deaa | ||
|
|
60efdc0071 | ||
|
|
4dc1155a9e | ||
|
|
5cabe6fb42 | ||
|
|
42239c305f | ||
|
|
fd3c763349 | ||
|
|
daa9bbf2c9 | ||
|
|
c7dad00908 | ||
|
|
24317717e8 | ||
|
|
dd3eac6db6 | ||
|
|
1606f8517f | ||
|
|
3a98401ada | ||
|
|
4764251241 | ||
|
|
3de04b7b9d | ||
|
|
04908495e9 | ||
|
|
3c835c848e | ||
|
|
0f1788f122 | ||
|
|
3d72e700a4 | ||
|
|
a5cf41e65f | ||
|
|
7029bc41d7 | ||
|
|
b87d40c844 | ||
|
|
9e154376d3 | ||
|
|
4a9fdbce57 | ||
|
|
775e335292 | ||
|
|
e553bf4deb | ||
|
|
db0e09ec6e | ||
|
|
ba50760f92 | ||
|
|
524e6d4f81 | ||
|
|
db93a669ab | ||
|
|
423f5b0502 | ||
|
|
2bc45c25fe | ||
|
|
d341463f67 | ||
|
|
19d1ecb36a | ||
|
|
ffe4047f97 | ||
|
|
15a3c29e7a | ||
|
|
6a32f85e60 | ||
|
|
42ff593004 | ||
|
|
5140af4e6f | ||
|
|
0f5b4c00a9 | ||
|
|
feb69f4987 | ||
|
|
84eb9a58ca | ||
|
|
fbd96f473a | ||
|
|
69228157dc | ||
|
|
6808f32b8d | ||
|
|
f29c62ec33 | ||
|
|
d77981230b | ||
|
|
e2b92c15f0 | ||
|
|
14614f4803 | ||
|
|
37d3489b07 | ||
|
|
f81225cc0d | ||
|
|
eb47f43940 | ||
|
|
7618a5e2c9 | ||
|
|
ab3ff842b2 | ||
|
|
82f0f92c15 | ||
|
|
545d9434d8 | ||
|
|
bbc43d5113 | ||
|
|
a6709acf65 | ||
|
|
509a027742 | ||
|
|
7244023233 | ||
|
|
c5f987d8b2 | ||
|
|
793696d4c0 | ||
|
|
305ca05f04 | ||
|
|
f4d7d1920a | ||
|
|
458aad0161 | ||
|
|
9e3132461f | ||
|
|
8301291215 | ||
|
|
daed14e228 | ||
|
|
7db82c5ba5 | ||
|
|
91d03c22c2 | ||
|
|
bc188f0d2b | ||
|
|
3981225824 | ||
|
|
1886d9d72f | ||
|
|
2a7dec8892 | ||
|
|
35d4a5b297 | ||
|
|
26345bfa50 | ||
|
|
8c9b8676dd | ||
|
|
5593c7a75f | ||
|
|
5b70c14ffe | ||
|
|
5e4d611044 | ||
|
|
7ab9d57156 | ||
|
|
9ea6f51126 | ||
|
|
649fe4f4f0 | ||
|
|
53df86c585 | ||
|
|
87c708e3c1 | ||
|
|
ba927b0490 | ||
|
|
2a09725c98 | ||
|
|
9fa0d17933 | ||
|
|
8d9f8a996a | ||
|
|
8814b60d0b | ||
|
|
541c07c53a | ||
|
|
6cbed80815 | ||
|
|
a3c1fdc0f4 | ||
|
|
ddf789b01c | ||
|
|
ab86cc0bf3 | ||
|
|
dc8fab5820 | ||
|
|
813c4f845a | ||
|
|
6ed42e9521 | ||
|
|
fb01ba60ec | ||
|
|
ea4210ded5 | ||
|
|
75e5cf54d6 | ||
|
|
7cebc85a95 | ||
|
|
c00faafa6d | ||
|
|
c9b14f0742 | ||
|
|
9624137c0d | ||
|
|
3eb433368f | ||
|
|
58691f4f5f | ||
|
|
5e9295abd5 | ||
|
|
6ed0ae55b2 | ||
|
|
84448d0aa1 | ||
|
|
31ced24966 | ||
|
|
24681840af | ||
|
|
5d28aa4f2e | ||
|
|
7dabdf3085 | ||
|
|
d7cbd5570c | ||
|
|
80011d4aea | ||
|
|
c6fe440a01 | ||
|
|
ba8d6dc3fa | ||
|
|
378f4f8304 | ||
|
|
aa414485a5 | ||
|
|
3a35a5d66a | ||
|
|
43b0a72b09 | ||
|
|
521ac2d13f | ||
|
|
30520c50c2 | ||
|
|
819f07eba3 | ||
|
|
d8d6aa7136 | ||
|
|
0bdcfea276 | ||
|
|
718f76313f | ||
|
|
ed75a365d8 | ||
|
|
f5ff13ffe4 | ||
|
|
44c69b1716 | ||
|
|
559ca7ffb8 | ||
|
|
524f34e8c1 | ||
|
|
d749be11f0 | ||
|
|
13dc9ff3cb | ||
|
|
24b4fce326 | ||
|
|
f506210bf8 | ||
|
|
cb0cbd06ce | ||
|
|
3356239089 | ||
|
|
9a5b2edc08 | ||
|
|
2d41b4bd83 | ||
|
|
58f7758ee1 | ||
|
|
9dbb642883 | ||
|
|
c5222e4d1d | ||
|
|
a5a695a17c | ||
|
|
7d1dc86cfb | ||
|
|
03224f914a | ||
|
|
1cf1f07232 | ||
|
|
838d36a74e | ||
|
|
6c9300d01b | ||
|
|
3059f7efef | ||
|
|
fbce7d9afa | ||
|
|
1c9f3ed9fa | ||
|
|
8c47d2d400 | ||
|
|
8a18f25b5d | ||
|
|
e7ae0058ed | ||
|
|
98bf3a3e33 | ||
|
|
379fcd4494 | ||
|
|
8589777bac | ||
|
|
c10a21ecbd | ||
|
|
eddc616b14 | ||
|
|
70fc1a9579 | ||
|
|
f27ec4d6a4 | ||
|
|
1e6e956e2d | ||
|
|
0a2a3530d1 | ||
|
|
9e4c820e26 | ||
|
|
05290bfe9e | ||
|
|
607f4ce353 | ||
|
|
4b819ead1d | ||
|
|
d07d9d3f31 | ||
|
|
d08776bf19 | ||
|
|
7a61fd44fd | ||
|
|
151da1487c | ||
|
|
e3f6dfad5b | ||
|
|
32080ce918 | ||
|
|
aedb2138c8 | ||
|
|
90e6938f1c | ||
|
|
eadff35250 | ||
|
|
487450ec64 | ||
|
|
f2f730bab5 | ||
|
|
ceecee37a7 | ||
|
|
394377bea9 | ||
|
|
2b47818deb | ||
|
|
9f72465052 | ||
|
|
ac33b4a322 | ||
|
|
911c844e54 | ||
|
|
12b9655565 | ||
|
|
2935717a06 | ||
|
|
2c8d2cfa21 | ||
|
|
d67c0eb757 | ||
|
|
7bcbcd5a7f | ||
|
|
1c06e7f36e | ||
|
|
407297adc0 | ||
|
|
b082b31562 | ||
|
|
fcbeb0f82f | ||
|
|
7094f8f265 | ||
|
|
48aaa13420 | ||
|
|
d2434cf91f | ||
|
|
8dbe0d2793 | ||
|
|
7b308cf984 | ||
|
|
520af504aa | ||
|
|
4bee130599 | ||
|
|
19a9ed3e19 | ||
|
|
0dac1b93ae | ||
|
|
e824863de1 | ||
|
|
9ff8becd62 | ||
|
|
fcaa1bcfa8 | ||
|
|
39f51bcc4f | ||
|
|
1b904ee2c9 | ||
|
|
e2baafc426 | ||
|
|
6dabe73002 | ||
|
|
d9b2b99c86 | ||
|
|
bdf23a7c4e | ||
|
|
c1723e0806 | ||
|
|
93590bd482 | ||
|
|
fbaa9d9e58 | ||
|
|
ba78a8558c | ||
|
|
513be04352 | ||
|
|
15317aa11b | ||
|
|
93e107f333 | ||
|
|
655b334b0a | ||
|
|
95cc1c58a6 | ||
|
|
0511d3e599 | ||
|
|
92a41b5c46 | ||
|
|
be16837c8c | ||
|
|
bf5f26cb12 | ||
|
|
ccbcef7eff | ||
|
|
d02a97b7f0 | ||
|
|
e0ca413c54 | ||
|
|
a272fc1c05 | ||
|
|
2c3f74d4ea | ||
|
|
c65b2fc0fd | ||
|
|
fd725adf27 | ||
|
|
ceba6da91f | ||
|
|
064e7d42ee | ||
|
|
cfdbf0c614 | ||
|
|
436777fe34 | ||
|
|
f08aa46222 | ||
|
|
e099ac514a | ||
|
|
873755f619 | ||
|
|
2094b7cf83 | ||
|
|
6ffdd81bb1 | ||
|
|
a69cb17602 | ||
|
|
7c82a9fd6e | ||
|
|
10d9a6c83d | ||
|
|
f6ed650ef6 | ||
|
|
df9ce6add9 | ||
|
|
28ee47d501 | ||
|
|
df2da479ad | ||
|
|
46eb9d8baf | ||
|
|
b6be871a21 | ||
|
|
ce2367fc0a | ||
|
|
7789e8cfea | ||
|
|
51a9effcaa | ||
|
|
fc3b953a8e | ||
|
|
a2ded3cecc | ||
|
|
ffb1390b51 | ||
|
|
3b92591c05 | ||
|
|
f173ddcf00 | ||
|
|
f78306f624 | ||
|
|
9852c9301e | ||
|
|
2e4f3de604 | ||
|
|
300dd97353 | ||
|
|
8e29ade83a | ||
|
|
971c770f6a | ||
|
|
7d31a06ae4 | ||
|
|
c5319ad7b1 | ||
|
|
f8bdb28ea6 | ||
|
|
2f8806d7c2 | ||
|
|
7d0a181c12 | ||
|
|
27cb7e53ed | ||
|
|
ee5154b510 | ||
|
|
080837201a | ||
|
|
656e6c0d94 | ||
|
|
b018f61bab | ||
|
|
b03b306848 | ||
|
|
19bf5c2b3e | ||
|
|
c22a716cf9 | ||
|
|
220c65da92 | ||
|
|
675f4b86f8 | ||
|
|
d31b3522b2 | ||
|
|
4ed2bab1d7 | ||
|
|
a572872806 | ||
|
|
e3ca23db0b | ||
|
|
67eb16a53f | ||
|
|
d7421cd1a3 | ||
|
|
c2e68ced66 | ||
|
|
10cf0db050 | ||
|
|
08f1a1dcfe | ||
|
|
11bf352295 | ||
|
|
5fd560b30a | ||
|
|
e6d01ca246 | ||
|
|
0ddf2fa00d | ||
|
|
8776143ec2 | ||
|
|
080c8e7af3 | ||
|
|
64998e762b | ||
|
|
b508da5ccc | ||
|
|
84a492655a | ||
|
|
9b9cfe4138 | ||
|
|
f362a7086a | ||
|
|
9e9ec57a5f | ||
|
|
da6a153985 | ||
|
|
b4bde3f510 | ||
|
|
8a5cebd635 | ||
|
|
ddf2733d3c | ||
|
|
cf65bfbcd0 | ||
|
|
03cce830bc | ||
|
|
913cf4c3e9 | ||
|
|
2ccce0beaf | ||
|
|
52239f71cd | ||
|
|
d9265af2e8 | ||
|
|
5877f6a627 | ||
|
|
e3e982c051 | ||
|
|
17f09ff3de | ||
|
|
7a73416c03 | ||
|
|
0f799d44ad | ||
|
|
24ebd44f87 | ||
|
|
572b10e655 | ||
|
|
60361c176b | ||
|
|
b232a2c58f | ||
|
|
2a44ac56fb | ||
|
|
d0340a3257 | ||
|
|
e708a53ddb | ||
|
|
23cdd70198 | ||
|
|
ba4bc30a78 | ||
|
|
e516ea146d | ||
|
|
61af638fe4 | ||
|
|
7a0af4142f | ||
|
|
1aa8d596a3 | ||
|
|
a457810623 | ||
|
|
4bccb7ab84 | ||
|
|
fcd5b2ce0a | ||
|
|
57a1184a16 | ||
|
|
ef176efed8 | ||
|
|
9943e0317d | ||
|
|
ae11c1c904 | ||
|
|
f937e069ca | ||
|
|
c9326da47b | ||
|
|
4698c05f9c | ||
|
|
15fd2cd5a0 | ||
|
|
193eb11095 | ||
|
|
59cc0096cd | ||
|
|
6bd7390eb8 | ||
|
|
eabeb18f34 | ||
|
|
4b6f539ba3 | ||
|
|
ea55fc5f41 | ||
|
|
94787229a4 | ||
|
|
0cb162022c | ||
|
|
5ff2ca311e | ||
|
|
44b8d452a8 | ||
|
|
82ccb1ab23 | ||
|
|
feb8b94e30 | ||
|
|
5adc73e277 | ||
|
|
c4ac983fc7 | ||
|
|
5ba7ba3aac | ||
|
|
e879479b3d | ||
|
|
7b49463297 | ||
|
|
66600c3373 | ||
|
|
19401c4bc6 | ||
|
|
bfc8660c5e | ||
|
|
6a83dc56ba | ||
|
|
82df9d8cad | ||
|
|
dd30fef078 | ||
|
|
79feb5a1cc | ||
|
|
0665524b11 | ||
|
|
d45367e840 | ||
|
|
cb0d988efc | ||
|
|
fc0c556967 | ||
|
|
00970164db | ||
|
|
7c3d76e9fe | ||
|
|
190c1f9620 | ||
|
|
f532325147 | ||
|
|
278dcb8808 | ||
|
|
309c25e10b | ||
|
|
6df728ea3e | ||
|
|
dcf4ef6d74 | ||
|
|
4de1369a5a | ||
|
|
2ccfdb1280 | ||
|
|
9fbf800639 | ||
|
|
577daf64df | ||
|
|
0b1943e9b3 | ||
|
|
30bd2dd876 | ||
|
|
cecd4d4179 | ||
|
|
364baab18d | ||
|
|
bb3d4d2171 | ||
|
|
2355faf899 | ||
|
|
858e0b24ff | ||
|
|
f7d0ed3988 | ||
|
|
9e69f5dcfa | ||
|
|
409ed9ad67 | ||
|
|
06e78e19d0 | ||
|
|
9a1d746170 | ||
|
|
ef87ce3507 | ||
|
|
2b9053eac4 | ||
|
|
116ef719be |
10
.github/pull_request_template.md
vendored
Normal file
10
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<!-- Thank you for contributing to Mol* -->
|
||||
|
||||
# Description
|
||||
|
||||
|
||||
## Actions
|
||||
|
||||
- [ ] Added description of changes to the `[Unreleased]` section of `CHANGELOG.md`
|
||||
- [ ] Updated headers of modified files
|
||||
- [ ] Added my name to `package.json`'s `contributors`
|
||||
1
.vscode/extensions.json
vendored
1
.vscode/extensions.json
vendored
@@ -6,7 +6,6 @@
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"firsttris.vscode-jest-runner",
|
||||
"msjsdiag.debugger-for-chrome",
|
||||
"slevesque.shader",
|
||||
"stpn.vscode-graphql",
|
||||
"wayou.vscode-todo-highlight"
|
||||
|
||||
90
CHANGELOG.md
90
CHANGELOG.md
@@ -6,6 +6,96 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v3.26.0] - 2022-12-04
|
||||
|
||||
- Support for ``powerPreference`` webgl attribute. Add ``PluginConfig.General.PowerPreference`` and ``power-preference`` Viewer GET param.
|
||||
- Excluded common protein caps `NME` and `ACE` from the ligand selection query
|
||||
- Add screen-space shadow post-processing effect
|
||||
- Add "Structure Molecular Surface" visual
|
||||
- Add `external-volume` theme (coloring of arbitrary geometries by user-selected volume)
|
||||
|
||||
## [v3.25.1] - 2022-11-20
|
||||
|
||||
- Fix edge-case in `Structure.eachUnitPair` with single-element units
|
||||
- Fix 'auto' structure-quality for coarse models
|
||||
|
||||
## [v3.25.0] - 2022-11-16
|
||||
|
||||
- Fix handling of gzipped assets (reverts #615)
|
||||
|
||||
## [v3.24.0] - 2022-11-13
|
||||
|
||||
- Make `PluginContext.initContainer` checkered canvas background optional
|
||||
- Store URL of downloaded assets to detect zip/gzip based on extension (#615)
|
||||
- Add optional `operator.key`; can be referenced in `IndexPairBonds`
|
||||
- Add overpaint/transparency/substance theme strength to representations
|
||||
- Fix viewport color for transparent background
|
||||
|
||||
## [v3.23.0] - 2022-10-19
|
||||
|
||||
- Add `PluginContext.initContainer/mount/unmount` methods; these should make it easier to reuse a plugin context with both custom and built-in UI
|
||||
- Add `PluginContext.canvas3dInitialized`
|
||||
- `createPluginUI` now resolves after the 3d canvas has been initialized
|
||||
- Change EM Volume Streaming default from `Whole Structure` to `Auto`
|
||||
|
||||
## [v3.22.0] - 2022-10-17
|
||||
|
||||
- Replace `VolumeIsosurfaceParams.pickingGranularity` param with `Volume.PickingGranuality`
|
||||
|
||||
## [v3.21.0] - 2022-10-17
|
||||
|
||||
- Add `VolumeIsosurfaceParams.pickingGranularity` param
|
||||
- Prevent component controls collapsing when option is selected
|
||||
|
||||
## [v3.20.0] - 2022-10-16
|
||||
|
||||
- [Breaking] Rename the ``model-index`` color theme to ``trajectory-index``
|
||||
- Add a new ``model-index`` color theme that uniquely colors each loaded model
|
||||
- Add the new ``model-index`` and ``structure-index`` color themes as an option for the carbon color in the ``element-symbol`` and ``ilustrative`` color themes
|
||||
- Add ``structure-index`` color theme that uniquely colors each root structure
|
||||
- Add ``nearest`` method to ``Lookup3D``
|
||||
- Add mipmap-based blur for skybox backgrounds
|
||||
|
||||
## [v3.19.0] - 2022-10-01
|
||||
|
||||
- Fix "empty textures" error on empty canvas
|
||||
- Optimize BinaryCIF integer packing encoder
|
||||
- Fix dual depth peeling when post-processing is off or when rendering direct-volumes
|
||||
- Add ``cameraClipping.minNear`` parameter
|
||||
- Fix black artifacts on specular highlights with transparent background
|
||||
|
||||
## [v3.18.0] - 2022-09-17
|
||||
|
||||
- Integration of Dual depth peeling - OIT method
|
||||
- Stereo camera improvements
|
||||
- Fix param updates not applied
|
||||
- Better param ranges and description
|
||||
- Add timer.mark for left/right camera
|
||||
|
||||
## [v3.17.0] - 2022-09-11
|
||||
|
||||
- [Fix] Clone ``Canvas3DParams`` when creating a ``Canvas3D`` instance to prevent shared state between multiple instances
|
||||
- Add ``includeResidueTest`` option to ``alignAndSuperposeWithSIFTSMapping``
|
||||
- Add ``parentDisplay`` param for interactions representation.
|
||||
- [Experimental] Add support for PyMOL, VMD, and Jmol atom expressions in selection scripts
|
||||
- Support for ``failIfMajorPerformanceCaveat`` webgl attribute. Add ``PluginConfig.General.AllowMajorPerformanceCaveat`` and ``allow-major-performance-caveat`` Viewer GET param.
|
||||
- Fix handling of PDB TER records (#549)
|
||||
- Add support for getting multiple loci from a representation (``.getAllLoci()``)
|
||||
- Add ``key`` property to intra- and inter-bonds for referencing source data
|
||||
- Fix click event triggered after move
|
||||
|
||||
## [v3.16.0] - 2022-08-25
|
||||
|
||||
- Support ``globalColorParams`` and ``globalSymmetryParams`` in common representation params
|
||||
- Support ``label`` parameter in ``Viewer.loadStructureFromUrl``
|
||||
- Fix ``ViewportHelpContent`` Mouse Controls section
|
||||
|
||||
## [v3.15.0] - 2022-08-23
|
||||
|
||||
- Fix wboit in Safari >=15 (add missing depth renderbuffer to wboit pass)
|
||||
- Add 'Around Camera' option to Volume streaming
|
||||
- Avoid queuing more than one update in Volume streaming
|
||||
|
||||
## [v3.14.0] - 2022-08-20
|
||||
|
||||
- Expose inter-bonds compute params in structure
|
||||
|
||||
4865
package-lock.json
generated
4865
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
72
package.json
72
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "3.14.0",
|
||||
"version": "3.26.0",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -89,71 +89,75 @@
|
||||
"Ludovic Autin <autin@scripps.edu>",
|
||||
"Michal Malý <michal.maly@ibt.cas.cz>",
|
||||
"Jiří Černý <jiri.cerny@ibt.cas.cz>",
|
||||
"Panagiotis Tourlas <panagiot_tourlov@hotmail.com>"
|
||||
"Panagiotis Tourlas <panagiot_tourlov@hotmail.com>",
|
||||
"Adam Midlik <midlik@gmail.com>",
|
||||
"Koya Sakuma <koya.sakuma.work@gmail.com>",
|
||||
"Gianluca Tomasello <giagitom@gmail.com>",
|
||||
"Jason Pattle <jpattle@exscientia.co.uk>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/add": "^3.2.1",
|
||||
"@graphql-codegen/cli": "^2.11.6",
|
||||
"@graphql-codegen/cli": "^2.15.0",
|
||||
"@graphql-codegen/time": "^3.2.1",
|
||||
"@graphql-codegen/typescript": "^2.7.3",
|
||||
"@graphql-codegen/typescript": "^2.8.3",
|
||||
"@graphql-codegen/typescript-graphql-files-modules": "^2.2.1",
|
||||
"@graphql-codegen/typescript-graphql-request": "^4.5.3",
|
||||
"@graphql-codegen/typescript-operations": "^2.5.3",
|
||||
"@graphql-codegen/typescript-graphql-request": "^4.5.8",
|
||||
"@graphql-codegen/typescript-operations": "^2.5.8",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/gl": "^4.1.1",
|
||||
"@types/jest": "^28.1.7",
|
||||
"@types/react": "^18.0.17",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"@types/gl": "^6.0.2",
|
||||
"@types/jest": "^29.2.3",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||
"@typescript-eslint/parser": "^5.45.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"concurrently": "^7.3.0",
|
||||
"concurrently": "^7.6.0",
|
||||
"cpx2": "^4.2.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^6.7.1",
|
||||
"eslint": "^8.22.0",
|
||||
"css-loader": "^6.7.2",
|
||||
"eslint": "^8.29.0",
|
||||
"extra-watch-webpack-plugin": "^1.0.3",
|
||||
"file-loader": "^6.2.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"fs-extra": "^11.1.0",
|
||||
"graphql": "^16.6.0",
|
||||
"http-server": "^14.1.1",
|
||||
"jest": "^28.1.3",
|
||||
"mini-css-extract-plugin": "^2.6.1",
|
||||
"jest": "^29.3.1",
|
||||
"mini-css-extract-plugin": "^2.7.1",
|
||||
"path-browserify": "^1.0.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"sass": "^1.54.5",
|
||||
"sass-loader": "^13.0.2",
|
||||
"simple-git": "^3.12.0",
|
||||
"sass": "^1.56.1",
|
||||
"sass-loader": "^13.2.0",
|
||||
"simple-git": "^3.15.1",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-jest": "^28.0.8",
|
||||
"typescript": "^4.7.4",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^4.10.0"
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "^4.9.3",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/argparse": "^2.0.10",
|
||||
"@types/benchmark": "^2.1.1",
|
||||
"@types/benchmark": "^2.1.2",
|
||||
"@types/compression": "1.7.2",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/node": "^16.11.51",
|
||||
"@types/express": "^4.17.14",
|
||||
"@types/node": "^16.18.4",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"@types/swagger-ui-dist": "3.30.1",
|
||||
"argparse": "^2.0.1",
|
||||
"body-parser": "^1.20.0",
|
||||
"body-parser": "^1.20.1",
|
||||
"compression": "^1.7.4",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.1",
|
||||
"express": "^4.18.2",
|
||||
"h264-mp4-encoder": "^1.0.12",
|
||||
"immer": "^9.0.15",
|
||||
"immer": "^9.0.16",
|
||||
"immutable": "^4.1.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"rxjs": "^7.5.6",
|
||||
"swagger-ui-dist": "^4.14.0",
|
||||
"tslib": "^2.4.0",
|
||||
"rxjs": "^7.6.0",
|
||||
"swagger-ui-dist": "^4.15.5",
|
||||
"tslib": "^2.4.1",
|
||||
"util.promisify": "^1.1.1",
|
||||
"xhr2": "^0.2.1"
|
||||
},
|
||||
|
||||
@@ -58,20 +58,22 @@ class Viewer {
|
||||
}
|
||||
|
||||
static async create(elementOrId: string | HTMLElement, colors = [Color(0x992211), Color(0xDDDDDD)], showButtons = true) {
|
||||
const o = { ...DefaultViewerOptions, ...{
|
||||
layoutIsExpanded: false,
|
||||
layoutShowControls: false,
|
||||
layoutShowRemoteState: false,
|
||||
layoutShowSequence: true,
|
||||
layoutShowLog: false,
|
||||
layoutShowLeftPanel: true,
|
||||
const o = {
|
||||
...DefaultViewerOptions, ...{
|
||||
layoutIsExpanded: false,
|
||||
layoutShowControls: false,
|
||||
layoutShowRemoteState: false,
|
||||
layoutShowSequence: true,
|
||||
layoutShowLog: false,
|
||||
layoutShowLeftPanel: true,
|
||||
|
||||
viewportShowExpand: true,
|
||||
viewportShowControls: false,
|
||||
viewportShowSettings: false,
|
||||
viewportShowSelectionMode: false,
|
||||
viewportShowAnimation: false,
|
||||
} };
|
||||
viewportShowExpand: true,
|
||||
viewportShowControls: false,
|
||||
viewportShowSettings: false,
|
||||
viewportShowSelectionMode: false,
|
||||
viewportShowAnimation: false,
|
||||
}
|
||||
};
|
||||
const defaultSpec = DefaultPluginUISpec();
|
||||
|
||||
const spec: PluginUISpec = {
|
||||
@@ -135,18 +137,16 @@ class Viewer {
|
||||
}
|
||||
};
|
||||
|
||||
plugin.behaviors.canvas3d.initialized.subscribe(v => {
|
||||
if (v) {
|
||||
PluginCommands.Canvas3D.SetSettings(plugin, { settings: {
|
||||
renderer: {
|
||||
...plugin.canvas3d!.props.renderer,
|
||||
backgroundColor: ColorNames.white,
|
||||
},
|
||||
camera: {
|
||||
...plugin.canvas3d!.props.camera,
|
||||
helper: { axes: { name: 'off', params: {} } }
|
||||
}
|
||||
} });
|
||||
PluginCommands.Canvas3D.SetSettings(plugin, {
|
||||
settings: {
|
||||
renderer: {
|
||||
...plugin.canvas3d!.props.renderer,
|
||||
backgroundColor: ColorNames.white,
|
||||
},
|
||||
camera: {
|
||||
...plugin.canvas3d!.props.camera,
|
||||
helper: { axes: { name: 'off', params: {} } }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -166,7 +166,7 @@ class Viewer {
|
||||
structures.push({ ref: structureProperties?.ref || structure.ref });
|
||||
}
|
||||
|
||||
// remove current structuresfrom hierarchy as they will be merged
|
||||
// remove current structures from hierarchy as they will be merged
|
||||
// TODO only works with using loadStructuresFromUrlsAndMerge once
|
||||
// need some more API metho to work with the hierarchy
|
||||
this.plugin.managers.structure.hierarchy.updateCurrent(this.plugin.managers.structure.hierarchy.current.structures, 'remove');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -31,7 +31,8 @@ function shinyStyle(plugin: PluginContext) {
|
||||
postprocessing: {
|
||||
...plugin.canvas3d!.props.postprocessing,
|
||||
occlusion: { name: 'off', params: {} },
|
||||
outline: { name: 'off', params: {} }
|
||||
shadow: { name: 'off', params: {} },
|
||||
outline: { name: 'off', params: {} },
|
||||
}
|
||||
} });
|
||||
}
|
||||
@@ -48,13 +49,14 @@ function occlusionStyle(plugin: PluginContext) {
|
||||
blurKernelSize: 15,
|
||||
radius: 5,
|
||||
samples: 32,
|
||||
resolutionScale: 1
|
||||
resolutionScale: 1,
|
||||
} },
|
||||
outline: { name: 'on', params: {
|
||||
scale: 1.0,
|
||||
threshold: 0.33,
|
||||
color: Color(0x0000),
|
||||
} }
|
||||
} },
|
||||
shadow: { name: 'off', params: {} },
|
||||
}
|
||||
} });
|
||||
}
|
||||
@@ -202,14 +204,14 @@ const InteractionsPreset = StructureRepresentationPresetProvider({
|
||||
const components = {
|
||||
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
|
||||
surroundings: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandSurroundings, `surroundings`),
|
||||
interactions: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandPlusSurroundings, `interactions`)
|
||||
interactions: await presetStaticComponent(plugin, structureCell, 'ligand'),
|
||||
};
|
||||
|
||||
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
|
||||
const representations = {
|
||||
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, material: CustomMaterial, sizeFactor: 0.3 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
|
||||
ballAndStick: builder.buildRepresentation(update, components.surroundings, { type: 'ball-and-stick', typeParams: { ...typeParams, material: CustomMaterial, sizeFactor: 0.1, sizeAspectRatio: 1 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ball-and-stick' }),
|
||||
interactions: builder.buildRepresentation(update, components.interactions, { type: InteractionsRepresentationProvider, typeParams: { ...typeParams, material: CustomMaterial }, color: InteractionTypeColorThemeProvider }, { tag: 'interactions' }),
|
||||
interactions: builder.buildRepresentation(update, components.interactions, { type: InteractionsRepresentationProvider, typeParams: { ...typeParams, material: CustomMaterial, includeParent: true, parentDisplay: 'between' }, color: InteractionTypeColorThemeProvider }, { tag: 'interactions' }),
|
||||
label: builder.buildRepresentation(update, components.surroundings, { type: 'label', typeParams: { ...typeParams, material: CustomMaterial, background: false, borderWidth: 0.1 }, color: 'uniform', colorParams: { value: Color(0x000000) } }, { tag: 'label' }),
|
||||
};
|
||||
|
||||
|
||||
@@ -88,7 +88,10 @@ const DefaultViewerOptions = {
|
||||
pickScale: PluginConfig.General.PickScale.defaultValue,
|
||||
pickPadding: PluginConfig.General.PickPadding.defaultValue,
|
||||
enableWboit: PluginConfig.General.EnableWboit.defaultValue,
|
||||
enableDpoit: PluginConfig.General.EnableDpoit.defaultValue,
|
||||
preferWebgl1: PluginConfig.General.PreferWebGl1.defaultValue,
|
||||
allowMajorPerformanceCaveat: PluginConfig.General.AllowMajorPerformanceCaveat.defaultValue,
|
||||
powerPreference: PluginConfig.General.PowerPreference.defaultValue,
|
||||
|
||||
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
|
||||
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
|
||||
@@ -158,7 +161,10 @@ export class Viewer {
|
||||
[PluginConfig.General.PickScale, o.pickScale],
|
||||
[PluginConfig.General.PickPadding, o.pickPadding],
|
||||
[PluginConfig.General.EnableWboit, o.enableWboit],
|
||||
[PluginConfig.General.EnableDpoit, o.enableDpoit],
|
||||
[PluginConfig.General.PreferWebGl1, o.preferWebgl1],
|
||||
[PluginConfig.General.AllowMajorPerformanceCaveat, o.allowMajorPerformanceCaveat],
|
||||
[PluginConfig.General.PowerPreference, o.powerPreference],
|
||||
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
|
||||
[PluginConfig.Viewport.ShowControls, o.viewportShowControls],
|
||||
[PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
|
||||
@@ -199,7 +205,7 @@ export class Viewer {
|
||||
return PluginCommands.State.Snapshots.OpenUrl(this.plugin, { url, type });
|
||||
}
|
||||
|
||||
loadStructureFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) {
|
||||
loadStructureFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions & { label?: string }) {
|
||||
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
|
||||
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
|
||||
source: {
|
||||
@@ -208,6 +214,7 @@ export class Viewer {
|
||||
url: Asset.Url(url),
|
||||
format: format as any,
|
||||
isBinary,
|
||||
label: options?.label,
|
||||
options: { ...params.source.params.options, representationParams: options?.representationParams as any },
|
||||
}
|
||||
}
|
||||
@@ -496,4 +503,4 @@ export const ViewerAutoPreset = StructureRepresentationPresetProvider({
|
||||
return await PresetStructureRepresentations.auto.apply(ref, params, plugin);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,6 +38,15 @@
|
||||
viewer.loadPdb('7bv2');
|
||||
viewer.loadEmdb('EMD-30210', { detail: 6 });
|
||||
// viewer.loadAllModelsOrAssemblyFromUrl('https://cs.litemol.org/5ire/full', 'mmcif', false, { representationParams: { theme: { globalName: 'operator-name' } } })
|
||||
// viewer.loadStructureFromUrl('my url', 'pdb', false, {
|
||||
// representationParams: {
|
||||
// theme: {
|
||||
// globalName: 'uniform',
|
||||
// globalColorParams: { value: 0xff0000 }
|
||||
// }
|
||||
// },
|
||||
// label: 'my structure'
|
||||
// });
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -60,7 +60,10 @@
|
||||
var pickScale = getParam('pick-scale', '[^&]+').trim();
|
||||
var pickPadding = getParam('pick-padding', '[^&]+').trim();
|
||||
var disableWboit = getParam('disable-wboit', '[^&]+').trim() === '1';
|
||||
var enableDpoit = getParam('enable-dpoit', '[^&]+').trim() === '1';
|
||||
var preferWebgl1 = getParam('prefer-webgl1', '[^&]+').trim() === '1' || void 0;
|
||||
var allowMajorPerformanceCaveat = getParam('allow-major-performance-caveat', '[^&]+').trim() === '1';
|
||||
var powerPreference = getParam('power-preference', '[^&]+').trim().toLowerCase();
|
||||
|
||||
molstar.Viewer.create('app', {
|
||||
layoutShowControls: !hideControls,
|
||||
@@ -74,8 +77,11 @@
|
||||
pixelScale: parseFloat(pixelScale) || 1,
|
||||
pickScale: parseFloat(pickScale) || 0.25,
|
||||
pickPadding: isNaN(parseFloat(pickPadding)) ? 1 : parseFloat(pickPadding),
|
||||
enableWboit: disableWboit ? false : void 0, // use default value if disable-wboit is not set
|
||||
enableWboit: (disableWboit || enableDpoit) ? false : void 0, // use default value if disable-wboit is not set
|
||||
enableDpoit: enableDpoit ? true : void 0,
|
||||
preferWebgl1: preferWebgl1,
|
||||
allowMajorPerformanceCaveat: allowMajorPerformanceCaveat,
|
||||
powerPreference: powerPreference || 'high-performance',
|
||||
}).then(viewer => {
|
||||
var snapshotId = getParam('snapshot-id', '[^&]+').trim();
|
||||
if (snapshotId) viewer.setRemoteSnapshot(snapshotId);
|
||||
|
||||
@@ -71,6 +71,7 @@ export function getFieldType(type: string, description: string, values?: string[
|
||||
case 'ec-type':
|
||||
case 'ucode-alphanum-csv':
|
||||
case 'id_list':
|
||||
case 'entity_id_list':
|
||||
return ListCol('str', ',', description);
|
||||
case 'id_list_spc':
|
||||
return ListCol('str', ' ', description);
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { AlphaOrbitalsExample } from '.';
|
||||
import { ParameterControls } from '../../mol-plugin-ui/controls/parameters';
|
||||
import { useBehavior } from '../../mol-plugin-ui/hooks/use-behavior';
|
||||
import { PluginContextContainer } from '../../mol-plugin-ui/plugin';
|
||||
|
||||
export function mountControls(orbitals: AlphaOrbitalsExample, parent: Element) {
|
||||
ReactDOM.render(<PluginContextContainer plugin={orbitals.plugin}>
|
||||
createRoot(parent).render(<PluginContextContainer plugin={orbitals.plugin}>
|
||||
<Controls orbitals={orbitals} />
|
||||
</PluginContextContainer>, parent);
|
||||
</PluginContextContainer>);
|
||||
}
|
||||
|
||||
function Controls({ orbitals }: { orbitals: AlphaOrbitalsExample }) {
|
||||
|
||||
@@ -82,24 +82,20 @@ export class AlphaOrbitalsExample {
|
||||
|
||||
this.plugin.managers.interactivity.setProps({ granularity: 'element' });
|
||||
|
||||
this.plugin.behaviors.canvas3d.initialized.subscribe(init => {
|
||||
if (!init) return;
|
||||
|
||||
if (!canComputeGrid3dOnGPU(this.plugin.canvas3d?.webgl)) {
|
||||
PluginCommands.Toast.Show(this.plugin, {
|
||||
title: 'Error',
|
||||
message: `Browser/device does not support required WebGL extension (OES_texture_float).`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.load({
|
||||
moleculeSdf: DemoMoleculeSDF,
|
||||
...DemoOrbitals
|
||||
if (!canComputeGrid3dOnGPU(this.plugin.canvas3d?.webgl)) {
|
||||
PluginCommands.Toast.Show(this.plugin, {
|
||||
title: 'Error',
|
||||
message: `Browser/device does not support required WebGL extension (OES_texture_float).`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
mountControls(this, document.getElementById('controls')!);
|
||||
this.load({
|
||||
moleculeSdf: DemoMoleculeSDF,
|
||||
...DemoOrbitals
|
||||
});
|
||||
|
||||
mountControls(this, document.getElementById('controls')!);
|
||||
}
|
||||
|
||||
readonly params = new BehaviorSubject<ParamDefinition.For<Params>>({} as any);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -25,7 +25,8 @@ const Canvas3DPresets = {
|
||||
canvas3d: <Preset>{
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } },
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000) } }
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000) } },
|
||||
shadow: { name: 'off', params: {} },
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 1.0,
|
||||
@@ -37,7 +38,8 @@ const Canvas3DPresets = {
|
||||
canvas3d: <Preset>{
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } },
|
||||
outline: { name: 'off', params: {} }
|
||||
outline: { name: 'off', params: {} },
|
||||
shadow: { name: 'off', params: {} },
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 0.4,
|
||||
@@ -50,7 +52,8 @@ const Canvas3DPresets = {
|
||||
canvas3d: <Preset>{
|
||||
postprocessing: {
|
||||
occlusion: { name: 'off', params: {} },
|
||||
outline: { name: 'off', params: {} }
|
||||
outline: { name: 'off', params: {} },
|
||||
shadow: { name: 'off', params: {} },
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 0.4,
|
||||
|
||||
@@ -72,6 +72,7 @@ export const Backgrounds = PluginBehavior.create<{ }>({
|
||||
lightness: 0,
|
||||
saturation: 0,
|
||||
opacity: 1,
|
||||
blur: 0.3,
|
||||
}
|
||||
}
|
||||
}, 'Purple Nebula Skybox'],
|
||||
|
||||
@@ -606,6 +606,15 @@ export const LoadCellPackModel = StateAction.build({
|
||||
resolutionScale: 1,
|
||||
}
|
||||
},
|
||||
shadow: {
|
||||
name: 'on',
|
||||
params: {
|
||||
bias: 0.6,
|
||||
maxDistance: 80,
|
||||
steps: 3,
|
||||
tolerance: 1.0,
|
||||
}
|
||||
},
|
||||
outline: {
|
||||
name: 'on',
|
||||
params: {
|
||||
|
||||
@@ -60,6 +60,8 @@ export class GeometryExporterUI extends CollapsableControls<{}, State> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.plugin.canvas3d) return;
|
||||
|
||||
const merged = merge(
|
||||
this.controls.behaviors.params,
|
||||
this.plugin.canvas3d!.reprCount
|
||||
|
||||
@@ -118,11 +118,13 @@ export class Mp4Controls extends PluginComponent {
|
||||
}
|
||||
|
||||
private init() {
|
||||
if (!this.plugin.canvas3d) return;
|
||||
|
||||
this.subscribe(this.plugin.managers.animation.events.updated.pipe(debounceTime(16)), () => {
|
||||
this.sync();
|
||||
});
|
||||
|
||||
this.subscribe(this.plugin.canvas3d?.resized!, () => this.syncInfo());
|
||||
this.subscribe(this.plugin.canvas3d.resized, () => this.syncInfo());
|
||||
this.subscribe(this.plugin.helpers.viewportScreenshot?.events.previewed!, () => this.syncInfo());
|
||||
|
||||
this.subscribe(this.plugin.behaviors.state.isBusy, b => this.updateCanApply(b));
|
||||
|
||||
@@ -4,7 +4,7 @@ export type InputMaybe<T> = Maybe<T>;
|
||||
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
||||
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
|
||||
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
|
||||
// Generated on 2022-08-20T16:36:05-07:00
|
||||
// Generated on 2022-12-03T21:55:37-08:00
|
||||
|
||||
/** All built-in and custom scalars, mapped to their actual values */
|
||||
export type Scalars = {
|
||||
@@ -343,6 +343,14 @@ export type Citation = {
|
||||
*
|
||||
*/
|
||||
readonly journal_abbrev?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* Full name of the cited journal; relevant for journal articles.
|
||||
*
|
||||
* Examples:
|
||||
* Journal of Molecular Biology
|
||||
*
|
||||
*/
|
||||
readonly journal_full?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The American Society for Testing and Materials (ASTM) code
|
||||
* assigned to the journal cited (also referred to as the CODEN
|
||||
@@ -550,6 +558,7 @@ export type CoreBranchedEntityInstance = {
|
||||
readonly rcsb_id: Scalars['String'];
|
||||
readonly rcsb_latest_revision?: Maybe<RcsbLatestRevision>;
|
||||
readonly rcsb_ligand_neighbors?: Maybe<ReadonlyArray<Maybe<RcsbLigandNeighbors>>>;
|
||||
readonly struct_asym?: Maybe<StructAsym>;
|
||||
};
|
||||
|
||||
export type CoreChemComp = {
|
||||
@@ -661,6 +670,7 @@ export type CoreEntry = {
|
||||
readonly exptl?: Maybe<ReadonlyArray<Maybe<Exptl>>>;
|
||||
readonly exptl_crystal?: Maybe<ReadonlyArray<Maybe<ExptlCrystal>>>;
|
||||
readonly exptl_crystal_grow?: Maybe<ReadonlyArray<Maybe<ExptlCrystalGrow>>>;
|
||||
readonly ma_data?: Maybe<ReadonlyArray<Maybe<MaData>>>;
|
||||
/** Get all non-polymer (non-solvent) entities for this PDB entry. */
|
||||
readonly nonpolymer_entities?: Maybe<ReadonlyArray<Maybe<CoreNonpolymerEntity>>>;
|
||||
readonly pdbx_SG_project?: Maybe<ReadonlyArray<Maybe<PdbxSgProject>>>;
|
||||
@@ -701,6 +711,7 @@ export type CoreEntry = {
|
||||
/** The list of content types associated with this entry. */
|
||||
readonly rcsb_associated_holdings?: Maybe<CurrentEntry>;
|
||||
readonly rcsb_binding_affinity?: Maybe<ReadonlyArray<Maybe<RcsbBindingAffinity>>>;
|
||||
readonly rcsb_comp_model_provenance?: Maybe<RcsbCompModelProvenance>;
|
||||
readonly rcsb_entry_container_identifiers: RcsbEntryContainerIdentifiers;
|
||||
readonly rcsb_entry_group_membership?: Maybe<ReadonlyArray<Maybe<RcsbEntryGroupMembership>>>;
|
||||
readonly rcsb_entry_info: RcsbEntryInfo;
|
||||
@@ -713,6 +724,7 @@ export type CoreEntry = {
|
||||
*
|
||||
*/
|
||||
readonly rcsb_id: Scalars['String'];
|
||||
readonly rcsb_ma_qa_metric_global?: Maybe<ReadonlyArray<Maybe<RcsbMaQaMetricGlobal>>>;
|
||||
readonly rcsb_primary_citation?: Maybe<RcsbPrimaryCitation>;
|
||||
readonly refine?: Maybe<ReadonlyArray<Maybe<Refine>>>;
|
||||
readonly refine_analyze?: Maybe<ReadonlyArray<Maybe<RefineAnalyze>>>;
|
||||
@@ -786,6 +798,7 @@ export type CoreNonpolymerEntityInstance = {
|
||||
readonly rcsb_nonpolymer_instance_validation_score?: Maybe<ReadonlyArray<Maybe<RcsbNonpolymerInstanceValidationScore>>>;
|
||||
readonly rcsb_nonpolymer_struct_conn?: Maybe<ReadonlyArray<Maybe<RcsbNonpolymerStructConn>>>;
|
||||
readonly rcsb_target_neighbors?: Maybe<ReadonlyArray<Maybe<RcsbTargetNeighbors>>>;
|
||||
readonly struct_asym?: Maybe<StructAsym>;
|
||||
};
|
||||
|
||||
export type CorePfam = {
|
||||
@@ -919,6 +932,7 @@ export type CorePolymerEntityInstance = {
|
||||
readonly rcsb_polymer_instance_feature?: Maybe<ReadonlyArray<Maybe<RcsbPolymerInstanceFeature>>>;
|
||||
readonly rcsb_polymer_instance_feature_summary?: Maybe<ReadonlyArray<Maybe<RcsbPolymerInstanceFeatureSummary>>>;
|
||||
readonly rcsb_polymer_struct_conn?: Maybe<ReadonlyArray<Maybe<RcsbPolymerStructConn>>>;
|
||||
readonly struct_asym?: Maybe<StructAsym>;
|
||||
};
|
||||
|
||||
export type CorePubmed = {
|
||||
@@ -1284,9 +1298,9 @@ export type Em2dCrystalEntity = {
|
||||
readonly id: Scalars['String'];
|
||||
/** pointer to _em_image_processing.id in the EM_IMAGE_PROCESSING category. */
|
||||
readonly image_processing_id: Scalars['String'];
|
||||
/** Unit-cell length a in Angstroms. */
|
||||
/** Unit-cell length a in angstroms. */
|
||||
readonly length_a?: Maybe<Scalars['Float']>;
|
||||
/** Unit-cell length b in Angstroms. */
|
||||
/** Unit-cell length b in angstroms. */
|
||||
readonly length_b?: Maybe<Scalars['Float']>;
|
||||
/** Thickness of 2D crystal */
|
||||
readonly length_c?: Maybe<Scalars['Float']>;
|
||||
@@ -1317,11 +1331,11 @@ export type Em3dCrystalEntity = {
|
||||
readonly id: Scalars['String'];
|
||||
/** pointer to _em_image_processing.id in the EM_IMAGE_PROCESSING category. */
|
||||
readonly image_processing_id: Scalars['String'];
|
||||
/** Unit-cell length a in Angstroms. */
|
||||
/** Unit-cell length a in angstroms. */
|
||||
readonly length_a?: Maybe<Scalars['Float']>;
|
||||
/** Unit-cell length b in Angstroms. */
|
||||
/** Unit-cell length b in angstroms. */
|
||||
readonly length_b?: Maybe<Scalars['Float']>;
|
||||
/** Unit-cell length c in Angstroms. */
|
||||
/** Unit-cell length c in angstroms. */
|
||||
readonly length_c?: Maybe<Scalars['Float']>;
|
||||
/**
|
||||
* Space group name.
|
||||
@@ -1482,7 +1496,7 @@ export type Em3dReconstruction = {
|
||||
*/
|
||||
readonly refinement_type?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The final resolution (in Angstroms)of the 3D reconstruction.
|
||||
* The final resolution (in angstroms)of the 3D reconstruction.
|
||||
*
|
||||
* Examples:
|
||||
* null, null
|
||||
@@ -1558,7 +1572,7 @@ export type EmDiffractionShell = {
|
||||
*/
|
||||
readonly fourier_space_coverage?: Maybe<Scalars['Float']>;
|
||||
/**
|
||||
* High resolution limit for this shell (Angstroms)
|
||||
* High resolution limit for this shell (angstroms)
|
||||
*
|
||||
* Examples:
|
||||
* null
|
||||
@@ -1568,7 +1582,7 @@ export type EmDiffractionShell = {
|
||||
/** Unique identifier for the category em_diffraction_shell */
|
||||
readonly id: Scalars['String'];
|
||||
/**
|
||||
* Low resolution limit for this shell (Angstroms)
|
||||
* Low resolution limit for this shell (angstroms)
|
||||
*
|
||||
* Examples:
|
||||
* null
|
||||
@@ -1614,7 +1628,7 @@ export type EmDiffractionStats = {
|
||||
*/
|
||||
readonly fourier_space_coverage?: Maybe<Scalars['Float']>;
|
||||
/**
|
||||
* High resolution limit of the structure factor data, in Angstroms
|
||||
* High resolution limit of the structure factor data, in angstroms
|
||||
*
|
||||
* Examples:
|
||||
* null
|
||||
@@ -1998,12 +2012,12 @@ export type EmImaging = {
|
||||
/** The magnification indicated by the microscope readout. */
|
||||
readonly nominal_magnification?: Maybe<Scalars['Int']>;
|
||||
/**
|
||||
* The specimen temperature maximum (degrees Kelvin) for the duration
|
||||
* The specimen temperature maximum (kelvin) for the duration
|
||||
* of imaging.
|
||||
*/
|
||||
readonly recording_temperature_maximum?: Maybe<Scalars['Float']>;
|
||||
/**
|
||||
* The specimen temperature minimum (degrees Kelvin) for the duration
|
||||
* The specimen temperature minimum (kelvin) for the duration
|
||||
* of imaging.
|
||||
*/
|
||||
readonly recording_temperature_minimum?: Maybe<Scalars['Float']>;
|
||||
@@ -2028,7 +2042,7 @@ export type EmImaging = {
|
||||
/** Foreign key to the EM_SPECIMEN category */
|
||||
readonly specimen_id?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The mean specimen stage temperature (degrees Kelvin) during imaging
|
||||
* The mean specimen stage temperature (in kelvin) during imaging
|
||||
* in the microscope.
|
||||
*/
|
||||
readonly temperature?: Maybe<Scalars['Float']>;
|
||||
@@ -2215,7 +2229,7 @@ export type EmStaining = {
|
||||
};
|
||||
|
||||
export type EmVitrification = {
|
||||
/** The temperature (in degrees Kelvin) of the sample just prior to vitrification. */
|
||||
/** The temperature (in kelvin) of the sample just prior to vitrification. */
|
||||
readonly chamber_temperature?: Maybe<Scalars['Float']>;
|
||||
/**
|
||||
* This is the name of the cryogen.
|
||||
@@ -2259,7 +2273,7 @@ export type EmVitrification = {
|
||||
/** This data item is a pointer to _em_specimen.id */
|
||||
readonly specimen_id: Scalars['String'];
|
||||
/**
|
||||
* The vitrification temperature (in degrees Kelvin), e.g.,
|
||||
* The vitrification temperature (in kelvin), e.g.,
|
||||
* temperature of the plunge instrument cryogen bath.
|
||||
*/
|
||||
readonly temp?: Maybe<Scalars['Float']>;
|
||||
@@ -2364,6 +2378,14 @@ export type EntityPoly = {
|
||||
*
|
||||
*/
|
||||
readonly pdbx_seq_one_letter_code_can?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* Evidence for the assignment of the polymer sequence.
|
||||
*
|
||||
* Allowable values:
|
||||
* depositor provided, derived from coordinates
|
||||
*
|
||||
*/
|
||||
readonly pdbx_sequence_evidence_code?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The PDB strand/chain id(s) corresponding to this polymer entity.
|
||||
*
|
||||
@@ -3005,6 +3027,8 @@ export type Entry = {
|
||||
* identifier.
|
||||
*/
|
||||
readonly id: Scalars['String'];
|
||||
/** An identifier for the model collection associated with the entry. */
|
||||
readonly ma_collection_id?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Exptl = {
|
||||
@@ -3263,6 +3287,29 @@ export type InterfacePartnerFeatureFeaturePositions = {
|
||||
readonly values?: Maybe<ReadonlyArray<Maybe<Scalars['Float']>>>;
|
||||
};
|
||||
|
||||
export type MaData = {
|
||||
/**
|
||||
* The type of data held in the dataset.
|
||||
*
|
||||
* Allowable values:
|
||||
* coevolution MSA, input structure, model coordinates, other, polymeric template library, spatial restraints, target, target-template alignment, template structure
|
||||
*
|
||||
*/
|
||||
readonly content_type?: Maybe<Scalars['String']>;
|
||||
/** Details for other content types. */
|
||||
readonly content_type_other_details?: Maybe<Scalars['String']>;
|
||||
/** A unique identifier for the data. */
|
||||
readonly id: Scalars['Int'];
|
||||
/**
|
||||
* An author-given name for the content held in the dataset.
|
||||
*
|
||||
* Examples:
|
||||
* NMR NOE Distances, Target Template Alignment, Coevolution Data
|
||||
*
|
||||
*/
|
||||
readonly name?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type MethodDetails = {
|
||||
/** A description of special aspects of the clustering process */
|
||||
readonly description?: Maybe<Scalars['String']>;
|
||||
@@ -4199,7 +4246,7 @@ export type PdbxNmrExptlSampleConditions = {
|
||||
*/
|
||||
readonly pressure_units?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The temperature (in Kelvin) at which NMR data were
|
||||
* The temperature (in kelvin) at which NMR data were
|
||||
* collected.
|
||||
*/
|
||||
readonly temperature?: Maybe<Scalars['String']>;
|
||||
@@ -4453,7 +4500,7 @@ export type PdbxPrdAudit = {
|
||||
* An identifier for the wwPDB site creating or modifying the molecule.
|
||||
*
|
||||
* Allowable values:
|
||||
* BMRB, PDBC, PDBJ, PDBe, RCSB
|
||||
* BMRB, PDBC, PDBE, PDBJ, RCSB
|
||||
*
|
||||
*/
|
||||
readonly processing_site?: Maybe<Scalars['String']>;
|
||||
@@ -6817,7 +6864,7 @@ export type Query = {
|
||||
readonly assemblies?: Maybe<ReadonlyArray<Maybe<CoreAssembly>>>;
|
||||
/** Get an assembly given the PDB ID and ASSEMBLY ID. Here ASSEMBLY ID is '1', '2', '3', etc. or 'deposited' for deposited coordinates. */
|
||||
readonly assembly?: Maybe<CoreAssembly>;
|
||||
/** Get a list of PDB branched entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. */
|
||||
/** Get a list of PDB branched entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. Note that the ENTRY ID part must be upper case. */
|
||||
readonly branched_entities?: Maybe<ReadonlyArray<Maybe<CoreBranchedEntity>>>;
|
||||
/** Get a PDB branched entity, given the PDB ID and ENTITY ID. Here ENTITY ID is a '1', '2', '3', etc. */
|
||||
readonly branched_entity?: Maybe<CoreBranchedEntity>;
|
||||
@@ -6841,9 +6888,9 @@ export type Query = {
|
||||
readonly group_provenance?: Maybe<GroupProvenance>;
|
||||
/** Get a pairwise polymeric interface given the PDB ID, ASSEMBLY ID and INTERFACE ID. */
|
||||
readonly interface?: Maybe<CoreInterface>;
|
||||
/** Get a list of pairwise polymeric interfaces given a list of INTERFACE IDs. Here INTERFACE ID is a compound identifier that includes entry_id, assembly_id and interface_id e.g. 1XXX-1.1. */
|
||||
/** Get a list of pairwise polymeric interfaces given a list of INTERFACE IDs. Here INTERFACE ID is a compound identifier that includes entry_id, assembly_id and interface_id e.g. 1XXX-1.1. Note that the ENTRY ID part must be upper case. */
|
||||
readonly interfaces?: Maybe<ReadonlyArray<Maybe<CoreInterface>>>;
|
||||
/** Get a list of PDB non-polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. */
|
||||
/** Get a list of PDB non-polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. Note that the ENTRY ID part must be upper case. */
|
||||
readonly nonpolymer_entities?: Maybe<ReadonlyArray<Maybe<CoreNonpolymerEntity>>>;
|
||||
/** Get a PDB non-polymer entity, given the PDB ID and ENTITY ID. Here ENTITY ID is a '1', '2', '3', etc. */
|
||||
readonly nonpolymer_entity?: Maybe<CoreNonpolymerEntity>;
|
||||
@@ -6851,7 +6898,7 @@ export type Query = {
|
||||
readonly nonpolymer_entity_instance?: Maybe<CoreNonpolymerEntityInstance>;
|
||||
/** Get a list of PDB non-polymer entity instances (chains), given the list of ENTITY INSTANCE IDs. Here ENTITY INSTANCE ID identifies structural element in the asymmetric unit, e.g. 'A', 'B', etc. */
|
||||
readonly nonpolymer_entity_instances?: Maybe<ReadonlyArray<Maybe<CoreNonpolymerEntityInstance>>>;
|
||||
/** Get a list of PDB polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. */
|
||||
/** Get a list of PDB polymer entities given a list of ENTITY IDs. Here ENTITY ID is a compound identifier that includes entry_id and entity_id separated by '_', e.g. 1XXX_1. Note that the ENTRY ID part must be upper case. */
|
||||
readonly polymer_entities?: Maybe<ReadonlyArray<Maybe<CorePolymerEntity>>>;
|
||||
/** Get a PDB polymer entity, given the PDB ID and ENTITY ID. Here ENTITY ID is a '1', '2', '3', etc. */
|
||||
readonly polymer_entity?: Maybe<CorePolymerEntity>;
|
||||
@@ -8421,6 +8468,29 @@ export type RcsbClusterMembership = {
|
||||
readonly identity?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type RcsbCompModelProvenance = {
|
||||
/**
|
||||
* Entry identifier corresponding to the computed structure model.
|
||||
*
|
||||
* Examples:
|
||||
* AF-P60325-F1, ma-bak-cepc-0019
|
||||
*
|
||||
*/
|
||||
readonly entry_id: Scalars['String'];
|
||||
/**
|
||||
* Source database for the computed structure model.
|
||||
*
|
||||
* Allowable values:
|
||||
* AlphaFoldDB, ModelArchive
|
||||
*
|
||||
*/
|
||||
readonly source_db?: Maybe<Scalars['String']>;
|
||||
/** Source filename for the computed structure model. */
|
||||
readonly source_filename?: Maybe<Scalars['String']>;
|
||||
/** Source URL for computed structure model file. */
|
||||
readonly source_url?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type RcsbEntityHostOrganism = {
|
||||
/**
|
||||
* The beginning polymer sequence position for the polymer section corresponding
|
||||
@@ -8657,7 +8727,7 @@ export type RcsbEntitySourceOrganism = {
|
||||
* A code indicating the provenance of the source organism details for the entity
|
||||
*
|
||||
* Allowable values:
|
||||
* PDB Primary Data
|
||||
* PDB Primary Data, UniProt
|
||||
*
|
||||
*/
|
||||
readonly provenance_source?: Maybe<Scalars['String']>;
|
||||
@@ -8731,7 +8801,7 @@ export type RcsbEntryContainerIdentifiers = {
|
||||
* Entry identifier for the container.
|
||||
*
|
||||
* Examples:
|
||||
* 1KIP, 4HHB
|
||||
* 4HHB, AF_AFP60325F1, MA_MABAKCEPC0019
|
||||
*
|
||||
*/
|
||||
readonly entry_id: Scalars['String'];
|
||||
@@ -8879,6 +8949,15 @@ export type RcsbEntryInfo = {
|
||||
*
|
||||
*/
|
||||
readonly na_polymer_entity_types?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* This data item identifies secondary structure
|
||||
* features of nucleic acids in the entry.
|
||||
*
|
||||
* Allowable values:
|
||||
* a-form double helix, b-form double helix, bulge loop, double helix, four-way junction, hairpin loop, internal loop, mismatched base pair, other right-handed double helix, parallel strands, quadruple helix, tetraloop, three-way junction, triple helix, two-way junction, z-form double helix
|
||||
*
|
||||
*/
|
||||
readonly ndb_struct_conf_na_feature_combined?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>;
|
||||
/** Bound nonpolymer components in this entry. */
|
||||
readonly nonpolymer_bound_components?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>;
|
||||
/** The number of distinct non-polymer entities in the structure entry exclusive of solvent. */
|
||||
@@ -8955,6 +9034,21 @@ export type RcsbEntryInfo = {
|
||||
readonly software_programs_combined?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>;
|
||||
/** The number of distinct solvent entities per deposited structure model. */
|
||||
readonly solvent_entity_count?: Maybe<Scalars['Int']>;
|
||||
/**
|
||||
* Indicates if the structure was determined using experimental or computational methods.
|
||||
*
|
||||
* Allowable values:
|
||||
* computational, experimental
|
||||
*
|
||||
*/
|
||||
readonly structure_determination_methodology: Scalars['String'];
|
||||
/**
|
||||
* Indicates the priority of the value in _rcsb_entry_info.structure_determination_methodology.
|
||||
* The lower the number the higher the priority.
|
||||
* Priority values for "experimental" structures is currently set to 10 and
|
||||
* the values for "computational" structures is set to 100.
|
||||
*/
|
||||
readonly structure_determination_methodology_priority?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type RcsbEntryInfoDiffrnResolutionHigh = {
|
||||
@@ -9294,6 +9388,49 @@ export type RcsbLigandNeighbors = {
|
||||
readonly seq_id?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type RcsbMaQaMetricGlobal = {
|
||||
readonly ma_qa_metric_global?: Maybe<ReadonlyArray<Maybe<RcsbMaQaMetricGlobalMaQaMetricGlobal>>>;
|
||||
/** The model identifier. */
|
||||
readonly model_id: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type RcsbMaQaMetricGlobalMaQaMetricGlobal = {
|
||||
/**
|
||||
* Description of the global QA metric.
|
||||
*
|
||||
* Examples:
|
||||
* confidence score predicting accuracy according to the CA-only Local Distance Difference Test (lDDT-CA) in [0,100]
|
||||
*
|
||||
*/
|
||||
readonly description?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* Name of the global QA metric.
|
||||
*
|
||||
* Examples:
|
||||
* pLDDT
|
||||
*
|
||||
*/
|
||||
readonly name: Scalars['String'];
|
||||
/**
|
||||
* The type of global QA metric.
|
||||
*
|
||||
* Allowable values:
|
||||
* PAE, contact probability, distance, energy, ipTM, normalized score, other, pLDDT, pLDDT all-atom, pLDDT all-atom in [0,1], pLDDT in [0,1], pTM, zscore
|
||||
*
|
||||
*/
|
||||
readonly type: Scalars['String'];
|
||||
/** Details for other type of global QA metric. */
|
||||
readonly type_other_details?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* Value of the global QA metric.
|
||||
*
|
||||
* Examples:
|
||||
* null
|
||||
*
|
||||
*/
|
||||
readonly value: Scalars['Float'];
|
||||
};
|
||||
|
||||
export type RcsbMembraneLineage = {
|
||||
/** Hierarchy depth. */
|
||||
readonly depth?: Maybe<Scalars['Int']>;
|
||||
@@ -10332,7 +10469,7 @@ export type RcsbPolymerEntityContainerIdentifiersReferenceSequenceIdentifiers =
|
||||
* Source of the reference database assignment
|
||||
*
|
||||
* Allowable values:
|
||||
* PDB, RCSB, SIFTS
|
||||
* PDB, RCSB, SIFTS, UniProt
|
||||
*
|
||||
*/
|
||||
readonly provenance_source?: Maybe<Scalars['String']>;
|
||||
@@ -10737,7 +10874,7 @@ export type RcsbPolymerInstanceFeature = {
|
||||
* A type or category of the feature.
|
||||
*
|
||||
* Allowable values:
|
||||
* ANGLE_OUTLIER, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SCOP, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ, ASA
|
||||
* ANGLE_OUTLIER, BEND, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, HELX_LH_PP_P, HELX_RH_3T_P, HELX_RH_AL_P, HELX_RH_PI_P, MA_QA_METRIC_LOCAL_TYPE_CONTACT_PROBABILITY, MA_QA_METRIC_LOCAL_TYPE_DISTANCE, MA_QA_METRIC_LOCAL_TYPE_ENERGY, MA_QA_METRIC_LOCAL_TYPE_IPTM, MA_QA_METRIC_LOCAL_TYPE_NORMALIZED_SCORE, MA_QA_METRIC_LOCAL_TYPE_OTHER, MA_QA_METRIC_LOCAL_TYPE_PAE, MA_QA_METRIC_LOCAL_TYPE_PLDDT, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM_[0,1], MA_QA_METRIC_LOCAL_TYPE_PLDDT_[0,1], MA_QA_METRIC_LOCAL_TYPE_PTM, MA_QA_METRIC_LOCAL_TYPE_ZSCORE, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SCOP, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, STRN, TURN_TY1_P, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ, ASA
|
||||
*
|
||||
*/
|
||||
readonly type?: Maybe<Scalars['String']>;
|
||||
@@ -10748,7 +10885,7 @@ export type RcsbPolymerInstanceFeatureAdditionalProperties = {
|
||||
* The additional property name.
|
||||
*
|
||||
* Allowable values:
|
||||
* CATH_DOMAIN_ID, CATH_NAME, ECOD_DOMAIN_ID, ECOD_FAMILY_NAME, OMEGA_ANGLE, PARTNER_ASYM_ID, PARTNER_BOND_DISTANCE, PARTNER_COMP_ID, SCOP2_DOMAIN_ID, SCOP2_FAMILY_ID, SCOP2_FAMILY_NAME, SCOP2_SUPERFAMILY_ID, SCOP2_SUPERFAMILY_NAME, SCOP_DOMAIN_ID, SCOP_NAME, SCOP_SUN_ID, SHEET_SENSE
|
||||
* CATH_DOMAIN_ID, CATH_NAME, ECOD_DOMAIN_ID, ECOD_FAMILY_NAME, MODELCIF_MODEL_ID, OMEGA_ANGLE, PARTNER_ASYM_ID, PARTNER_BOND_DISTANCE, PARTNER_COMP_ID, SCOP2_DOMAIN_ID, SCOP2_FAMILY_ID, SCOP2_FAMILY_NAME, SCOP2_SUPERFAMILY_ID, SCOP2_SUPERFAMILY_NAME, SCOP_DOMAIN_ID, SCOP_NAME, SCOP_SUN_ID, SHEET_SENSE
|
||||
*
|
||||
*/
|
||||
readonly name?: Maybe<Scalars['String']>;
|
||||
@@ -10818,7 +10955,7 @@ export type RcsbPolymerInstanceFeatureSummary = {
|
||||
* Type or category of the feature.
|
||||
*
|
||||
* Allowable values:
|
||||
* ANGLE_OUTLIER, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SAbDab Antibody Heavy Chain Subclass, SAbDab Antibody Light Chain Subclass, SAbDab Antibody Light Chain Type, SCOP, SCOP2 Family, SCOP2 Superfamily, SCOP2B Superfamily, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ
|
||||
* ANGLE_OUTLIER, BEND, BINDING_SITE, BOND_OUTLIER, C-MANNOSYLATION_SITE, CATH, CIS-PEPTIDE, ECOD, HELIX_P, HELX_LH_PP_P, HELX_RH_3T_P, HELX_RH_AL_P, HELX_RH_PI_P, MA_QA_METRIC_LOCAL_TYPE_CONTACT_PROBABILITY, MA_QA_METRIC_LOCAL_TYPE_DISTANCE, MA_QA_METRIC_LOCAL_TYPE_ENERGY, MA_QA_METRIC_LOCAL_TYPE_IPTM, MA_QA_METRIC_LOCAL_TYPE_NORMALIZED_SCORE, MA_QA_METRIC_LOCAL_TYPE_OTHER, MA_QA_METRIC_LOCAL_TYPE_PAE, MA_QA_METRIC_LOCAL_TYPE_PLDDT, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM, MA_QA_METRIC_LOCAL_TYPE_PLDDT_ALL-ATOM_[0,1], MA_QA_METRIC_LOCAL_TYPE_PLDDT_[0,1], MA_QA_METRIC_LOCAL_TYPE_PTM, MA_QA_METRIC_LOCAL_TYPE_ZSCORE, MEMBRANE_SEGMENT, MOGUL_ANGLE_OUTLIER, MOGUL_BOND_OUTLIER, N-GLYCOSYLATION_SITE, O-GLYCOSYLATION_SITE, RAMACHANDRAN_OUTLIER, ROTAMER_OUTLIER, RSCC_OUTLIER, RSRZ_OUTLIER, S-GLYCOSYLATION_SITE, SABDAB_ANTIBODY_HEAVY_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_SUBCLASS, SABDAB_ANTIBODY_LIGHT_CHAIN_TYPE, SCOP, SCOP2B_SUPERFAMILY, SCOP2_FAMILY, SCOP2_SUPERFAMILY, SHEET, STEREO_OUTLIER, STRN, TURN_TY1_P, UNASSIGNED_SEC_STRUCT, UNOBSERVED_ATOM_XYZ, UNOBSERVED_RESIDUE_XYZ, ZERO_OCCUPANCY_ATOM_XYZ, ZERO_OCCUPANCY_RESIDUE_XYZ
|
||||
*
|
||||
*/
|
||||
readonly type?: Maybe<Scalars['String']>;
|
||||
@@ -13377,6 +13514,11 @@ export type ReflnsShell = {
|
||||
};
|
||||
|
||||
export type Software = {
|
||||
/**
|
||||
* This data item is a pointer to _citation.id in the CITATION
|
||||
* category.
|
||||
*/
|
||||
readonly citation_id?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The classification of the program according to its
|
||||
* major function.
|
||||
@@ -13527,6 +13669,37 @@ export type Struct = {
|
||||
readonly title?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type StructAsym = {
|
||||
/**
|
||||
* This data item is a pointer to _atom_site.pdbx_PDB_strand_id the
|
||||
* ATOM_SITE category.
|
||||
*
|
||||
* Examples:
|
||||
* 1ABC
|
||||
*
|
||||
*/
|
||||
readonly pdbx_PDB_id?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* This data item is a pointer to _atom_site.ndb_alias_strand_id the
|
||||
* ATOM_SITE category.
|
||||
*/
|
||||
readonly pdbx_alt_id?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* This data item gives the order of the structural elements in the
|
||||
* ATOM_SITE category.
|
||||
*/
|
||||
readonly pdbx_order?: Maybe<Scalars['Int']>;
|
||||
/**
|
||||
* This data item describes the general type of the structural elements
|
||||
* in the ATOM_SITE category.
|
||||
*
|
||||
* Allowable values:
|
||||
* ATOMN, ATOMP, ATOMS, HETAC, HETAD, HETAI, HETAIN, HETAS, HETIC
|
||||
*
|
||||
*/
|
||||
readonly pdbx_type?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type StructKeywords = {
|
||||
/**
|
||||
* Terms characterizing the macromolecular structure.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
@@ -260,7 +260,8 @@ namespace Camera {
|
||||
radius: 0,
|
||||
radiusMax: 10,
|
||||
fog: 50,
|
||||
clipFar: true
|
||||
clipFar: true,
|
||||
minNear: 5,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -276,6 +277,7 @@ namespace Camera {
|
||||
radiusMax: number
|
||||
fog: number
|
||||
clipFar: boolean
|
||||
minNear: number
|
||||
}
|
||||
|
||||
export function copySnapshot(out: Snapshot, source?: Partial<Snapshot>) {
|
||||
@@ -292,6 +294,7 @@ namespace Camera {
|
||||
if (typeof source.radiusMax !== 'undefined') out.radiusMax = source.radiusMax;
|
||||
if (typeof source.fog !== 'undefined') out.fog = source.fog;
|
||||
if (typeof source.clipFar !== 'undefined') out.clipFar = source.clipFar;
|
||||
if (typeof source.minNear !== 'undefined') out.minNear = source.minNear;
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -303,6 +306,7 @@ namespace Camera {
|
||||
&& a.radiusMax === b.radiusMax
|
||||
&& a.fog === b.fog
|
||||
&& a.clipFar === b.clipFar
|
||||
&& a.minNear === b.minNear
|
||||
&& Vec3.exactEquals(a.position, b.position)
|
||||
&& Vec3.exactEquals(a.up, b.up)
|
||||
&& Vec3.exactEquals(a.target, b.target);
|
||||
@@ -370,7 +374,7 @@ function updatePers(camera: Camera) {
|
||||
}
|
||||
|
||||
function updateClip(camera: Camera) {
|
||||
let { radius, radiusMax, mode, fog, clipFar } = camera.state;
|
||||
let { radius, radiusMax, mode, fog, clipFar, minNear } = camera.state;
|
||||
if (radius < 0.01) radius = 0.01;
|
||||
|
||||
const normalizedFar = clipFar ? radius : radiusMax;
|
||||
@@ -384,12 +388,12 @@ function updateClip(camera: Camera) {
|
||||
|
||||
if (mode === 'perspective') {
|
||||
// set at least to 5 to avoid slow sphere impostor rendering
|
||||
near = Math.max(Math.min(radiusMax, 5), near);
|
||||
far = Math.max(5, far);
|
||||
near = Math.max(Math.min(radiusMax, minNear), near);
|
||||
far = Math.max(minNear, far);
|
||||
} else {
|
||||
// not too close to 0 as it causes issues with outline rendering
|
||||
near = Math.max(Math.min(radiusMax, 5), near);
|
||||
far = Math.max(5, far);
|
||||
near = Math.max(Math.min(radiusMax, minNear), near);
|
||||
far = Math.max(minNear, far);
|
||||
}
|
||||
|
||||
if (near === far) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
@@ -13,8 +13,8 @@ import { Camera, ICamera } from '../camera';
|
||||
import { Viewport } from './util';
|
||||
|
||||
export const StereoCameraParams = {
|
||||
eyeSeparation: PD.Numeric(0.064, { min: 0.01, max: 0.5, step: 0.001 }),
|
||||
focus: PD.Numeric(10, { min: 1, max: 100, step: 0.01 }),
|
||||
eyeSeparation: PD.Numeric(0.062, { min: 0.02, max: 0.1, step: 0.001 }, { description: 'Distance between left and right camera.' }),
|
||||
focus: PD.Numeric(10, { min: 1, max: 20, step: 0.1 }, { description: 'Apparent object distance.' }),
|
||||
};
|
||||
export const DefaultStereoCameraProps = PD.getDefaultValues(StereoCameraParams);
|
||||
export type StereoCameraProps = PD.Values<typeof StereoCameraParams>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { BehaviorSubject, Subscription } from 'rxjs';
|
||||
@@ -39,9 +40,10 @@ import { Helper } from './helper/helper';
|
||||
import { Passes } from './passes/passes';
|
||||
import { shallowEqual } from '../mol-util';
|
||||
import { MarkingParams } from './passes/marking';
|
||||
import { GraphicsRenderVariantsBlended, GraphicsRenderVariantsWboit } from '../mol-gl/webgl/render-item';
|
||||
import { GraphicsRenderVariantsBlended, GraphicsRenderVariantsWboit, GraphicsRenderVariantsDpoit } from '../mol-gl/webgl/render-item';
|
||||
import { degToRad, radToDeg } from '../mol-math/misc';
|
||||
import { AssetManager } from '../mol-util/assets';
|
||||
import { deepClone } from '../mol-util/object';
|
||||
|
||||
export const Canvas3DParams = {
|
||||
camera: PD.Group({
|
||||
@@ -63,6 +65,7 @@ export const Canvas3DParams = {
|
||||
cameraClipping: PD.Group({
|
||||
radius: PD.Numeric(100, { min: 0, max: 99, step: 1 }, { label: 'Clipping', description: 'How much of the scene to show.' }),
|
||||
far: PD.Boolean(true, { description: 'Hide scene in the distance' }),
|
||||
minNear: PD.Numeric(5, { min: 0.1, max: 10, step: 0.1 }, { description: 'Note, may cause performance issues rendering impostors when set too small and cause issues with outline rendering when too close to 0.' }),
|
||||
}, { pivot: 'radius' }),
|
||||
viewport: PD.MappedStatic('canvas', {
|
||||
canvas: PD.Group({}),
|
||||
@@ -83,6 +86,7 @@ export const Canvas3DParams = {
|
||||
cameraResetDurationMs: PD.Numeric(250, { min: 0, max: 1000, step: 1 }, { description: 'The time it takes to reset the camera.' }),
|
||||
sceneRadiusFactor: PD.Numeric(1, { min: 1, max: 10, step: 0.1 }),
|
||||
transparentBackground: PD.Boolean(false),
|
||||
dpoitIterations: PD.Numeric(2, { min: 1, max: 10, step: 1 }),
|
||||
|
||||
multiSample: PD.Group(MultiSampleParams),
|
||||
postprocessing: PD.Group(PostprocessingParams),
|
||||
@@ -116,6 +120,8 @@ interface Canvas3DContext {
|
||||
|
||||
namespace Canvas3DContext {
|
||||
export const DefaultAttribs = {
|
||||
powerPreference: 'high-performance' as WebGLContextAttributes['powerPreference'],
|
||||
failIfMajorPerformanceCaveat: false,
|
||||
/** true by default to avoid issues with Safari (Jan 2021) */
|
||||
antialias: true,
|
||||
/** true to support multiple Canvas3D objects with a single context */
|
||||
@@ -125,14 +131,20 @@ namespace Canvas3DContext {
|
||||
/** extra pixels to around target to check in case target is empty */
|
||||
pickPadding: 1,
|
||||
enableWboit: true,
|
||||
enableDpoit: false,
|
||||
preferWebGl1: false
|
||||
};
|
||||
export type Attribs = typeof DefaultAttribs
|
||||
|
||||
export function fromCanvas(canvas: HTMLCanvasElement, assetManager: AssetManager, attribs: Partial<Attribs> = {}): Canvas3DContext {
|
||||
const a = { ...DefaultAttribs, ...attribs };
|
||||
const { antialias, preserveDrawingBuffer, pixelScale, preferWebGl1 } = a;
|
||||
|
||||
if (a.enableWboit && a.enableDpoit) throw new Error('Multiple transparency methods not allowed.');
|
||||
|
||||
const { powerPreference, failIfMajorPerformanceCaveat, antialias, preserveDrawingBuffer, pixelScale, preferWebGl1 } = a;
|
||||
const gl = getGLContext(canvas, {
|
||||
powerPreference,
|
||||
failIfMajorPerformanceCaveat,
|
||||
antialias,
|
||||
preserveDrawingBuffer,
|
||||
alpha: true, // the renderer requires an alpha channel
|
||||
@@ -285,7 +297,7 @@ namespace Canvas3D {
|
||||
export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys, page?: Vec2, position?: Vec3 }
|
||||
|
||||
export function create({ webgl, input, passes, attribs, assetManager }: Canvas3DContext, props: Partial<Canvas3DProps> = {}): Canvas3D {
|
||||
const p: Canvas3DProps = { ...DefaultCanvas3DParams, ...props };
|
||||
const p: Canvas3DProps = { ...deepClone(DefaultCanvas3DParams), ...deepClone(props) };
|
||||
|
||||
const reprRenderObjects = new Map<Representation.Any, Set<GraphicsRenderObject>>();
|
||||
const reprUpdatedSubscriptions = new Map<Representation.Any, Subscription>();
|
||||
@@ -302,8 +314,7 @@ namespace Canvas3D {
|
||||
let width = 128;
|
||||
let height = 128;
|
||||
updateViewport();
|
||||
|
||||
const scene = Scene.create(webgl, passes.draw.wboitEnabled ? GraphicsRenderVariantsWboit : GraphicsRenderVariantsBlended);
|
||||
const scene = Scene.create(webgl, passes.draw.dpoitEnabled ? GraphicsRenderVariantsDpoit : (passes.draw.wboitEnabled ? GraphicsRenderVariantsWboit : GraphicsRenderVariantsBlended));
|
||||
|
||||
function getSceneRadius() {
|
||||
return scene.boundingSphere.radius * p.sceneRadiusFactor;
|
||||
@@ -314,6 +325,7 @@ namespace Canvas3D {
|
||||
mode: p.camera.mode,
|
||||
fog: p.cameraFog.name === 'on' ? p.cameraFog.params.intensity : 0,
|
||||
clipFar: p.cameraClipping.far,
|
||||
minNear: p.cameraClipping.minNear,
|
||||
fov: degToRad(p.camera.fov),
|
||||
}, { x, y, width, height }, { pixelScale: attribs.pixelScale });
|
||||
const stereoCamera = new StereoCamera(camera, p.camera.stereo.params);
|
||||
@@ -679,10 +691,11 @@ namespace Canvas3D {
|
||||
cameraFog: camera.state.fog > 0
|
||||
? { name: 'on' as const, params: { intensity: camera.state.fog } }
|
||||
: { name: 'off' as const, params: {} },
|
||||
cameraClipping: { far: camera.state.clipFar, radius },
|
||||
cameraClipping: { far: camera.state.clipFar, radius, minNear: camera.state.minNear },
|
||||
cameraResetDurationMs: p.cameraResetDurationMs,
|
||||
sceneRadiusFactor: p.sceneRadiusFactor,
|
||||
transparentBackground: p.transparentBackground,
|
||||
dpoitIterations: p.dpoitIterations,
|
||||
viewport: p.viewport,
|
||||
|
||||
postprocessing: { ...p.postprocessing },
|
||||
@@ -805,6 +818,9 @@ namespace Canvas3D {
|
||||
if (props.cameraClipping.far !== undefined && props.cameraClipping.far !== camera.state.clipFar) {
|
||||
cameraState.clipFar = props.cameraClipping.far;
|
||||
}
|
||||
if (props.cameraClipping.minNear !== undefined && props.cameraClipping.minNear !== camera.state.minNear) {
|
||||
cameraState.minNear = props.cameraClipping.minNear;
|
||||
}
|
||||
if (props.cameraClipping.radius !== undefined) {
|
||||
const radius = (getSceneRadius() / 100) * (100 - props.cameraClipping.radius);
|
||||
if (radius > 0 && radius !== cameraState.radius) {
|
||||
@@ -817,9 +833,13 @@ namespace Canvas3D {
|
||||
|
||||
if (props.camera?.helper) helper.camera.setProps(props.camera.helper);
|
||||
if (props.camera?.manualReset !== undefined) p.camera.manualReset = props.camera.manualReset;
|
||||
if (props.camera?.stereo !== undefined) Object.assign(p.camera.stereo, props.camera.stereo);
|
||||
if (props.camera?.stereo !== undefined) {
|
||||
Object.assign(p.camera.stereo, props.camera.stereo);
|
||||
stereoCamera.setProps(p.camera.stereo.params);
|
||||
}
|
||||
if (props.cameraResetDurationMs !== undefined) p.cameraResetDurationMs = props.cameraResetDurationMs;
|
||||
if (props.transparentBackground !== undefined) p.transparentBackground = props.transparentBackground;
|
||||
if (props.dpoitIterations !== undefined) p.dpoitIterations = props.dpoitIterations;
|
||||
if (props.viewport !== undefined) {
|
||||
const doNotUpdate = p.viewport === props.viewport ||
|
||||
(p.viewport.name === props.viewport.name && shallowEqual(p.viewport.params, props.viewport.params));
|
||||
@@ -855,7 +875,7 @@ namespace Canvas3D {
|
||||
}
|
||||
},
|
||||
getImagePass: (props: Partial<ImageProps> = {}) => {
|
||||
return new ImagePass(webgl, assetManager, renderer, scene, camera, helper, passes.draw.wboitEnabled, props);
|
||||
return new ImagePass(webgl, assetManager, renderer, scene, camera, helper, passes.draw.wboitEnabled, passes.draw.dpoitEnabled, props);
|
||||
},
|
||||
getRenderObjects(): GraphicsRenderObject[] {
|
||||
const renderObjects: GraphicsRenderObject[] = [];
|
||||
@@ -920,4 +940,4 @@ namespace Canvas3D {
|
||||
Viewport.set(controls.viewport, x, y, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ const SkyboxParams = {
|
||||
pz: PD.File({ label: 'Positive Z / Front', accept: 'image/*' }),
|
||||
}, { isExpanded: true, label: 'Files' }),
|
||||
}),
|
||||
blur: PD.Numeric(0, { min: 0.0, max: 1.0, step: 0.01 }, { description: 'Note, this only works in WebGL2 or when "EXT_shader_texture_lod" is available.' }),
|
||||
...SharedParams,
|
||||
};
|
||||
type SkyboxProps = PD.Values<typeof SkyboxParams>
|
||||
@@ -170,6 +171,7 @@ export class BackgroundPass {
|
||||
Mat4.invert(m, m);
|
||||
ValueCell.update(this.renderable.values.uViewDirectionProjectionInverse, m);
|
||||
|
||||
ValueCell.updateIfChanged(this.renderable.values.uBlur, props.blur);
|
||||
ValueCell.updateIfChanged(this.renderable.values.uOpacity, props.opacity);
|
||||
ValueCell.updateIfChanged(this.renderable.values.uSaturation, props.saturation);
|
||||
ValueCell.updateIfChanged(this.renderable.values.uLightness, props.lightness);
|
||||
@@ -367,7 +369,7 @@ function getSkyboxTexture(ctx: WebGLContext, assetManager: AssetManager, faces:
|
||||
const cubeAssets = getCubeAssets(assetManager, faces);
|
||||
const cubeFaces = getCubeFaces(assetManager, cubeAssets);
|
||||
const assets = [cubeAssets.nx, cubeAssets.ny, cubeAssets.nz, cubeAssets.px, cubeAssets.py, cubeAssets.pz];
|
||||
const texture = ctx.resources.cubeTexture(cubeFaces, false, onload);
|
||||
const texture = ctx.resources.cubeTexture(cubeFaces, true, onload);
|
||||
return { texture, assets };
|
||||
}
|
||||
|
||||
@@ -424,12 +426,15 @@ const BackgroundSchema = {
|
||||
uGradientColorA: UniformSpec('v3'),
|
||||
uGradientColorB: UniformSpec('v3'),
|
||||
uGradientRatio: UniformSpec('f'),
|
||||
uBlur: UniformSpec('f'),
|
||||
uOpacity: UniformSpec('f'),
|
||||
uSaturation: UniformSpec('f'),
|
||||
uLightness: UniformSpec('f'),
|
||||
dVariant: DefineSpec('string', ['skybox', 'image', 'verticalGradient', 'horizontalGradient', 'radialGradient']),
|
||||
};
|
||||
const SkyboxShaderCode = ShaderCode('background', background_vert, background_frag);
|
||||
const SkyboxShaderCode = ShaderCode('background', background_vert, background_frag, {
|
||||
shaderTextureLod: 'optional'
|
||||
});
|
||||
type BackgroundRenderable = ComputeRenderable<Values<typeof BackgroundSchema>>
|
||||
|
||||
function getBackgroundRenderable(ctx: WebGLContext, width: number, height: number): BackgroundRenderable {
|
||||
@@ -448,6 +453,7 @@ function getBackgroundRenderable(ctx: WebGLContext, width: number, height: numbe
|
||||
uGradientColorA: ValueCell.create(Vec3()),
|
||||
uGradientColorB: ValueCell.create(Vec3()),
|
||||
uGradientRatio: ValueCell.create(0.5),
|
||||
uBlur: ValueCell.create(0),
|
||||
uOpacity: ValueCell.create(1),
|
||||
uSaturation: ValueCell.create(0),
|
||||
uLightness: ValueCell.create(0),
|
||||
|
||||
309
src/mol-canvas3d/passes/dpoit.ts
Normal file
309
src/mol-canvas3d/passes/dpoit.ts
Normal file
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*
|
||||
* Adapted from https://github.com/tsherif/webgl2examples, The MIT License, Copyright © 2017 Tarek Sherif, Shuai Shao
|
||||
*/
|
||||
|
||||
import { QuadSchema, QuadValues } from '../../mol-gl/compute/util';
|
||||
import { ComputeRenderable, createComputeRenderable } from '../../mol-gl/renderable';
|
||||
import { TextureSpec, UniformSpec, Values } from '../../mol-gl/renderable/schema';
|
||||
import { ShaderCode } from '../../mol-gl/shader-code';
|
||||
import { WebGLContext } from '../../mol-gl/webgl/context';
|
||||
import { createComputeRenderItem } from '../../mol-gl/webgl/render-item';
|
||||
import { Texture } from '../../mol-gl/webgl/texture';
|
||||
import { ValueCell } from '../../mol-util';
|
||||
import { quad_vert } from '../../mol-gl/shader/quad.vert';
|
||||
import { evaluateDpoit_frag } from '../../mol-gl/shader/evaluate-dpoit.frag';
|
||||
import { blendBackDpoit_frag } from '../../mol-gl/shader/blend-back-dpoit.frag';
|
||||
import { Framebuffer } from '../../mol-gl/webgl/framebuffer';
|
||||
import { Vec2 } from '../../mol-math/linear-algebra';
|
||||
import { isDebugMode, isTimingMode } from '../../mol-util/debug';
|
||||
import { isWebGL2 } from '../../mol-gl/webgl/compat';
|
||||
|
||||
const BlendBackDpoitSchema = {
|
||||
...QuadSchema,
|
||||
tDpoitBackColor: TextureSpec('texture', 'rgba', 'float', 'nearest'),
|
||||
uTexSize: UniformSpec('v2'),
|
||||
};
|
||||
const BlendBackDpoitShaderCode = ShaderCode('blend-back-dpoit', quad_vert, blendBackDpoit_frag);
|
||||
type BlendBackDpoitRenderable = ComputeRenderable<Values<typeof BlendBackDpoitSchema>>
|
||||
|
||||
function getBlendBackDpoitRenderable(ctx: WebGLContext, dopitBlendBackTexture: Texture): BlendBackDpoitRenderable {
|
||||
const values: Values<typeof BlendBackDpoitSchema> = {
|
||||
...QuadValues,
|
||||
tDpoitBackColor: ValueCell.create(dopitBlendBackTexture),
|
||||
uTexSize: ValueCell.create(Vec2.create(dopitBlendBackTexture.getWidth(), dopitBlendBackTexture.getHeight())),
|
||||
};
|
||||
|
||||
const schema = { ...BlendBackDpoitSchema };
|
||||
const renderItem = createComputeRenderItem(ctx, 'triangles', BlendBackDpoitShaderCode, schema, values);
|
||||
|
||||
return createComputeRenderable(renderItem, values);
|
||||
}
|
||||
|
||||
const EvaluateDpoitSchema = {
|
||||
...QuadSchema,
|
||||
tDpoitFrontColor: TextureSpec('texture', 'rgba', 'float', 'nearest'),
|
||||
uTexSize: UniformSpec('v2'),
|
||||
};
|
||||
const EvaluateDpoitShaderCode = ShaderCode('evaluate-dpoit', quad_vert, evaluateDpoit_frag);
|
||||
type EvaluateDpoitRenderable = ComputeRenderable<Values<typeof EvaluateDpoitSchema>>
|
||||
|
||||
function getEvaluateDpoitRenderable(ctx: WebGLContext, dpoitFrontColorTexture: Texture): EvaluateDpoitRenderable {
|
||||
const values: Values<typeof EvaluateDpoitSchema> = {
|
||||
...QuadValues,
|
||||
tDpoitFrontColor: ValueCell.create(dpoitFrontColorTexture),
|
||||
uTexSize: ValueCell.create(Vec2.create(dpoitFrontColorTexture.getWidth(), dpoitFrontColorTexture.getHeight())),
|
||||
};
|
||||
|
||||
const schema = { ...EvaluateDpoitSchema };
|
||||
const renderItem = createComputeRenderItem(ctx, 'triangles', EvaluateDpoitShaderCode, schema, values);
|
||||
|
||||
return createComputeRenderable(renderItem, values);
|
||||
}
|
||||
|
||||
export class DpoitPass {
|
||||
private readonly DEPTH_CLEAR_VALUE = -99999.0; // NOTE same constant is set in shaders
|
||||
private readonly MAX_DEPTH = 1.0;
|
||||
private readonly MIN_DEPTH = 0.0;
|
||||
|
||||
private passCount = 0;
|
||||
private writeId: number;
|
||||
private readId: number;
|
||||
|
||||
private readonly blendBackRenderable: BlendBackDpoitRenderable;
|
||||
private readonly renderable: EvaluateDpoitRenderable;
|
||||
|
||||
private readonly depthFramebuffers: Framebuffer[];
|
||||
private readonly colorFramebuffers: Framebuffer[];
|
||||
|
||||
private readonly depthTextures: Texture[];
|
||||
private readonly colorFrontTextures: Texture[];
|
||||
private readonly colorBackTextures: Texture[];
|
||||
|
||||
private _supported = false;
|
||||
get supported() {
|
||||
return this._supported;
|
||||
}
|
||||
|
||||
bind() {
|
||||
const { state, gl, extensions: { blendMinMax } } = this.webgl;
|
||||
|
||||
// initialize
|
||||
this.passCount = 0;
|
||||
|
||||
this.depthFramebuffers[0].bind();
|
||||
state.clearColor(this.DEPTH_CLEAR_VALUE, this.DEPTH_CLEAR_VALUE, 0, 0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
this.depthFramebuffers[1].bind();
|
||||
state.clearColor(-this.MIN_DEPTH, this.MAX_DEPTH, 0, 0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
this.colorFramebuffers[0].bind();
|
||||
state.clearColor(0, 0, 0, 0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
this.colorFramebuffers[1].bind();
|
||||
state.clearColor(0, 0, 0, 0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
this.depthFramebuffers[0].bind();
|
||||
state.blendEquation(blendMinMax!.MAX);
|
||||
state.depthMask(false);
|
||||
|
||||
return {
|
||||
depth: this.depthTextures[1],
|
||||
frontColor: this.colorFrontTextures[1],
|
||||
backColor: this.colorBackTextures[1]
|
||||
};
|
||||
}
|
||||
|
||||
bindDualDepthPeeling() {
|
||||
const { state, gl, extensions: { blendMinMax } } = this.webgl;
|
||||
|
||||
this.readId = this.passCount % 2;
|
||||
this.writeId = 1 - this.readId; // ping-pong: 0 or 1
|
||||
|
||||
this.passCount += 1; // increment for next pass
|
||||
|
||||
this.depthFramebuffers[this.writeId].bind();
|
||||
state.clearColor(this.DEPTH_CLEAR_VALUE, this.DEPTH_CLEAR_VALUE, 0, 0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
this.colorFramebuffers[this.writeId].bind();
|
||||
state.clearColor(0, 0, 0, 0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
this.depthFramebuffers[this.writeId].bind();
|
||||
state.blendEquation(blendMinMax!.MAX);
|
||||
state.depthMask(false);
|
||||
|
||||
return {
|
||||
depth: this.depthTextures[this.readId],
|
||||
frontColor: this.colorFrontTextures[this.readId],
|
||||
backColor: this.colorBackTextures[this.readId]
|
||||
};
|
||||
}
|
||||
|
||||
renderBlendBack() {
|
||||
if (isTimingMode) this.webgl.timer.mark('DpoitPass.renderBlendBack');
|
||||
const { state, gl } = this.webgl;
|
||||
|
||||
state.blendEquation(gl.FUNC_ADD);
|
||||
state.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
ValueCell.update(this.blendBackRenderable.values.tDpoitBackColor, this.colorBackTextures[this.writeId]);
|
||||
|
||||
this.blendBackRenderable.update();
|
||||
this.blendBackRenderable.render();
|
||||
if (isTimingMode) this.webgl.timer.markEnd('DpoitPass.renderBlendBack');
|
||||
}
|
||||
|
||||
render() {
|
||||
if (isTimingMode) this.webgl.timer.mark('DpoitPass.render');
|
||||
const { state, gl } = this.webgl;
|
||||
|
||||
state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
ValueCell.update(this.renderable.values.tDpoitFrontColor, this.colorFrontTextures[this.writeId]);
|
||||
|
||||
this.renderable.update();
|
||||
this.renderable.render();
|
||||
if (isTimingMode) this.webgl.timer.markEnd('DpoitPass.render');
|
||||
}
|
||||
|
||||
setSize(width: number, height: number) {
|
||||
const [w, h] = this.renderable.values.uTexSize.ref.value;
|
||||
if (width !== w || height !== h) {
|
||||
for (let i = 0; i < 2; i++) {
|
||||
this.depthTextures[i].define(width, height);
|
||||
this.colorFrontTextures[i].define(width, height);
|
||||
this.colorBackTextures[i].define(width, height);
|
||||
}
|
||||
ValueCell.update(this.renderable.values.uTexSize, Vec2.set(this.renderable.values.uTexSize.ref.value, width, height));
|
||||
ValueCell.update(this.blendBackRenderable.values.uTexSize, Vec2.set(this.blendBackRenderable.values.uTexSize.ref.value, width, height));
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
if (this._supported) this._init();
|
||||
}
|
||||
|
||||
private _init() {
|
||||
const { extensions: { drawBuffers } } = this.webgl;
|
||||
for (let i = 0; i < 2; i++) {
|
||||
// depth
|
||||
this.depthFramebuffers[i].bind();
|
||||
drawBuffers!.drawBuffers([
|
||||
drawBuffers!.COLOR_ATTACHMENT0,
|
||||
drawBuffers!.COLOR_ATTACHMENT1,
|
||||
drawBuffers!.COLOR_ATTACHMENT2
|
||||
]);
|
||||
|
||||
this.colorFrontTextures[i].attachFramebuffer(this.depthFramebuffers[i], 'color0');
|
||||
this.colorBackTextures[i].attachFramebuffer(this.depthFramebuffers[i], 'color1');
|
||||
this.depthTextures[i].attachFramebuffer(this.depthFramebuffers[i], 'color2');
|
||||
|
||||
// color
|
||||
this.colorFramebuffers[i].bind();
|
||||
drawBuffers!.drawBuffers([
|
||||
drawBuffers!.COLOR_ATTACHMENT0,
|
||||
drawBuffers!.COLOR_ATTACHMENT1
|
||||
]);
|
||||
|
||||
this.colorFrontTextures[i].attachFramebuffer(this.colorFramebuffers[i], 'color0');
|
||||
this.colorBackTextures[i].attachFramebuffer(this.colorFramebuffers[i], 'color1');
|
||||
}
|
||||
}
|
||||
|
||||
static isSupported(webgl: WebGLContext) {
|
||||
const { extensions: { drawBuffers, textureFloat, colorBufferFloat, blendMinMax } } = webgl;
|
||||
if (!textureFloat || !colorBufferFloat || !drawBuffers || !blendMinMax) {
|
||||
if (isDebugMode) {
|
||||
const missing: string[] = [];
|
||||
if (!textureFloat) missing.push('textureFloat');
|
||||
if (!colorBufferFloat) missing.push('colorBufferFloat');
|
||||
if (!drawBuffers) missing.push('drawBuffers');
|
||||
if (!blendMinMax) missing.push('blendMinMax');
|
||||
console.log(`Missing "${missing.join('", "')}" extensions required for "dpoit"`);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private webgl: WebGLContext, width: number, height: number) {
|
||||
if (!DpoitPass.isSupported(webgl)) return;
|
||||
|
||||
const { resources, extensions: { colorBufferHalfFloat, textureHalfFloat } } = webgl;
|
||||
|
||||
// textures
|
||||
|
||||
if (isWebGL2(webgl.gl)) {
|
||||
this.depthTextures = [
|
||||
resources.texture('image-float32', 'rg', 'float', 'nearest'),
|
||||
resources.texture('image-float32', 'rg', 'float', 'nearest')
|
||||
];
|
||||
|
||||
this.colorFrontTextures = colorBufferHalfFloat && textureHalfFloat ? [
|
||||
resources.texture('image-float16', 'rgba', 'fp16', 'nearest'),
|
||||
resources.texture('image-float16', 'rgba', 'fp16', 'nearest')
|
||||
] : [
|
||||
resources.texture('image-float32', 'rgba', 'float', 'nearest'),
|
||||
resources.texture('image-float32', 'rgba', 'float', 'nearest')
|
||||
];
|
||||
|
||||
this.colorBackTextures = colorBufferHalfFloat && textureHalfFloat ? [
|
||||
resources.texture('image-float16', 'rgba', 'fp16', 'nearest'),
|
||||
resources.texture('image-float16', 'rgba', 'fp16', 'nearest')
|
||||
] : [
|
||||
resources.texture('image-float32', 'rgba', 'float', 'nearest'),
|
||||
resources.texture('image-float32', 'rgba', 'float', 'nearest')
|
||||
];
|
||||
} else {
|
||||
// in webgl1 drawbuffers must be in the same format for some reason
|
||||
|
||||
this.depthTextures = [
|
||||
resources.texture('image-float32', 'rgba', 'float', 'nearest'),
|
||||
resources.texture('image-float32', 'rgba', 'float', 'nearest')
|
||||
];
|
||||
|
||||
this.colorFrontTextures = [
|
||||
resources.texture('image-float32', 'rgba', 'float', 'nearest'),
|
||||
resources.texture('image-float32', 'rgba', 'float', 'nearest')
|
||||
];
|
||||
|
||||
this.colorBackTextures = [
|
||||
resources.texture('image-float32', 'rgba', 'float', 'nearest'),
|
||||
resources.texture('image-float32', 'rgba', 'float', 'nearest')
|
||||
];
|
||||
}
|
||||
|
||||
this.depthTextures[0].define(width, height);
|
||||
this.depthTextures[1].define(width, height);
|
||||
|
||||
this.colorFrontTextures[0].define(width, height);
|
||||
this.colorFrontTextures[1].define(width, height);
|
||||
|
||||
this.colorBackTextures[0].define(width, height);
|
||||
this.colorBackTextures[1].define(width, height);
|
||||
|
||||
// framebuffers
|
||||
|
||||
this.depthFramebuffers = [resources.framebuffer(), resources.framebuffer()];
|
||||
this.colorFramebuffers = [resources.framebuffer(), resources.framebuffer()];
|
||||
|
||||
// renderables
|
||||
|
||||
this.blendBackRenderable = getBlendBackDpoitRenderable(webgl, this.colorBackTextures[0]);
|
||||
this.renderable = getEvaluateDpoitRenderable(webgl, this.colorFrontTextures[0]);
|
||||
|
||||
this._supported = true;
|
||||
this._init();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { WebGLContext } from '../../mol-gl/webgl/context';
|
||||
@@ -17,6 +18,7 @@ import { Helper } from '../helper/helper';
|
||||
|
||||
import { StereoCamera } from '../camera/stereo';
|
||||
import { WboitPass } from './wboit';
|
||||
import { DpoitPass } from './dpoit';
|
||||
import { AntialiasingPass, PostprocessingPass, PostprocessingProps } from './postprocessing';
|
||||
import { MarkingPass, MarkingProps } from './marking';
|
||||
import { CopyRenderable, createCopyRenderable } from '../../mol-gl/compute/util';
|
||||
@@ -27,6 +29,7 @@ type Props = {
|
||||
postprocessing: PostprocessingProps;
|
||||
marking: MarkingProps;
|
||||
transparentBackground: boolean;
|
||||
dpoitIterations: number;
|
||||
}
|
||||
|
||||
type RenderContext = {
|
||||
@@ -52,6 +55,7 @@ export class DrawPass {
|
||||
private copyFboPostprocessing: CopyRenderable;
|
||||
|
||||
private readonly wboit: WboitPass | undefined;
|
||||
private readonly dpoit: DpoitPass | undefined;
|
||||
private readonly marking: MarkingPass;
|
||||
readonly postprocessing: PostprocessingPass;
|
||||
private readonly antialiasing: AntialiasingPass;
|
||||
@@ -60,9 +64,12 @@ export class DrawPass {
|
||||
return !!this.wboit?.supported;
|
||||
}
|
||||
|
||||
constructor(private webgl: WebGLContext, assetManager: AssetManager, width: number, height: number, enableWboit: boolean) {
|
||||
const { extensions, resources, isWebGL2 } = webgl;
|
||||
get dpoitEnabled() {
|
||||
return !!this.dpoit?.supported;
|
||||
}
|
||||
|
||||
constructor(private webgl: WebGLContext, assetManager: AssetManager, width: number, height: number, enableWboit: boolean, enableDpoit: boolean) {
|
||||
const { extensions, resources, isWebGL2 } = webgl;
|
||||
this.drawTarget = createNullRenderTarget(webgl.gl);
|
||||
this.colorTarget = webgl.createRenderTarget(width, height, true, 'uint8', 'linear');
|
||||
this.packedDepth = !extensions.depthTexture;
|
||||
@@ -78,6 +85,7 @@ export class DrawPass {
|
||||
}
|
||||
|
||||
this.wboit = enableWboit ? new WboitPass(webgl, width, height) : undefined;
|
||||
this.dpoit = enableDpoit ? new DpoitPass(webgl, width, height) : undefined;
|
||||
this.marking = new MarkingPass(webgl, width, height);
|
||||
this.postprocessing = new PostprocessingPass(webgl, assetManager, this);
|
||||
this.antialiasing = new AntialiasingPass(webgl, this);
|
||||
@@ -88,6 +96,7 @@ export class DrawPass {
|
||||
|
||||
reset() {
|
||||
this.wboit?.reset();
|
||||
this.dpoit?.reset();
|
||||
}
|
||||
|
||||
setSize(width: number, height: number) {
|
||||
@@ -111,12 +120,70 @@ export class DrawPass {
|
||||
this.wboit.setSize(width, height);
|
||||
}
|
||||
|
||||
if (this.dpoit?.supported) {
|
||||
this.dpoit.setSize(width, height);
|
||||
}
|
||||
|
||||
this.marking.setSize(width, height);
|
||||
this.postprocessing.setSize(width, height);
|
||||
this.antialiasing.setSize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
private _renderDpoit(renderer: Renderer, camera: ICamera, scene: Scene, iterations: number, transparentBackground: boolean, postprocessingProps: PostprocessingProps) {
|
||||
if (!this.dpoit?.supported) throw new Error('expected dpoit to be supported');
|
||||
|
||||
this.depthTextureOpaque.attachFramebuffer(this.colorTarget.framebuffer, 'depth');
|
||||
renderer.clear(true);
|
||||
|
||||
// render opaque primitives
|
||||
if (scene.hasOpaque) {
|
||||
renderer.renderDpoitOpaque(scene.primitives, camera, null);
|
||||
}
|
||||
|
||||
if (PostprocessingPass.isEnabled(postprocessingProps)) {
|
||||
if (PostprocessingPass.isOutlineEnabled(postprocessingProps)) {
|
||||
this.depthTargetTransparent.bind();
|
||||
renderer.clearDepth(true);
|
||||
if (scene.opacityAverage < 1) {
|
||||
renderer.renderDepthTransparent(scene.primitives, camera, this.depthTextureOpaque);
|
||||
}
|
||||
}
|
||||
|
||||
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps, renderer.light);
|
||||
}
|
||||
|
||||
this.depthTextureOpaque.detachFramebuffer(this.colorTarget.framebuffer, 'depth');
|
||||
|
||||
// render transparent primitives
|
||||
if (scene.opacityAverage < 1) {
|
||||
const target = PostprocessingPass.isEnabled(postprocessingProps)
|
||||
? this.postprocessing.target : this.colorTarget;
|
||||
|
||||
const dpoitTextures = this.dpoit.bind();
|
||||
renderer.renderDpoitTransparent(scene.primitives, camera, this.depthTextureOpaque, dpoitTextures);
|
||||
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
if (isTimingMode) this.webgl.timer.mark('DpoitPass.layer');
|
||||
const dpoitTextures = this.dpoit.bindDualDepthPeeling();
|
||||
renderer.renderDpoitTransparent(scene.primitives, camera, this.depthTextureOpaque, dpoitTextures);
|
||||
|
||||
target.bind();
|
||||
this.dpoit.renderBlendBack();
|
||||
if (isTimingMode) this.webgl.timer.markEnd('DpoitPass.layer');
|
||||
}
|
||||
|
||||
// evaluate dpoit
|
||||
target.bind();
|
||||
this.dpoit.render();
|
||||
}
|
||||
|
||||
// render transparent volumes
|
||||
if (scene.volumes.renderables.length > 0) {
|
||||
renderer.renderDpoitVolume(scene.volumes, camera, this.depthTextureOpaque);
|
||||
}
|
||||
}
|
||||
|
||||
private _renderWboit(renderer: Renderer, camera: ICamera, scene: Scene, transparentBackground: boolean, postprocessingProps: PostprocessingProps) {
|
||||
if (!this.wboit?.supported) throw new Error('expected wboit to be supported');
|
||||
|
||||
@@ -137,7 +204,7 @@ export class DrawPass {
|
||||
}
|
||||
}
|
||||
|
||||
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps);
|
||||
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps, renderer.light);
|
||||
}
|
||||
|
||||
// render transparent primitives and volumes
|
||||
@@ -201,7 +268,7 @@ export class DrawPass {
|
||||
}
|
||||
}
|
||||
|
||||
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps);
|
||||
this.postprocessing.render(camera, false, transparentBackground, renderer.props.backgroundColor, postprocessingProps, renderer.light);
|
||||
|
||||
if (!this.packedDepth) {
|
||||
this.depthTextureOpaque.attachFramebuffer(this.postprocessing.target.framebuffer, 'depth');
|
||||
@@ -254,13 +321,15 @@ export class DrawPass {
|
||||
|
||||
if (this.wboitEnabled) {
|
||||
this._renderWboit(renderer, camera, scene, transparentBackground, props.postprocessing);
|
||||
} else if (this.dpoitEnabled) {
|
||||
this._renderDpoit(renderer, camera, scene, props.dpoitIterations, transparentBackground, props.postprocessing);
|
||||
} else {
|
||||
this._renderBlended(renderer, camera, scene, !volumeRendering && !postprocessingEnabled && !antialiasingEnabled && toDrawingBuffer, transparentBackground, props.postprocessing);
|
||||
}
|
||||
|
||||
const target = postprocessingEnabled
|
||||
? this.postprocessing.target
|
||||
: !toDrawingBuffer || volumeRendering || this.wboitEnabled
|
||||
: !toDrawingBuffer || volumeRendering || this.wboitEnabled || this.dpoitEnabled
|
||||
? this.colorTarget
|
||||
: this.drawTarget;
|
||||
|
||||
@@ -303,7 +372,7 @@ export class DrawPass {
|
||||
this.webgl.state.disable(this.webgl.gl.DEPTH_TEST);
|
||||
if (postprocessingEnabled) {
|
||||
this.copyFboPostprocessing.render();
|
||||
} else if (volumeRendering || this.wboitEnabled) {
|
||||
} else if (volumeRendering || this.wboitEnabled || this.dpoitEnabled) {
|
||||
this.copyFboTarget.render();
|
||||
}
|
||||
}
|
||||
@@ -323,8 +392,12 @@ export class DrawPass {
|
||||
renderer.setPixelRatio(this.webgl.pixelRatio);
|
||||
|
||||
if (StereoCamera.is(camera)) {
|
||||
if (isTimingMode) this.webgl.timer.mark('StereoCamera.left');
|
||||
this._render(renderer, camera.left, scene, helper, toDrawingBuffer, transparentBackground, props);
|
||||
if (isTimingMode) this.webgl.timer.markEnd('StereoCamera.left');
|
||||
if (isTimingMode) this.webgl.timer.mark('StereoCamera.right');
|
||||
this._render(renderer, camera.right, scene, helper, toDrawingBuffer, transparentBackground, props);
|
||||
if (isTimingMode) this.webgl.timer.markEnd('StereoCamera.right');
|
||||
} else {
|
||||
this._render(renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, props);
|
||||
}
|
||||
@@ -339,4 +412,4 @@ export class DrawPass {
|
||||
}
|
||||
return this.colorTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { AssetManager } from '../../mol-util/assets';
|
||||
|
||||
export const ImageParams = {
|
||||
transparentBackground: PD.Boolean(false),
|
||||
dpoitIterations: PD.Numeric(2, { min: 1, max: 10, step: 1 }),
|
||||
multiSample: PD.Group(MultiSampleParams),
|
||||
postprocessing: PD.Group(PostprocessingParams),
|
||||
marking: PD.Group(MarkingParams),
|
||||
@@ -48,10 +49,10 @@ export class ImagePass {
|
||||
get width() { return this._width; }
|
||||
get height() { return this._height; }
|
||||
|
||||
constructor(private webgl: WebGLContext, assetManager: AssetManager, private renderer: Renderer, private scene: Scene, private camera: Camera, helper: Helper, enableWboit: boolean, props: Partial<ImageProps>) {
|
||||
constructor(private webgl: WebGLContext, assetManager: AssetManager, private renderer: Renderer, private scene: Scene, private camera: Camera, helper: Helper, enableWboit: boolean, enableDpoit: boolean, props: Partial<ImageProps>) {
|
||||
this.props = { ...PD.getDefaultValues(ImageParams), ...props };
|
||||
|
||||
this.drawPass = new DrawPass(webgl, assetManager, 128, 128, enableWboit);
|
||||
this.drawPass = new DrawPass(webgl, assetManager, 128, 128, enableWboit, enableDpoit);
|
||||
this.multiSamplePass = new MultiSamplePass(webgl, this.drawPass);
|
||||
this.multiSampleHelper = new MultiSampleHelper(this.multiSamplePass);
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ type Props = {
|
||||
postprocessing: PostprocessingProps
|
||||
marking: MarkingProps
|
||||
transparentBackground: boolean;
|
||||
dpoitIterations: number;
|
||||
}
|
||||
|
||||
type RenderContext = {
|
||||
|
||||
@@ -15,16 +15,19 @@ export class Passes {
|
||||
readonly pick: PickPass;
|
||||
readonly multiSample: MultiSamplePass;
|
||||
|
||||
constructor(private webgl: WebGLContext, assetManager: AssetManager, attribs: Partial<{ pickScale: number, enableWboit: boolean }> = {}) {
|
||||
constructor(private webgl: WebGLContext, assetManager: AssetManager, attribs: Partial<{ pickScale: number, enableWboit: boolean, enableDpoit: boolean }> = {}) {
|
||||
const { gl } = webgl;
|
||||
this.draw = new DrawPass(webgl, assetManager, gl.drawingBufferWidth, gl.drawingBufferHeight, attribs.enableWboit || false);
|
||||
this.draw = new DrawPass(webgl, assetManager, gl.drawingBufferWidth, gl.drawingBufferHeight, attribs.enableWboit || false, attribs.enableDpoit || false);
|
||||
this.pick = new PickPass(webgl, this.draw, attribs.pickScale || 0.25);
|
||||
this.multiSample = new MultiSamplePass(webgl, this.draw);
|
||||
}
|
||||
|
||||
updateSize() {
|
||||
const { gl } = this.webgl;
|
||||
this.draw.setSize(gl.drawingBufferWidth, gl.drawingBufferHeight);
|
||||
// Avoid setting dimensions to 0x0 because it causes "empty textures are not allowed" error.
|
||||
const width = Math.max(gl.drawingBufferWidth, 2);
|
||||
const height = Math.max(gl.drawingBufferHeight, 2);
|
||||
this.draw.setSize(width, height);
|
||||
this.pick.syncSize();
|
||||
this.multiSample.syncSize();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
|
||||
* @author Ludovic Autin <ludovic.autin@gmail.com>
|
||||
*/
|
||||
|
||||
import { CopyRenderable, createCopyRenderable, QuadSchema, QuadValues } from '../../mol-gl/compute/util';
|
||||
@@ -30,6 +31,8 @@ import { SmaaParams, SmaaPass } from './smaa';
|
||||
import { isTimingMode } from '../../mol-util/debug';
|
||||
import { BackgroundParams, BackgroundPass } from './background';
|
||||
import { AssetManager } from '../../mol-util/assets';
|
||||
import { Light } from '../../mol-gl/renderer';
|
||||
import { shadows_frag } from '../../mol-gl/shader/shadows.frag';
|
||||
|
||||
const OutlinesSchema = {
|
||||
...QuadSchema,
|
||||
@@ -69,6 +72,64 @@ function getOutlinesRenderable(ctx: WebGLContext, depthTextureOpaque: Texture, d
|
||||
return createComputeRenderable(renderItem, values);
|
||||
}
|
||||
|
||||
const ShadowsSchema = {
|
||||
...QuadSchema,
|
||||
tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
uTexSize: UniformSpec('v2'),
|
||||
|
||||
uProjection: UniformSpec('m4'),
|
||||
uInvProjection: UniformSpec('m4'),
|
||||
uBounds: UniformSpec('v4'),
|
||||
|
||||
dOrthographic: DefineSpec('number'),
|
||||
uNear: UniformSpec('f'),
|
||||
uFar: UniformSpec('f'),
|
||||
|
||||
dSteps: DefineSpec('number'),
|
||||
uMaxDistance: UniformSpec('f'),
|
||||
uTolerance: UniformSpec('f'),
|
||||
uBias: UniformSpec('f'),
|
||||
|
||||
uLightDirection: UniformSpec('v3[]'),
|
||||
uLightColor: UniformSpec('v3[]'),
|
||||
dLightCount: DefineSpec('number'),
|
||||
};
|
||||
type ShadowsRenderable = ComputeRenderable<Values<typeof ShadowsSchema>>
|
||||
|
||||
function getShadowsRenderable(ctx: WebGLContext, depthTexture: Texture): ShadowsRenderable {
|
||||
const width = depthTexture.getWidth();
|
||||
const height = depthTexture.getHeight();
|
||||
|
||||
const values: Values<typeof ShadowsSchema> = {
|
||||
...QuadValues,
|
||||
tDepth: ValueCell.create(depthTexture),
|
||||
uTexSize: ValueCell.create(Vec2.create(width, height)),
|
||||
|
||||
uProjection: ValueCell.create(Mat4.identity()),
|
||||
uInvProjection: ValueCell.create(Mat4.identity()),
|
||||
uBounds: ValueCell.create(Vec4()),
|
||||
|
||||
dOrthographic: ValueCell.create(0),
|
||||
uNear: ValueCell.create(1),
|
||||
uFar: ValueCell.create(10000),
|
||||
|
||||
dSteps: ValueCell.create(1),
|
||||
uMaxDistance: ValueCell.create(3.0),
|
||||
uTolerance: ValueCell.create(1.0),
|
||||
uBias: ValueCell.create(0.6),
|
||||
|
||||
uLightDirection: ValueCell.create([]),
|
||||
uLightColor: ValueCell.create([]),
|
||||
dLightCount: ValueCell.create(0),
|
||||
};
|
||||
|
||||
const schema = { ...ShadowsSchema };
|
||||
const shaderCode = ShaderCode('shadows', quad_vert, shadows_frag);
|
||||
const renderItem = createComputeRenderItem(ctx, 'triangles', shaderCode, schema, values);
|
||||
|
||||
return createComputeRenderable(renderItem, values);
|
||||
}
|
||||
|
||||
const SsaoSchema = {
|
||||
...QuadSchema,
|
||||
tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
@@ -204,6 +265,7 @@ const PostprocessingSchema = {
|
||||
tColor: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
tDepthOpaque: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
tDepthTransparent: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
tShadows: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
tOutlines: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
uTexSize: UniformSpec('v2'),
|
||||
|
||||
@@ -221,19 +283,22 @@ const PostprocessingSchema = {
|
||||
dOcclusionEnable: DefineSpec('boolean'),
|
||||
uOcclusionOffset: UniformSpec('v2'),
|
||||
|
||||
dShadowEnable: DefineSpec('boolean'),
|
||||
|
||||
dOutlineEnable: DefineSpec('boolean'),
|
||||
dOutlineScale: DefineSpec('number'),
|
||||
uOutlineThreshold: UniformSpec('f'),
|
||||
};
|
||||
type PostprocessingRenderable = ComputeRenderable<Values<typeof PostprocessingSchema>>
|
||||
|
||||
function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTextureOpaque: Texture, depthTextureTransparent: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture): PostprocessingRenderable {
|
||||
function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, depthTextureOpaque: Texture, depthTextureTransparent: Texture, shadowsTexture: Texture, outlinesTexture: Texture, ssaoDepthTexture: Texture): PostprocessingRenderable {
|
||||
const values: Values<typeof PostprocessingSchema> = {
|
||||
...QuadValues,
|
||||
tSsaoDepth: ValueCell.create(ssaoDepthTexture),
|
||||
tColor: ValueCell.create(colorTexture),
|
||||
tDepthOpaque: ValueCell.create(depthTextureOpaque),
|
||||
tDepthTransparent: ValueCell.create(depthTextureTransparent),
|
||||
tShadows: ValueCell.create(shadowsTexture),
|
||||
tOutlines: ValueCell.create(outlinesTexture),
|
||||
uTexSize: ValueCell.create(Vec2.create(colorTexture.getWidth(), colorTexture.getHeight())),
|
||||
|
||||
@@ -251,6 +316,8 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
|
||||
dOcclusionEnable: ValueCell.create(true),
|
||||
uOcclusionOffset: ValueCell.create(Vec2.create(0, 0)),
|
||||
|
||||
dShadowEnable: ValueCell.create(false),
|
||||
|
||||
dOutlineEnable: ValueCell.create(false),
|
||||
dOutlineScale: ValueCell.create(1),
|
||||
uOutlineThreshold: ValueCell.create(0.33),
|
||||
@@ -274,6 +341,15 @@ export const PostprocessingParams = {
|
||||
}),
|
||||
off: PD.Group({})
|
||||
}, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }),
|
||||
shadow: PD.MappedStatic('off', {
|
||||
on: PD.Group({
|
||||
steps: PD.Numeric(1, { min: 1, max: 64, step: 1 }),
|
||||
bias: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }),
|
||||
maxDistance: PD.Numeric(3, { min: 0, max: 256, step: 1 }),
|
||||
tolerance: PD.Numeric(1.0, { min: 0.0, max: 10.0, step: 0.1 }),
|
||||
}),
|
||||
off: PD.Group({})
|
||||
}, { cycle: true, description: 'Simplistic shadows' }),
|
||||
outline: PD.MappedStatic('off', {
|
||||
on: PD.Group({
|
||||
scale: PD.Numeric(1, { min: 1, max: 5, step: 1 }),
|
||||
@@ -289,11 +365,12 @@ export const PostprocessingParams = {
|
||||
}, { options: [['fxaa', 'FXAA'], ['smaa', 'SMAA'], ['off', 'Off']], description: 'Smooth pixel edges' }),
|
||||
background: PD.Group(BackgroundParams, { isFlat: true }),
|
||||
};
|
||||
|
||||
export type PostprocessingProps = PD.Values<typeof PostprocessingParams>
|
||||
|
||||
export class PostprocessingPass {
|
||||
static isEnabled(props: PostprocessingProps) {
|
||||
return props.occlusion.name === 'on' || props.outline.name === 'on' || props.background.variant.name !== 'off';
|
||||
return props.occlusion.name === 'on' || props.shadow.name === 'on' || props.outline.name === 'on' || props.background.variant.name !== 'off';
|
||||
}
|
||||
|
||||
static isOutlineEnabled(props: PostprocessingProps) {
|
||||
@@ -305,6 +382,9 @@ export class PostprocessingPass {
|
||||
private readonly outlinesTarget: RenderTarget;
|
||||
private readonly outlinesRenderable: OutlinesRenderable;
|
||||
|
||||
private readonly shadowsTarget: RenderTarget;
|
||||
private readonly shadowsRenderable: ShadowsRenderable;
|
||||
|
||||
private readonly ssaoFramebuffer: Framebuffer;
|
||||
private readonly ssaoBlurFirstPassFramebuffer: Framebuffer;
|
||||
private readonly ssaoBlurSecondPassFramebuffer: Framebuffer;
|
||||
@@ -350,6 +430,9 @@ export class PostprocessingPass {
|
||||
this.outlinesTarget = webgl.createRenderTarget(width, height, false);
|
||||
this.outlinesRenderable = getOutlinesRenderable(webgl, depthTextureOpaque, depthTextureTransparent);
|
||||
|
||||
this.shadowsTarget = webgl.createRenderTarget(width, height, false);
|
||||
this.shadowsRenderable = getShadowsRenderable(webgl, depthTextureOpaque);
|
||||
|
||||
this.ssaoFramebuffer = webgl.resources.framebuffer();
|
||||
this.ssaoBlurFirstPassFramebuffer = webgl.resources.framebuffer();
|
||||
this.ssaoBlurSecondPassFramebuffer = webgl.resources.framebuffer();
|
||||
@@ -373,7 +456,7 @@ export class PostprocessingPass {
|
||||
this.ssaoRenderable = getSsaoRenderable(webgl, this.downsampleFactor === 1 ? depthTextureOpaque : this.downsampledDepthTarget.texture);
|
||||
this.ssaoBlurFirstPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthTexture, 'horizontal');
|
||||
this.ssaoBlurSecondPassRenderable = getSsaoBlurRenderable(webgl, this.ssaoDepthBlurProxyTexture, 'vertical');
|
||||
this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.outlinesTarget.texture, this.ssaoDepthTexture);
|
||||
this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTextureOpaque, depthTextureTransparent, this.shadowsTarget.texture, this.outlinesTarget.texture, this.ssaoDepthTexture);
|
||||
|
||||
this.background = new BackgroundPass(webgl, assetManager, width, height);
|
||||
}
|
||||
@@ -389,12 +472,14 @@ export class PostprocessingPass {
|
||||
const sh = Math.floor(height * this.ssaoScale);
|
||||
this.target.setSize(width, height);
|
||||
this.outlinesTarget.setSize(width, height);
|
||||
this.shadowsTarget.setSize(width, height);
|
||||
this.downsampledDepthTarget.setSize(sw, sh);
|
||||
this.ssaoDepthTexture.define(sw, sh);
|
||||
this.ssaoDepthBlurProxyTexture.define(sw, sh);
|
||||
|
||||
ValueCell.update(this.renderable.values.uTexSize, Vec2.set(this.renderable.values.uTexSize.ref.value, width, height));
|
||||
ValueCell.update(this.outlinesRenderable.values.uTexSize, Vec2.set(this.outlinesRenderable.values.uTexSize.ref.value, width, height));
|
||||
ValueCell.update(this.shadowsRenderable.values.uTexSize, Vec2.set(this.shadowsRenderable.values.uTexSize.ref.value, width, height));
|
||||
ValueCell.update(this.downsampleDepthRenderable.values.uTexSize, Vec2.set(this.downsampleDepthRenderable.values.uTexSize.ref.value, sw, sh));
|
||||
ValueCell.update(this.ssaoRenderable.values.uTexSize, Vec2.set(this.ssaoRenderable.values.uTexSize.ref.value, sw, sh));
|
||||
ValueCell.update(this.ssaoBlurFirstPassRenderable.values.uTexSize, Vec2.set(this.ssaoBlurFirstPassRenderable.values.uTexSize.ref.value, sw, sh));
|
||||
@@ -404,25 +489,28 @@ export class PostprocessingPass {
|
||||
}
|
||||
}
|
||||
|
||||
private updateState(camera: ICamera, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps) {
|
||||
private updateState(camera: ICamera, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps, light: Light) {
|
||||
let needsUpdateShadows = false;
|
||||
let needsUpdateMain = false;
|
||||
let needsUpdateSsao = false;
|
||||
let needsUpdateSsaoBlur = false;
|
||||
|
||||
const orthographic = camera.state.mode === 'orthographic' ? 1 : 0;
|
||||
const outlinesEnabled = props.outline.name === 'on';
|
||||
const shadowsEnabled = props.shadow.name === 'on';
|
||||
const occlusionEnabled = props.occlusion.name === 'on';
|
||||
|
||||
const invProjection = Mat4.identity();
|
||||
Mat4.invert(invProjection, camera.projection);
|
||||
|
||||
const [w, h] = this.renderable.values.uTexSize.ref.value;
|
||||
const v = camera.viewport;
|
||||
|
||||
if (props.occlusion.name === 'on') {
|
||||
ValueCell.update(this.ssaoRenderable.values.uProjection, camera.projection);
|
||||
ValueCell.update(this.ssaoRenderable.values.uInvProjection, invProjection);
|
||||
|
||||
const [w, h] = this.renderable.values.uTexSize.ref.value;
|
||||
const b = this.ssaoRenderable.values.uBounds;
|
||||
const v = camera.viewport;
|
||||
const s = this.ssaoScale;
|
||||
Vec4.set(b.ref.value,
|
||||
Math.floor(v.x * s) / (w * s),
|
||||
@@ -494,6 +582,38 @@ export class PostprocessingPass {
|
||||
}
|
||||
}
|
||||
|
||||
if (props.shadow.name === 'on') {
|
||||
ValueCell.update(this.shadowsRenderable.values.uProjection, camera.projection);
|
||||
ValueCell.update(this.shadowsRenderable.values.uInvProjection, invProjection);
|
||||
|
||||
Vec4.set(this.shadowsRenderable.values.uBounds.ref.value,
|
||||
v.x / w,
|
||||
v.y / h,
|
||||
(v.x + v.width) / w,
|
||||
(v.y + v.height) / h
|
||||
);
|
||||
ValueCell.update(this.shadowsRenderable.values.uBounds, this.shadowsRenderable.values.uBounds.ref.value);
|
||||
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uNear, camera.near);
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uFar, camera.far);
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.dOrthographic, orthographic);
|
||||
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uMaxDistance, props.shadow.params.maxDistance);
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uTolerance, props.shadow.params.tolerance);
|
||||
ValueCell.updateIfChanged(this.shadowsRenderable.values.uBias, props.shadow.params.bias);
|
||||
if (this.shadowsRenderable.values.dSteps.ref.value !== props.shadow.params.steps) {
|
||||
ValueCell.update(this.shadowsRenderable.values.dSteps, props.shadow.params.steps);
|
||||
needsUpdateShadows = true;
|
||||
}
|
||||
|
||||
ValueCell.update(this.shadowsRenderable.values.uLightDirection, light.direction);
|
||||
ValueCell.update(this.shadowsRenderable.values.uLightColor, light.color);
|
||||
if (this.shadowsRenderable.values.dLightCount.ref.value !== light.count) {
|
||||
ValueCell.update(this.shadowsRenderable.values.dLightCount, light.count);
|
||||
needsUpdateShadows = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (props.outline.name === 'on') {
|
||||
let { threshold } = props.outline.params;
|
||||
// orthographic needs lower threshold
|
||||
@@ -522,11 +642,18 @@ export class PostprocessingPass {
|
||||
ValueCell.updateIfChanged(this.renderable.values.uTransparentBackground, transparentBackground);
|
||||
if (this.renderable.values.dOrthographic.ref.value !== orthographic) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dOrthographic, orthographic);
|
||||
|
||||
if (this.renderable.values.dOutlineEnable.ref.value !== outlinesEnabled) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dOutlineEnable, outlinesEnabled);
|
||||
if (this.renderable.values.dShadowEnable.ref.value !== shadowsEnabled) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dShadowEnable, shadowsEnabled);
|
||||
if (this.renderable.values.dOcclusionEnable.ref.value !== occlusionEnabled) { needsUpdateMain = true; }
|
||||
ValueCell.updateIfChanged(this.renderable.values.dOcclusionEnable, occlusionEnabled);
|
||||
|
||||
if (needsUpdateShadows) {
|
||||
this.shadowsRenderable.update();
|
||||
}
|
||||
|
||||
if (needsUpdateSsao) {
|
||||
this.ssaoRenderable.update();
|
||||
}
|
||||
@@ -564,15 +691,20 @@ export class PostprocessingPass {
|
||||
this.transparentBackground = value;
|
||||
}
|
||||
|
||||
render(camera: ICamera, toDrawingBuffer: boolean, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps) {
|
||||
render(camera: ICamera, toDrawingBuffer: boolean, transparentBackground: boolean, backgroundColor: Color, props: PostprocessingProps, light: Light) {
|
||||
if (isTimingMode) this.webgl.timer.mark('PostprocessingPass.render');
|
||||
this.updateState(camera, transparentBackground, backgroundColor, props);
|
||||
this.updateState(camera, transparentBackground, backgroundColor, props, light);
|
||||
|
||||
if (props.outline.name === 'on') {
|
||||
this.outlinesTarget.bind();
|
||||
this.outlinesRenderable.render();
|
||||
}
|
||||
|
||||
if (props.shadow.name === 'on') {
|
||||
this.shadowsTarget.bind();
|
||||
this.shadowsRenderable.render();
|
||||
}
|
||||
|
||||
// don't render occlusion if offset is given,
|
||||
// which will reuse the existing occlusion
|
||||
if (props.occlusion.name === 'on' && this.occlusionOffset[0] === 0 && this.occlusionOffset[1] === 0) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -11,7 +11,7 @@ import { ShaderCode } from '../../mol-gl/shader-code';
|
||||
import { WebGLContext } from '../../mol-gl/webgl/context';
|
||||
import { createComputeRenderItem } from '../../mol-gl/webgl/render-item';
|
||||
import { RenderTarget } from '../../mol-gl/webgl/render-target';
|
||||
import { createTexture, loadImageTexture, Texture } from '../../mol-gl/webgl/texture';
|
||||
import { loadImageTexture, Texture } from '../../mol-gl/webgl/texture';
|
||||
import { Vec2, Vec4 } from '../../mol-math/linear-algebra';
|
||||
import { ValueCell } from '../../mol-util';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
@@ -74,6 +74,7 @@ export class SmaaPass {
|
||||
state.viewport(x, y, width, height);
|
||||
state.scissor(x, y, width, height);
|
||||
|
||||
state.colorMask(true, true, true, true);
|
||||
state.clearColor(0, 0, 0, 1);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
@@ -191,8 +192,8 @@ function getWeightsRenderable(ctx: WebGLContext, edgesTexture: Texture): Weights
|
||||
const width = edgesTexture.getWidth();
|
||||
const height = edgesTexture.getHeight();
|
||||
|
||||
const areaTexture = createTexture(ctx.gl, ctx.extensions, 'image-uint8', 'rgb', 'ubyte', 'linear');
|
||||
const searchTexture = createTexture(ctx.gl, ctx.extensions, 'image-uint8', 'rgba', 'ubyte', 'nearest');
|
||||
const areaTexture = ctx.resources.texture('image-uint8', 'rgb', 'ubyte', 'linear');
|
||||
const searchTexture = ctx.resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest');
|
||||
|
||||
const values: Values<typeof WeightsSchema> = {
|
||||
...QuadValues,
|
||||
|
||||
@@ -18,6 +18,8 @@ import { evaluateWboit_frag } from '../../mol-gl/shader/evaluate-wboit.frag';
|
||||
import { Framebuffer } from '../../mol-gl/webgl/framebuffer';
|
||||
import { Vec2 } from '../../mol-math/linear-algebra';
|
||||
import { isDebugMode, isTimingMode } from '../../mol-util/debug';
|
||||
import { isWebGL2 } from '../../mol-gl/webgl/compat';
|
||||
import { Renderbuffer } from '../../mol-gl/webgl/renderbuffer';
|
||||
|
||||
const EvaluateWboitSchema = {
|
||||
...QuadSchema,
|
||||
@@ -50,6 +52,7 @@ export class WboitPass {
|
||||
private readonly framebuffer: Framebuffer;
|
||||
private readonly textureA: Texture;
|
||||
private readonly textureB: Texture;
|
||||
private readonly depthRenderbuffer: Renderbuffer;
|
||||
|
||||
private _supported = false;
|
||||
get supported() {
|
||||
@@ -87,6 +90,7 @@ export class WboitPass {
|
||||
if (width !== w || height !== h) {
|
||||
this.textureA.define(width, height);
|
||||
this.textureB.define(width, height);
|
||||
this.depthRenderbuffer.setSize(width, height);
|
||||
ValueCell.update(this.renderable.values.uTexSize, Vec2.set(this.renderable.values.uTexSize.ref.value, width, height));
|
||||
}
|
||||
}
|
||||
@@ -106,6 +110,8 @@ export class WboitPass {
|
||||
|
||||
this.textureA.attachFramebuffer(this.framebuffer, 'color0');
|
||||
this.textureB.attachFramebuffer(this.framebuffer, 'color1');
|
||||
|
||||
this.depthRenderbuffer.attachFramebuffer(this.framebuffer);
|
||||
}
|
||||
|
||||
static isSupported(webgl: WebGLContext) {
|
||||
@@ -128,7 +134,7 @@ export class WboitPass {
|
||||
constructor(private webgl: WebGLContext, width: number, height: number) {
|
||||
if (!WboitPass.isSupported(webgl)) return;
|
||||
|
||||
const { resources } = webgl;
|
||||
const { resources, gl } = webgl;
|
||||
|
||||
this.textureA = resources.texture('image-float32', 'rgba', 'float', 'nearest');
|
||||
this.textureA.define(width, height);
|
||||
@@ -136,6 +142,10 @@ export class WboitPass {
|
||||
this.textureB = resources.texture('image-float32', 'rgba', 'float', 'nearest');
|
||||
this.textureB.define(width, height);
|
||||
|
||||
this.depthRenderbuffer = isWebGL2(gl)
|
||||
? resources.renderbuffer('depth32f', 'depth', width, height)
|
||||
: resources.renderbuffer('depth16', 'depth', width, height);
|
||||
|
||||
this.renderable = getEvaluateWboitRenderable(webgl, this.textureA, this.textureB);
|
||||
this.framebuffer = resources.framebuffer();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -21,6 +21,7 @@ export type OverpaintData = {
|
||||
uOverpaintGridDim: ValueCell<Vec3>,
|
||||
uOverpaintGridTransform: ValueCell<Vec4>,
|
||||
dOverpaintType: ValueCell<string>,
|
||||
uOverpaintStrength: ValueCell<number>,
|
||||
}
|
||||
|
||||
export function applyOverpaintColor(array: Uint8Array, start: number, end: number, color: Color) {
|
||||
@@ -54,6 +55,7 @@ export function createOverpaint(count: number, type: OverpaintType, overpaintDat
|
||||
uOverpaintGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uOverpaintGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dOverpaintType: ValueCell.create(type),
|
||||
uOverpaintStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -74,6 +76,7 @@ export function createEmptyOverpaint(overpaintData?: OverpaintData): OverpaintDa
|
||||
uOverpaintGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uOverpaintGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dOverpaintType: ValueCell.create('groupInstance'),
|
||||
uOverpaintStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2021-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -21,6 +21,7 @@ export type SubstanceData = {
|
||||
uSubstanceGridDim: ValueCell<Vec3>,
|
||||
uSubstanceGridTransform: ValueCell<Vec4>,
|
||||
dSubstanceType: ValueCell<string>,
|
||||
uSubstanceStrength: ValueCell<number>,
|
||||
}
|
||||
|
||||
export function applySubstanceMaterial(array: Uint8Array, start: number, end: number, material: Material) {
|
||||
@@ -54,6 +55,7 @@ export function createSubstance(count: number, type: SubstanceType, substanceDat
|
||||
uSubstanceGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uSubstanceGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dSubstanceType: ValueCell.create(type),
|
||||
uSubstanceStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -74,6 +76,7 @@ export function createEmptySubstance(substanceData?: SubstanceData): SubstanceDa
|
||||
uSubstanceGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uSubstanceGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dSubstanceType: ValueCell.create('groupInstance'),
|
||||
uSubstanceStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -88,7 +88,7 @@ export class FontAtlas {
|
||||
this.scratchCanvas.width = this.maxWidth;
|
||||
this.scratchCanvas.height = this.lineHeight;
|
||||
|
||||
this.scratchContext = this.scratchCanvas.getContext('2d')!;
|
||||
this.scratchContext = this.scratchCanvas.getContext('2d', { willReadFrequently: true })!;
|
||||
this.scratchContext.font = `${p.fontStyle} ${p.fontVariant} ${p.fontWeight} ${fontSize}px ${p.fontFamily}`;
|
||||
this.scratchContext.fillStyle = 'black';
|
||||
this.scratchContext.textBaseline = 'middle';
|
||||
|
||||
@@ -387,6 +387,8 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
|
||||
const type = isInstanceType ? 'volumeInstance' : 'volume';
|
||||
if (isTimingMode) webgl.timer.markEnd('calcTextureMeshColorSmoothing');
|
||||
|
||||
// printTextureImage(readTexture(webgl, texture), { scale: 0.75 });
|
||||
|
||||
return { texture, gridDim, gridTexDim: Vec2.create(width, height), gridTransform, type };
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { ValueCell } from '../../../mol-util';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { LocationIterator } from '../../../mol-geo/util/location-iterator';
|
||||
import { LocationIterator, PositionLocation } from '../../../mol-geo/util/location-iterator';
|
||||
import { TransformData } from '../transform-data';
|
||||
import { createColors } from '../color-data';
|
||||
import { createMarkers } from '../marker-data';
|
||||
@@ -20,11 +20,12 @@ import { createEmptyTransparency } from '../transparency-data';
|
||||
import { TextureMeshValues } from '../../../mol-gl/renderable/texture-mesh';
|
||||
import { calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
|
||||
import { createNullTexture, Texture } from '../../../mol-gl/webgl/texture';
|
||||
import { Vec2, Vec4 } from '../../../mol-math/linear-algebra';
|
||||
import { Vec2, Vec3, Vec4 } from '../../../mol-math/linear-algebra';
|
||||
import { createEmptyClipping } from '../clipping-data';
|
||||
import { NullLocation } from '../../../mol-model/location';
|
||||
import { createEmptySubstance } from '../substance-data';
|
||||
import { RenderableState } from '../../../mol-gl/renderable';
|
||||
import { WebGLContext } from '../../../mol-gl/webgl/context';
|
||||
|
||||
export interface TextureMesh {
|
||||
readonly kind: 'texture-mesh',
|
||||
@@ -43,7 +44,10 @@ export interface TextureMesh {
|
||||
|
||||
readonly boundingSphere: Sphere3D
|
||||
|
||||
readonly meta: { [k: string]: unknown }
|
||||
readonly meta: {
|
||||
webgl?: WebGLContext
|
||||
[k: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export namespace TextureMesh {
|
||||
@@ -131,9 +135,42 @@ export namespace TextureMesh {
|
||||
updateBoundingSphere,
|
||||
createRenderableState,
|
||||
updateRenderableState,
|
||||
createPositionIterator: () => LocationIterator(1, 1, 1, () => NullLocation)
|
||||
createPositionIterator,
|
||||
};
|
||||
|
||||
const TextureMeshName = 'texture-mesh';
|
||||
|
||||
function createPositionIterator(textureMesh: TextureMesh, transform: TransformData): LocationIterator {
|
||||
const webgl = textureMesh.meta.webgl;
|
||||
if (!webgl) return LocationIterator(1, 1, 1, () => NullLocation);
|
||||
|
||||
if (!webgl.namedFramebuffers[TextureMeshName]) {
|
||||
webgl.namedFramebuffers[TextureMeshName] = webgl.resources.framebuffer();
|
||||
}
|
||||
const framebuffer = webgl.namedFramebuffers[TextureMeshName];
|
||||
const [width, height] = textureMesh.geoTextureDim.ref.value;
|
||||
const vertices = new Float32Array(width * height * 4);
|
||||
framebuffer.bind();
|
||||
textureMesh.vertexTexture.ref.value.attachFramebuffer(framebuffer, 0);
|
||||
webgl.readPixels(0, 0, width, height, vertices);
|
||||
|
||||
const groupCount = textureMesh.vertexCount;
|
||||
const instanceCount = transform.instanceCount.ref.value;
|
||||
const location = PositionLocation();
|
||||
const p = location.position;
|
||||
const v = vertices;
|
||||
const m = transform.aTransform.ref.value;
|
||||
const getLocation = (groupIndex: number, instanceIndex: number) => {
|
||||
if (instanceIndex < 0) {
|
||||
Vec3.fromArray(p, v, groupIndex * 4);
|
||||
} else {
|
||||
Vec3.transformMat4Offset(p, v, m, 0, groupIndex * 4, instanceIndex * 16);
|
||||
}
|
||||
return location;
|
||||
};
|
||||
return LocationIterator(groupCount, instanceCount, 1, getLocation);
|
||||
}
|
||||
|
||||
function createValues(textureMesh: TextureMesh, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: PD.Values<Params>): TextureMeshValues {
|
||||
const { instanceCount, groupCount } = locationIt;
|
||||
const positionIt = Utils.createPositionIterator(textureMesh, transform);
|
||||
|
||||
@@ -21,6 +21,7 @@ export type TransparencyData = {
|
||||
uTransparencyGridDim: ValueCell<Vec3>,
|
||||
uTransparencyGridTransform: ValueCell<Vec4>,
|
||||
dTransparencyType: ValueCell<string>,
|
||||
uTransparencyStrength: ValueCell<number>,
|
||||
}
|
||||
|
||||
export function applyTransparencyValue(array: Uint8Array, start: number, end: number, value: number) {
|
||||
@@ -63,6 +64,7 @@ export function createTransparency(count: number, type: TransparencyType, transp
|
||||
uTransparencyGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uTransparencyGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dTransparencyType: ValueCell.create(type),
|
||||
uTransparencyStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -84,6 +86,7 @@ export function createEmptyTransparency(transparencyData?: TransparencyData): Tr
|
||||
uTransparencyGridDim: ValueCell.create(Vec3.create(1, 1, 1)),
|
||||
uTransparencyGridTransform: ValueCell.create(Vec4.create(0, 0, 0, 1)),
|
||||
dTransparencyType: ValueCell.create('groupInstance'),
|
||||
uTransparencyStrength: ValueCell.create(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -53,17 +53,17 @@ describe('renderer', () => {
|
||||
scene.commit();
|
||||
expect(ctx.stats.resourceCounts.attribute).toBe(ctx.isWebGL2 ? 4 : 5);
|
||||
expect(ctx.stats.resourceCounts.texture).toBe(9);
|
||||
expect(ctx.stats.resourceCounts.vertexArray).toBe(ctx.extensions.vertexArrayObject ? 5 : 0);
|
||||
expect(ctx.stats.resourceCounts.program).toBe(5);
|
||||
expect(ctx.stats.resourceCounts.shader).toBe(10);
|
||||
expect(ctx.stats.resourceCounts.vertexArray).toBe(ctx.extensions.vertexArrayObject ? 6 : 0);
|
||||
expect(ctx.stats.resourceCounts.program).toBe(6);
|
||||
expect(ctx.stats.resourceCounts.shader).toBe(12);
|
||||
|
||||
scene.remove(points);
|
||||
scene.commit();
|
||||
expect(ctx.stats.resourceCounts.attribute).toBe(0);
|
||||
expect(ctx.stats.resourceCounts.texture).toBe(1);
|
||||
expect(ctx.stats.resourceCounts.vertexArray).toBe(0);
|
||||
expect(ctx.stats.resourceCounts.program).toBe(5);
|
||||
expect(ctx.stats.resourceCounts.shader).toBe(10);
|
||||
expect(ctx.stats.resourceCounts.program).toBe(6);
|
||||
expect(ctx.stats.resourceCounts.shader).toBe(12);
|
||||
|
||||
ctx.resources.destroy();
|
||||
expect(ctx.stats.resourceCounts.program).toBe(0);
|
||||
|
||||
@@ -197,7 +197,7 @@ export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture,
|
||||
gl.finish();
|
||||
if (isTimingMode) ctx.timer.markEnd('createHistogramPyramid');
|
||||
|
||||
// printTexture(ctx, pyramidTex, 2)
|
||||
// printTextureImage(readTexture(ctx, pyramidTex), { scale: 0.75 });
|
||||
|
||||
//
|
||||
|
||||
|
||||
@@ -115,6 +115,7 @@ export function calcActiveVoxels(ctx: WebGLContext, volumeData: Texture, gridDim
|
||||
// console.log('gridScale', gridScale, 'gridTexDim', gridTexDim, 'gridDim', gridDim);
|
||||
// console.log('volumeData', volumeData);
|
||||
// console.log('at', readTexture(ctx, activeVoxelsTex));
|
||||
// printTextureImage(readTexture(ctx, activeVoxelsTex), { scale: 0.75 });
|
||||
|
||||
gl.finish();
|
||||
if (isTimingMode) ctx.timer.markEnd('calcActiveVoxels');
|
||||
|
||||
@@ -199,6 +199,10 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
|
||||
gl.finish();
|
||||
if (isTimingMode) ctx.timer.markEnd('createIsosurfaceBuffers');
|
||||
|
||||
// printTextureImage(readTexture(ctx, vertexTexture, new Float32Array(width * height * 4)), { scale: 0.75 });
|
||||
// printTextureImage(readTexture(ctx, groupTexture, new Uint8Array(width * height * 4)), { scale: 0.75 });
|
||||
// printTextureImage(readTexture(ctx, normalTexture, new Float32Array(width * height * 4)), { scale: 0.75 });
|
||||
|
||||
return { vertexTexture, groupTexture, normalTexture, vertexCount: count };
|
||||
}
|
||||
|
||||
|
||||
@@ -75,9 +75,9 @@ export function getSharedCopyRenderable(ctx: WebGLContext, texture: Texture) {
|
||||
const ReadTextureName = 'read-texture';
|
||||
const ReadAlphaTextureName = 'read-alpha-texture';
|
||||
|
||||
export function readTexture(ctx: WebGLContext, texture: Texture) {
|
||||
export function readTexture<T extends Uint8Array | Float32Array | Int32Array = Uint8Array>(ctx: WebGLContext, texture: Texture, array?: T) {
|
||||
const { gl, resources } = ctx;
|
||||
if (texture.type !== gl.UNSIGNED_BYTE) throw new Error('unsupported texture type');
|
||||
if (!array && texture.type !== gl.UNSIGNED_BYTE) throw new Error('unsupported texture type');
|
||||
|
||||
if (!ctx.namedFramebuffers[ReadTextureName]) {
|
||||
ctx.namedFramebuffers[ReadTextureName] = resources.framebuffer();
|
||||
@@ -86,7 +86,7 @@ export function readTexture(ctx: WebGLContext, texture: Texture) {
|
||||
|
||||
const width = texture.getWidth();
|
||||
const height = texture.getHeight();
|
||||
const array = new Uint8Array(width * height * 4);
|
||||
if (!array) array = new Uint8Array(width * height * 4) as T;
|
||||
framebuffer.bind();
|
||||
texture.attachFramebuffer(framebuffer, 0);
|
||||
ctx.readPixels(0, 0, width, height, array);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { ValueCell } from '../../mol-util';
|
||||
@@ -167,6 +168,11 @@ export type GlobalUniformValues = Values<GlobalUniformSchema>
|
||||
|
||||
export const GlobalTextureSchema = {
|
||||
tDepth: TextureSpec('texture', 'depth', 'ushort', 'nearest'),
|
||||
|
||||
// dpoit
|
||||
tDpoitDepth: TextureSpec('texture', 'rg', 'float', 'nearest'),
|
||||
tDpoitFrontColor: TextureSpec('texture', 'rgba', 'float', 'nearest'),
|
||||
tDpoitBackColor: TextureSpec('texture', 'rgba', 'float', 'nearest')
|
||||
} as const;
|
||||
export type GlobalTextureSchema = typeof GlobalTextureSchema
|
||||
export type GlobalTextureValues = Values<GlobalTextureSchema>
|
||||
@@ -223,6 +229,7 @@ export const OverpaintSchema = {
|
||||
uOverpaintGridTransform: UniformSpec('v4'),
|
||||
tOverpaintGrid: TextureSpec('texture', 'rgba', 'ubyte', 'linear'),
|
||||
dOverpaintType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']),
|
||||
uOverpaintStrength: UniformSpec('f', 'material'),
|
||||
} as const;
|
||||
export type OverpaintSchema = typeof OverpaintSchema
|
||||
export type OverpaintValues = Values<OverpaintSchema>
|
||||
@@ -237,6 +244,7 @@ export const TransparencySchema = {
|
||||
uTransparencyGridTransform: UniformSpec('v4'),
|
||||
tTransparencyGrid: TextureSpec('texture', 'alpha', 'ubyte', 'linear'),
|
||||
dTransparencyType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']),
|
||||
uTransparencyStrength: UniformSpec('f', 'material'),
|
||||
} as const;
|
||||
export type TransparencySchema = typeof TransparencySchema
|
||||
export type TransparencyValues = Values<TransparencySchema>
|
||||
@@ -250,6 +258,7 @@ export const SubstanceSchema = {
|
||||
uSubstanceGridTransform: UniformSpec('v4'),
|
||||
tSubstanceGrid: TextureSpec('texture', 'rgba', 'ubyte', 'linear'),
|
||||
dSubstanceType: DefineSpec('string', ['instance', 'groupInstance', 'volumeInstance']),
|
||||
uSubstanceStrength: UniformSpec('f', 'material'),
|
||||
} as const;
|
||||
export type SubstanceSchema = typeof SubstanceSchema
|
||||
export type SubstanceValues = Values<SubstanceSchema>
|
||||
@@ -327,4 +336,4 @@ export const BaseSchema = {
|
||||
invariantBoundingSphere: ValueSpec('sphere'),
|
||||
} as const;
|
||||
export type BaseSchema = typeof BaseSchema
|
||||
export type BaseValues = Values<BaseSchema>
|
||||
export type BaseValues = Values<BaseSchema>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -8,6 +8,7 @@ import { Sphere3D } from '../../mol-math/geometry';
|
||||
import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
|
||||
import { BoundaryHelper } from '../../mol-math/geometry/boundary-helper';
|
||||
import { TextureFilter } from '../webgl/texture';
|
||||
import { arrayMinMax } from '../../mol-util/array';
|
||||
|
||||
export function calculateTextureInfo(n: number, itemSize: number) {
|
||||
n = Math.max(n, 2); // observed issues with 1 pixel textures
|
||||
@@ -42,7 +43,8 @@ export function createTextureImage<T extends Uint8Array | Float32Array>(n: numbe
|
||||
const DefaultPrintImageOptions = {
|
||||
scale: 1,
|
||||
pixelated: false,
|
||||
id: 'molstar.debug.image'
|
||||
id: 'molstar.debug.image',
|
||||
normalize: false,
|
||||
};
|
||||
export type PrintImageOptions = typeof DefaultPrintImageOptions
|
||||
|
||||
@@ -58,7 +60,17 @@ export function printTextureImage(textureImage: TextureImage<any>, options: Part
|
||||
}
|
||||
}
|
||||
} else if (itemSize === 4) {
|
||||
data.set(array);
|
||||
if (options.normalize) {
|
||||
const [min, max] = arrayMinMax(array);
|
||||
for (let i = 0, il = width * height * 4; i < il; i += 4) {
|
||||
data[i] = ((array[i] - min) / (max - min)) * 255;
|
||||
data[i + 1] = ((array[i + 1] - min) / (max - min)) * 255;
|
||||
data[i + 2] = ((array[i + 2] - min) / (max - min)) * 255;
|
||||
data[i + 3] = 255;
|
||||
}
|
||||
} else {
|
||||
data.set(array);
|
||||
}
|
||||
} else {
|
||||
console.warn(`itemSize '${itemSize}' not supported`);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { Viewport } from '../mol-canvas3d/camera/util';
|
||||
@@ -53,6 +54,7 @@ export const enum MarkingType {
|
||||
interface Renderer {
|
||||
readonly stats: RendererStats
|
||||
readonly props: Readonly<RendererProps>
|
||||
readonly light: Readonly<Light>
|
||||
|
||||
clear: (toBackgroundColor: boolean, ignoreTransparentBackground?: boolean) => void
|
||||
clearDepth: (packed?: boolean) => void
|
||||
@@ -70,6 +72,9 @@ interface Renderer {
|
||||
renderBlendedVolume: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
|
||||
renderWboitOpaque: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
|
||||
renderWboitTransparent: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
|
||||
renderDpoitOpaque: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
|
||||
renderDpoitTransparent: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null, dpoitTextures: { depth: Texture, frontColor: Texture, backColor: Texture }) => void
|
||||
renderDpoitVolume: (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => void
|
||||
|
||||
setProps: (props: Partial<RendererProps>) => void
|
||||
setViewport: (x: number, y: number, width: number, height: number) => void
|
||||
@@ -99,13 +104,13 @@ export const RendererParams = {
|
||||
xrayEdgeFalloff: PD.Numeric(1, { min: 0.0, max: 3.0, step: 0.1 }),
|
||||
|
||||
light: PD.ObjectList({
|
||||
inclination: PD.Numeric(180, { min: 0, max: 180, step: 1 }),
|
||||
azimuth: PD.Numeric(0, { min: 0, max: 360, step: 1 }),
|
||||
inclination: PD.Numeric(150, { min: 0, max: 180, step: 1 }),
|
||||
azimuth: PD.Numeric(320, { min: 0, max: 360, step: 1 }),
|
||||
color: PD.Color(Color.fromNormalizedRgb(1.0, 1.0, 1.0)),
|
||||
intensity: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }),
|
||||
}, o => Color.toHexString(o.color), { defaultValue: [{
|
||||
inclination: 180,
|
||||
azimuth: 0,
|
||||
inclination: 150,
|
||||
azimuth: 320,
|
||||
color: Color.fromNormalizedRgb(1.0, 1.0, 1.0),
|
||||
intensity: 0.6
|
||||
}] }),
|
||||
@@ -114,7 +119,7 @@ export const RendererParams = {
|
||||
};
|
||||
export type RendererProps = PD.Values<typeof RendererParams>
|
||||
|
||||
type Light = {
|
||||
export type Light = {
|
||||
count: number
|
||||
direction: number[]
|
||||
color: number[]
|
||||
@@ -141,7 +146,7 @@ namespace Renderer {
|
||||
const enum Flag {
|
||||
None = 0,
|
||||
BlendedFront = 1,
|
||||
BlendedBack = 2
|
||||
BlendedBack = 2,
|
||||
}
|
||||
|
||||
const enum Mask {
|
||||
@@ -268,7 +273,7 @@ namespace Renderer {
|
||||
}
|
||||
|
||||
if (r.values.dGeometryType.ref.value === 'directVolume') {
|
||||
if (variant !== 'colorWboit' && variant !== 'colorBlended') {
|
||||
if (variant !== 'colorDpoit' && variant !== 'colorWboit' && variant !== 'colorBlended') {
|
||||
return; // only color supported
|
||||
}
|
||||
|
||||
@@ -602,6 +607,71 @@ namespace Renderer {
|
||||
if (isTimingMode) ctx.timer.markEnd('Renderer.renderWboitTransparent');
|
||||
};
|
||||
|
||||
const renderDpoitOpaque = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
|
||||
if (isTimingMode) ctx.timer.mark('Renderer.renderDpoitOpaque');
|
||||
state.disable(gl.BLEND);
|
||||
state.enable(gl.DEPTH_TEST);
|
||||
state.depthMask(true);
|
||||
|
||||
updateInternal(group, camera, depthTexture, Mask.Opaque, false);
|
||||
|
||||
const { renderables } = group;
|
||||
for (let i = 0, il = renderables.length; i < il; ++i) {
|
||||
const r = renderables[i];
|
||||
|
||||
// TODO: simplify, handle in renderable.state???
|
||||
// uAlpha is updated in "render" so we need to recompute it here
|
||||
const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
|
||||
if ((alpha === 1 && r.values.transparencyAverage.ref.value !== 1 && r.values.dPointStyle?.ref.value !== 'fuzzy' && !r.values.dXrayShaded?.ref.value) || r.values.dTransparentBackfaces?.ref.value === 'opaque') {
|
||||
renderObject(r, 'colorDpoit', Flag.None);
|
||||
}
|
||||
}
|
||||
if (isTimingMode) ctx.timer.markEnd('Renderer.renderDpoitOpaque');
|
||||
};
|
||||
|
||||
const renderDpoitTransparent = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null, dpoitTextures: { depth: Texture, frontColor: Texture, backColor: Texture }) => {
|
||||
if (isTimingMode) ctx.timer.mark('Renderer.renderDpoitTransparent');
|
||||
|
||||
state.enable(gl.BLEND);
|
||||
|
||||
arrayMapUpsert(sharedTexturesList, 'tDpoitDepth', dpoitTextures.depth);
|
||||
arrayMapUpsert(sharedTexturesList, 'tDpoitFrontColor', dpoitTextures.frontColor);
|
||||
arrayMapUpsert(sharedTexturesList, 'tDpoitBackColor', dpoitTextures.backColor);
|
||||
|
||||
updateInternal(group, camera, depthTexture, Mask.Transparent, false);
|
||||
|
||||
const { renderables } = group;
|
||||
|
||||
for (let i = 0, il = renderables.length; i < il; ++i) {
|
||||
const r = renderables[i];
|
||||
|
||||
// TODO: simplify, handle in renderable.state???
|
||||
// uAlpha is updated in "render" so we need to recompute it here
|
||||
const alpha = clamp(r.values.alpha.ref.value * r.state.alphaFactor, 0, 1);
|
||||
if (alpha < 1 || r.values.transparencyAverage.ref.value > 0 || r.values.dPointStyle?.ref.value === 'fuzzy' || !!r.values.uBackgroundColor || r.values.dXrayShaded?.ref.value) {
|
||||
renderObject(r, 'colorDpoit', Flag.None);
|
||||
}
|
||||
}
|
||||
if (isTimingMode) ctx.timer.markEnd('Renderer.renderDpoitTransparent');
|
||||
};
|
||||
|
||||
const renderDpoitVolume = (group: Scene.Group, camera: ICamera, depthTexture: Texture | null) => {
|
||||
if (isTimingMode) ctx.timer.mark('Renderer.renderDpoitVolume');
|
||||
state.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
state.enable(gl.BLEND);
|
||||
|
||||
updateInternal(group, camera, depthTexture, Mask.Transparent, false);
|
||||
|
||||
const { renderables } = group;
|
||||
for (let i = 0, il = renderables.length; i < il; ++i) {
|
||||
const r = renderables[i];
|
||||
if (r.values.dGeometryType.ref.value === 'directVolume') {
|
||||
renderObject(r, 'colorDpoit', Flag.None);
|
||||
}
|
||||
}
|
||||
if (isTimingMode) ctx.timer.markEnd('Renderer.renderDpoitVolume');
|
||||
};
|
||||
|
||||
return {
|
||||
clear: (toBackgroundColor: boolean, ignoreTransparentBackground?: boolean) => {
|
||||
state.enable(gl.SCISSOR_TEST);
|
||||
@@ -645,6 +715,9 @@ namespace Renderer {
|
||||
renderBlendedVolume,
|
||||
renderWboitOpaque,
|
||||
renderWboitTransparent,
|
||||
renderDpoitOpaque,
|
||||
renderDpoitTransparent,
|
||||
renderDpoitVolume,
|
||||
|
||||
setProps: (props: Partial<RendererProps>) => {
|
||||
if (props.backgroundColor !== undefined && props.backgroundColor !== p.backgroundColor) {
|
||||
@@ -755,6 +828,9 @@ namespace Renderer {
|
||||
instancedDrawCount: stats.instancedDrawCount,
|
||||
};
|
||||
},
|
||||
get light(): Light {
|
||||
return light;
|
||||
},
|
||||
dispose: () => {
|
||||
// TODO
|
||||
}
|
||||
@@ -762,4 +838,4 @@ namespace Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
export { Renderer };
|
||||
export { Renderer };
|
||||
|
||||
@@ -45,8 +45,8 @@ function calculateBoundingSphere(renderables: GraphicsRenderable[], boundingSphe
|
||||
}
|
||||
|
||||
function renderableSort(a: GraphicsRenderable, b: GraphicsRenderable) {
|
||||
const drawProgramIdA = (a.getProgram('colorBlended') || a.getProgram('colorWboit')).id;
|
||||
const drawProgramIdB = (b.getProgram('colorBlended') || a.getProgram('colorWboit')).id;
|
||||
const drawProgramIdA = (a.getProgram('colorBlended') || a.getProgram('colorWboit') || a.getProgram('colorDpoit')).id;
|
||||
const drawProgramIdB = (b.getProgram('colorBlended') || b.getProgram('colorWboit') || b.getProgram('colorDpoit')).id;
|
||||
const materialIdA = a.materialId;
|
||||
const materialIdB = b.materialId;
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ import { texture3d_from_1d_trilinear } from './shader/chunks/texture3d-from-1d-t
|
||||
import { texture3d_from_2d_linear } from './shader/chunks/texture3d-from-2d-linear.glsl';
|
||||
import { texture3d_from_2d_nearest } from './shader/chunks/texture3d-from-2d-nearest.glsl';
|
||||
import { wboit_write } from './shader/chunks/wboit-write.glsl';
|
||||
import { dpoit_write } from './shader/chunks/dpoit-write.glsl';
|
||||
|
||||
const ShaderChunks: { [k: string]: string } = {
|
||||
apply_fog,
|
||||
@@ -99,7 +100,8 @@ const ShaderChunks: { [k: string]: string } = {
|
||||
texture3d_from_1d_trilinear,
|
||||
texture3d_from_2d_linear,
|
||||
texture3d_from_2d_nearest,
|
||||
wboit_write
|
||||
wboit_write,
|
||||
dpoit_write
|
||||
};
|
||||
|
||||
const reInclude = /^(?!\/\/)\s*#include\s+(\S+)/gm;
|
||||
|
||||
@@ -6,6 +6,7 @@ precision mediump sampler2D;
|
||||
#if defined(dVariant_skybox)
|
||||
uniform samplerCube tSkybox;
|
||||
uniform mat4 uViewDirectionProjectionInverse;
|
||||
uniform float uBlur;
|
||||
uniform float uOpacity;
|
||||
uniform float uSaturation;
|
||||
uniform float uLightness;
|
||||
@@ -49,7 +50,11 @@ vec3 lightenColor(vec3 c, float amount) {
|
||||
void main() {
|
||||
#if defined(dVariant_skybox)
|
||||
vec4 t = uViewDirectionProjectionInverse * vPosition;
|
||||
gl_FragColor = textureCube(tSkybox, normalize(t.xyz / t.w));
|
||||
#ifdef enabledShaderTextureLod
|
||||
gl_FragColor = textureCubeLodEXT(tSkybox, normalize(t.xyz / t.w), uBlur * 8.0);
|
||||
#else
|
||||
gl_FragColor = textureCube(tSkybox, normalize(t.xyz / t.w));
|
||||
#endif
|
||||
gl_FragColor.a = uOpacity;
|
||||
gl_FragColor.rgb = lightenColor(saturateColor(gl_FragColor.rgb, uSaturation), uLightness);
|
||||
#elif defined(dVariant_image)
|
||||
|
||||
20
src/mol-gl/shader/blend-back-dpoit.frag.ts
Normal file
20
src/mol-gl/shader/blend-back-dpoit.frag.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
export const blendBackDpoit_frag = `
|
||||
precision highp float;
|
||||
|
||||
uniform sampler2D tDpoitBackColor;
|
||||
uniform vec2 uTexSize;
|
||||
|
||||
void main() {
|
||||
vec2 coords = gl_FragCoord.xy / uTexSize;
|
||||
gl_FragColor = texture2D(tDpoitBackColor, coords);
|
||||
if (gl_FragColor.a == 0.0) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -12,8 +12,19 @@ if (!uTransparentBackground) {
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, uFogColor, fogFactor);
|
||||
}
|
||||
} else {
|
||||
// pre-multiplied alpha expected for transparent background
|
||||
gl_FragColor.rgb *= fogAlpha;
|
||||
gl_FragColor.a = fogAlpha;
|
||||
#if defined(dRenderVariant_colorDpoit)
|
||||
if (gl_FragColor.a < 1.0) {
|
||||
// transparent objects are blended with background color
|
||||
gl_FragColor.a = fogAlpha;
|
||||
} else {
|
||||
// opaque objects need to be pre-multiplied alpha
|
||||
gl_FragColor.rgb *= fogAlpha;
|
||||
gl_FragColor.a = fogAlpha;
|
||||
}
|
||||
#else
|
||||
// pre-multiplied alpha expected for transparent background
|
||||
gl_FragColor.rgb *= fogAlpha;
|
||||
gl_FragColor.a = fogAlpha;
|
||||
#endif
|
||||
}
|
||||
`;
|
||||
@@ -57,6 +57,7 @@ export const apply_light_color = `
|
||||
RE_IndirectSpecular_Physical(radiance, iblIrradiance, clearcoatRadiance, geometry, physicalMaterial, reflectedLight);
|
||||
|
||||
vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular;
|
||||
outgoingLight = clamp(outgoingLight, 0.01, 0.99); // prevents black artifacts on specular highlight with transparent background
|
||||
|
||||
gl_FragColor = vec4(outgoingLight, color.a);
|
||||
#endif
|
||||
|
||||
@@ -42,6 +42,7 @@ export const assign_color_varying = `
|
||||
#else
|
||||
vOverpaint.rgb = mix(vColor.rgb, vOverpaint.rgb, vOverpaint.a);
|
||||
#endif
|
||||
vOverpaint *= uOverpaintStrength;
|
||||
#endif
|
||||
|
||||
#ifdef dSubstance
|
||||
@@ -58,6 +59,7 @@ export const assign_color_varying = `
|
||||
|
||||
// pre-mix to avoid artifacts due to empty substance
|
||||
vSubstance.rgb = mix(vec3(uMetalness, uRoughness, uBumpiness), vSubstance.rgb, vSubstance.a);
|
||||
vSubstance *= uSubstanceStrength;
|
||||
#endif
|
||||
#elif defined(dRenderVariant_pick)
|
||||
#ifdef requiredDrawBuffers
|
||||
@@ -86,5 +88,6 @@ export const assign_color_varying = `
|
||||
vec3 tgridPos = (uTransparencyGridTransform.w * (vModelPosition - uTransparencyGridTransform.xyz)) / uTransparencyGridDim;
|
||||
vTransparency = texture3dFrom2dLinear(tTransparencyGrid, tgridPos, uTransparencyGridDim, uTransparencyTexDim).a;
|
||||
#endif
|
||||
vTransparency *= uTransparencyStrength;
|
||||
#endif
|
||||
`;
|
||||
@@ -86,7 +86,7 @@ export const assign_material_color = `
|
||||
// apply per-group transparency
|
||||
#if defined(dTransparency) && (defined(dRenderVariant_pick) || defined(dRenderVariant_color))
|
||||
float ta = 1.0 - vTransparency;
|
||||
if (vTransparency < 0.2) ta = 1.0; // hard cutoff looks better
|
||||
if (vTransparency < 0.09) ta = 1.0; // hard cutoff looks better
|
||||
|
||||
#if defined(dRenderVariant_pick)
|
||||
if (ta < uPickingAlphaThreshold)
|
||||
|
||||
@@ -39,6 +39,7 @@ uniform float uBumpiness;
|
||||
uniform vec4 uOverpaintGridTransform;
|
||||
uniform sampler2D tOverpaintGrid;
|
||||
#endif
|
||||
uniform float uOverpaintStrength;
|
||||
#endif
|
||||
|
||||
#ifdef dSubstance
|
||||
@@ -53,6 +54,7 @@ uniform float uBumpiness;
|
||||
uniform vec4 uSubstanceGridTransform;
|
||||
uniform sampler2D tSubstanceGrid;
|
||||
#endif
|
||||
uniform float uSubstanceStrength;
|
||||
#endif
|
||||
#elif defined(dRenderVariant_pick)
|
||||
#if __VERSION__ == 100 || !defined(dVaryingGroup)
|
||||
@@ -86,5 +88,6 @@ uniform float uBumpiness;
|
||||
uniform vec4 uTransparencyGridTransform;
|
||||
uniform sampler2D tTransparencyGrid;
|
||||
#endif
|
||||
uniform float uTransparencyStrength;
|
||||
#endif
|
||||
`;
|
||||
@@ -39,6 +39,12 @@ uniform int uMarkingType;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(dRenderVariant_colorDpoit)
|
||||
#define MAX_DPOIT_DEPTH 99999.0 // NOTE constant also set in TypeScript
|
||||
uniform sampler2D tDpoitDepth;
|
||||
uniform sampler2D tDpoitFrontColor;
|
||||
#endif
|
||||
|
||||
varying vec3 vModelPosition;
|
||||
varying vec3 vViewPosition;
|
||||
|
||||
|
||||
@@ -44,10 +44,9 @@ varying vec3 vModelPosition;
|
||||
varying vec3 vViewPosition;
|
||||
|
||||
#if defined(noNonInstancedActiveAttribs)
|
||||
#define VertexID gl_VertexID // for testing
|
||||
// // int() is needed for some Safari versions
|
||||
// // see https://bugs.webkit.org/show_bug.cgi?id=244152
|
||||
// #define VertexID int(gl_VertexID)
|
||||
// int() is needed for some Safari versions
|
||||
// see https://bugs.webkit.org/show_bug.cgi?id=244152
|
||||
#define VertexID int(gl_VertexID)
|
||||
#else
|
||||
attribute float aVertex;
|
||||
#define VertexID int(aVertex)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const common = `
|
||||
// TODO find a better place for these convenience defines
|
||||
|
||||
#if defined(dRenderVariant_colorBlended) || defined(dRenderVariant_colorWboit)
|
||||
#if defined(dRenderVariant_colorBlended) || defined(dRenderVariant_colorWboit) || defined(dRenderVariant_colorDpoit)
|
||||
#define dRenderVariant_color
|
||||
#endif
|
||||
|
||||
|
||||
70
src/mol-gl/shader/chunks/dpoit-write.glsl.ts
Normal file
70
src/mol-gl/shader/chunks/dpoit-write.glsl.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
export const dpoit_write = `
|
||||
#if defined(dRenderVariant_colorDpoit)
|
||||
if (uRenderMask == MaskOpaque) {
|
||||
if (preFogAlpha < 1.0) {
|
||||
discard;
|
||||
}
|
||||
} else if (uRenderMask == MaskTransparent) {
|
||||
// the 'fragmentDepth > 0.99' check is to handle precision issues with packed depth
|
||||
vec2 coords = gl_FragCoord.xy / uDrawingBufferSize;
|
||||
if (preFogAlpha != 1.0 && (fragmentDepth < getDepth(coords) || fragmentDepth > 0.99)) {
|
||||
#ifdef dTransparentBackfaces_off
|
||||
if (interior) discard;
|
||||
#endif
|
||||
|
||||
// adapted from https://github.com/tsherif/webgl2examples
|
||||
// The MIT License, Copyright 2017 Tarek Sherif, Shuai Shao
|
||||
|
||||
vec2 lastDepth = texture2D(tDpoitDepth, coords).rg;
|
||||
vec4 lastFrontColor = texture2D(tDpoitFrontColor, coords);
|
||||
|
||||
vec4 fragColor = gl_FragColor;
|
||||
|
||||
// depth value always increases
|
||||
// so we can use MAX blend equation
|
||||
gl_FragData[2].rg = vec2(-MAX_DPOIT_DEPTH);
|
||||
|
||||
// front color always increases
|
||||
// so we can use MAX blend equation
|
||||
gl_FragColor = lastFrontColor;
|
||||
|
||||
// back color is separately blend afterwards each pass
|
||||
gl_FragData[1] = vec4(0.0);
|
||||
|
||||
float nearestDepth = -lastDepth.x;
|
||||
float furthestDepth = lastDepth.y;
|
||||
float alphaMultiplier = 1.0 - lastFrontColor.a;
|
||||
|
||||
if (fragmentDepth < nearestDepth || fragmentDepth > furthestDepth) {
|
||||
// Skip this depth since it's been peeled.
|
||||
return;
|
||||
}
|
||||
|
||||
if (fragmentDepth > nearestDepth && fragmentDepth < furthestDepth) {
|
||||
// This needs to be peeled.
|
||||
// The ones remaining after MAX blended for
|
||||
// all need-to-peel will be peeled next pass.
|
||||
gl_FragData[2].rg = vec2(-fragmentDepth, fragmentDepth);
|
||||
return;
|
||||
}
|
||||
|
||||
// write to back and front color buffer
|
||||
if (fragmentDepth == nearestDepth) {
|
||||
gl_FragColor.rgb += fragColor.rgb * fragColor.a * alphaMultiplier;
|
||||
gl_FragColor.a = 1.0 - alphaMultiplier * (1.0 - fragColor.a);
|
||||
} else {
|
||||
gl_FragData[1] += fragColor;
|
||||
}
|
||||
|
||||
} else {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
`;
|
||||
@@ -109,14 +109,14 @@ void main() {
|
||||
|
||||
vec3 vViewPosition = vModelPosition + intersection.x * rayDir;
|
||||
vViewPosition = (uView * vec4(vViewPosition, 1.0)).xyz;
|
||||
gl_FragDepthEXT = calcDepth(vViewPosition);
|
||||
float fragmentDepth = calcDepth(vViewPosition);
|
||||
|
||||
if (fragmentDepth < 0.0) discard;
|
||||
if (fragmentDepth > 1.0) discard;
|
||||
|
||||
gl_FragDepthEXT = fragmentDepth;
|
||||
|
||||
vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
|
||||
|
||||
if (gl_FragDepthEXT < 0.0) discard;
|
||||
if (gl_FragDepthEXT > 1.0) discard;
|
||||
|
||||
float fragmentDepth = gl_FragDepthEXT;
|
||||
#include assign_material_color
|
||||
|
||||
#if defined(dRenderVariant_pick)
|
||||
@@ -142,6 +142,7 @@ void main() {
|
||||
#include apply_marker_color
|
||||
#include apply_fog
|
||||
#include wboit_write
|
||||
#include dpoit_write
|
||||
#endif
|
||||
}
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -270,16 +270,16 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 rayDir) {
|
||||
#elif defined(dColorType_groupInstance)
|
||||
material.rgb = readFromTexture(tColor, vInstance * float(uGroupCount) + group, uColorTexDim).rgb;
|
||||
#elif defined(dColorType_vertex)
|
||||
material.rgb = texture3dFrom1dTrilinear(tColor, isoPos, uGridDim, uColorTexDim, 0.0).rgb;
|
||||
material.rgb = texture3dFrom1dTrilinear(tColor, unitPos, uGridDim, uColorTexDim, 0.0).rgb;
|
||||
#elif defined(dColorType_vertexInstance)
|
||||
material.rgb = texture3dFrom1dTrilinear(tColor, isoPos, uGridDim, uColorTexDim, vInstance * float(uVertexCount)).rgb;
|
||||
material.rgb = texture3dFrom1dTrilinear(tColor, unitPos, uGridDim, uColorTexDim, vInstance * float(uVertexCount)).rgb;
|
||||
#endif
|
||||
|
||||
#ifdef dOverpaint
|
||||
#if defined(dOverpaintType_groupInstance)
|
||||
overpaint = readFromTexture(tOverpaint, vInstance * float(uGroupCount) + group, uOverpaintTexDim);
|
||||
#elif defined(dOverpaintType_vertexInstance)
|
||||
overpaint = texture3dFrom1dTrilinear(tOverpaint, isoPos, uGridDim, uOverpaintTexDim, vInstance * float(uVertexCount));
|
||||
overpaint = texture3dFrom1dTrilinear(tOverpaint, unitPos, uGridDim, uOverpaintTexDim, vInstance * float(uVertexCount));
|
||||
#endif
|
||||
|
||||
material.rgb = mix(material.rgb, overpaint.rgb, overpaint.a);
|
||||
@@ -356,4 +356,4 @@ void main() {
|
||||
float preFogAlpha = clamp(preFogAlphaBlended, 0.0, 1.0);
|
||||
#include wboit_write
|
||||
}
|
||||
`;
|
||||
`;
|
||||
|
||||
17
src/mol-gl/shader/evaluate-dpoit.frag.ts
Normal file
17
src/mol-gl/shader/evaluate-dpoit.frag.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
export const evaluateDpoit_frag = `
|
||||
precision highp float;
|
||||
|
||||
uniform sampler2D tDpoitFrontColor;
|
||||
uniform vec2 uTexSize;
|
||||
|
||||
void main() {
|
||||
vec2 coords = gl_FragCoord.xy / uTexSize;
|
||||
gl_FragColor = texture2D(tDpoitFrontColor, coords);
|
||||
}
|
||||
`;
|
||||
@@ -159,6 +159,7 @@ void main() {
|
||||
#include apply_marker_color
|
||||
#include apply_fog
|
||||
#include wboit_write
|
||||
#include dpoit_write
|
||||
#endif
|
||||
}
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -39,6 +39,7 @@ void main(){
|
||||
#include apply_marker_color
|
||||
#include apply_fog
|
||||
#include wboit_write
|
||||
#include dpoit_write
|
||||
#endif
|
||||
}
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -62,6 +62,7 @@ void main() {
|
||||
#include apply_marker_color
|
||||
#include apply_fog
|
||||
#include wboit_write
|
||||
#include dpoit_write
|
||||
#endif
|
||||
}
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -55,6 +55,7 @@ void main(){
|
||||
#include apply_marker_color
|
||||
#include apply_fog
|
||||
#include wboit_write
|
||||
#include dpoit_write
|
||||
#endif
|
||||
}
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -14,6 +14,7 @@ uniform sampler2D tSsaoDepth;
|
||||
uniform sampler2D tColor;
|
||||
uniform sampler2D tDepthOpaque;
|
||||
uniform sampler2D tDepthTransparent;
|
||||
uniform sampler2D tShadows;
|
||||
uniform sampler2D tOutlines;
|
||||
uniform vec2 uTexSize;
|
||||
|
||||
@@ -120,7 +121,20 @@ void main(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// outline needs to be handled after occlusion to keep them clean
|
||||
#ifdef dShadowEnable
|
||||
if (!isBackground(opaqueDepth)) {
|
||||
viewDist = abs(getViewZ(opaqueDepth));
|
||||
fogFactor = smoothstep(uFogNear, uFogFar, viewDist);
|
||||
vec4 shadow = texture2D(tShadows, coords);
|
||||
if (!uTransparentBackground) {
|
||||
color.rgb = mix(mix(vec3(0), uFogColor, fogFactor), color.rgb, shadow.a);
|
||||
} else {
|
||||
color.rgb = mix(vec3(0) * (1.0 - fogFactor), color.rgb, shadow.a);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// outline needs to be handled after occlusion and shadow to keep them clean
|
||||
#ifdef dOutlineEnable
|
||||
float closestTexel;
|
||||
float outline = getOutline(coords, opaqueDepth, closestTexel);
|
||||
|
||||
131
src/mol-gl/shader/shadows.frag.ts
Normal file
131
src/mol-gl/shader/shadows.frag.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Ludovic Autin <ludovic.autin@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
export const shadows_frag = `
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
precision highp sampler2D;
|
||||
|
||||
#include common
|
||||
|
||||
uniform sampler2D tDepth;
|
||||
uniform vec2 uTexSize;
|
||||
uniform vec4 uBounds;
|
||||
|
||||
uniform float uNear;
|
||||
uniform float uFar;
|
||||
|
||||
#if dLightCount != 0
|
||||
uniform vec3 uLightDirection[dLightCount];
|
||||
uniform vec3 uLightColor[dLightCount];
|
||||
#endif
|
||||
|
||||
uniform mat4 uProjection;
|
||||
uniform mat4 uInvProjection;
|
||||
|
||||
uniform float uMaxDistance;
|
||||
uniform float uTolerance;
|
||||
uniform float uBias;
|
||||
|
||||
bool isBackground(const in float depth) {
|
||||
return depth == 1.0;
|
||||
}
|
||||
|
||||
bool outsideBounds(const in vec2 p) {
|
||||
return p.x < uBounds.x || p.y < uBounds.y || p.x > uBounds.z || p.y > uBounds.w;
|
||||
}
|
||||
|
||||
float getViewZ(const in float depth) {
|
||||
#if dOrthographic == 1
|
||||
return orthographicDepthToViewZ(depth, uNear, uFar);
|
||||
#else
|
||||
return perspectiveDepthToViewZ(depth, uNear, uFar);
|
||||
#endif
|
||||
}
|
||||
|
||||
float getDepth(const in vec2 coords) {
|
||||
#ifdef depthTextureSupport
|
||||
return texture2D(tDepth, coords).r;
|
||||
#else
|
||||
return unpackRGBAToDepth(texture2D(tDepth, coords));
|
||||
#endif
|
||||
}
|
||||
|
||||
float screenFade(const in vec2 coords) {
|
||||
vec2 c = (coords - uBounds.xy) / (uBounds.zw - uBounds.xy);
|
||||
vec2 fade = max(12.0 * abs(c - 0.5) - 5.0, vec2(0.0));
|
||||
return saturate(1.0 - dot(fade, fade));
|
||||
}
|
||||
|
||||
// based on https://panoskarabelas.com/posts/screen_space_shadows/
|
||||
float screenSpaceShadow(const in vec3 position, const in vec3 lightDirection, const in float stepLength) {
|
||||
// Ray position and direction (in view-space)
|
||||
vec3 rayPos = position;
|
||||
vec3 rayDir = -lightDirection;
|
||||
|
||||
// Compute ray step
|
||||
vec3 rayStep = rayDir * stepLength;
|
||||
|
||||
// Ray march towards the light
|
||||
float occlusion = 0.0;
|
||||
vec4 rayCoords = vec4(0.0);
|
||||
for (int i = 0; i < dSteps; ++i) {
|
||||
// Step the ray
|
||||
rayPos += rayStep;
|
||||
|
||||
rayCoords = uProjection * vec4(rayPos, 1.0);
|
||||
rayCoords.xyz = (rayCoords.xyz / rayCoords.w) * 0.5 + 0.5;
|
||||
|
||||
if (outsideBounds(rayCoords.xy))
|
||||
return 1.0;
|
||||
|
||||
// Compute the difference between the ray's and the camera's depth
|
||||
float depth = getDepth(rayCoords.xy);
|
||||
float viewZ = getViewZ(depth);
|
||||
float zDelta = rayPos.z - viewZ;
|
||||
|
||||
if (zDelta < uTolerance) {
|
||||
occlusion = 1.0;
|
||||
|
||||
// Fade out as we approach the edges of the screen
|
||||
occlusion *= screenFade(rayCoords.xy);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1.0 - (uBias * occlusion);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec2 invTexSize = 1.0 / uTexSize;
|
||||
vec2 selfCoords = gl_FragCoord.xy * invTexSize;
|
||||
|
||||
float selfDepth = getDepth(selfCoords);
|
||||
|
||||
if (isBackground(selfDepth)) {
|
||||
gl_FragColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 selfViewPos = screenSpaceToViewSpace(vec3(selfCoords, selfDepth), uInvProjection);
|
||||
float stepLength = uMaxDistance / float(dSteps);
|
||||
|
||||
float o = 1.0;
|
||||
#if dLightCount != 0
|
||||
float sh[dLightCount];
|
||||
#pragma unroll_loop_start
|
||||
for (int i = 0; i < dLightCount; ++i) {
|
||||
sh[i] = screenSpaceShadow(selfViewPos, uLightDirection[i], stepLength);
|
||||
o = min(o, sh[i]);
|
||||
}
|
||||
#pragma unroll_loop_end
|
||||
#endif
|
||||
|
||||
gl_FragColor = vec4(o);
|
||||
}
|
||||
`;
|
||||
@@ -70,17 +70,17 @@ void main(void){
|
||||
}
|
||||
|
||||
vec3 vViewPosition = cameraPos;
|
||||
gl_FragDepthEXT = calcDepth(vViewPosition);
|
||||
if (!flag && gl_FragDepthEXT >= 0.0) {
|
||||
gl_FragDepthEXT = 0.0 + (0.0000001 / vRadius);
|
||||
float fragmentDepth = calcDepth(vViewPosition);
|
||||
if (!flag && fragmentDepth >= 0.0) {
|
||||
fragmentDepth = 0.0 + (0.0000001 / vRadius);
|
||||
}
|
||||
|
||||
if (fragmentDepth < 0.0) discard;
|
||||
if (fragmentDepth > 1.0) discard;
|
||||
|
||||
gl_FragDepthEXT = fragmentDepth;
|
||||
|
||||
vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
|
||||
|
||||
if (gl_FragDepthEXT < 0.0) discard;
|
||||
if (gl_FragDepthEXT > 1.0) discard;
|
||||
|
||||
float fragmentDepth = gl_FragDepthEXT;
|
||||
#include assign_material_color
|
||||
|
||||
#if defined(dRenderVariant_pick)
|
||||
@@ -105,6 +105,7 @@ void main(void){
|
||||
#include apply_marker_color
|
||||
#include apply_fog
|
||||
#include wboit_write
|
||||
#include dpoit_write
|
||||
#endif
|
||||
}
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -83,6 +83,7 @@ void main(){
|
||||
#include apply_marker_color
|
||||
#include apply_fog
|
||||
#include wboit_write
|
||||
#include dpoit_write
|
||||
#endif
|
||||
}
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -19,6 +19,9 @@ export function isWebGL2(gl: any): gl is WebGL2RenderingContext {
|
||||
return typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/ANGLE_instanced_arrays/
|
||||
*/
|
||||
export interface COMPAT_instanced_arrays {
|
||||
drawArraysInstanced(mode: number, first: number, count: number, primcount: number): void;
|
||||
drawElementsInstanced(mode: number, count: number, type: number, offset: number, primcount: number): void;
|
||||
@@ -46,6 +49,9 @@ export function getInstancedArrays(gl: GLRenderingContext): COMPAT_instanced_arr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/OES_standard_derivatives/
|
||||
*/
|
||||
export interface COMPAT_standard_derivatives {
|
||||
readonly FRAGMENT_SHADER_DERIVATIVE_HINT: number;
|
||||
}
|
||||
@@ -60,6 +66,9 @@ export function getStandardDerivatives(gl: GLRenderingContext): COMPAT_standard_
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/OES_element_index_uint/
|
||||
*/
|
||||
export interface COMPAT_element_index_uint {
|
||||
}
|
||||
|
||||
@@ -67,6 +76,9 @@ export function getElementIndexUint(gl: GLRenderingContext): COMPAT_element_inde
|
||||
return isWebGL2(gl) ? {} : gl.getExtension('OES_element_index_uint');
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/OES_vertex_array_object/
|
||||
*/
|
||||
export interface COMPAT_vertex_array_object {
|
||||
readonly VERTEX_ARRAY_BINDING: number;
|
||||
bindVertexArray(arrayObject: WebGLVertexArrayObject | null): void;
|
||||
@@ -132,6 +144,9 @@ export function getTextureHalfFloatLinear(gl: GLRenderingContext): COMPAT_textur
|
||||
return gl.getExtension('OES_texture_half_float_linear');
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/EXT_blend_minmax/
|
||||
*/
|
||||
export interface COMPAT_blend_minmax {
|
||||
readonly MIN: number
|
||||
readonly MAX: number
|
||||
@@ -147,6 +162,9 @@ export function getBlendMinMax(gl: GLRenderingContext): COMPAT_blend_minmax | nu
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/EXT_frag_depth/
|
||||
*/
|
||||
export interface COMPAT_frag_depth {
|
||||
}
|
||||
|
||||
@@ -196,6 +214,9 @@ export function getColorBufferHalfFloat(gl: GLRenderingContext): COMPAT_color_bu
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/WEBGL_draw_buffers/
|
||||
*/
|
||||
export interface COMPAT_draw_buffers {
|
||||
drawBuffers(buffers: number[]): void;
|
||||
readonly COLOR_ATTACHMENT0: number;
|
||||
@@ -268,6 +289,73 @@ export function getDrawBuffers(gl: GLRenderingContext): COMPAT_draw_buffers | nu
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/OES_draw_buffers_indexed/
|
||||
*/
|
||||
export interface COMPAT_draw_buffers_indexed {
|
||||
/**
|
||||
* Enables blending for an individual draw buffer.
|
||||
*
|
||||
* @param target must be BLEND.
|
||||
* @param index is an integer i specifying the draw buffer associated with the symbolic constant DRAW_BUFFERi.
|
||||
*/
|
||||
enablei: (target: number, index: number) => void;
|
||||
/**
|
||||
* Disables blending for an individual draw buffer.
|
||||
*
|
||||
* @param target must be BLEND.
|
||||
* @param index is an integer i specifying the draw buffer associated with the symbolic constant DRAW_BUFFERi.
|
||||
*/
|
||||
disablei: (buf: number, mode: number) => void;
|
||||
/**
|
||||
* The buf argument is an integer i that indicates that the blend equations should be modified for DRAW_BUFFERi.
|
||||
*
|
||||
* mode accepts the same tokens as mode in blendEquation.
|
||||
*/
|
||||
blendEquationi: (target: number, index: number) => void;
|
||||
/**
|
||||
* The buf argument is an integer i that indicates that the blend equations should be modified for DRAW_BUFFERi.
|
||||
*
|
||||
* modeRGB and modeAlpha accept the same tokens as modeRGB and modeAlpha in blendEquationSeparate.
|
||||
*/
|
||||
blendEquationSeparatei: (buf: number, modeRGB: number, modeAlpha: number) => void;
|
||||
/**
|
||||
* The buf argument is an integer i that indicates that the blend functions should be modified for DRAW_BUFFERi.
|
||||
*
|
||||
* src and dst accept the same tokens as src and dst in blendFunc.
|
||||
*/
|
||||
blendFunci: (buf: number, src: number, dst: number) => void;
|
||||
/**
|
||||
* The buf argument is an integer i that indicates that the blend functions should be modified for DRAW_BUFFERi.
|
||||
*
|
||||
* srcRGB, dstRGB, srcAlpha, and dstAlpha accept the same tokens as srcRGB, dstRGB, srcAlpha, and dstAlpha parameters in blendEquationSeparate.
|
||||
*/
|
||||
blendFuncSeparatei: (buf: number, srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => void;
|
||||
/**
|
||||
* The buf argument is an integer i that indicates that the write mask should be modified for DRAW_BUFFERi.
|
||||
*
|
||||
* r, g, b, and a indicate whether R, G, B, or A values, respectively, are written or not (a value of TRUE means that the corresponding value is written).
|
||||
*/
|
||||
colorMaski: (buf: number, r: boolean, g: boolean, b: boolean, a: boolean) => void;
|
||||
}
|
||||
|
||||
export function getDrawBuffersIndexed(gl: GLRenderingContext): COMPAT_draw_buffers_indexed | null {
|
||||
const ext = gl.getExtension('OES_draw_buffers_indexed');
|
||||
if (ext === null) return null;
|
||||
return {
|
||||
enablei: ext.enableiOES.bind(ext),
|
||||
disablei: ext.disableiOES.bind(ext),
|
||||
blendEquationi: ext.blendEquationiOES.bind(ext),
|
||||
blendEquationSeparatei: ext.blendEquationSeparateiOES.bind(ext),
|
||||
blendFunci: ext.blendFunciOES.bind(ext),
|
||||
blendFuncSeparatei: ext.blendFuncSeparateiOES.bind(ext),
|
||||
colorMaski: ext.colorMaskiOES.bind(ext),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/EXT_shader_texture_lod/
|
||||
*/
|
||||
export interface COMPAT_shader_texture_lod {
|
||||
}
|
||||
|
||||
@@ -275,6 +363,9 @@ export function getShaderTextureLod(gl: GLRenderingContext): COMPAT_shader_textu
|
||||
return isWebGL2(gl) ? {} : gl.getExtension('EXT_shader_texture_lod');
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/WEBGL_depth_texture/
|
||||
*/
|
||||
export interface COMPAT_depth_texture {
|
||||
readonly UNSIGNED_INT_24_8: number;
|
||||
}
|
||||
@@ -293,6 +384,9 @@ export function getDepthTexture(gl: GLRenderingContext): COMPAT_depth_texture |
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/EXT_sRGB/
|
||||
*/
|
||||
export interface COMPAT_sRGB {
|
||||
readonly FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: number;
|
||||
readonly SRGB8_ALPHA8: number;
|
||||
@@ -320,6 +414,9 @@ export function getSRGB(gl: GLRenderingContext): COMPAT_sRGB | null {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/EXT_disjoint_timer_query/ and https://registry.khronos.org/webgl/extensions/EXT_disjoint_timer_query_webgl2/
|
||||
*/
|
||||
export interface COMPAT_disjoint_timer_query {
|
||||
/** A GLint indicating the number of bits used to hold the query result for the given target. */
|
||||
QUERY_COUNTER_BITS: number
|
||||
@@ -401,6 +498,31 @@ export function getDisjointTimerQuery(gl: GLRenderingContext): COMPAT_disjoint_t
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/KHR_parallel_shader_compile/
|
||||
*/
|
||||
export interface COMPAT_parallel_shader_compile {
|
||||
readonly COMPLETION_STATUS: number;
|
||||
}
|
||||
|
||||
export function getParallelShaderCompile(gl: GLRenderingContext): COMPAT_parallel_shader_compile | null {
|
||||
const ext = gl.getExtension('KHR_parallel_shader_compile');
|
||||
if (ext === null) return null;
|
||||
return {
|
||||
COMPLETION_STATUS: ext.COMPLETION_STATUS_KHR,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/extensions/OES_fbo_render_mipmap/
|
||||
*/
|
||||
export interface COMPAT_fboRenderMipmap {
|
||||
}
|
||||
|
||||
export function getFboRenderMipmap(gl: GLRenderingContext): COMPAT_fboRenderMipmap | null {
|
||||
return isWebGL2(gl) ? {} : gl.getExtension('OES_fbo_render_mipmap');
|
||||
}
|
||||
|
||||
export function getNoNonInstancedActiveAttribs(gl: GLRenderingContext): boolean {
|
||||
if (!isWebGL2(gl)) return false;
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture, COMPAT_sRGB, getSRGB, getTextureHalfFloat, getTextureHalfFloatLinear, COMPAT_texture_half_float, COMPAT_texture_half_float_linear, COMPAT_color_buffer_half_float, getColorBufferHalfFloat, getVertexArrayObject, getDisjointTimerQuery, COMPAT_disjoint_timer_query, getNoNonInstancedActiveAttribs } from './compat';
|
||||
import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture, COMPAT_sRGB, getSRGB, getTextureHalfFloat, getTextureHalfFloatLinear, COMPAT_texture_half_float, COMPAT_texture_half_float_linear, COMPAT_color_buffer_half_float, getColorBufferHalfFloat, getVertexArrayObject, getDisjointTimerQuery, COMPAT_disjoint_timer_query, getNoNonInstancedActiveAttribs, getDrawBuffersIndexed, COMPAT_draw_buffers_indexed, getParallelShaderCompile, COMPAT_parallel_shader_compile, getFboRenderMipmap, COMPAT_fboRenderMipmap } from './compat';
|
||||
import { isDebugMode } from '../../mol-util/debug';
|
||||
|
||||
export type WebGLExtensions = {
|
||||
instancedArrays: COMPAT_instanced_arrays
|
||||
elementIndexUint: COMPAT_element_index_uint
|
||||
standardDerivatives: COMPAT_standard_derivatives
|
||||
|
||||
standardDerivatives: COMPAT_standard_derivatives | null
|
||||
textureFloat: COMPAT_texture_float | null
|
||||
textureFloatLinear: COMPAT_texture_float_linear | null
|
||||
textureHalfFloat: COMPAT_texture_half_float | null
|
||||
@@ -23,9 +23,12 @@ export type WebGLExtensions = {
|
||||
colorBufferFloat: COMPAT_color_buffer_float | null
|
||||
colorBufferHalfFloat: COMPAT_color_buffer_half_float | null
|
||||
drawBuffers: COMPAT_draw_buffers | null
|
||||
drawBuffersIndexed: COMPAT_draw_buffers_indexed | null
|
||||
shaderTextureLod: COMPAT_shader_texture_lod | null
|
||||
sRGB: COMPAT_sRGB | null
|
||||
disjointTimerQuery: COMPAT_disjoint_timer_query | null
|
||||
parallelShaderCompile: COMPAT_parallel_shader_compile | null
|
||||
fboRenderMipmap: COMPAT_fboRenderMipmap | null
|
||||
|
||||
noNonInstancedActiveAttribs: boolean
|
||||
}
|
||||
@@ -94,6 +97,10 @@ export function createExtensions(gl: GLRenderingContext): WebGLExtensions {
|
||||
if (isDebugMode && drawBuffers === null) {
|
||||
console.log('Could not find support for "draw_buffers"');
|
||||
}
|
||||
const drawBuffersIndexed = getDrawBuffersIndexed(gl);
|
||||
if (isDebugMode && drawBuffersIndexed === null) {
|
||||
console.log('Could not find support for "draw_buffers_indexed"');
|
||||
}
|
||||
const shaderTextureLod = getShaderTextureLod(gl);
|
||||
if (isDebugMode && shaderTextureLod === null) {
|
||||
console.log('Could not find support for "shader_texture_lod"');
|
||||
@@ -106,28 +113,39 @@ export function createExtensions(gl: GLRenderingContext): WebGLExtensions {
|
||||
if (isDebugMode && disjointTimerQuery === null) {
|
||||
console.log('Could not find support for "disjoint_timer_query"');
|
||||
}
|
||||
const parallelShaderCompile = getParallelShaderCompile(gl);
|
||||
if (isDebugMode && parallelShaderCompile === null) {
|
||||
console.log('Could not find support for "parallel_shader_compile"');
|
||||
}
|
||||
const fboRenderMipmap = getFboRenderMipmap(gl);
|
||||
if (isDebugMode && fboRenderMipmap === null) {
|
||||
console.log('Could not find support for "fbo_render_mipmap"');
|
||||
}
|
||||
|
||||
const noNonInstancedActiveAttribs = getNoNonInstancedActiveAttribs(gl);
|
||||
|
||||
return {
|
||||
instancedArrays,
|
||||
standardDerivatives,
|
||||
elementIndexUint,
|
||||
|
||||
textureFloat,
|
||||
textureFloatLinear,
|
||||
textureHalfFloat,
|
||||
textureHalfFloatLinear,
|
||||
elementIndexUint,
|
||||
depthTexture,
|
||||
|
||||
blendMinMax,
|
||||
vertexArrayObject,
|
||||
fragDepth,
|
||||
colorBufferFloat,
|
||||
colorBufferHalfFloat,
|
||||
drawBuffers,
|
||||
drawBuffersIndexed,
|
||||
shaderTextureLod,
|
||||
sRGB,
|
||||
disjointTimerQuery,
|
||||
parallelShaderCompile,
|
||||
fboRenderMipmap,
|
||||
|
||||
noNonInstancedActiveAttribs,
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { createAttributeBuffers, ElementsBuffer, AttributeKind } from './buffer';
|
||||
@@ -49,11 +50,12 @@ export interface RenderItem<T extends string> {
|
||||
|
||||
//
|
||||
|
||||
const GraphicsRenderVariant = { colorBlended: '', colorWboit: '', pick: '', depth: '', marking: '' };
|
||||
const GraphicsRenderVariant = { colorBlended: '', colorWboit: '', colorDpoit: '', pick: '', depth: '', marking: '' };
|
||||
export type GraphicsRenderVariant = keyof typeof GraphicsRenderVariant
|
||||
export const GraphicsRenderVariants = Object.keys(GraphicsRenderVariant) as GraphicsRenderVariant[];
|
||||
export const GraphicsRenderVariantsBlended = GraphicsRenderVariants.filter(v => v !== 'colorWboit');
|
||||
export const GraphicsRenderVariantsWboit = GraphicsRenderVariants.filter(v => v !== 'colorBlended');
|
||||
export const GraphicsRenderVariantsBlended = GraphicsRenderVariants.filter(v => !['colorWboit', 'colorDpoit'].includes(v));
|
||||
export const GraphicsRenderVariantsWboit = GraphicsRenderVariants.filter(v => !['colorBlended', 'colorDpoit'].includes(v));
|
||||
export const GraphicsRenderVariantsDpoit = GraphicsRenderVariants.filter(v => !['colorWboit', 'colorBlended'].includes(v));
|
||||
|
||||
const ComputeRenderVariant = { compute: '' };
|
||||
export type ComputeRenderVariant = keyof typeof ComputeRenderVariant
|
||||
@@ -367,4 +369,4 @@ export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode:
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { WebGLContext } from './context';
|
||||
@@ -31,7 +32,7 @@ export type TextureKindValue = {
|
||||
export type TextureValueType = ValueOf<TextureKindValue>
|
||||
export type TextureKind = keyof TextureKindValue
|
||||
export type TextureType = 'ubyte' | 'ushort' | 'float' | 'fp16' | 'int'
|
||||
export type TextureFormat = 'alpha' | 'rgb' | 'rgba' | 'depth'
|
||||
export type TextureFormat = 'alpha' | 'rg' | 'rgb' | 'rgba' | 'depth'
|
||||
/** Numbers are shortcuts for color attachment */
|
||||
export type TextureAttachment = 'depth' | 'stencil' | 'color0' | 'color1' | 'color2' | 'color3' | 'color4' | 'color5' | 'color6' | 'color7' | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
|
||||
export type TextureFilter = 'nearest' | 'linear'
|
||||
@@ -63,6 +64,10 @@ export function getFormat(gl: GLRenderingContext, format: TextureFormat, type: T
|
||||
case 'rgb':
|
||||
if (isWebGL2(gl) && type === 'int') return gl.RGB_INTEGER;
|
||||
return gl.RGB;
|
||||
case 'rg':
|
||||
if (isWebGL2(gl) && type === 'float') return gl.RG;
|
||||
else if (isWebGL2(gl) && type === 'int') return gl.RG_INTEGER;
|
||||
else throw new Error('texture format "rg" requires webgl2 and type "float" or int"');
|
||||
case 'rgba':
|
||||
if (isWebGL2(gl) && type === 'int') return gl.RGBA_INTEGER;
|
||||
return gl.RGBA;
|
||||
@@ -80,6 +85,13 @@ export function getInternalFormat(gl: GLRenderingContext, format: TextureFormat,
|
||||
case 'fp16': return gl.R16F;
|
||||
case 'int': return gl.R32I;
|
||||
}
|
||||
case 'rg':
|
||||
switch (type) {
|
||||
case 'ubyte': return gl.RG;
|
||||
case 'float': return gl.RG32F;
|
||||
case 'fp16': return gl.RG16F;
|
||||
case 'int': return gl.RG32I;
|
||||
}
|
||||
case 'rgb':
|
||||
switch (type) {
|
||||
case 'ubyte': return gl.RGB;
|
||||
@@ -112,6 +124,7 @@ function getByteCount(format: TextureFormat, type: TextureType, width: number, h
|
||||
function getFormatSize(format: TextureFormat) {
|
||||
switch (format) {
|
||||
case 'alpha': return 1;
|
||||
case 'rg': return 2;
|
||||
case 'rgb': return 3;
|
||||
case 'rgba': return 4;
|
||||
case 'depth': return 4;
|
||||
|
||||
@@ -264,28 +264,35 @@ export namespace ArrayEncoding {
|
||||
return false;
|
||||
}
|
||||
|
||||
function packingSize(data: Int32Array, upperLimit: number) {
|
||||
function packingSizeUnsigned(data: Int32Array, upperLimit: number) {
|
||||
let size = 0;
|
||||
for (let i = 0, n = data.length; i < n; i++) {
|
||||
size += (data[i] / upperLimit) | 0;
|
||||
}
|
||||
size += data.length;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
function packingSizeSigned(data: Int32Array, upperLimit: number) {
|
||||
const lowerLimit = -upperLimit - 1;
|
||||
let size = 0;
|
||||
for (let i = 0, n = data.length; i < n; i++) {
|
||||
const value = data[i];
|
||||
if (value === 0) {
|
||||
size += 1;
|
||||
} else if (value > 0) {
|
||||
size += Math.ceil(value / upperLimit);
|
||||
if (value % upperLimit === 0) size += 1;
|
||||
if (value >= 0) {
|
||||
size += (value / upperLimit) | 0;
|
||||
} else {
|
||||
size += Math.ceil(value / lowerLimit);
|
||||
if (value % lowerLimit === 0) size += 1;
|
||||
size += (value / lowerLimit) | 0;
|
||||
}
|
||||
}
|
||||
size += data.length;
|
||||
return size;
|
||||
}
|
||||
|
||||
function determinePacking(data: Int32Array): { isSigned: boolean, size: number, bytesPerElement: number } {
|
||||
const signed = isSigned(data);
|
||||
const size8 = signed ? packingSize(data, 0x7F) : packingSize(data, 0xFF);
|
||||
const size16 = signed ? packingSize(data, 0x7FFF) : packingSize(data, 0xFFFF);
|
||||
const size8 = signed ? packingSizeSigned(data, 0x7F) : packingSizeUnsigned(data, 0xFF);
|
||||
const size16 = signed ? packingSizeSigned(data, 0x7FFF) : packingSizeUnsigned(data, 0xFFFF);
|
||||
|
||||
if (data.length * 4 < size16 * 2) {
|
||||
// 4 byte packing is the most effective
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.360, IHM 1.17, MA 1.4.2.
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.363, IHM 1.17, MA 1.4.3.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.360, IHM 1.17, MA 1.4.2.
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.363, IHM 1.17, MA 1.4.3.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.360, IHM 1.17, MA 1.4.2.
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.363, IHM 1.17, MA 1.4.3.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { GridLookup3D } from '../../geometry';
|
||||
@@ -24,9 +25,17 @@ describe('GridLookup3d', () => {
|
||||
expect(r.count).toBe(1);
|
||||
expect(r.indices[0]).toBe(0);
|
||||
|
||||
r = grid.nearest(0, 0, 0, 1);
|
||||
expect(r.count).toBe(1);
|
||||
expect(r.indices[0]).toBe(0);
|
||||
|
||||
r = grid.find(0, 0, 0, 1);
|
||||
expect(r.count).toBe(3);
|
||||
expect(sortArray(r.indices)).toEqual([0, 1, 2]);
|
||||
|
||||
r = grid.nearest(0, 0, 0, 3);
|
||||
expect(r.count).toBe(3);
|
||||
expect(sortArray(r.indices)).toEqual([0, 1, 2]);
|
||||
});
|
||||
|
||||
it('radius', () => {
|
||||
@@ -38,9 +47,17 @@ describe('GridLookup3d', () => {
|
||||
expect(r.count).toBe(1);
|
||||
expect(r.indices[0]).toBe(0);
|
||||
|
||||
r = grid.nearest(0, 0, 0, 1);
|
||||
expect(r.count).toBe(1);
|
||||
expect(r.indices[0]).toBe(0);
|
||||
|
||||
r = grid.find(0, 0, 0, 0.5);
|
||||
expect(r.count).toBe(2);
|
||||
expect(sortArray(r.indices)).toEqual([0, 1]);
|
||||
|
||||
r = grid.nearest(0, 0, 0, 3);
|
||||
expect(r.count).toBe(3);
|
||||
expect(sortArray(r.indices)).toEqual([0, 1, 2]);
|
||||
});
|
||||
|
||||
it('indexed', () => {
|
||||
@@ -51,8 +68,15 @@ describe('GridLookup3d', () => {
|
||||
let r = grid.find(0, 0, 0, 0);
|
||||
expect(r.count).toBe(0);
|
||||
|
||||
r = grid.nearest(0, 0, 0, 1);
|
||||
expect(r.count).toBe(1);
|
||||
|
||||
r = grid.find(0, 0, 0, 0.5);
|
||||
expect(r.count).toBe(1);
|
||||
expect(sortArray(r.indices)).toEqual([0]);
|
||||
|
||||
r = grid.nearest(0, 0, 0, 3);
|
||||
expect(r.count).toBe(1);
|
||||
expect(sortArray(r.indices)).toEqual([0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -204,7 +204,7 @@ function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionDat
|
||||
render(texture, false);
|
||||
}
|
||||
|
||||
// printTexture(webgl, minDistTex, 0.75);
|
||||
// printTextureImage(readTexture(webgl, minDistTex), { scale: 0.75 });
|
||||
|
||||
return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim, gridTexScale, radiusFactor, resolution, maxRadius };
|
||||
}
|
||||
|
||||
@@ -41,8 +41,9 @@ export namespace Result {
|
||||
export interface Lookup3D<T = number> {
|
||||
// The result is mutated with each call to find.
|
||||
find(x: number, y: number, z: number, radius: number, result?: Result<T>): Result<T>,
|
||||
nearest(x: number, y: number, z: number, k: number, stopIf?: Function, result?: Result<T>): Result<T>,
|
||||
check(x: number, y: number, z: number, radius: number): boolean,
|
||||
readonly boundary: { readonly box: Box3D, readonly sphere: Sphere3D }
|
||||
/** transient result */
|
||||
readonly result: Result<T>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { Result, Lookup3D } from './common';
|
||||
@@ -12,6 +13,7 @@ import { PositionData } from '../common';
|
||||
import { Vec3 } from '../../linear-algebra';
|
||||
import { OrderedSet } from '../../../mol-data/int';
|
||||
import { Boundary } from '../boundary';
|
||||
import { FibonacciHeap } from '../../../mol-util/fibonacci-heap';
|
||||
|
||||
interface GridLookup3D<T = number> extends Lookup3D<T> {
|
||||
readonly buckets: { readonly offset: ArrayLike<number>, readonly count: ArrayLike<number>, readonly array: ArrayLike<number> }
|
||||
@@ -40,6 +42,17 @@ class GridLookup3DImpl<T extends number = number> implements GridLookup3D<T> {
|
||||
return ret;
|
||||
}
|
||||
|
||||
nearest(x: number, y: number, z: number, k: number = 1, stopIf?: Function, result?: Result<T>): Result<T> {
|
||||
this.ctx.x = x;
|
||||
this.ctx.y = y;
|
||||
this.ctx.z = z;
|
||||
this.ctx.k = k;
|
||||
this.ctx.stopIf = stopIf;
|
||||
const ret = result ?? this.result;
|
||||
queryNearest(this.ctx, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
check(x: number, y: number, z: number, radius: number): boolean {
|
||||
this.ctx.x = x;
|
||||
this.ctx.y = y;
|
||||
@@ -221,12 +234,14 @@ interface QueryContext {
|
||||
x: number,
|
||||
y: number,
|
||||
z: number,
|
||||
k: number,
|
||||
stopIf?: Function,
|
||||
radius: number,
|
||||
isCheck: boolean
|
||||
}
|
||||
|
||||
function createContext(grid: Grid3D): QueryContext {
|
||||
return { grid, x: 0.1, y: 0.1, z: 0.1, radius: 0.1, isCheck: false };
|
||||
return { grid, x: 0.1, y: 0.1, z: 0.1, k: 1, stopIf: undefined, radius: 0.1, isCheck: false };
|
||||
}
|
||||
|
||||
function query<T extends number = number>(ctx: QueryContext, result: Result<T>): boolean {
|
||||
@@ -277,4 +292,152 @@ function query<T extends number = number>(ctx: QueryContext, result: Result<T>):
|
||||
}
|
||||
}
|
||||
return result.count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
const tmpDirVec = Vec3();
|
||||
const tmpVec = Vec3();
|
||||
const tmpSetG = new Set<number>();
|
||||
const tmpSetG2 = new Set<number>();
|
||||
const tmpArrG1 = [0.1];
|
||||
const tmpArrG2 = [0.1];
|
||||
const tmpArrG3 = [0.1];
|
||||
const tmpHeapG = new FibonacciHeap();
|
||||
function queryNearest<T extends number = number>(ctx: QueryContext, result: Result<T>): boolean {
|
||||
const { min, expandedBox: box, boundingSphere: { center }, size: [sX, sY, sZ], bucketOffset, bucketCounts, bucketArray, grid, data: { x: px, y: py, z: pz, indices, radius }, delta, maxRadius } = ctx.grid;
|
||||
const { x, y, z, k, stopIf } = ctx;
|
||||
const indicesCount = OrderedSet.size(indices);
|
||||
Result.reset(result);
|
||||
if (indicesCount === 0 || k <= 0) return false;
|
||||
let gX, gY, gZ, stop = false, gCount = 1, expandGrid = true, nextGCount = 0, arrG = tmpArrG1, nextArrG = tmpArrG2, maxRange = 0, expandRange = true, gridId: number, gridPointsFinished = false;
|
||||
const expandedArrG = tmpArrG3, sqMaxRadius = maxRadius * maxRadius;
|
||||
arrG.length = 0;
|
||||
expandedArrG.length = 0;
|
||||
tmpSetG.clear();
|
||||
tmpHeapG.clear();
|
||||
Vec3.set(tmpVec, x, y, z);
|
||||
if (!Box3D.containsVec3(box, tmpVec)) {
|
||||
// intersect ray pointing to box center
|
||||
Box3D.nearestIntersectionWithRay(tmpVec, box, tmpVec, Vec3.normalize(tmpDirVec, Vec3.sub(tmpDirVec, center, tmpVec)));
|
||||
gX = Math.max(0, Math.min(sX - 1, Math.floor((tmpVec[0] - min[0]) / delta[0])));
|
||||
gY = Math.max(0, Math.min(sY - 1, Math.floor((tmpVec[1] - min[1]) / delta[1])));
|
||||
gZ = Math.max(0, Math.min(sZ - 1, Math.floor((tmpVec[2] - min[2]) / delta[2])));
|
||||
} else {
|
||||
gX = Math.floor((x - min[0]) / delta[0]);
|
||||
gY = Math.floor((y - min[1]) / delta[1]);
|
||||
gZ = Math.floor((z - min[2]) / delta[2]);
|
||||
}
|
||||
const dX = maxRadius !== 0 ? Math.max(1, Math.min(sX - 1, Math.ceil(maxRadius / delta[0]))) : 1;
|
||||
const dY = maxRadius !== 0 ? Math.max(1, Math.min(sY - 1, Math.ceil(maxRadius / delta[1]))) : 1;
|
||||
const dZ = maxRadius !== 0 ? Math.max(1, Math.min(sZ - 1, Math.ceil(maxRadius / delta[2]))) : 1;
|
||||
arrG.push(gX, gY, gZ, (((gX * sY) + gY) * sZ) + gZ);
|
||||
while (result.count < indicesCount) {
|
||||
const arrGLen = gCount * 4;
|
||||
for (let ig = 0; ig < arrGLen; ig += 4) {
|
||||
gridId = arrG[ig + 3];
|
||||
if (!tmpSetG.has(gridId)) {
|
||||
tmpSetG.add(gridId);
|
||||
gridPointsFinished = tmpSetG.size >= grid.length;
|
||||
const bucketIdx = grid[gridId];
|
||||
if (bucketIdx !== 0) {
|
||||
const _maxRange = maxRange;
|
||||
const ki = bucketIdx - 1;
|
||||
const offset = bucketOffset[ki];
|
||||
const count = bucketCounts[ki];
|
||||
const end = offset + count;
|
||||
for (let i = offset; i < end; i++) {
|
||||
const bIdx = bucketArray[i];
|
||||
const idx = OrderedSet.getAt(indices, bIdx);
|
||||
const dx = px[idx] - x;
|
||||
const dy = py[idx] - y;
|
||||
const dz = pz[idx] - z;
|
||||
let distSq = dx * dx + dy * dy + dz * dz;
|
||||
if (maxRadius !== 0) {
|
||||
const r = radius![idx];
|
||||
distSq -= r * r;
|
||||
}
|
||||
if (expandRange && distSq > maxRange) {
|
||||
maxRange = distSq;
|
||||
}
|
||||
tmpHeapG.insert(distSq, bIdx);
|
||||
}
|
||||
if (_maxRange < maxRange) expandRange = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// find next grid points
|
||||
nextArrG.length = 0;
|
||||
nextGCount = 0;
|
||||
tmpSetG2.clear();
|
||||
for (let ig = 0; ig < arrGLen; ig += 4) {
|
||||
gX = arrG[ig];
|
||||
gY = arrG[ig + 1];
|
||||
gZ = arrG[ig + 2];
|
||||
// fill grid points array with valid adiacent positions
|
||||
for (let ix = -dX; ix <= dX; ix++) {
|
||||
const xPos = gX + ix;
|
||||
if (xPos < 0 || xPos >= sX) continue;
|
||||
for (let iy = -dY; iy <= dY; iy++) {
|
||||
const yPos = gY + iy;
|
||||
if (yPos < 0 || yPos >= sY) continue;
|
||||
for (let iz = -dZ; iz <= dZ; iz++) {
|
||||
const zPos = gZ + iz;
|
||||
if (zPos < 0 || zPos >= sZ) continue;
|
||||
gridId = (((xPos * sY) + yPos) * sZ) + zPos;
|
||||
if (tmpSetG2.has(gridId)) continue; // already scanned
|
||||
tmpSetG2.add(gridId);
|
||||
if (tmpSetG.has(gridId)) continue; // already visited
|
||||
if (!expandGrid) {
|
||||
const xP = min[0] + xPos * delta[0] - x;
|
||||
const yP = min[1] + yPos * delta[1] - y;
|
||||
const zP = min[2] + zPos * delta[2] - z;
|
||||
const distSqG = (xP * xP) + (yP * yP) + (zP * zP) - sqMaxRadius; // is sqMaxRadius necessary?
|
||||
if (distSqG > maxRange) {
|
||||
expandedArrG.push(xPos, yPos, zPos, gridId);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nextArrG.push(xPos, yPos, zPos, gridId);
|
||||
nextGCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
expandGrid = false;
|
||||
if (nextGCount === 0) {
|
||||
if (k === 1) {
|
||||
const node = tmpHeapG.findMinimum();
|
||||
if (node) {
|
||||
const { key: squaredDistance, value: index } = node!;
|
||||
// const squaredDistance = node!.key, index = node!.value;
|
||||
Result.add(result, index as number, squaredDistance as number);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
while (!tmpHeapG.isEmpty() && (gridPointsFinished || tmpHeapG.findMinimum()!.key as number <= maxRange) && result.count < k) {
|
||||
const node = tmpHeapG.extractMinimum();
|
||||
const squaredDistance = node!.key, index = node!.value;
|
||||
Result.add(result, index as number, squaredDistance as number);
|
||||
if (stopIf && !stop) {
|
||||
stop = stopIf(index, squaredDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.count >= k || stop || result.count >= indicesCount) return result.count > 0;
|
||||
expandGrid = true;
|
||||
expandRange = true;
|
||||
if (expandedArrG.length > 0) {
|
||||
for (let i = 0, l = expandedArrG.length; i < l; i++) {
|
||||
arrG.push(expandedArrG[i]);
|
||||
}
|
||||
expandedArrG.length = 0;
|
||||
gCount = arrG.length;
|
||||
}
|
||||
} else {
|
||||
const tmp = arrG;
|
||||
arrG = nextArrG;
|
||||
nextArrG = tmp;
|
||||
gCount = nextGCount;
|
||||
}
|
||||
}
|
||||
return result.count > 0;
|
||||
}
|
||||
|
||||
@@ -138,6 +138,48 @@ namespace Box3D {
|
||||
a.max[2] < b.min[2] || a.min[2] > b.max[2]
|
||||
);
|
||||
}
|
||||
|
||||
// const tmpTransformV = Vec3();
|
||||
export function nearestIntersectionWithRay(out: Vec3, box: Box3D, origin: Vec3, dir: Vec3): Vec3 {
|
||||
const [minX, minY, minZ] = box.min;
|
||||
const [maxX, maxY, maxZ] = box.max;
|
||||
const [x, y, z] = origin;
|
||||
const invDirX = 1.0 / dir[0];
|
||||
const invDirY = 1.0 / dir[1];
|
||||
const invDirZ = 1.0 / dir[2];
|
||||
let tmin, tmax, tymin, tymax, tzmin, tzmax;
|
||||
if (invDirX >= 0) {
|
||||
tmin = (minX - x) * invDirX;
|
||||
tmax = (maxX - x) * invDirX;
|
||||
} else {
|
||||
tmin = (maxX - x) * invDirX;
|
||||
tmax = (minX - x) * invDirX;
|
||||
}
|
||||
if (invDirY >= 0) {
|
||||
tymin = (minY - y) * invDirY;
|
||||
tymax = (maxY - y) * invDirY;
|
||||
} else {
|
||||
tymin = (maxY - y) * invDirY;
|
||||
tymax = (minY - y) * invDirY;
|
||||
}
|
||||
if (invDirZ >= 0) {
|
||||
tzmin = (minZ - z) * invDirZ;
|
||||
tzmax = (maxZ - z) * invDirZ;
|
||||
} else {
|
||||
tzmin = (maxZ - z) * invDirZ;
|
||||
tzmax = (minZ - z) * invDirZ;
|
||||
}
|
||||
if (tymin > tmin)
|
||||
tmin = tymin;
|
||||
if (tymax < tmax)
|
||||
tmax = tymax;
|
||||
if (tzmin > tmin)
|
||||
tmin = tzmin;
|
||||
if (tzmax < tmax)
|
||||
tmax = tzmax;
|
||||
Vec3.scale(out, dir, tmin);
|
||||
return Vec3.set(out, out[0] + x, out[1] + y, out[2] + z);
|
||||
}
|
||||
}
|
||||
|
||||
export { Box3D };
|
||||
export { Box3D };
|
||||
|
||||
@@ -277,6 +277,12 @@ namespace Sphere3D {
|
||||
export function distance(a: Sphere3D, b: Sphere3D) {
|
||||
return Vec3.distance(a.center, b.center) - a.radius + b.radius;
|
||||
}
|
||||
|
||||
/** Get the distance of v from sphere. If negative, v is inside sphere */
|
||||
export function distanceToVec(sphere: Sphere3D, v: Vec3): number {
|
||||
const { center, radius } = sphere;
|
||||
return Vec3.distance(v, center) - radius;
|
||||
}
|
||||
}
|
||||
|
||||
export { Sphere3D };
|
||||
export { Sphere3D };
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { lerp as scalar_lerp } from '../../mol-math/interpolate';
|
||||
import { defaults } from '../../mol-util';
|
||||
import { Mat3 } from '../linear-algebra/3d/mat3';
|
||||
import { Mat4 } from '../linear-algebra/3d/mat4';
|
||||
import { Quat } from '../linear-algebra/3d/quat';
|
||||
@@ -29,11 +29,13 @@ interface SymmetryOperator {
|
||||
readonly hkl: Vec3,
|
||||
/** spacegroup symmetry operator index, -1 if not applicable */
|
||||
readonly spgrOp: number,
|
||||
/** unique (external) key, -1 if not available */
|
||||
readonly key: number,
|
||||
|
||||
readonly matrix: Mat4,
|
||||
// cache the inverse of the transform
|
||||
/** cache the inverse of the transform */
|
||||
readonly inverse: Mat4,
|
||||
// optimize the identity case
|
||||
/** optimize the identity case */
|
||||
readonly isIdentity: boolean,
|
||||
|
||||
/**
|
||||
@@ -51,19 +53,20 @@ namespace SymmetryOperator {
|
||||
|
||||
export const RotationTranslationEpsilon = 0.005;
|
||||
|
||||
export type CreateInfo = { assembly?: SymmetryOperator['assembly'], ncsId?: number, hkl?: Vec3, spgrOp?: number }
|
||||
export type CreateInfo = { assembly?: SymmetryOperator['assembly'], ncsId?: number, hkl?: Vec3, spgrOp?: number, key?: number }
|
||||
export function create(name: string, matrix: Mat4, info?: CreateInfo | SymmetryOperator): SymmetryOperator {
|
||||
let { assembly, ncsId, hkl, spgrOp } = info || { };
|
||||
let { assembly, ncsId, hkl, spgrOp, key } = info || { };
|
||||
const _hkl = hkl ? Vec3.clone(hkl) : Vec3();
|
||||
spgrOp = defaults(spgrOp, -1);
|
||||
spgrOp = spgrOp ?? -1;
|
||||
key = key ?? -1;
|
||||
ncsId = ncsId || -1;
|
||||
const isIdentity = Mat4.isIdentity(matrix);
|
||||
const suffix = getSuffix(info, isIdentity);
|
||||
if (isIdentity) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, spgrOp, ncsId, suffix };
|
||||
if (isIdentity) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, spgrOp, ncsId, suffix, key };
|
||||
if (!Mat4.isRotationAndTranslation(matrix, RotationTranslationEpsilon)) {
|
||||
console.warn(`Symmetry operator (${name}) should be a composition of rotation and translation.`);
|
||||
}
|
||||
return { name, assembly, matrix, inverse: Mat4.invert(Mat4(), matrix), isIdentity: false, hkl: _hkl, spgrOp, ncsId, suffix };
|
||||
return { name, assembly, matrix, inverse: Mat4.invert(Mat4(), matrix), isIdentity: false, hkl: _hkl, spgrOp, key, ncsId, suffix };
|
||||
}
|
||||
|
||||
function isSymmetryOperator(x: any): x is SymmetryOperator {
|
||||
|
||||
@@ -35,7 +35,7 @@ function Vec3() {
|
||||
|
||||
namespace Vec3 {
|
||||
export function zero(): Vec3 {
|
||||
const out = [0.1, 0.0, 0.0];
|
||||
const out = [0.1, 0.0, 0.0]; // ensure backing array of type double
|
||||
out[0] = 0;
|
||||
return out as any;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ const DnaAtomIdsList = [
|
||||
/** Used to reduce false positives for atom name-based type guessing */
|
||||
const NonPolymerNames = new Set([
|
||||
'FMN', 'NCN', 'FNS', 'FMA', 'ATP', 'ADP', 'AMP', 'GTP', 'GDP', 'GMP', // Mononucleotides
|
||||
'LIG'
|
||||
]);
|
||||
|
||||
const StandardComponents = (function () {
|
||||
|
||||
@@ -39,7 +39,7 @@ export function getAtomSiteTemplate(data: string, count: number) {
|
||||
};
|
||||
}
|
||||
|
||||
export function getAtomSite(sites: AtomSiteTemplate, hasTer: boolean): { [K in keyof mmCIF_Schema['atom_site'] | 'partial_charge']?: CifField } {
|
||||
export function getAtomSite(sites: AtomSiteTemplate, terIndices: Set<number>): { [K in keyof mmCIF_Schema['atom_site'] | 'partial_charge']?: CifField } {
|
||||
const pdbx_PDB_model_num = CifField.ofStrings(sites.pdbx_PDB_model_num);
|
||||
const auth_asym_id = CifField.ofTokens(sites.auth_asym_id);
|
||||
const auth_seq_id = CifField.ofTokens(sites.auth_seq_id);
|
||||
@@ -67,21 +67,17 @@ export function getAtomSite(sites: AtomSiteTemplate, hasTer: boolean): { [K in k
|
||||
const seqId = auth_seq_id.int(i);
|
||||
let atomId = auth_atom_id.str(i);
|
||||
|
||||
let asymIdChanged = false;
|
||||
|
||||
if (modelNum !== currModelNum) {
|
||||
asymIdCounts.clear();
|
||||
atomIdCounts.clear();
|
||||
currModelNum = modelNum;
|
||||
currAsymId = asymId;
|
||||
currSeqId = seqId;
|
||||
asymIdChanged = true;
|
||||
currLabelAsymId = asymId;
|
||||
} else if (currAsymId !== asymId) {
|
||||
atomIdCounts.clear();
|
||||
currAsymId = asymId;
|
||||
currSeqId = seqId;
|
||||
asymIdChanged = true;
|
||||
currLabelAsymId = asymId;
|
||||
} else if (currSeqId !== seqId) {
|
||||
atomIdCounts.clear();
|
||||
@@ -91,7 +87,7 @@ export function getAtomSite(sites: AtomSiteTemplate, hasTer: boolean): { [K in k
|
||||
if (asymIdCounts.has(asymId)) {
|
||||
// only change the chains name if there are TER records
|
||||
// otherwise assume repeated chain name use is from interleaved chains
|
||||
if (hasTer && asymIdChanged) {
|
||||
if (terIndices.has(i)) {
|
||||
const asymIdCount = asymIdCounts.get(asymId)! + 1;
|
||||
asymIdCounts.set(asymId, asymIdCount);
|
||||
currLabelAsymId = `${asymId}_${asymIdCount}`;
|
||||
|
||||
@@ -51,7 +51,7 @@ export async function pdbToMmCif(pdb: PdbFile): Promise<CifFrame> {
|
||||
|
||||
let modelNum = 0, modelStr = '';
|
||||
let conectRange: [number, number] | undefined = undefined;
|
||||
let hasTer = false;
|
||||
const terIndices = new Set<number>();
|
||||
|
||||
for (let i = 0, _i = lines.count; i < _i; i++) {
|
||||
let s = indices[2 * i], e = indices[2 * i + 1];
|
||||
@@ -164,7 +164,7 @@ export async function pdbToMmCif(pdb: PdbFile): Promise<CifFrame> {
|
||||
break;
|
||||
case 'T':
|
||||
if (substringStartsWith(data, s, e, 'TER')) {
|
||||
hasTer = true;
|
||||
terIndices.add(atomSite.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,7 +183,7 @@ export async function pdbToMmCif(pdb: PdbFile): Promise<CifFrame> {
|
||||
atomSite.label_entity_id[i] = entityBuilder.getEntityId(compId, moleculeType, asymIds.value(i));
|
||||
}
|
||||
|
||||
const atom_site = getAtomSite(atomSite, hasTer);
|
||||
const atom_site = getAtomSite(atomSite, terIndices);
|
||||
if (!isPdbqt) delete atom_site.partial_charge;
|
||||
|
||||
if (conectRange) {
|
||||
|
||||
@@ -65,7 +65,7 @@ export namespace ComponentBond {
|
||||
return e;
|
||||
}
|
||||
|
||||
const { comp_id, atom_id_1, atom_id_2, value_order, pdbx_aromatic_flag, _rowCount } = data;
|
||||
const { comp_id, atom_id_1, atom_id_2, value_order, pdbx_aromatic_flag, _rowCount, pdbx_ordinal } = data;
|
||||
|
||||
let entry = addEntry(comp_id.value(0)!);
|
||||
for (let i = 0; i < _rowCount; i++) {
|
||||
@@ -74,6 +74,7 @@ export namespace ComponentBond {
|
||||
const nameB = atom_id_2.value(i)!;
|
||||
const order = value_order.value(i)!;
|
||||
const aromatic = pdbx_aromatic_flag.value(i) === 'y';
|
||||
const key = pdbx_ordinal.value(i);
|
||||
|
||||
if (entry.id !== id) {
|
||||
entry = addEntry(id);
|
||||
@@ -89,29 +90,29 @@ export namespace ComponentBond {
|
||||
case 'quad': ord = 4; break;
|
||||
}
|
||||
|
||||
entry.add(nameA, nameB, ord, flags);
|
||||
entry.add(nameA, nameB, ord, flags, key);
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
export class Entry {
|
||||
readonly map: Map<string, Map<string, { order: number, flags: number }>> = new Map();
|
||||
readonly map: Map<string, Map<string, { order: number, flags: number, key: number }>> = new Map();
|
||||
|
||||
add(a: string, b: string, order: number, flags: number, swap = true) {
|
||||
add(a: string, b: string, order: number, flags: number, key: number, swap = true) {
|
||||
const e = this.map.get(a);
|
||||
if (e !== void 0) {
|
||||
const f = e.get(b);
|
||||
if (f === void 0) {
|
||||
e.set(b, { order, flags });
|
||||
e.set(b, { order, flags, key });
|
||||
}
|
||||
} else {
|
||||
const map = new Map<string, { order: number, flags: number }>();
|
||||
map.set(b, { order, flags });
|
||||
const map = new Map<string, { order: number, flags: number, key: number }>();
|
||||
map.set(b, { order, flags, key });
|
||||
this.map.set(a, map);
|
||||
}
|
||||
|
||||
if (swap) this.add(b, a, order, flags, false);
|
||||
if (swap) this.add(b, a, order, flags, key, false);
|
||||
}
|
||||
|
||||
constructor(public readonly id: string) { }
|
||||
|
||||
@@ -14,6 +14,8 @@ import { ElementIndex } from '../../../../mol-model/structure';
|
||||
|
||||
export type IndexPairsProps = {
|
||||
readonly key: ArrayLike<number>
|
||||
readonly operatorA: ArrayLike<number>
|
||||
readonly operatorB: ArrayLike<number>
|
||||
readonly order: ArrayLike<number>
|
||||
readonly distance: ArrayLike<number>
|
||||
readonly flag: ArrayLike<BondType.Flag>
|
||||
@@ -24,18 +26,22 @@ export type IndexPairBonds = { bonds: IndexPairs, maxDistance: number }
|
||||
function getGraph(indexA: ArrayLike<ElementIndex>, indexB: ArrayLike<ElementIndex>, props: Partial<IndexPairsProps>, count: number): IndexPairs {
|
||||
const builder = new IntAdjacencyGraph.EdgeBuilder(count, indexA, indexB);
|
||||
const key = new Int32Array(builder.slotCount);
|
||||
const operatorA = new Array(builder.slotCount);
|
||||
const operatorB = new Array(builder.slotCount);
|
||||
const order = new Int8Array(builder.slotCount);
|
||||
const distance = new Array(builder.slotCount);
|
||||
const flag = new Array(builder.slotCount);
|
||||
for (let i = 0, _i = builder.edgeCount; i < _i; i++) {
|
||||
builder.addNextEdge();
|
||||
builder.assignProperty(key, props.key ? props.key[i] : -1);
|
||||
builder.assignProperty(operatorA, props.operatorA ? props.operatorA[i] : -1);
|
||||
builder.assignProperty(operatorB, props.operatorB ? props.operatorB[i] : -1);
|
||||
builder.assignProperty(order, props.order ? props.order[i] : 1);
|
||||
builder.assignProperty(distance, props.distance ? props.distance[i] : -1);
|
||||
builder.assignProperty(flag, props.flag ? props.flag[i] : BondType.Flag.Covalent);
|
||||
}
|
||||
|
||||
return builder.createGraph({ key, order, distance, flag });
|
||||
return builder.createGraph({ key, operatorA, operatorB, order, distance, flag });
|
||||
}
|
||||
|
||||
export namespace IndexPairBonds {
|
||||
@@ -50,6 +56,10 @@ export namespace IndexPairBonds {
|
||||
indexA: Column<number>,
|
||||
indexB: Column<number>,
|
||||
key?: Column<number>,
|
||||
/** Operator key for indexA. Used in bond computation. */
|
||||
operatorA?: Column<number>,
|
||||
/** Operator key for indexB. Used in bond computation. */
|
||||
operatorB?: Column<number>,
|
||||
order?: Column<number>,
|
||||
/**
|
||||
* Useful for bonds in periodic cells. That is, only bonds within the given
|
||||
@@ -83,12 +93,30 @@ export namespace IndexPairBonds {
|
||||
const indexA = pairs.indexA.toArray() as ArrayLike<ElementIndex>;
|
||||
const indexB = pairs.indexB.toArray() as ArrayLike<ElementIndex>;
|
||||
const key = pairs.key && pairs.key.toArray();
|
||||
const operatorA = pairs.operatorA && pairs.operatorA.toArray();
|
||||
const operatorB = pairs.operatorB && pairs.operatorB.toArray();
|
||||
const order = pairs.order && pairs.order.toArray();
|
||||
const distance = pairs.distance && pairs.distance.toArray();
|
||||
const flag = pairs.flag && pairs.flag.toArray();
|
||||
return {
|
||||
bonds: getGraph(indexA, indexB, { key, order, distance, flag }, count),
|
||||
bonds: getGraph(indexA, indexB, { key, operatorA, operatorB, order, distance, flag }, count),
|
||||
maxDistance: p.maxDistance
|
||||
};
|
||||
}
|
||||
|
||||
/** Like `getEdgeIndex` but taking `edgeProps.operatorA` and `edgeProps.operatorB` into account */
|
||||
export function getEdgeIndexForOperators(bonds: IndexPairs, i: ElementIndex, j: ElementIndex, opI: number, opJ: number): number {
|
||||
let a, b, opA, opB;
|
||||
if (i < j) {
|
||||
a = i; b = j;
|
||||
opA = opI; opB = opJ;
|
||||
} else {
|
||||
a = j; b = i;
|
||||
opA = opJ; opB = opI;
|
||||
}
|
||||
for (let t = bonds.offset[a], _t = bonds.offset[a + 1]; t < _t; t++) {
|
||||
if (bonds.b[t] === b && bonds.edgeProps.operatorA[t] === opA && bonds.edgeProps.operatorB[t] === opB) return t;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -71,12 +71,12 @@ namespace CustomModelProperty {
|
||||
},
|
||||
ref: (data: Model, add: boolean) => data.customProperties.reference(builder.descriptor, add),
|
||||
get: (data: Model) => get(data)?.data,
|
||||
set: (data: Model, props: Partial<PD.Values<Params>> = {}) => {
|
||||
set: (data: Model, props: Partial<PD.Values<Params>> = {}, value?: Value) => {
|
||||
const property = get(data);
|
||||
const p = PD.merge(builder.defaultParams, property.props, props);
|
||||
if (!PD.areEqual(builder.defaultParams, property.props, p)) {
|
||||
// this invalidates property.value
|
||||
set(data, p, undefined);
|
||||
set(data, p, value);
|
||||
// dispose of assets
|
||||
data.customProperties.assets(builder.descriptor);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ namespace CustomModelProperty {
|
||||
getParams: () => ({ value: PD.Value(defaultValue, { isHidden: true }) }),
|
||||
isApplicable: () => true,
|
||||
obtain: async (ctx: CustomProperty.Context, data: Model, props: Partial<PD.Values<typeof defaultParams>>) => {
|
||||
return { value: props.value ?? defaultValue };
|
||||
return { ...PD.getDefaultValues(defaultParams), ...props };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import { LocationIterator } from '../../../mol-geo/util/location-iterator';
|
||||
import { InteractionFlag } from '../interactions/common';
|
||||
import { Unit } from '../../../mol-model/structure/structure';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
import { assertUnreachable } from '../../../mol-util/type-helpers';
|
||||
import { InteractionsSharedParams } from './shared';
|
||||
|
||||
function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<InteractionsInterUnitParams>, mesh?: Mesh) {
|
||||
if (!structure.hasAtomic) return Mesh.createEmpty(mesh);
|
||||
@@ -31,7 +33,7 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S
|
||||
const { contacts, unitsFeatures } = interactions;
|
||||
|
||||
const { edgeCount, edges } = contacts;
|
||||
const { sizeFactor } = props;
|
||||
const { sizeFactor, parentDisplay } = props;
|
||||
|
||||
if (!edgeCount) return Mesh.createEmpty(mesh);
|
||||
|
||||
@@ -70,14 +72,48 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S
|
||||
|
||||
if (child) {
|
||||
const b = edges[edgeIndex];
|
||||
const childUnitA = child.unitMap.get(b.unitA);
|
||||
if (!childUnitA) return true;
|
||||
|
||||
const unitA = structure.unitMap.get(b.unitA);
|
||||
const { offsets, members } = unitsFeatures.get(b.unitA);
|
||||
for (let i = offsets[b.indexA], il = offsets[b.indexA + 1]; i < il; ++i) {
|
||||
const eA = unitA.elements[members[i]];
|
||||
if (!SortedArray.has(childUnitA.elements, eA)) return true;
|
||||
if (parentDisplay === 'stub') {
|
||||
const childUnitA = child.unitMap.get(b.unitA);
|
||||
if (!childUnitA) return true;
|
||||
|
||||
const unitA = structure.unitMap.get(b.unitA);
|
||||
const { offsets, members } = unitsFeatures.get(b.unitA);
|
||||
for (let i = offsets[b.indexA], il = offsets[b.indexA + 1]; i < il; ++i) {
|
||||
const eA = unitA.elements[members[i]];
|
||||
if (!SortedArray.has(childUnitA.elements, eA)) return true;
|
||||
}
|
||||
} else if (parentDisplay === 'full' || parentDisplay === 'between') {
|
||||
let flagA = false;
|
||||
let flagB = false;
|
||||
|
||||
const childUnitA = child.unitMap.get(b.unitA);
|
||||
if (!childUnitA) {
|
||||
flagA = true;
|
||||
} else {
|
||||
const unitA = structure.unitMap.get(b.unitA);
|
||||
const { offsets, members } = unitsFeatures.get(b.unitA);
|
||||
for (let i = offsets[b.indexA], il = offsets[b.indexA + 1]; i < il; ++i) {
|
||||
const eA = unitA.elements[members[i]];
|
||||
if (!SortedArray.has(childUnitA.elements, eA)) flagA = true;
|
||||
}
|
||||
}
|
||||
|
||||
const childUnitB = child.unitMap.get(b.unitB);
|
||||
if (!childUnitB) {
|
||||
flagB = true;
|
||||
} else {
|
||||
const unitB = structure.unitMap.get(b.unitB);
|
||||
const { offsets, members } = unitsFeatures.get(b.unitB);
|
||||
for (let i = offsets[b.indexB], il = offsets[b.indexB + 1]; i < il; ++i) {
|
||||
const eB = unitB.elements[members[i]];
|
||||
if (!SortedArray.has(childUnitB.elements, eB)) flagB = true;
|
||||
}
|
||||
}
|
||||
|
||||
return parentDisplay === 'full' ? flagA && flagB : flagA === flagB;
|
||||
} else {
|
||||
assertUnreachable(parentDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,10 +137,7 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S
|
||||
export const InteractionsInterUnitParams = {
|
||||
...ComplexMeshParams,
|
||||
...LinkCylinderParams,
|
||||
sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }),
|
||||
dashCount: PD.Numeric(6, { min: 2, max: 10, step: 2 }),
|
||||
dashScale: PD.Numeric(0.4, { min: 0, max: 2, step: 0.1 }),
|
||||
includeParent: PD.Boolean(false),
|
||||
...InteractionsSharedParams,
|
||||
};
|
||||
export type InteractionsInterUnitParams = typeof InteractionsInterUnitParams
|
||||
|
||||
@@ -121,7 +154,8 @@ export function InteractionsInterUnitVisual(materialId: number): ComplexVisual<I
|
||||
newProps.dashCount !== currentProps.dashCount ||
|
||||
newProps.dashScale !== currentProps.dashScale ||
|
||||
newProps.dashCap !== currentProps.dashCap ||
|
||||
newProps.radialSegments !== currentProps.radialSegments
|
||||
newProps.radialSegments !== currentProps.radialSegments ||
|
||||
newProps.parentDisplay !== currentProps.parentDisplay
|
||||
);
|
||||
|
||||
const interactionsHash = InteractionsProvider.get(newStructure).version;
|
||||
|
||||
@@ -22,6 +22,8 @@ import { Interactions } from '../interactions/interactions';
|
||||
import { InteractionFlag } from '../interactions/common';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
import { StructureGroup } from '../../../mol-repr/structure/visual/util/common';
|
||||
import { assertUnreachable } from '../../../mol-util/type-helpers';
|
||||
import { InteractionsSharedParams } from './shared';
|
||||
|
||||
async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<InteractionsIntraUnitParams>, mesh?: Mesh) {
|
||||
if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh);
|
||||
@@ -38,7 +40,7 @@ async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit:
|
||||
|
||||
const { x, y, z, members, offsets } = features;
|
||||
const { edgeCount, a, b, edgeProps: { flag } } = contacts;
|
||||
const { sizeFactor } = props;
|
||||
const { sizeFactor, parentDisplay } = props;
|
||||
|
||||
if (!edgeCount) return Mesh.createEmpty(mesh);
|
||||
|
||||
@@ -60,10 +62,31 @@ async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit:
|
||||
if (flag[edgeIndex] === InteractionFlag.Filtered) return true;
|
||||
|
||||
if (childUnit) {
|
||||
const f = a[edgeIndex];
|
||||
for (let i = offsets[f], jl = offsets[f + 1]; i < jl; ++i) {
|
||||
const e = unit.elements[members[offsets[i]]];
|
||||
if (!SortedArray.has(childUnit.elements, e)) return true;
|
||||
if (parentDisplay === 'stub') {
|
||||
const f = a[edgeIndex];
|
||||
for (let i = offsets[f], il = offsets[f + 1]; i < il; ++i) {
|
||||
const e = unit.elements[members[offsets[i]]];
|
||||
if (!SortedArray.has(childUnit.elements, e)) return true;
|
||||
}
|
||||
} else if (parentDisplay === 'full' || parentDisplay === 'between') {
|
||||
let flagA = false;
|
||||
let flagB = false;
|
||||
|
||||
const fA = a[edgeIndex];
|
||||
for (let i = offsets[fA], il = offsets[fA + 1]; i < il; ++i) {
|
||||
const eA = unit.elements[members[offsets[i]]];
|
||||
if (!SortedArray.has(childUnit.elements, eA)) flagA = true;
|
||||
}
|
||||
|
||||
const fB = b[edgeIndex];
|
||||
for (let i = offsets[fB], il = offsets[fB + 1]; i < il; ++i) {
|
||||
const eB = unit.elements[members[offsets[i]]];
|
||||
if (!SortedArray.has(childUnit.elements, eB)) flagB = true;
|
||||
}
|
||||
|
||||
return parentDisplay === 'full' ? flagA && flagB : flagA === flagB;
|
||||
} else {
|
||||
assertUnreachable(parentDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,10 +109,7 @@ async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit:
|
||||
export const InteractionsIntraUnitParams = {
|
||||
...UnitsMeshParams,
|
||||
...LinkCylinderParams,
|
||||
sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }),
|
||||
dashCount: PD.Numeric(6, { min: 2, max: 10, step: 2 }),
|
||||
dashScale: PD.Numeric(0.4, { min: 0, max: 2, step: 0.1 }),
|
||||
includeParent: PD.Boolean(false),
|
||||
...InteractionsSharedParams,
|
||||
};
|
||||
export type InteractionsIntraUnitParams = typeof InteractionsIntraUnitParams
|
||||
|
||||
@@ -106,7 +126,8 @@ export function InteractionsIntraUnitVisual(materialId: number): UnitsVisual<Int
|
||||
newProps.dashCount !== currentProps.dashCount ||
|
||||
newProps.dashScale !== currentProps.dashScale ||
|
||||
newProps.dashCap !== currentProps.dashCap ||
|
||||
newProps.radialSegments !== currentProps.radialSegments
|
||||
newProps.radialSegments !== currentProps.radialSegments ||
|
||||
newProps.parentDisplay !== currentProps.parentDisplay
|
||||
);
|
||||
|
||||
const interactionsHash = InteractionsProvider.get(newStructureGroup.structure).version;
|
||||
|
||||
16
src/mol-model-props/computed/representations/shared.ts
Normal file
16
src/mol-model-props/computed/representations/shared.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
|
||||
export const InteractionsSharedParams = {
|
||||
sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }),
|
||||
dashCount: PD.Numeric(6, { min: 2, max: 10, step: 2 }),
|
||||
dashScale: PD.Numeric(0.4, { min: 0, max: 2, step: 0.1 }),
|
||||
includeParent: PD.Boolean(false),
|
||||
parentDisplay: PD.Select('stub', PD.arrayToOptions(['stub', 'full', 'between'] as const), { description: 'Only has an effect when "includeParent" is enabled. "Stub" shows just the child side of interactions to the parent. "Full" shows both sides of interactions to the parent. "Between" shows only interactions to the parent.' }),
|
||||
};
|
||||
export type InteractionsSharedParams = typeof InteractionsSharedParams
|
||||
@@ -241,7 +241,9 @@ namespace Loci {
|
||||
? Structure.toStructureElementLoci(loci.structure)
|
||||
: ShapeGroup.isLoci(loci)
|
||||
? Shape.Loci(loci.shape)
|
||||
: loci;
|
||||
: Volume.Cell.isLoci(loci)
|
||||
? Volume.Loci(loci.volume)
|
||||
: loci;
|
||||
},
|
||||
'elementInstances': (loci: Loci) => {
|
||||
return StructureElement.Loci.is(loci)
|
||||
|
||||
@@ -213,6 +213,9 @@ export namespace Model {
|
||||
export type Index = number;
|
||||
export const Index = CustomModelProperty.createSimple<Index>('index', 'static');
|
||||
|
||||
export type MaxIndex = number;
|
||||
export const MaxIndex = CustomModelProperty.createSimple<MaxIndex>('max_index', 'static');
|
||||
|
||||
export function getRoot(model: Model) {
|
||||
return model.parent || model;
|
||||
}
|
||||
|
||||
@@ -285,6 +285,10 @@ export const AminoAcidNamesD = new Set([
|
||||
]);
|
||||
export const AminoAcidNames = SetUtils.unionMany(AminoAcidNamesL, AminoAcidNamesD);
|
||||
|
||||
export const CommonProteinCaps = new Set([
|
||||
'NME', 'ACE'
|
||||
]);
|
||||
|
||||
export const RnaBaseNames = new Set([
|
||||
'A', 'C', 'T', 'G', 'I', 'U',
|
||||
'N' // unknown RNA base from CCD
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -12,6 +12,7 @@ import * as modifiers from './query/queries/modifiers';
|
||||
import * as filters from './query/queries/filters';
|
||||
import * as combinators from './query/queries/combinators';
|
||||
import * as internal from './query/queries/internal';
|
||||
import * as atomset from './query/queries/atom-set';
|
||||
import { Predicates as pred } from './query/predicates';
|
||||
|
||||
export const Queries = {
|
||||
@@ -20,7 +21,8 @@ export const Queries = {
|
||||
modifiers,
|
||||
combinators,
|
||||
pred,
|
||||
internal
|
||||
internal,
|
||||
atomset
|
||||
};
|
||||
|
||||
export { StructureSelection, StructureQuery };
|
||||
export { StructureSelection, StructureQuery };
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Structure, StructureElement, Unit } from '../structure';
|
||||
@@ -113,6 +114,7 @@ class QueryContextBondInfo<U extends Unit = Unit> {
|
||||
bIndex: StructureElement.UnitIndex = 0 as StructureElement.UnitIndex;
|
||||
type: BondType = BondType.Flag.None;
|
||||
order: number = 0;
|
||||
key: number = -1;
|
||||
|
||||
private testFn: QueryPredicate = defaultBondTest;
|
||||
|
||||
@@ -153,6 +155,6 @@ class QueryContextBondInfo<U extends Unit = Unit> {
|
||||
}
|
||||
|
||||
get length() {
|
||||
return StructureElement.Location.distance(this.a, this. b);
|
||||
return StructureElement.Location.distance(this.a, this.b);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user