@aics/vole-core 3.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/LICENSE.txt +26 -0
  2. package/README.md +119 -0
  3. package/es/Atlas2DSlice.js +224 -0
  4. package/es/Channel.js +264 -0
  5. package/es/FileSaver.js +31 -0
  6. package/es/FusedChannelData.js +192 -0
  7. package/es/Histogram.js +250 -0
  8. package/es/ImageInfo.js +127 -0
  9. package/es/Light.js +74 -0
  10. package/es/Lut.js +500 -0
  11. package/es/MarchingCubes.js +507 -0
  12. package/es/MeshVolume.js +334 -0
  13. package/es/NaiveSurfaceNets.js +251 -0
  14. package/es/PathTracedVolume.js +482 -0
  15. package/es/RayMarchedAtlasVolume.js +250 -0
  16. package/es/RenderToBuffer.js +31 -0
  17. package/es/ThreeJsPanel.js +633 -0
  18. package/es/Timing.js +28 -0
  19. package/es/TrackballControls.js +538 -0
  20. package/es/View3d.js +848 -0
  21. package/es/Volume.js +352 -0
  22. package/es/VolumeCache.js +161 -0
  23. package/es/VolumeDims.js +16 -0
  24. package/es/VolumeDrawable.js +702 -0
  25. package/es/VolumeMaker.js +101 -0
  26. package/es/VolumeRenderImpl.js +1 -0
  27. package/es/VolumeRenderSettings.js +203 -0
  28. package/es/constants/basicShaders.js +29 -0
  29. package/es/constants/colors.js +59 -0
  30. package/es/constants/denoiseShader.js +43 -0
  31. package/es/constants/lights.js +42 -0
  32. package/es/constants/materials.js +85 -0
  33. package/es/constants/pathtraceOutputShader.js +13 -0
  34. package/es/constants/scaleBarSVG.js +21 -0
  35. package/es/constants/time.js +34 -0
  36. package/es/constants/volumePTshader.js +153 -0
  37. package/es/constants/volumeRayMarchShader.js +123 -0
  38. package/es/constants/volumeSliceShader.js +115 -0
  39. package/es/index.js +21 -0
  40. package/es/loaders/IVolumeLoader.js +131 -0
  41. package/es/loaders/JsonImageInfoLoader.js +255 -0
  42. package/es/loaders/OmeZarrLoader.js +495 -0
  43. package/es/loaders/OpenCellLoader.js +65 -0
  44. package/es/loaders/RawArrayLoader.js +89 -0
  45. package/es/loaders/TiffLoader.js +219 -0
  46. package/es/loaders/VolumeLoadError.js +44 -0
  47. package/es/loaders/VolumeLoaderUtils.js +221 -0
  48. package/es/loaders/index.js +40 -0
  49. package/es/loaders/zarr_utils/ChunkPrefetchIterator.js +143 -0
  50. package/es/loaders/zarr_utils/WrappedStore.js +51 -0
  51. package/es/loaders/zarr_utils/types.js +24 -0
  52. package/es/loaders/zarr_utils/utils.js +225 -0
  53. package/es/loaders/zarr_utils/validation.js +49 -0
  54. package/es/test/ChunkPrefetchIterator.test.js +208 -0
  55. package/es/test/RequestQueue.test.js +442 -0
  56. package/es/test/SubscribableRequestQueue.test.js +244 -0
  57. package/es/test/VolumeCache.test.js +118 -0
  58. package/es/test/VolumeRenderSettings.test.js +71 -0
  59. package/es/test/lut.test.js +671 -0
  60. package/es/test/num_utils.test.js +140 -0
  61. package/es/test/volume.test.js +98 -0
  62. package/es/test/zarr_utils.test.js +358 -0
  63. package/es/types/Atlas2DSlice.d.ts +41 -0
  64. package/es/types/Channel.d.ts +44 -0
  65. package/es/types/FileSaver.d.ts +6 -0
  66. package/es/types/FusedChannelData.d.ts +26 -0
  67. package/es/types/Histogram.d.ts +57 -0
  68. package/es/types/ImageInfo.d.ts +87 -0
  69. package/es/types/Light.d.ts +27 -0
  70. package/es/types/Lut.d.ts +67 -0
  71. package/es/types/MarchingCubes.d.ts +53 -0
  72. package/es/types/MeshVolume.d.ts +40 -0
  73. package/es/types/NaiveSurfaceNets.d.ts +11 -0
  74. package/es/types/PathTracedVolume.d.ts +65 -0
  75. package/es/types/RayMarchedAtlasVolume.d.ts +41 -0
  76. package/es/types/RenderToBuffer.d.ts +17 -0
  77. package/es/types/ThreeJsPanel.d.ts +107 -0
  78. package/es/types/Timing.d.ts +11 -0
  79. package/es/types/TrackballControls.d.ts +51 -0
  80. package/es/types/View3d.d.ts +357 -0
  81. package/es/types/Volume.d.ts +152 -0
  82. package/es/types/VolumeCache.d.ts +43 -0
  83. package/es/types/VolumeDims.d.ts +28 -0
  84. package/es/types/VolumeDrawable.d.ts +108 -0
  85. package/es/types/VolumeMaker.d.ts +49 -0
  86. package/es/types/VolumeRenderImpl.d.ts +22 -0
  87. package/es/types/VolumeRenderSettings.d.ts +98 -0
  88. package/es/types/constants/basicShaders.d.ts +4 -0
  89. package/es/types/constants/colors.d.ts +2 -0
  90. package/es/types/constants/denoiseShader.d.ts +40 -0
  91. package/es/types/constants/lights.d.ts +38 -0
  92. package/es/types/constants/materials.d.ts +20 -0
  93. package/es/types/constants/pathtraceOutputShader.d.ts +11 -0
  94. package/es/types/constants/scaleBarSVG.d.ts +2 -0
  95. package/es/types/constants/time.d.ts +19 -0
  96. package/es/types/constants/volumePTshader.d.ts +137 -0
  97. package/es/types/constants/volumeRayMarchShader.d.ts +117 -0
  98. package/es/types/constants/volumeSliceShader.d.ts +109 -0
  99. package/es/types/glsl.d.js +0 -0
  100. package/es/types/index.d.ts +28 -0
  101. package/es/types/loaders/IVolumeLoader.d.ts +113 -0
  102. package/es/types/loaders/JsonImageInfoLoader.d.ts +80 -0
  103. package/es/types/loaders/OmeZarrLoader.d.ts +87 -0
  104. package/es/types/loaders/OpenCellLoader.d.ts +9 -0
  105. package/es/types/loaders/RawArrayLoader.d.ts +33 -0
  106. package/es/types/loaders/TiffLoader.d.ts +45 -0
  107. package/es/types/loaders/VolumeLoadError.d.ts +18 -0
  108. package/es/types/loaders/VolumeLoaderUtils.d.ts +38 -0
  109. package/es/types/loaders/index.d.ts +22 -0
  110. package/es/types/loaders/zarr_utils/ChunkPrefetchIterator.d.ts +22 -0
  111. package/es/types/loaders/zarr_utils/WrappedStore.d.ts +24 -0
  112. package/es/types/loaders/zarr_utils/types.d.ts +94 -0
  113. package/es/types/loaders/zarr_utils/utils.d.ts +23 -0
  114. package/es/types/loaders/zarr_utils/validation.d.ts +7 -0
  115. package/es/types/test/ChunkPrefetchIterator.test.d.ts +1 -0
  116. package/es/types/test/RequestQueue.test.d.ts +1 -0
  117. package/es/types/test/SubscribableRequestQueue.test.d.ts +1 -0
  118. package/es/types/test/VolumeCache.test.d.ts +1 -0
  119. package/es/types/test/VolumeRenderSettings.test.d.ts +1 -0
  120. package/es/types/test/lut.test.d.ts +1 -0
  121. package/es/types/test/num_utils.test.d.ts +1 -0
  122. package/es/types/test/volume.test.d.ts +1 -0
  123. package/es/types/test/zarr_utils.test.d.ts +1 -0
  124. package/es/types/types.d.ts +115 -0
  125. package/es/types/utils/RequestQueue.d.ts +112 -0
  126. package/es/types/utils/SubscribableRequestQueue.d.ts +52 -0
  127. package/es/types/utils/num_utils.d.ts +43 -0
  128. package/es/types/workers/VolumeLoaderContext.d.ts +106 -0
  129. package/es/types/workers/types.d.ts +101 -0
  130. package/es/types/workers/util.d.ts +3 -0
  131. package/es/types.js +75 -0
  132. package/es/typings.d.js +0 -0
  133. package/es/utils/RequestQueue.js +267 -0
  134. package/es/utils/SubscribableRequestQueue.js +187 -0
  135. package/es/utils/num_utils.js +231 -0
  136. package/es/workers/FetchTiffWorker.js +153 -0
  137. package/es/workers/VolumeLoadWorker.js +129 -0
  138. package/es/workers/VolumeLoaderContext.js +271 -0
  139. package/es/workers/types.js +41 -0
  140. package/es/workers/util.js +8 -0
  141. package/package.json +83 -0
