@cosmos.gl/graph 2.6.2 → 2.7.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +147 -0
- package/.github/SECURITY.md +13 -0
- package/.github/dco.yml +4 -0
- package/.github/workflows/github_pages.yml +54 -0
- package/.storybook/main.ts +26 -0
- package/.storybook/manager-head.html +1 -0
- package/.storybook/manager.ts +14 -0
- package/.storybook/preview.ts +29 -0
- package/.storybook/style.css +3 -0
- package/CHARTER.md +69 -0
- package/CODE_OF_CONDUCT.md +178 -0
- package/CONTRIBUTING.md +22 -0
- package/GOVERNANCE.md +21 -0
- package/cosmos-2-0-migration-notes.md +98 -0
- package/cosmos_awesome.md +96 -0
- package/dist/config.d.ts +5 -18
- package/dist/graph/utils/error-message.d.ts +1 -1
- package/dist/helper.d.ts +39 -2
- package/dist/index-FUIgayhu.js +19827 -0
- package/dist/index-FUIgayhu.js.map +1 -0
- package/dist/index.d.ts +17 -64
- package/dist/index.js +14 -14658
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1062 -475
- package/dist/index.min.js.map +1 -1
- package/dist/modules/Clusters/index.d.ts +11 -3
- package/dist/modules/ForceCenter/index.d.ts +10 -3
- package/dist/modules/ForceGravity/index.d.ts +5 -1
- package/dist/modules/ForceLink/index.d.ts +8 -5
- package/dist/modules/ForceManyBody/index.d.ts +16 -7
- package/dist/modules/ForceMouse/index.d.ts +5 -1
- package/dist/modules/GraphData/index.d.ts +0 -1
- package/dist/modules/Lines/index.d.ts +11 -5
- package/dist/modules/Points/index.d.ts +31 -13
- package/dist/modules/Store/index.d.ts +93 -0
- package/dist/modules/core-module.d.ts +3 -3
- package/dist/stories/beginners/basic-set-up/data-gen.d.ts +4 -0
- package/dist/stories/beginners/basic-set-up/index.d.ts +6 -0
- package/dist/stories/beginners/link-hovering/data-generator.d.ts +19 -0
- package/dist/stories/beginners/link-hovering/index.d.ts +6 -0
- package/dist/stories/beginners/point-labels/data.d.ts +13 -0
- package/dist/stories/beginners/point-labels/index.d.ts +10 -0
- package/dist/stories/beginners/point-labels/labels.d.ts +8 -0
- package/dist/stories/beginners/quick-start.d.ts +6 -0
- package/dist/stories/beginners/remove-points/config.d.ts +2 -0
- package/dist/stories/beginners/remove-points/data-gen.d.ts +4 -0
- package/dist/stories/beginners/remove-points/index.d.ts +6 -0
- package/dist/stories/beginners.stories.d.ts +10 -0
- package/dist/stories/clusters/polygon-selection/index.d.ts +6 -0
- package/dist/stories/clusters/polygon-selection/polygon.d.ts +20 -0
- package/dist/stories/clusters/radial.d.ts +6 -0
- package/dist/stories/clusters/with-labels.d.ts +6 -0
- package/dist/stories/clusters/worm.d.ts +6 -0
- package/dist/stories/clusters.stories.d.ts +9 -0
- package/dist/stories/create-cluster-labels.d.ts +4 -0
- package/dist/stories/create-cosmos.d.ts +17 -0
- package/dist/stories/create-story.d.ts +16 -0
- package/dist/stories/experiments/full-mesh.d.ts +6 -0
- package/dist/stories/experiments/mesh-with-holes.d.ts +6 -0
- package/dist/stories/experiments.stories.d.ts +7 -0
- package/dist/stories/generate-mesh-data.d.ts +12 -0
- package/dist/stories/geospatial/moscow-metro-stations/index.d.ts +16 -0
- package/dist/stories/geospatial/moscow-metro-stations/moscow-metro-coords.d.ts +1 -0
- package/dist/stories/geospatial/moscow-metro-stations/point-colors.d.ts +1 -0
- package/dist/stories/geospatial.stories.d.ts +6 -0
- package/dist/stories/shapes/all-shapes/index.d.ts +6 -0
- package/dist/stories/shapes/image-example/index.d.ts +6 -0
- package/dist/stories/shapes.stories.d.ts +7 -0
- package/dist/stories/test-luma-migration.d.ts +6 -0
- package/dist/stories/test.stories.d.ts +6 -0
- package/dist/webgl-device-B9ewDj5L.js +3923 -0
- package/dist/webgl-device-B9ewDj5L.js.map +1 -0
- package/logo.svg +3 -0
- package/package.json +5 -7
- package/rollup.config.js +70 -0
- package/src/config.ts +728 -0
- package/src/declaration.d.ts +12 -0
- package/src/graph/utils/error-message.ts +23 -0
- package/src/helper.ts +113 -0
- package/src/index.ts +1769 -0
- package/src/modules/Clusters/calculate-centermass.frag +12 -0
- package/src/modules/Clusters/calculate-centermass.vert +38 -0
- package/src/modules/Clusters/force-cluster.frag +55 -0
- package/src/modules/Clusters/index.ts +578 -0
- package/src/modules/Drag/index.ts +33 -0
- package/src/modules/FPSMonitor/css.ts +53 -0
- package/src/modules/FPSMonitor/index.ts +28 -0
- package/src/modules/ForceCenter/calculate-centermass.frag +9 -0
- package/src/modules/ForceCenter/calculate-centermass.vert +26 -0
- package/src/modules/ForceCenter/force-center.frag +37 -0
- package/src/modules/ForceCenter/index.ts +284 -0
- package/src/modules/ForceGravity/force-gravity.frag +40 -0
- package/src/modules/ForceGravity/index.ts +107 -0
- package/src/modules/ForceLink/force-spring.ts +89 -0
- package/src/modules/ForceLink/index.ts +293 -0
- package/src/modules/ForceManyBody/calculate-level.frag +9 -0
- package/src/modules/ForceManyBody/calculate-level.vert +37 -0
- package/src/modules/ForceManyBody/force-centermass.frag +61 -0
- package/src/modules/ForceManyBody/force-level.frag +138 -0
- package/src/modules/ForceManyBody/index.ts +525 -0
- package/src/modules/ForceManyBody/quadtree-frag-shader.ts +89 -0
- package/src/modules/ForceManyBodyQuadtree/calculate-level.frag +9 -0
- package/src/modules/ForceManyBodyQuadtree/calculate-level.vert +25 -0
- package/src/modules/ForceManyBodyQuadtree/index.ts +157 -0
- package/src/modules/ForceManyBodyQuadtree/quadtree-frag-shader.ts +93 -0
- package/src/modules/ForceMouse/force-mouse.frag +35 -0
- package/src/modules/ForceMouse/index.ts +102 -0
- package/src/modules/GraphData/index.ts +383 -0
- package/src/modules/Lines/draw-curve-line.frag +59 -0
- package/src/modules/Lines/draw-curve-line.vert +248 -0
- package/src/modules/Lines/geometry.ts +18 -0
- package/src/modules/Lines/hovered-line-index.frag +43 -0
- package/src/modules/Lines/hovered-line-index.vert +13 -0
- package/src/modules/Lines/index.ts +661 -0
- package/src/modules/Points/atlas-utils.ts +137 -0
- package/src/modules/Points/drag-point.frag +34 -0
- package/src/modules/Points/draw-highlighted.frag +44 -0
- package/src/modules/Points/draw-highlighted.vert +145 -0
- package/src/modules/Points/draw-points.frag +259 -0
- package/src/modules/Points/draw-points.vert +203 -0
- package/src/modules/Points/fill-sampled-points.frag +12 -0
- package/src/modules/Points/fill-sampled-points.vert +51 -0
- package/src/modules/Points/find-hovered-point.frag +15 -0
- package/src/modules/Points/find-hovered-point.vert +90 -0
- package/src/modules/Points/find-points-on-area-selection.frag +88 -0
- package/src/modules/Points/find-points-on-polygon-selection.frag +89 -0
- package/src/modules/Points/index.ts +2292 -0
- package/src/modules/Points/track-positions.frag +30 -0
- package/src/modules/Points/update-position.frag +39 -0
- package/src/modules/Shared/buffer.ts +39 -0
- package/src/modules/Shared/clear.frag +10 -0
- package/src/modules/Shared/quad.vert +13 -0
- package/src/modules/Store/index.ts +283 -0
- package/src/modules/Zoom/index.ts +148 -0
- package/src/modules/core-module.ts +28 -0
- package/src/stories/1. welcome.mdx +75 -0
- package/src/stories/2. configuration.mdx +111 -0
- package/src/stories/3. api-reference.mdx +591 -0
- package/src/stories/beginners/basic-set-up/data-gen.ts +33 -0
- package/src/stories/beginners/basic-set-up/index.ts +167 -0
- package/src/stories/beginners/basic-set-up/style.css +35 -0
- package/src/stories/beginners/link-hovering/data-generator.ts +198 -0
- package/src/stories/beginners/link-hovering/index.ts +65 -0
- package/src/stories/beginners/link-hovering/style.css +73 -0
- package/src/stories/beginners/point-labels/data.ts +73 -0
- package/src/stories/beginners/point-labels/index.ts +69 -0
- package/src/stories/beginners/point-labels/labels.ts +46 -0
- package/src/stories/beginners/point-labels/style.css +16 -0
- package/src/stories/beginners/quick-start.ts +54 -0
- package/src/stories/beginners/remove-points/config.ts +25 -0
- package/src/stories/beginners/remove-points/data-gen.ts +30 -0
- package/src/stories/beginners/remove-points/index.ts +96 -0
- package/src/stories/beginners/remove-points/style.css +31 -0
- package/src/stories/beginners.stories.ts +130 -0
- package/src/stories/clusters/polygon-selection/index.ts +52 -0
- package/src/stories/clusters/polygon-selection/polygon.ts +143 -0
- package/src/stories/clusters/polygon-selection/style.css +8 -0
- package/src/stories/clusters/radial.ts +24 -0
- package/src/stories/clusters/with-labels.ts +54 -0
- package/src/stories/clusters/worm.ts +40 -0
- package/src/stories/clusters.stories.ts +77 -0
- package/src/stories/create-cluster-labels.ts +50 -0
- package/src/stories/create-cosmos.ts +72 -0
- package/src/stories/create-story.ts +51 -0
- package/src/stories/experiments/full-mesh.ts +13 -0
- package/src/stories/experiments/mesh-with-holes.ts +13 -0
- package/src/stories/experiments.stories.ts +43 -0
- package/src/stories/generate-mesh-data.ts +125 -0
- package/src/stories/geospatial/moscow-metro-stations/index.ts +66 -0
- package/src/stories/geospatial/moscow-metro-stations/moscow-metro-coords.ts +1 -0
- package/src/stories/geospatial/moscow-metro-stations/point-colors.ts +46 -0
- package/src/stories/geospatial/moscow-metro-stations/style.css +30 -0
- package/src/stories/geospatial.stories.ts +30 -0
- package/src/stories/shapes/all-shapes/index.ts +73 -0
- package/src/stories/shapes/image-example/icons/box.png +0 -0
- package/src/stories/shapes/image-example/icons/lego.png +0 -0
- package/src/stories/shapes/image-example/icons/s.png +0 -0
- package/src/stories/shapes/image-example/icons/swift.png +0 -0
- package/src/stories/shapes/image-example/icons/toolbox.png +0 -0
- package/src/stories/shapes/image-example/index.ts +246 -0
- package/src/stories/shapes.stories.ts +37 -0
- package/src/stories/test-luma-migration.ts +195 -0
- package/src/stories/test.stories.ts +25 -0
- package/src/variables.ts +68 -0
- package/tsconfig.json +41 -0
- package/vite.config.ts +52 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export function forceFrag (maxLinks: number): string {
|
|
2
|
+
return `#version 300 es
|
|
3
|
+
precision highp float;
|
|
4
|
+
|
|
5
|
+
uniform sampler2D positionsTexture;
|
|
6
|
+
uniform sampler2D linkInfoTexture; // Texture storing first link indices and amount
|
|
7
|
+
uniform sampler2D linkIndicesTexture;
|
|
8
|
+
uniform sampler2D linkPropertiesTexture; // Texture storing link bias and strength
|
|
9
|
+
uniform sampler2D linkRandomDistanceTexture;
|
|
10
|
+
|
|
11
|
+
#ifdef USE_UNIFORM_BUFFERS
|
|
12
|
+
layout(std140) uniform forceLinkUniforms {
|
|
13
|
+
float linkSpring;
|
|
14
|
+
float linkDistance;
|
|
15
|
+
vec2 linkDistRandomVariationRange;
|
|
16
|
+
float pointsTextureSize;
|
|
17
|
+
float linksTextureSize;
|
|
18
|
+
float alpha;
|
|
19
|
+
} forceLink;
|
|
20
|
+
|
|
21
|
+
#define linkSpring forceLink.linkSpring
|
|
22
|
+
#define linkDistance forceLink.linkDistance
|
|
23
|
+
#define linkDistRandomVariationRange forceLink.linkDistRandomVariationRange
|
|
24
|
+
#define pointsTextureSize forceLink.pointsTextureSize
|
|
25
|
+
#define linksTextureSize forceLink.linksTextureSize
|
|
26
|
+
#define alpha forceLink.alpha
|
|
27
|
+
#else
|
|
28
|
+
uniform float linkSpring;
|
|
29
|
+
uniform float linkDistance;
|
|
30
|
+
uniform vec2 linkDistRandomVariationRange;
|
|
31
|
+
uniform float pointsTextureSize;
|
|
32
|
+
uniform float linksTextureSize;
|
|
33
|
+
uniform float alpha;
|
|
34
|
+
#endif
|
|
35
|
+
|
|
36
|
+
in vec2 textureCoords;
|
|
37
|
+
out vec4 fragColor;
|
|
38
|
+
|
|
39
|
+
const float MAX_LINKS = ${maxLinks}.0;
|
|
40
|
+
|
|
41
|
+
void main() {
|
|
42
|
+
vec4 pointPosition = texture(positionsTexture, textureCoords);
|
|
43
|
+
vec4 velocity = vec4(0.0);
|
|
44
|
+
|
|
45
|
+
vec4 linkInfo = texture(linkInfoTexture, textureCoords);
|
|
46
|
+
float iCount = linkInfo.r;
|
|
47
|
+
float jCount = linkInfo.g;
|
|
48
|
+
float linkAmount = linkInfo.b;
|
|
49
|
+
if (linkAmount > 0.0) {
|
|
50
|
+
for (float i = 0.0; i < MAX_LINKS; i += 1.0) {
|
|
51
|
+
if (i < linkAmount) {
|
|
52
|
+
if (iCount >= linksTextureSize) {
|
|
53
|
+
iCount = 0.0;
|
|
54
|
+
jCount += 1.0;
|
|
55
|
+
}
|
|
56
|
+
vec2 linkTextureIndex = (vec2(iCount, jCount) + 0.5) / linksTextureSize;
|
|
57
|
+
vec4 connectedPointIndex = texture(linkIndicesTexture, linkTextureIndex);
|
|
58
|
+
vec4 biasAndStrength = texture(linkPropertiesTexture, linkTextureIndex);
|
|
59
|
+
vec4 randomMinDistance = texture(linkRandomDistanceTexture, linkTextureIndex);
|
|
60
|
+
float bias = biasAndStrength.r;
|
|
61
|
+
float strength = biasAndStrength.g;
|
|
62
|
+
float randomMinLinkDist = randomMinDistance.r * (linkDistRandomVariationRange.g - linkDistRandomVariationRange.r) + linkDistRandomVariationRange.r;
|
|
63
|
+
randomMinLinkDist *= linkDistance;
|
|
64
|
+
|
|
65
|
+
iCount += 1.0;
|
|
66
|
+
|
|
67
|
+
vec4 connectedPointPosition = texture(positionsTexture, (connectedPointIndex.rg + 0.5) / pointsTextureSize);
|
|
68
|
+
float x = connectedPointPosition.x - (pointPosition.x + velocity.x);
|
|
69
|
+
float y = connectedPointPosition.y - (pointPosition.y + velocity.y);
|
|
70
|
+
float l = sqrt(x * x + y * y);
|
|
71
|
+
|
|
72
|
+
// Apply the link force
|
|
73
|
+
l = max(l, randomMinLinkDist * 0.99);
|
|
74
|
+
l = (l - randomMinLinkDist) / l;
|
|
75
|
+
l *= linkSpring * alpha;
|
|
76
|
+
l *= strength;
|
|
77
|
+
l *= bias;
|
|
78
|
+
x *= l;
|
|
79
|
+
y *= l;
|
|
80
|
+
velocity.x += x;
|
|
81
|
+
velocity.y += y;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fragColor = vec4(velocity.rg, 0.0, 0.0);
|
|
87
|
+
}
|
|
88
|
+
`
|
|
89
|
+
}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { Buffer, RenderPass, Texture, UniformStore } from '@luma.gl/core'
|
|
2
|
+
import { Model } from '@luma.gl/engine'
|
|
3
|
+
import { CoreModule } from '@/graph/modules/core-module'
|
|
4
|
+
import { forceFrag } from '@/graph/modules/ForceLink/force-spring'
|
|
5
|
+
import updateVert from '@/graph/modules/Shared/quad.vert?raw'
|
|
6
|
+
|
|
7
|
+
export enum LinkDirection {
|
|
8
|
+
OUTGOING = 'outgoing',
|
|
9
|
+
INCOMING = 'incoming'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class ForceLink extends CoreModule {
|
|
13
|
+
private linkFirstIndicesAndAmount: Float32Array = new Float32Array()
|
|
14
|
+
private indices: Float32Array = new Float32Array()
|
|
15
|
+
private maxPointDegree = 0
|
|
16
|
+
private previousMaxPointDegree: number | undefined
|
|
17
|
+
private previousPointsTextureSize: number | undefined
|
|
18
|
+
private previousLinksTextureSize: number | undefined
|
|
19
|
+
|
|
20
|
+
private runCommand: Model | undefined
|
|
21
|
+
private vertexCoordBuffer: Buffer | undefined
|
|
22
|
+
private uniformStore: UniformStore<{
|
|
23
|
+
forceLinkUniforms: {
|
|
24
|
+
linkSpring: number;
|
|
25
|
+
linkDistance: number;
|
|
26
|
+
linkDistRandomVariationRange: [number, number];
|
|
27
|
+
pointsTextureSize: number;
|
|
28
|
+
linksTextureSize: number;
|
|
29
|
+
alpha: number;
|
|
30
|
+
};
|
|
31
|
+
}> | undefined
|
|
32
|
+
|
|
33
|
+
private linkFirstIndicesAndAmountTexture: Texture | undefined
|
|
34
|
+
private indicesTexture: Texture | undefined
|
|
35
|
+
private biasAndStrengthTexture: Texture | undefined
|
|
36
|
+
private randomDistanceTexture: Texture | undefined
|
|
37
|
+
|
|
38
|
+
public create (direction: LinkDirection): void {
|
|
39
|
+
const { device, store: { pointsTextureSize, linksTextureSize }, data } = this
|
|
40
|
+
if (!pointsTextureSize || !linksTextureSize) return
|
|
41
|
+
|
|
42
|
+
this.linkFirstIndicesAndAmount = new Float32Array(pointsTextureSize * pointsTextureSize * 4)
|
|
43
|
+
this.indices = new Float32Array(linksTextureSize * linksTextureSize * 4)
|
|
44
|
+
const linkBiasAndStrengthState = new Float32Array(linksTextureSize * linksTextureSize * 4)
|
|
45
|
+
const linkDistanceState = new Float32Array(linksTextureSize * linksTextureSize * 4)
|
|
46
|
+
|
|
47
|
+
const grouped = direction === LinkDirection.INCOMING ? data.sourceIndexToTargetIndices : data.targetIndexToSourceIndices
|
|
48
|
+
this.maxPointDegree = 0
|
|
49
|
+
let linkIndex = 0
|
|
50
|
+
grouped?.forEach((connectedPointIndices, pointIndex) => {
|
|
51
|
+
if (connectedPointIndices) {
|
|
52
|
+
this.linkFirstIndicesAndAmount[pointIndex * 4 + 0] = linkIndex % linksTextureSize
|
|
53
|
+
this.linkFirstIndicesAndAmount[pointIndex * 4 + 1] = Math.floor(linkIndex / linksTextureSize)
|
|
54
|
+
this.linkFirstIndicesAndAmount[pointIndex * 4 + 2] = connectedPointIndices.length ?? 0
|
|
55
|
+
|
|
56
|
+
connectedPointIndices.forEach(([connectedPointIndex, initialLinkIndex]) => {
|
|
57
|
+
this.indices[linkIndex * 4 + 0] = connectedPointIndex % pointsTextureSize
|
|
58
|
+
this.indices[linkIndex * 4 + 1] = Math.floor(connectedPointIndex / pointsTextureSize)
|
|
59
|
+
const degree = data.degree?.[connectedPointIndex] ?? 0
|
|
60
|
+
const connectedDegree = data.degree?.[pointIndex] ?? 0
|
|
61
|
+
const degreeSum = degree + connectedDegree
|
|
62
|
+
// Prevent division by zero
|
|
63
|
+
const bias = degreeSum !== 0 ? degree / degreeSum : 0.5
|
|
64
|
+
const minDegree = Math.min(degree, connectedDegree)
|
|
65
|
+
// Prevent division by zero
|
|
66
|
+
let strength = data.linkStrength?.[initialLinkIndex] ?? (1 / Math.max(minDegree, 1))
|
|
67
|
+
strength = Math.sqrt(strength)
|
|
68
|
+
linkBiasAndStrengthState[linkIndex * 4 + 0] = bias
|
|
69
|
+
linkBiasAndStrengthState[linkIndex * 4 + 1] = strength
|
|
70
|
+
linkDistanceState[linkIndex * 4] = this.store.getRandomFloat(0, 1)
|
|
71
|
+
|
|
72
|
+
linkIndex += 1
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
this.maxPointDegree = Math.max(this.maxPointDegree, connectedPointIndices.length ?? 0)
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// Recreate textures if sizes changed
|
|
80
|
+
const recreatePointTextures =
|
|
81
|
+
!this.linkFirstIndicesAndAmountTexture ||
|
|
82
|
+
this.linkFirstIndicesAndAmountTexture.width !== pointsTextureSize ||
|
|
83
|
+
this.linkFirstIndicesAndAmountTexture.height !== pointsTextureSize
|
|
84
|
+
|
|
85
|
+
const recreateLinkTextures =
|
|
86
|
+
!this.indicesTexture ||
|
|
87
|
+
this.indicesTexture.width !== linksTextureSize ||
|
|
88
|
+
this.indicesTexture.height !== linksTextureSize
|
|
89
|
+
|
|
90
|
+
if (recreatePointTextures) {
|
|
91
|
+
if (this.linkFirstIndicesAndAmountTexture && !this.linkFirstIndicesAndAmountTexture.destroyed) {
|
|
92
|
+
this.linkFirstIndicesAndAmountTexture.destroy()
|
|
93
|
+
}
|
|
94
|
+
this.linkFirstIndicesAndAmountTexture = device.createTexture({
|
|
95
|
+
width: pointsTextureSize,
|
|
96
|
+
height: pointsTextureSize,
|
|
97
|
+
format: 'rgba32float',
|
|
98
|
+
usage: Texture.SAMPLE | Texture.COPY_DST,
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
this.linkFirstIndicesAndAmountTexture!.copyImageData({
|
|
102
|
+
data: this.linkFirstIndicesAndAmount,
|
|
103
|
+
bytesPerRow: pointsTextureSize,
|
|
104
|
+
mipLevel: 0,
|
|
105
|
+
x: 0,
|
|
106
|
+
y: 0,
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
if (recreateLinkTextures) {
|
|
110
|
+
if (this.indicesTexture && !this.indicesTexture.destroyed) this.indicesTexture.destroy()
|
|
111
|
+
if (this.biasAndStrengthTexture && !this.biasAndStrengthTexture.destroyed) this.biasAndStrengthTexture.destroy()
|
|
112
|
+
if (this.randomDistanceTexture && !this.randomDistanceTexture.destroyed) this.randomDistanceTexture.destroy()
|
|
113
|
+
|
|
114
|
+
this.indicesTexture = device.createTexture({
|
|
115
|
+
width: linksTextureSize,
|
|
116
|
+
height: linksTextureSize,
|
|
117
|
+
format: 'rgba32float',
|
|
118
|
+
usage: Texture.SAMPLE | Texture.COPY_DST,
|
|
119
|
+
})
|
|
120
|
+
this.biasAndStrengthTexture = device.createTexture({
|
|
121
|
+
width: linksTextureSize,
|
|
122
|
+
height: linksTextureSize,
|
|
123
|
+
format: 'rgba32float',
|
|
124
|
+
usage: Texture.SAMPLE | Texture.COPY_DST,
|
|
125
|
+
})
|
|
126
|
+
this.randomDistanceTexture = device.createTexture({
|
|
127
|
+
width: linksTextureSize,
|
|
128
|
+
height: linksTextureSize,
|
|
129
|
+
format: 'rgba32float',
|
|
130
|
+
usage: Texture.SAMPLE | Texture.COPY_DST,
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.indicesTexture!.copyImageData({
|
|
135
|
+
data: this.indices,
|
|
136
|
+
bytesPerRow: linksTextureSize,
|
|
137
|
+
mipLevel: 0,
|
|
138
|
+
x: 0,
|
|
139
|
+
y: 0,
|
|
140
|
+
})
|
|
141
|
+
this.biasAndStrengthTexture!.copyImageData({
|
|
142
|
+
data: linkBiasAndStrengthState,
|
|
143
|
+
bytesPerRow: linksTextureSize,
|
|
144
|
+
mipLevel: 0,
|
|
145
|
+
x: 0,
|
|
146
|
+
y: 0,
|
|
147
|
+
})
|
|
148
|
+
this.randomDistanceTexture!.copyImageData({
|
|
149
|
+
data: linkDistanceState,
|
|
150
|
+
bytesPerRow: linksTextureSize,
|
|
151
|
+
mipLevel: 0,
|
|
152
|
+
x: 0,
|
|
153
|
+
y: 0,
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// Force shader rebuild if degree changed
|
|
157
|
+
if (this.previousMaxPointDegree !== undefined && this.previousMaxPointDegree !== this.maxPointDegree) {
|
|
158
|
+
this.runCommand?.destroy()
|
|
159
|
+
this.runCommand = undefined
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
this.previousMaxPointDegree = this.maxPointDegree
|
|
163
|
+
this.previousPointsTextureSize = pointsTextureSize
|
|
164
|
+
this.previousLinksTextureSize = linksTextureSize
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public initPrograms (): void {
|
|
168
|
+
const { device, store, points } = this
|
|
169
|
+
if (!points || !store.pointsTextureSize || !store.linksTextureSize) return
|
|
170
|
+
if (!this.linkFirstIndicesAndAmountTexture || !this.indicesTexture || !this.biasAndStrengthTexture || !this.randomDistanceTexture) return
|
|
171
|
+
|
|
172
|
+
if (!this.vertexCoordBuffer || this.vertexCoordBuffer.destroyed) {
|
|
173
|
+
this.vertexCoordBuffer = device.createBuffer({
|
|
174
|
+
data: new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!this.uniformStore) {
|
|
179
|
+
this.uniformStore = new UniformStore({
|
|
180
|
+
forceLinkUniforms: {
|
|
181
|
+
uniformTypes: {
|
|
182
|
+
linkSpring: 'f32',
|
|
183
|
+
linkDistance: 'f32',
|
|
184
|
+
linkDistRandomVariationRange: 'vec2<f32>',
|
|
185
|
+
pointsTextureSize: 'f32',
|
|
186
|
+
linksTextureSize: 'f32',
|
|
187
|
+
alpha: 'f32',
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (!this.runCommand) {
|
|
194
|
+
this.runCommand = new Model(device, {
|
|
195
|
+
fs: forceFrag(this.maxPointDegree),
|
|
196
|
+
vs: updateVert,
|
|
197
|
+
topology: 'triangle-strip',
|
|
198
|
+
vertexCount: 4,
|
|
199
|
+
attributes: {
|
|
200
|
+
vertexCoord: this.vertexCoordBuffer,
|
|
201
|
+
},
|
|
202
|
+
bufferLayout: [
|
|
203
|
+
{ name: 'vertexCoord', format: 'float32x2' },
|
|
204
|
+
],
|
|
205
|
+
defines: {
|
|
206
|
+
USE_UNIFORM_BUFFERS: true,
|
|
207
|
+
},
|
|
208
|
+
bindings: {
|
|
209
|
+
forceLinkUniforms: this.uniformStore.getManagedUniformBuffer(device, 'forceLinkUniforms'),
|
|
210
|
+
positionsTexture: points.previousPositionTexture!,
|
|
211
|
+
linkInfoTexture: this.linkFirstIndicesAndAmountTexture,
|
|
212
|
+
linkIndicesTexture: this.indicesTexture,
|
|
213
|
+
linkPropertiesTexture: this.biasAndStrengthTexture,
|
|
214
|
+
linkRandomDistanceTexture: this.randomDistanceTexture,
|
|
215
|
+
},
|
|
216
|
+
parameters: {
|
|
217
|
+
depthWriteEnabled: false,
|
|
218
|
+
depthCompare: 'always',
|
|
219
|
+
},
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
public run (renderPass?: RenderPass): void {
|
|
225
|
+
const { device, store, points } = this
|
|
226
|
+
if (!points || !this.runCommand || !this.uniformStore) return
|
|
227
|
+
if (!points.previousPositionTexture || points.previousPositionTexture.destroyed) return
|
|
228
|
+
if (!this.linkFirstIndicesAndAmountTexture || !this.indicesTexture || !this.biasAndStrengthTexture || !this.randomDistanceTexture) return
|
|
229
|
+
if (!renderPass && (!points.velocityFbo || points.velocityFbo.destroyed)) return
|
|
230
|
+
|
|
231
|
+
// Skip if sizes changed and create() wasn't called again
|
|
232
|
+
if (
|
|
233
|
+
store.pointsTextureSize !== this.previousPointsTextureSize ||
|
|
234
|
+
store.linksTextureSize !== this.previousLinksTextureSize
|
|
235
|
+
) {
|
|
236
|
+
return
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
this.uniformStore.setUniforms({
|
|
240
|
+
forceLinkUniforms: {
|
|
241
|
+
linkSpring: this.config.simulationLinkSpring ?? 0,
|
|
242
|
+
linkDistance: this.config.simulationLinkDistance ?? 0,
|
|
243
|
+
linkDistRandomVariationRange: [
|
|
244
|
+
this.config.simulationLinkDistRandomVariationRange?.[0] ?? 0,
|
|
245
|
+
this.config.simulationLinkDistRandomVariationRange?.[1] ?? 0,
|
|
246
|
+
],
|
|
247
|
+
pointsTextureSize: store.pointsTextureSize,
|
|
248
|
+
linksTextureSize: store.linksTextureSize,
|
|
249
|
+
alpha: store.alpha,
|
|
250
|
+
},
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
this.runCommand.setBindings({
|
|
254
|
+
forceLinkUniforms: this.uniformStore.getManagedUniformBuffer(device, 'forceLinkUniforms'),
|
|
255
|
+
positionsTexture: points.previousPositionTexture!,
|
|
256
|
+
linkInfoTexture: this.linkFirstIndicesAndAmountTexture,
|
|
257
|
+
linkIndicesTexture: this.indicesTexture,
|
|
258
|
+
linkPropertiesTexture: this.biasAndStrengthTexture,
|
|
259
|
+
linkRandomDistanceTexture: this.randomDistanceTexture,
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
const pass = renderPass ?? device.beginRenderPass({
|
|
263
|
+
framebuffer: points.velocityFbo,
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
this.runCommand.draw(pass)
|
|
267
|
+
|
|
268
|
+
if (!renderPass) pass.end()
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
public destroy (): void {
|
|
272
|
+
this.uniformStore?.destroy()
|
|
273
|
+
this.uniformStore = undefined
|
|
274
|
+
|
|
275
|
+
this.runCommand?.destroy()
|
|
276
|
+
this.runCommand = undefined
|
|
277
|
+
|
|
278
|
+
if (this.vertexCoordBuffer && !this.vertexCoordBuffer.destroyed) this.vertexCoordBuffer.destroy()
|
|
279
|
+
this.vertexCoordBuffer = undefined
|
|
280
|
+
|
|
281
|
+
if (this.linkFirstIndicesAndAmountTexture && !this.linkFirstIndicesAndAmountTexture.destroyed) this.linkFirstIndicesAndAmountTexture.destroy()
|
|
282
|
+
this.linkFirstIndicesAndAmountTexture = undefined
|
|
283
|
+
|
|
284
|
+
if (this.indicesTexture && !this.indicesTexture.destroyed) this.indicesTexture.destroy()
|
|
285
|
+
this.indicesTexture = undefined
|
|
286
|
+
|
|
287
|
+
if (this.biasAndStrengthTexture && !this.biasAndStrengthTexture.destroyed) this.biasAndStrengthTexture.destroy()
|
|
288
|
+
this.biasAndStrengthTexture = undefined
|
|
289
|
+
|
|
290
|
+
if (this.randomDistanceTexture && !this.randomDistanceTexture.destroyed) this.randomDistanceTexture.destroy()
|
|
291
|
+
this.randomDistanceTexture = undefined
|
|
292
|
+
}
|
|
293
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#version 300 es
|
|
2
|
+
precision highp float;
|
|
3
|
+
|
|
4
|
+
uniform sampler2D positionsTexture;
|
|
5
|
+
|
|
6
|
+
#ifdef USE_UNIFORM_BUFFERS
|
|
7
|
+
layout(std140) uniform calculateLevelsUniforms {
|
|
8
|
+
float pointsTextureSize;
|
|
9
|
+
float levelTextureSize;
|
|
10
|
+
float cellSize;
|
|
11
|
+
} calculateLevels;
|
|
12
|
+
|
|
13
|
+
#define pointsTextureSize calculateLevels.pointsTextureSize
|
|
14
|
+
#define levelTextureSize calculateLevels.levelTextureSize
|
|
15
|
+
#define cellSize calculateLevels.cellSize
|
|
16
|
+
#else
|
|
17
|
+
uniform float pointsTextureSize;
|
|
18
|
+
uniform float levelTextureSize;
|
|
19
|
+
uniform float cellSize;
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
in vec2 pointIndices;
|
|
23
|
+
|
|
24
|
+
out vec4 vColor;
|
|
25
|
+
|
|
26
|
+
void main() {
|
|
27
|
+
vec4 pointPosition = texture(positionsTexture, pointIndices / pointsTextureSize);
|
|
28
|
+
vColor = vec4(pointPosition.rg, 1.0, 0.0);
|
|
29
|
+
|
|
30
|
+
float n = floor(pointPosition.x / cellSize);
|
|
31
|
+
float m = floor(pointPosition.y / cellSize);
|
|
32
|
+
|
|
33
|
+
vec2 levelPosition = 2.0 * (vec2(n, m) + 0.5) / levelTextureSize - 1.0;
|
|
34
|
+
|
|
35
|
+
gl_Position = vec4(levelPosition, 0.0, 1.0);
|
|
36
|
+
gl_PointSize = 1.0;
|
|
37
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#version 300 es
|
|
2
|
+
precision highp float;
|
|
3
|
+
|
|
4
|
+
uniform sampler2D positionsTexture;
|
|
5
|
+
uniform sampler2D levelFbo;
|
|
6
|
+
uniform sampler2D randomValues;
|
|
7
|
+
|
|
8
|
+
#ifdef USE_UNIFORM_BUFFERS
|
|
9
|
+
layout(std140) uniform forceCenterUniforms {
|
|
10
|
+
float levelTextureSize;
|
|
11
|
+
float repulsion;
|
|
12
|
+
float alpha;
|
|
13
|
+
} forceCenter;
|
|
14
|
+
|
|
15
|
+
#define levelTextureSize forceCenter.levelTextureSize
|
|
16
|
+
#define repulsion forceCenter.repulsion
|
|
17
|
+
#define alpha forceCenter.alpha
|
|
18
|
+
#else
|
|
19
|
+
uniform float levelTextureSize;
|
|
20
|
+
uniform float repulsion;
|
|
21
|
+
uniform float alpha;
|
|
22
|
+
#endif
|
|
23
|
+
|
|
24
|
+
in vec2 textureCoords;
|
|
25
|
+
out vec4 fragColor;
|
|
26
|
+
|
|
27
|
+
// Calculate the additional velocity based on the center of mass
|
|
28
|
+
vec2 calculateAdditionalVelocity (vec2 ij, vec2 pp) {
|
|
29
|
+
vec2 add = vec2(0.0);
|
|
30
|
+
vec4 centermass = texture(levelFbo, ij);
|
|
31
|
+
if (centermass.r > 0.0 && centermass.g > 0.0 && centermass.b > 0.0) {
|
|
32
|
+
vec2 centermassPosition = vec2(centermass.rg / centermass.b);
|
|
33
|
+
vec2 distVector = pp - centermassPosition;
|
|
34
|
+
float l = dot(distVector, distVector);
|
|
35
|
+
float dist = sqrt(l);
|
|
36
|
+
if (l > 0.0) {
|
|
37
|
+
float angle = atan(distVector.y, distVector.x);
|
|
38
|
+
float c = alpha * repulsion * centermass.b;
|
|
39
|
+
|
|
40
|
+
float distanceMin2 = 1.0;
|
|
41
|
+
if (l < distanceMin2) l = sqrt(distanceMin2 * l);
|
|
42
|
+
float addV = c / sqrt(l);
|
|
43
|
+
add = addV * vec2(cos(angle), sin(angle));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return add;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
void main() {
|
|
50
|
+
vec4 pointPosition = texture(positionsTexture, textureCoords);
|
|
51
|
+
vec4 random = texture(randomValues, textureCoords);
|
|
52
|
+
|
|
53
|
+
vec4 velocity = vec4(0.0);
|
|
54
|
+
|
|
55
|
+
// Calculate additional velocity based on the point position
|
|
56
|
+
velocity.xy += calculateAdditionalVelocity(pointPosition.xy / levelTextureSize, pointPosition.xy);
|
|
57
|
+
// Apply random factor to the velocity
|
|
58
|
+
velocity.xy += velocity.xy * random.rg;
|
|
59
|
+
|
|
60
|
+
fragColor = velocity;
|
|
61
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#version 300 es
|
|
2
|
+
precision highp float;
|
|
3
|
+
|
|
4
|
+
uniform sampler2D positionsTexture;
|
|
5
|
+
uniform sampler2D levelFbo;
|
|
6
|
+
|
|
7
|
+
#ifdef USE_UNIFORM_BUFFERS
|
|
8
|
+
layout(std140) uniform forceUniforms {
|
|
9
|
+
float level;
|
|
10
|
+
float levels;
|
|
11
|
+
float levelTextureSize;
|
|
12
|
+
float repulsion;
|
|
13
|
+
float alpha;
|
|
14
|
+
float spaceSize;
|
|
15
|
+
float theta;
|
|
16
|
+
} force;
|
|
17
|
+
|
|
18
|
+
#define level force.level
|
|
19
|
+
#define levels force.levels
|
|
20
|
+
#define levelTextureSize force.levelTextureSize
|
|
21
|
+
#define repulsion force.repulsion
|
|
22
|
+
#define alpha force.alpha
|
|
23
|
+
#define spaceSize force.spaceSize
|
|
24
|
+
#define theta force.theta
|
|
25
|
+
#else
|
|
26
|
+
uniform float level;
|
|
27
|
+
uniform float levels;
|
|
28
|
+
uniform float levelTextureSize;
|
|
29
|
+
uniform float repulsion;
|
|
30
|
+
uniform float alpha;
|
|
31
|
+
uniform float spaceSize;
|
|
32
|
+
uniform float theta;
|
|
33
|
+
#endif
|
|
34
|
+
|
|
35
|
+
in vec2 textureCoords;
|
|
36
|
+
out vec4 fragColor;
|
|
37
|
+
|
|
38
|
+
const float MAX_LEVELS_NUM = 14.0;
|
|
39
|
+
|
|
40
|
+
vec2 calculateAdditionalVelocity (vec2 ij, vec2 pp) {
|
|
41
|
+
vec2 add = vec2(0.0);
|
|
42
|
+
vec4 centermass = texture(levelFbo, ij);
|
|
43
|
+
if (centermass.r > 0.0 && centermass.g > 0.0 && centermass.b > 0.0) {
|
|
44
|
+
vec2 centermassPosition = vec2(centermass.rg / centermass.b);
|
|
45
|
+
vec2 distVector = pp - centermassPosition;
|
|
46
|
+
float l = dot(distVector, distVector);
|
|
47
|
+
float dist = sqrt(l);
|
|
48
|
+
if (l > 0.0) {
|
|
49
|
+
float c = alpha * repulsion * centermass.b;
|
|
50
|
+
|
|
51
|
+
float distanceMin2 = 1.0;
|
|
52
|
+
if (l < distanceMin2) l = sqrt(distanceMin2 * l);
|
|
53
|
+
float addV = c / sqrt(l);
|
|
54
|
+
add = addV * normalize(distVector);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return add;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
void main() {
|
|
61
|
+
vec4 pointPosition = texture(positionsTexture, textureCoords);
|
|
62
|
+
float x = pointPosition.x;
|
|
63
|
+
float y = pointPosition.y;
|
|
64
|
+
|
|
65
|
+
float left = 0.0;
|
|
66
|
+
float top = 0.0;
|
|
67
|
+
float right = spaceSize;
|
|
68
|
+
float bottom = spaceSize;
|
|
69
|
+
|
|
70
|
+
float n_left = 0.0;
|
|
71
|
+
float n_top = 0.0;
|
|
72
|
+
float n_right = 0.0;
|
|
73
|
+
float n_bottom = 0.0;
|
|
74
|
+
|
|
75
|
+
float cellSize = 0.0;
|
|
76
|
+
|
|
77
|
+
// Iterate over levels to adjust the boundaries based on the current level
|
|
78
|
+
for (float i = 0.0; i < MAX_LEVELS_NUM; i += 1.0) {
|
|
79
|
+
if (i <= level) {
|
|
80
|
+
left += cellSize * n_left;
|
|
81
|
+
top += cellSize * n_top;
|
|
82
|
+
right -= cellSize * n_right;
|
|
83
|
+
bottom -= cellSize * n_bottom;
|
|
84
|
+
|
|
85
|
+
cellSize = pow(2.0 , levels - i - 1.0);
|
|
86
|
+
|
|
87
|
+
float dist_left = x - left;
|
|
88
|
+
n_left = max(0.0, floor(dist_left / cellSize - theta));
|
|
89
|
+
|
|
90
|
+
float dist_top = y - top;
|
|
91
|
+
n_top = max(0.0, floor(dist_top / cellSize - theta));
|
|
92
|
+
|
|
93
|
+
float dist_right = right - x;
|
|
94
|
+
n_right = max(0.0, floor(dist_right / cellSize - theta));
|
|
95
|
+
|
|
96
|
+
float dist_bottom = bottom - y;
|
|
97
|
+
n_bottom = max(0.0, floor(dist_bottom / cellSize - theta));
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
vec4 velocity = vec4(vec2(0.0), 1.0, 0.0);
|
|
103
|
+
|
|
104
|
+
// Calculate the additional velocity based on neighboring cells
|
|
105
|
+
for (float i = 0.0; i < 12.0; i += 1.0) {
|
|
106
|
+
for (float j = 0.0; j < 4.0; j += 1.0) {
|
|
107
|
+
float n = left + cellSize * j;
|
|
108
|
+
float m = top + cellSize * n_top + cellSize * i;
|
|
109
|
+
|
|
110
|
+
if (n < (left + n_left * cellSize) && m < bottom) {
|
|
111
|
+
velocity.xy += calculateAdditionalVelocity(vec2(n / cellSize, m / cellSize) / levelTextureSize, pointPosition.xy);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
n = left + cellSize * i;
|
|
115
|
+
m = top + cellSize * j;
|
|
116
|
+
|
|
117
|
+
if (n < (right - n_right * cellSize) && m < (top + n_top * cellSize)) {
|
|
118
|
+
velocity.xy += calculateAdditionalVelocity(vec2(n / cellSize, m / cellSize) / levelTextureSize, pointPosition.xy);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
n = right - n_right * cellSize + cellSize * j;
|
|
122
|
+
m = top + cellSize * i;
|
|
123
|
+
|
|
124
|
+
if (n < right && m < (bottom - n_bottom * cellSize)) {
|
|
125
|
+
velocity.xy += calculateAdditionalVelocity(vec2(n / cellSize, m / cellSize) / levelTextureSize, pointPosition.xy);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
n = left + n_left * cellSize + cellSize * i;
|
|
129
|
+
m = bottom - n_bottom * cellSize + cellSize * j;
|
|
130
|
+
|
|
131
|
+
if (n < right && m < bottom) {
|
|
132
|
+
velocity.xy += calculateAdditionalVelocity(vec2(n / cellSize, m / cellSize) / levelTextureSize, pointPosition.xy);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
fragColor = velocity;
|
|
138
|
+
}
|