@@ -0,0 +1,250 @@
1
+ import { Box3, Box3Helper, BoxGeometry, BufferAttribute, BufferGeometry, Color, DataTexture, Group, LineBasicMaterial, LineSegments, Matrix4, Mesh, ShaderMaterial, Vector2, Vector3 } from "three";
2
+ import FusedChannelData from "./FusedChannelData.js";
3
+ import { rayMarchingVertexShaderSrc, rayMarchingFragmentShaderSrc, rayMarchingShaderUniforms } from "./constants/volumeRayMarchShader.js";
4
+ import { VolumeRenderSettings, SettingsFlags } from "./VolumeRenderSettings.js";
5
+ const BOUNDING_BOX_DEFAULT_COLOR = new Color(0xffff00);
6
+ export default class RayMarchedAtlasVolume {
7
+ /**
8
+ * Creates a new RayMarchedAtlasVolume.
9
+ * @param volume The volume that this renderer should render data from.
10
+ * @param settings Optional settings object. If set, updates the renderer with
11
+ * the given settings. Otherwise, uses the default VolumeRenderSettings.
12
+ */
13
+ constructor(volume, settings = new VolumeRenderSettings(volume)) {
14
+ this.volume = volume;
15
+ this.uniforms = rayMarchingShaderUniforms();
16
+ [this.geometry, this.geometryMesh] = this.createGeometry(this.uniforms);
17
+ this.boxHelper = new Box3Helper(new Box3(new Vector3(-0.5, -0.5, -0.5), new Vector3(0.5, 0.5, 0.5)), BOUNDING_BOX_DEFAULT_COLOR);
18
+ this.boxHelper.updateMatrixWorld();
19
+ this.boxHelper.visible = false;
20
+ this.tickMarksMesh = this.createTickMarks();
21
+ this.tickMarksMesh.updateMatrixWorld();
22
+ this.tickMarksMesh.visible = false;
23
+ this.geometryTransformNode = new Group();
24
+ this.geometryTransformNode.name = "VolumeContainerNode";
25
+ this.geometryTransformNode.add(this.boxHelper, this.tickMarksMesh, this.geometryMesh);
26
+ this.emptyPositionTex = new DataTexture(new Uint8Array(Array(16).fill(0)), 2, 2);
27
+ this.settings = settings;
28
+ this.updateSettings(settings, SettingsFlags.ALL);
29
+ // TODO this is doing *more* redundant work! Fix?
30
+ this.updateVolumeDimensions();
31
+ }
32
+ updateVolumeDimensions() {
33
+ const {
34
+ normPhysicalSize,
35
+ normRegionSize
36
+ } = this.volume;
37
+ // Set offset
38
+ this.geometryMesh.position.copy(this.volume.getContentCenter().multiply(this.settings.scale));
39
+ // Set scale
40
+ const fullRegionScale = normPhysicalSize.clone().multiply(this.settings.scale);
41
+ this.geometryMesh.scale.copy(fullRegionScale).multiply(normRegionSize);
42
+ this.setUniform("volumeScale", normPhysicalSize);
43
+ this.boxHelper.box.set(fullRegionScale.clone().multiplyScalar(-0.5), fullRegionScale.clone().multiplyScalar(0.5));
44
+ this.tickMarksMesh.scale.copy(fullRegionScale);
45
+ this.settings && this.updateSettings(this.settings, SettingsFlags.ROI);
46
+
47
+ // Set atlas dimension uniforms
48
+ const {
49
+ atlasTileDims,
50
+ subregionSize
51
+ } = this.volume.imageInfo;
52
+ const atlasSize = new Vector2(subregionSize.x, subregionSize.y).multiply(atlasTileDims);
53
+ this.setUniform("ATLAS_DIMS", atlasTileDims);
54
+ this.setUniform("textureRes", atlasSize);
55
+ this.setUniform("SLICES", this.volume.imageInfo.volumeSize.z);
56
+
57
+ // (re)create channel data
58
+ if (!this.channelData || this.channelData.width !== atlasSize.x || this.channelData.height !== atlasSize.y) {
59
+ this.channelData?.cleanup();
60
+ this.channelData = new FusedChannelData(atlasSize.x, atlasSize.y);
61
+ }
62
+ }
63
+ viewpointMoved() {
64
+ return;
65
+ }
66
+ updateSettings(newSettings, dirtyFlags) {
67
+ if (dirtyFlags === undefined) {
68
+ dirtyFlags = SettingsFlags.ALL;
69
+ }
70
+ this.settings = newSettings;
71
+ if (dirtyFlags & SettingsFlags.VIEW) {
72
+ this.geometryMesh.visible = this.settings.visible;
73
+ // Configure ortho
74
+ this.setUniform("orthoScale", this.settings.orthoScale);
75
+ this.setUniform("isOrtho", this.settings.isOrtho ? 1.0 : 0.0);
76
+ // Ortho line thickness
77
+ const axis = this.settings.viewAxis;
78
+ if (this.settings.isOrtho && axis) {
79
+ // TODO: Does this code do any relevant changes?
80
+ const maxVal = this.settings.bounds.bmax[axis];
81
+ const minVal = this.settings.bounds.bmin[axis];
82
+ const thicknessPct = maxVal - minVal;
83
+ this.setUniform("orthoThickness", thicknessPct);
84
+ } else {
85
+ this.setUniform("orthoThickness", 1.0);
86
+ }
87
+ }
88
+ if (dirtyFlags & SettingsFlags.VIEW || dirtyFlags & SettingsFlags.BOUNDING_BOX) {
89
+ // Update tick marks with either view or bounding box changes
90
+ this.tickMarksMesh.visible = this.settings.showBoundingBox && !this.settings.isOrtho;
91
+ this.setUniform("maxProject", this.settings.maxProjectMode ? 1 : 0);
92
+ }
93
+ if (dirtyFlags & SettingsFlags.BOUNDING_BOX) {
94
+ // Configure bounding box
95
+ this.boxHelper.visible = this.settings.showBoundingBox;
96
+ const colorVector = this.settings.boundingBoxColor;
97
+ const newBoxColor = new Color(colorVector[0], colorVector[1], colorVector[2]);
98
+ this.boxHelper.material.color = newBoxColor;
99
+ this.tickMarksMesh.material.color = newBoxColor;
100
+ }
101
+ if (dirtyFlags & SettingsFlags.TRANSFORM) {
102
+ // Set rotation and translation
103
+ this.geometryTransformNode.position.copy(this.settings.translation);
104
+ this.geometryTransformNode.rotation.copy(this.settings.rotation);
105
+ // TODO this does some redundant work. Including a new call to this very function! Fix?
106
+ this.updateVolumeDimensions();
107
+ this.setUniform("flipVolume", this.settings.flipAxes);
108
+ }
109
+ if (dirtyFlags & SettingsFlags.MATERIAL) {
110
+ this.setUniform("DENSITY", this.settings.density);
111
+ }
112
+ if (dirtyFlags & SettingsFlags.CAMERA) {
113
+ // TODO brightness and exposure should be the same thing?
114
+ this.setUniform("BRIGHTNESS", this.settings.brightness * 2.0);
115
+ // Gamma
116
+ this.setUniform("GAMMA_MIN", this.settings.gammaMin);
117
+ this.setUniform("GAMMA_MAX", this.settings.gammaMax);
118
+ this.setUniform("GAMMA_SCALE", this.settings.gammaLevel);
119
+ }
120
+ if (dirtyFlags & SettingsFlags.ROI) {
121
+ // Normalize and set bounds
122
+ const bounds = this.settings.bounds;
123
+ const {
124
+ normRegionSize,
125
+ normRegionOffset
126
+ } = this.volume;
127
+ const offsetToCenter = normRegionSize.clone().divideScalar(2).add(normRegionOffset).subScalar(0.5);
128
+ const bmin = bounds.bmin.clone().sub(offsetToCenter).divide(normRegionSize).clampScalar(-0.5, 0.5);
129
+ const bmax = bounds.bmax.clone().sub(offsetToCenter).divide(normRegionSize).clampScalar(-0.5, 0.5);
130
+ this.setUniform("AABB_CLIP_MIN", bmin);
131
+ this.setUniform("AABB_CLIP_MAX", bmax);
132
+ }
133
+ if (dirtyFlags & SettingsFlags.SAMPLING) {
134
+ this.setUniform("interpolationEnabled", this.settings.useInterpolation);
135
+ this.setUniform("iResolution", this.settings.resolution);
136
+ }
137
+ if (dirtyFlags & SettingsFlags.MASK_ALPHA) {
138
+ this.setUniform("maskAlpha", this.settings.maskChannelIndex < 0 ? 1.0 : this.settings.maskAlpha);
139
+ }
140
+ if (dirtyFlags & SettingsFlags.MASK_DATA) {
141
+ this.channelData.setChannelAsMask(this.settings.maskChannelIndex, this.volume.getChannel(this.settings.maskChannelIndex));
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Creates the geometry mesh and material for rendering the volume.
147
+ * @param uniforms object containing uniforms to pass to the shader material.
148
+ * @returns the new geometry and geometry mesh.
149
+ */
150
+ createGeometry(uniforms) {
151
+ const geom = new BoxGeometry(1.0, 1.0, 1.0);
152
+ const mesh = new Mesh(geom);
153
+ mesh.name = "Volume";
154
+
155
+ // shader,vtx and frag.
156
+ const vtxsrc = rayMarchingVertexShaderSrc;
157
+ const fgmtsrc = rayMarchingFragmentShaderSrc;
158
+ const threeMaterial = new ShaderMaterial({
159
+ uniforms: uniforms,
160
+ vertexShader: vtxsrc,
161
+ fragmentShader: fgmtsrc,
162
+ transparent: true,
163
+ depthTest: true,
164
+ depthWrite: false
165
+ });
166
+ mesh.material = threeMaterial;
167
+ return [geom, mesh];
168
+ }
169
+ createTickMarks() {
170
+ // Length of tick mark lines in world units
171
+ const TICK_LENGTH = 0.025;
172
+ const {
173
+ tickMarkPhysicalLength,
174
+ physicalScale,
175
+ normPhysicalSize
176
+ } = this.volume;
177
+ const numTickMarks = physicalScale / tickMarkPhysicalLength;
178
+ const vertices = [];
179
+ const tickEndY = TICK_LENGTH / normPhysicalSize.y + 0.5;
180
+ const tickSpacingX = 1 / (normPhysicalSize.x * numTickMarks);
181
+ for (let x = -0.5; x <= 0.5; x += tickSpacingX) {
182
+ // prettier-ignore
183
+ vertices.push(x, 0.5, 0.5, x, tickEndY, 0.5, x, -0.5, -0.5, x, -tickEndY, -0.5, x, 0.5, -0.5, x, tickEndY, -0.5, x, -0.5, 0.5, x, -tickEndY, 0.5);
184
+ }
185
+ const tickEndX = TICK_LENGTH / normPhysicalSize.x + 0.5;
186
+ const tickSpacingY = 1 / (normPhysicalSize.y * numTickMarks);
187
+ for (let y = 0.5; y >= -0.5; y -= tickSpacingY) {
188
+ // prettier-ignore
189
+ vertices.push(-0.5, y, 0.5, -tickEndX, y, 0.5, -0.5, y, -0.5, -tickEndX, y, -0.5, 0.5, y, -0.5, tickEndX, y, -0.5, 0.5, y, 0.5, tickEndX, y, 0.5);
190
+ }
191
+ const tickSpacingZ = 1 / (normPhysicalSize.z * numTickMarks);
192
+ for (let z = 0.5; z >= -0.5; z -= tickSpacingZ) {
193
+ // prettier-ignore
194
+ vertices.push(-0.5, 0.5, z, -tickEndX, 0.5, z, -0.5, -0.5, z, -tickEndX, -0.5, z, 0.5, -0.5, z, tickEndX, -0.5, z, 0.5, 0.5, z, tickEndX, 0.5, z);
195
+ }
196
+ const geometry = new BufferGeometry();
197
+ geometry.setAttribute("position", new BufferAttribute(new Float32Array(vertices), 3));
198
+ return new LineSegments(geometry, new LineBasicMaterial({
199
+ color: BOUNDING_BOX_DEFAULT_COLOR
200
+ }));
201
+ }
202
+ cleanup() {
203
+ this.geometry.dispose();
204
+ this.geometryMesh.material.dispose();
205
+ this.channelData.cleanup();
206
+ }
207
+ doRender(renderer, camera, depthTexture) {
208
+ if (!this.geometryMesh.visible) {
209
+ return;
210
+ }
211
+ const depthTex = depthTexture ?? this.emptyPositionTex;
212
+ this.setUniform("textureDepth", depthTex);
213
+ this.setUniform("usingPositionTexture", depthTex.isDepthTexture ? 0 : 1);
214
+ this.setUniform("CLIP_NEAR", camera.near);
215
+ this.setUniform("CLIP_FAR", camera.far);
216
+ this.channelData.gpuFuse(renderer);
217
+ this.setUniform("textureAtlas", this.channelData.getFusedTexture());
218
+ this.geometryTransformNode.updateMatrixWorld(true);
219
+ const mvm = new Matrix4();
220
+ mvm.multiplyMatrices(camera.matrixWorldInverse, this.geometryMesh.matrixWorld);
221
+ mvm.invert();
222
+ this.setUniform("inverseModelViewMatrix", mvm);
223
+ this.setUniform("inverseProjMatrix", camera.projectionMatrixInverse);
224
+ }
225
+ get3dObject() {
226
+ return this.geometryTransformNode;
227
+ }
228
+
229
+ //////////////////////////////////////////
230
+ //////////////////////////////////////////
231
+
232
+ setUniform(name, value) {
233
+ if (!this.uniforms[name]) {
234
+ return;
235
+ }
236
+ this.uniforms[name].value = value;
237
+ }
238
+
239
+ // channelcolors is array of {rgbColor, lut} and channeldata is volume.channels
240
+ updateActiveChannels(channelcolors, channeldata) {
241
+ this.channelData.fuse(channelcolors, channeldata);
242
+
243
+ // update to fused texture
244
+ this.setUniform("textureAtlas", this.channelData.getFusedTexture());
245
+ this.setUniform("textureAtlasMask", this.channelData.maskTexture);
246
+ }
247
+ setRenderUpdateListener(_listener) {
248
+ return;
249
+ }
250
+ }
@@ -0,0 +1,31 @@
1
+ import { Mesh, OrthographicCamera, PlaneGeometry, Scene, ShaderMaterial } from "three";
2
+ import { renderToBufferVertShader } from "./constants/basicShaders.js";
3
+
4
+ /**
5
+ * Helper for render passes that just require a fragment shader: accepts a fragment shader and its
6
+ * uniforms, and handles the ceremony of rendering a fullscreen quad with a simple vertex shader.
7
+ */
8
+ export default class RenderToBuffer {
9
+ constructor(fragmentSrc, uniforms) {
10
+ this.scene = new Scene();
11
+ this.geometry = new PlaneGeometry(2, 2);
12
+ this.material = new ShaderMaterial({
13
+ vertexShader: renderToBufferVertShader,
14
+ fragmentShader: fragmentSrc,
15
+ uniforms
16
+ });
17
+ this.material.depthWrite = false;
18
+ this.material.depthTest = false;
19
+ this.mesh = new Mesh(this.geometry, this.material);
20
+ this.scene.add(this.mesh);
21
+ this.camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);
22
+ }
23
+
24
+ /** Renders this pass to `target` using `renderer`, or to the canvas if no `target` is given. */
25
+ render(renderer, target) {
26
+ renderer.setRenderTarget(target ?? null);
27
+ renderer.render(this.scene, this.camera);
28
+ // Reset the render target to the screen
29
+ renderer.setRenderTarget(null);
30
+ }
31
+ }