ngsolve-webgpu 0.0.1__py3-none-any.whl

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 (37) hide show
  1. ngsolve_webgpu/__init__.py +0 -0
  2. ngsolve_webgpu/_version.py +21 -0
  3. ngsolve_webgpu/animate.py +76 -0
  4. ngsolve_webgpu/cf.py +369 -0
  5. ngsolve_webgpu/clipping.py +155 -0
  6. ngsolve_webgpu/geometry.py +376 -0
  7. ngsolve_webgpu/isosurface.py +101 -0
  8. ngsolve_webgpu/jupyter.py +168 -0
  9. ngsolve_webgpu/lic.py +115 -0
  10. ngsolve_webgpu/mesh.py +424 -0
  11. ngsolve_webgpu/shaders/clipping/common.wgsl +120 -0
  12. ngsolve_webgpu/shaders/clipping/compute.wgsl +30 -0
  13. ngsolve_webgpu/shaders/clipping/render.wgsl +37 -0
  14. ngsolve_webgpu/shaders/compute.wgsl +59 -0
  15. ngsolve_webgpu/shaders/elements3d.wgsl +83 -0
  16. ngsolve_webgpu/shaders/eval/common.wgsl +14 -0
  17. ngsolve_webgpu/shaders/eval/seg.wgsl +30 -0
  18. ngsolve_webgpu/shaders/eval/tet.wgsl +61 -0
  19. ngsolve_webgpu/shaders/eval/trig.wgsl +121 -0
  20. ngsolve_webgpu/shaders/eval.wgsl +0 -0
  21. ngsolve_webgpu/shaders/geo_edge.wgsl +55 -0
  22. ngsolve_webgpu/shaders/geo_face.wgsl +47 -0
  23. ngsolve_webgpu/shaders/geo_vertex.wgsl +71 -0
  24. ngsolve_webgpu/shaders/isosurface/compute.wgsl +63 -0
  25. ngsolve_webgpu/shaders/isosurface/negative_clipping.wgsl +13 -0
  26. ngsolve_webgpu/shaders/isosurface/negative_surface.wgsl +15 -0
  27. ngsolve_webgpu/shaders/isosurface/render.wgsl +50 -0
  28. ngsolve_webgpu/shaders/line_integral_convolution.wgsl +100 -0
  29. ngsolve_webgpu/shaders/mesh.wgsl +296 -0
  30. ngsolve_webgpu/shaders/numbers.wgsl +40 -0
  31. ngsolve_webgpu/shaders/shader.wgsl +111 -0
  32. ngsolve_webgpu/shaders/uniforms.wgsl +93 -0
  33. ngsolve_webgpu-0.0.1.dist-info/METADATA +13 -0
  34. ngsolve_webgpu-0.0.1.dist-info/RECORD +37 -0
  35. ngsolve_webgpu-0.0.1.dist-info/WHEEL +5 -0
  36. ngsolve_webgpu-0.0.1.dist-info/licenses/LICENSE +504 -0
  37. ngsolve_webgpu-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,50 @@
1
+
2
+ struct MeshFragmentInput {
3
+ @builtin(position) fragPosition: vec4<f32>,
4
+ @location(0) color_val: f32,
5
+ @location(1) p: vec3<f32>,
6
+ @location(2) n: vec3<f32>,
7
+ @location(3) @interpolate(flat) id: u32,
8
+ @location(4) @interpolate(flat) index: u32,
9
+ };
10
+
11
+ @vertex
12
+ fn vertex_isosurface(@builtin(vertex_index) vertId: u32,
13
+ @builtin(instance_index) trigId: u32)
14
+ -> VertexOutputClip
15
+ {
16
+ let trig = subtrigs[trigId];
17
+ let points = get_tet_points(trig.id);
18
+ var lam = vec4<f32>(trig.lam[vertId], 1.);
19
+ lam[3] = 1.0 - lam[0] - lam[1] - lam[2];
20
+ var p = vec3<f32>(0.0, 0.0, 0.0);
21
+ for(var i = 0u; i < 4u; i = i + 1u) {
22
+ p = p + lam[i] * points[i];
23
+ }
24
+
25
+ var p0 = (1.-trig.lam[0][0]-trig.lam[0][1]-trig.lam[0][2]) * points[3];
26
+ for(var i=0u; i<3u; i=i+1u) {
27
+ p0 = p0 + trig.lam[0][i] * points[i];
28
+ }
29
+ var p1 = (1.-trig.lam[1][0]-trig.lam[1][1]-trig.lam[1][2]) * points[3];
30
+ for(var i=0u; i<3u; i=i+1u) {
31
+ p1 = p1 + trig.lam[1][i] * points[i];
32
+ }
33
+ var p2 = (1.-trig.lam[2][0]-trig.lam[2][1]-trig.lam[2][2]) * points[3];
34
+ for(var i=0u; i<3u; i=i+1u) {
35
+ p2 = p2 + trig.lam[2][i] * points[i];
36
+ }
37
+ let n = normalize(cross(p1 - p0, p2 - p0));
38
+
39
+ return VertexOutputClip(cameraMapPoint(p), p, -n, lam.xyz,
40
+ trig.id);
41
+ }
42
+
43
+
44
+ @fragment
45
+ fn fragment_isosurface(input: VertexOutputClip) -> @location(0) vec4<f32>
46
+ {
47
+ checkClipping(input.p);
48
+ let value = evalTet(&function_values_3d, input.elnr, 0, input.lam);
49
+ return lightCalcColor(input.n, getColor(value));
50
+ }
@@ -0,0 +1,100 @@
1
+ fn random(seed: u32) -> u32 {
2
+ // Xorshift32, see https://en.wikipedia.org/wiki/Xorshift
3
+ var value: u32 = seed;
4
+ value ^= value << 13;
5
+ value ^= value >> 17;
6
+ value ^= value << 5;
7
+ return value;
8
+ }
9
+
10
+ fn randomFloat(seed: u32) -> f32 {
11
+ return f32(random(seed)) / f32(0xFFFFFFFFu);
12
+ }
13
+
14
+ fn getSeed(j: u32, k: u32) -> u32 {
15
+ // create hash value as seed for random number generator
16
+ // https://www.burtleburtle.net/bob/hash/integer.html
17
+ let n = (k << 16) + j;
18
+ var seed = (n ^ 61) ^ (n >> 16);
19
+ seed *= seed * 9;
20
+ seed = seed ^ (seed >> 4);
21
+ seed = seed * 0x27d4eb2d;
22
+ seed = seed ^ (seed >> 15);
23
+ return seed;
24
+ }
25
+
26
+ fn noise(x: u32, y: u32) -> f32 {
27
+ let seed = getSeed(x, y);
28
+ return randomFloat(seed);
29
+ }
30
+
31
+ fn dropletNoise(x: u32, y: u32) -> f32 {
32
+ // large droplets for oriented line integral convolution
33
+ let n = u_line_integral_convolution.thickness;
34
+ let rand: f32 = noise(x / n, y / n);
35
+
36
+ if rand < 0.85 {
37
+ return 0.0;
38
+ }
39
+
40
+ let dx = f32(x % n) - f32(n) / 2.;
41
+ let dy = f32(y % n) - f32(n) / 2.;
42
+ let d = 4 * (dx * dx + dy * dy) / f32(n * n);
43
+
44
+ return clamp(1.0 - d, 0.0, 1.0);
45
+ }
46
+
47
+
48
+ fn lineIntegralConvolution(x: u32, y: u32) -> f32 {
49
+ let w = u_line_integral_convolution.width;
50
+ let h = u_line_integral_convolution.height;
51
+ let kernel_length = u_line_integral_convolution.kernel_length;
52
+ let oriented = u_line_integral_convolution.oriented;
53
+ var sum: f32 = 0;
54
+ var weight: f32 = 0;
55
+
56
+ for (var dir: i32 = -1; dir <= 1; dir += 2) {
57
+ var p = vec2f(f32(x) + .5, f32(y) + .5);
58
+
59
+ for (var k: u32 = 0; k < kernel_length; k++) {
60
+ var v = textureLoad(u_line_integral_convolution_input, vec2i(p), 0).xy;
61
+ v = normalize(v);
62
+
63
+ p += f32(dir) * v;
64
+
65
+ if p.x < 0.0 || p.x >= f32(w) || p.y < 0.0 || p.y >= f32(h) {
66
+ break;
67
+ }
68
+
69
+ let ix = u32(p.x);
70
+ let iy = u32(p.y);
71
+
72
+ var kernel_weight: f32 = f32(k) / f32(kernel_length);
73
+ if oriented == 0 {
74
+ kernel_weight = 1.0 - f32(k) / f32(kernel_length);
75
+ sum += kernel_weight * noise(ix, iy);
76
+ weight += kernel_weight;
77
+ } else {
78
+ var t = 0.5 * (1.0 + f32(dir) * f32(k) / f32(kernel_length));
79
+ kernel_weight = 0.1 + 0.9 * t * t * t * t;
80
+ sum += kernel_weight * dropletNoise(ix, iy);
81
+ weight += kernel_weight;
82
+ }
83
+ }
84
+ }
85
+
86
+ return sum / weight;
87
+ }
88
+
89
+ @compute @workgroup_size(16, 16, 1)
90
+ fn computeLineIntegralConvolution(@builtin(global_invocation_id) gid: vec3<u32>) {
91
+ let w = u_line_integral_convolution.width;
92
+ let h = u_line_integral_convolution.height;
93
+
94
+ if gid.x >= w || gid.y >= h {
95
+ return;
96
+ }
97
+
98
+ let value = lineIntegralConvolution(gid.x, gid.y);
99
+ textureStore(u_line_integral_convolution_output, gid.xy, vec4f(value, .0, .0, .0));
100
+ }
@@ -0,0 +1,296 @@
1
+ struct MeshFragmentInput {
2
+ @builtin(position) fragPosition: vec4<f32>,
3
+ @location(0) color: vec4<f32>,
4
+ @location(1) p: vec3<f32>,
5
+ @location(2) n: vec3<f32>,
6
+ @location(3) @interpolate(flat) id: u32,
7
+ @location(4) @interpolate(flat) index: u32,
8
+ };
9
+
10
+ // A triangle as part of a 3d element (thus, 3 barycentric coordinates)
11
+ struct SubTrig {
12
+ lam: array<vec3f, 3>,
13
+ id: u32,
14
+ }
15
+
16
+ struct ClipTetResult {
17
+ n: u32,
18
+ trigs: array<SubTrig, 2>,
19
+ }
20
+
21
+ // clip tet such that the clip triangle(s) have value 0 everywhere
22
+ fn clipTet(lam: array<vec3f, 4>, values: array<f32, 4>) -> ClipTetResult {
23
+ let ei = 0u;
24
+ var trigs = ClipTetResult(0, array<SubTrig, 2>(SubTrig(array<vec3f, 3>(vec3f(0.0), vec3f(0.0), vec3f(0.0)), 0), SubTrig(array<vec3f, 3>(vec3f(0.0), vec3f(0.0), vec3f(0.0)), 0)));
25
+ var p_pos = array<u32, 4>(0u, 0u, 0u, 0u);
26
+ var p_neg = array<u32, 4>(0u, 0u, 0u, 0u);
27
+
28
+ var n_pos: u32 = 0u;
29
+ var n_neg: u32 = 0u;
30
+
31
+ for (var i = 0u; i < 4u; i++) {
32
+ if values[i] > 0.0 {
33
+ p_pos[n_pos] = i;
34
+ n_pos++;
35
+ } else {
36
+ p_neg[n_neg] = i;
37
+ n_neg++;
38
+ }
39
+ }
40
+
41
+ if n_pos == 4u || n_neg == 4u {
42
+ return trigs;
43
+ }
44
+
45
+ if n_pos == 3u {
46
+ trigs.n = 1u;
47
+ n_pos = 1u;
48
+ n_neg = 3u;
49
+ p_pos[3] = p_neg[0];
50
+ p_neg[0] = p_pos[0];
51
+ p_neg[1] = p_pos[1];
52
+ p_neg[2] = p_pos[2];
53
+ p_pos[0] = p_pos[3];
54
+ }
55
+
56
+ if n_pos == 1u {
57
+ trigs.n = 1u;
58
+ trigs.trigs[0].id = ei;
59
+ for (var i = 0u; i < 3u; i++) {
60
+ let t = values[p_pos[0] ] / (values[p_pos[0] ] - values[p_neg[i] ]);
61
+ let lam_trig = mix(lam[p_pos[0] ], lam[p_neg[i] ], t);
62
+ trigs.trigs[0].lam[i] = lam_trig;
63
+ }
64
+ return trigs;
65
+ }
66
+
67
+ // two points before, two points behind clipping plane
68
+ // -> two triangles
69
+ trigs.n = 2u;
70
+ var pairs = array<vec2u,4>(
71
+ vec2u(p_pos[1], p_neg[0]),
72
+ vec2u(p_pos[0], p_neg[0]),
73
+ vec2u(p_pos[0], p_neg[1]),
74
+ vec2u(p_pos[1], p_neg[1])
75
+ );
76
+ var points: array<vec3f, 4> = array<vec3f, 4>(vec3f(0.0), vec3f(0.0), vec3f(0.0), vec3f(0.0));
77
+ for (var i = 0; i < 4; i++) {
78
+ let p0 = pairs[i].x;
79
+ let p1 = pairs[i].y;
80
+ let t = values[p0 ] / (values[p0] - values[p1]);
81
+ let lam_trig = mix(lam[p0], lam[p1], t);
82
+ points[i] = lam_trig;
83
+ }
84
+ trigs.trigs[0].id = ei;
85
+ trigs.trigs[0].lam = array(points[0], points[1], points[2]);
86
+ trigs.trigs[1].id = ei;
87
+ trigs.trigs[1].lam = array(points[0], points[2], points[3]);
88
+ return trigs;
89
+ }
90
+
91
+ fn calcMeshFace(color: vec4<f32>, p: array<vec3<f32>, 3>, vertId: u32, nr: u32, index: u32) -> MeshFragmentInput {
92
+ let n = cross(p[1] - p[0], p[2] - p[0]);
93
+ let point = p[vertId % 3];
94
+ let position = cameraMapPoint(point);
95
+ return MeshFragmentInput(position, color, point, n, nr, index);
96
+ }
97
+
98
+ @fragment
99
+ fn fragmentMesh(input: MeshFragmentInput) -> @location(0) vec4<f32> {
100
+ return lightCalcColor(input.n, input.color);
101
+ // checkClipping(input.p);
102
+ // let n4 = cameraMapNormal(input.n);
103
+ // let n = normalize(n4.xyz);
104
+ // let brightness = clamp(dot(n, normalize(vec3<f32>(-1., -3., -3.))), .0, 1.) * 0.7 + 0.3;
105
+ // let color = input.color.xyz * brightness;
106
+ // return vec4<f32>(color, input.color.w);
107
+ }
108
+
109
+ @vertex
110
+ fn vertexClipTet(@builtin(vertex_index) vertId: u32, @builtin(instance_index) elId: u32) -> MeshFragmentInput {
111
+ const N: u32 = 4;
112
+ let faceId: u32 = vertId / 3;
113
+ let el = u_tets[elId];
114
+ var p: array<vec3f, 4>;
115
+
116
+ for (var i = 0u; i < N; i++) {
117
+ let n = 3 * el.p[i];
118
+ p[i] = vec3<f32>(vertices[n], vertices[n + 1], vertices[n + 2]);
119
+ }
120
+
121
+ let lam = array(vec3f(1.0, 0.0, 0.0), vec3f(0.0, 1.0, 0.0), vec3f(0.0, 0.0, 1.0), vec3f(0.0, 0.0, 0.0));
122
+
123
+ let s = u_mesh.shrink;
124
+ let values = array(p[0].z-s, p[1].z-s, p[2].z-s, p[3].z-s);
125
+
126
+ let trigs = clipTet(lam, values);
127
+
128
+ var points = array<vec3<f32>, 3>(vec3f(0.0), vec3f(0.0), vec3f(0.0));
129
+ if(trigs.n > faceId) {
130
+ let trig = trigs.trigs[faceId];
131
+ for (var k = 0u; k < 3u; k++) {
132
+ let lam = vec4f(trig.lam[k], 1.0 - trig.lam[k].x - trig.lam[k].y - trig.lam[k].z);
133
+ for (var i = 0u; i < 3u; i++) {
134
+ points[k][i] = lam.x * p[0][i] + lam.y * p[1][i] + lam.z * p[2][i] + lam.w * p[3][i];
135
+ }
136
+ }
137
+ }
138
+
139
+ return calcMeshFace(vec4<f32>(1., 0., 0., 1.), points, vertId, el.nr, el.index);
140
+ }
141
+
142
+ @vertex
143
+ fn vertexMeshTet(@builtin(vertex_index) vertId: u32, @builtin(instance_index) elId: u32) -> MeshFragmentInput {
144
+ const N: u32 = 4;
145
+ let faceId: u32 = vertId / 3;
146
+ let el = u_tets[elId];
147
+ var p: array<vec3<f32>, 4>;
148
+
149
+ var center = vec3<f32>(0.0, 0.0, 0.0);
150
+ for (var i = 0u; i < N; i++) {
151
+ let n = 3 * el.p[i];
152
+ p[i] = vec3<f32>(vertices[n], vertices[n + 1], vertices[n + 2]);
153
+ center += p[i] / f32(N);
154
+ }
155
+
156
+ for (var i = 0u; i < 4u; i++) {
157
+ p[i] = mix(center, p[i], u_mesh.shrink);
158
+ }
159
+
160
+ let pi = TET_FACES[faceId];
161
+ let points = array<vec3<f32>, 3>(p[pi[0] ], p[pi[1] ], p[pi[2] ]);
162
+
163
+ return calcMeshFace(vec4<f32>(1., 0., 0., 1.), points, vertId, el.nr, el.index);
164
+ }
165
+
166
+
167
+ @vertex
168
+ fn vertexMeshPyramid(@builtin(vertex_index) vertId: u32, @builtin(instance_index) elId: u32) -> MeshFragmentInput {
169
+ const N: u32 = 5;
170
+ let faceId = vertId / 3;
171
+ let el = u_pyramids[elId];
172
+ var p: array<vec3<f32>, 5>;
173
+
174
+ var center = vec3<f32>(0.0, 0.0, 0.0);
175
+ for (var i = 0u; i < N; i++) {
176
+ p[i] = vec3<f32>(vertices[3 * el.p[i] ], vertices[3 * el.p[i] + 1], vertices[3 * el.p[i] + 2]);
177
+ center += p[i] / f32(N);
178
+ }
179
+
180
+ for (var i = 0u; i < N; i++) {
181
+ p[i] = mix(center, p[i], u_mesh.shrink);
182
+ }
183
+
184
+ let pi = PYRAMID_FACES[faceId];
185
+ var points = array<vec3<f32>, 3>(p[pi[0] ], p[pi[1] ], p[pi[2] ]);
186
+
187
+ return calcMeshFace(vec4<f32>(1., 0., 1., 1.), points, vertId, el.nr, el.index);
188
+ }
189
+
190
+
191
+ @vertex
192
+ fn vertexMeshPrism(@builtin(vertex_index) vertId: u32, @builtin(instance_index) elId: u32) -> MeshFragmentInput {
193
+ const N: u32 = 6;
194
+ let faceId = vertId / 3;
195
+ let el = u_prisms[elId];
196
+ var p: array<vec3<f32>, 6>;
197
+
198
+ var center = vec3<f32>(0.0, 0.0, 0.0);
199
+ for (var i = 0u; i < N; i++) {
200
+ p[i] = vec3<f32>(vertices[3 * el.p[i] ], vertices[3 * el.p[i] + 1], vertices[3 * el.p[i] + 2]);
201
+ center += p[i] / f32(N);
202
+ }
203
+
204
+ for (var i = 0u; i < N; i++) {
205
+ p[i] = mix(center, p[i], u_mesh.shrink);
206
+ }
207
+
208
+ let pi = PRISM_FACES[faceId];
209
+ var points = array<vec3<f32>, 3>(p[pi[0] ], p[pi[1] ], p[pi[2] ]);
210
+
211
+ return calcMeshFace(vec4<f32>(0., 1., 1., 1.), points, vertId, el.nr, el.index);
212
+ }
213
+
214
+
215
+ @vertex
216
+ fn vertexMeshHex(@builtin(vertex_index) vertId: u32, @builtin(instance_index) elId: u32) -> MeshFragmentInput {
217
+ const N: u32 = 8;
218
+ let faceId = vertId / 3;
219
+ let el = u_hexes[elId];
220
+ var p: array<vec3<f32>, 8>;
221
+
222
+ var center = vec3<f32>(0.0, 0.0, 0.0);
223
+ for (var i = 0u; i < N; i++) {
224
+ p[i] = vec3<f32>(vertices[3 * el.p[i] ], vertices[3 * el.p[i] + 1], vertices[3 * el.p[i] + 2]);
225
+ center += p[i] / f32(N);
226
+ }
227
+
228
+ for (var i = 0u; i < N; i++) {
229
+ p[i] = mix(center, p[i], u_mesh.shrink);
230
+ }
231
+
232
+ let pi = HEX_FACES[faceId];
233
+ var points = array<vec3<f32>, 3>(p[pi[0] ], p[pi[1] ], p[pi[2] ]);
234
+
235
+ return calcMeshFace(vec4<f32>(1., 1., 0., 1.), points, vertId, el.nr, el.index);
236
+ }
237
+
238
+ @group(0) @binding(54) var<storage> u_mesh_color: vec4<f32>;
239
+
240
+ @fragment
241
+ fn fragment2dElement(input: VertexOutput2d) -> @location(0) vec4<f32> {
242
+ checkClipping(input.p);
243
+ return lightCalcColor(-input.n, u_mesh_color);
244
+ }
245
+
246
+ @fragment
247
+ fn fragmentWireframe2d(input: VertexOutput2d) -> @location(0) vec4<f32> {
248
+ checkClipping(input.p);
249
+ if (input.lam[0] > 0.001 && input.lam[1] > 0.001 && input.lam[0] + input.lam[1] < 0.999) {
250
+ discard;
251
+ }
252
+ return lightCalcColor(-input.n, u_mesh_color);
253
+ }
254
+
255
+
256
+ const TET_FACES = array(
257
+ vec3i(0, 2, 1),
258
+ vec3i(0, 1, 3),
259
+ vec3i(1, 2, 3),
260
+ vec3i(2, 0, 3)
261
+ );
262
+
263
+ const PYRAMID_FACES = array(
264
+ vec3i(0, 2, 1),
265
+ vec3i(0, 3, 2),
266
+ vec3i(0, 1, 4),
267
+ vec3i(1, 2, 4),
268
+ vec3i(2, 3, 4),
269
+ vec3i(3, 0, 4)
270
+ );
271
+
272
+ const PRISM_FACES = array(
273
+ vec3i(0, 2, 1),
274
+ vec3i(3, 4, 5),
275
+ vec3i(0, 1, 4),
276
+ vec3i(0, 4, 3),
277
+ vec3i(1, 2, 5),
278
+ vec3i(1, 5, 4),
279
+ vec3i(2, 0, 3),
280
+ vec3i(2, 3, 5)
281
+ );
282
+
283
+ const HEX_FACES = array(
284
+ vec3i(0, 3, 1),
285
+ vec3i(3, 2, 1),
286
+ vec3i(4, 5, 6),
287
+ vec3i(4, 6, 7),
288
+ vec3i(0, 1, 5),
289
+ vec3i(0, 5, 4),
290
+ vec3i(1, 2, 6),
291
+ vec3i(1, 6, 5),
292
+ vec3i(2, 3, 7),
293
+ vec3i(2, 7, 6),
294
+ vec3i(3, 0, 4),
295
+ vec3i(3, 4, 7)
296
+ );
@@ -0,0 +1,40 @@
1
+ #import font
2
+ #import clipping
3
+ #import camera
4
+
5
+ @group(0) @binding(12) var<storage> vertices : array<f32>;
6
+
7
+ @vertex
8
+ fn vertexPointNumber(@builtin(vertex_index) vertexId: u32, @builtin(instance_index) pointId: u32) -> FontFragmentInput {
9
+ var p = vec3<f32>(vertices[3 * pointId], vertices[3 * pointId + 1], vertices[3 * pointId + 2]);
10
+
11
+ if calcClipping(p) == false {
12
+ return FontFragmentInput(vec4<f32>(-1.0, -1.0, 0.0, 1.0), vec2<f32>(0.));
13
+ }
14
+
15
+ var position = cameraMapPoint(p);
16
+
17
+ let i_digit = vertexId / 6;
18
+ let vi = vertexId % 6;
19
+
20
+ var length = 1u;
21
+ var n = 10u;
22
+ while n <= pointId + 1 {
23
+ length++;
24
+ n *= 10u;
25
+ }
26
+
27
+ if i_digit >= length {
28
+ return FontFragmentInput(vec4<f32>(-1.0, -1.0, 0.0, 1.0), vec2<f32>(0.));
29
+ }
30
+
31
+ var digit = pointId + 1;
32
+ for (var i = 0u; i < i_digit; i++) {
33
+ digit = digit / 10;
34
+ }
35
+ digit = digit % 10;
36
+
37
+ position.x += f32(length - i_digit - 1) * u_font.width_normalized * position.w;
38
+ return fontCalc(digit+48, position, vi);
39
+ }
40
+
@@ -0,0 +1,111 @@
1
+ #import eval/trig
2
+
3
+
4
+ struct VertexOutput1d {
5
+ @builtin(position) fragPosition: vec4<f32>,
6
+ @location(0) p: vec3<f32>,
7
+ @location(1) lam: f32,
8
+ @location(2) @interpolate(flat) id: u32,
9
+ };
10
+
11
+ struct VertexOutput2d {
12
+ @builtin(position) fragPosition: vec4<f32>,
13
+ @location(0) p: vec3<f32>,
14
+ @location(1) lam: vec2<f32>,
15
+ @location(2) @interpolate(flat) id: u32,
16
+ @location(3) n: vec3<f32>,
17
+ };
18
+
19
+ struct VertexOutput3d {
20
+ @builtin(position) fragPosition: vec4<f32>,
21
+ @location(0) p: vec3<f32>,
22
+ @location(1) lam: vec3<f32>,
23
+ @location(2) @interpolate(flat) id: u32,
24
+ @location(3) n: vec3<f32>,
25
+ };
26
+
27
+ @vertex
28
+ fn vertexEdgeP1(@builtin(vertex_index) vertexId: u32, @builtin(instance_index) edgeId: u32) -> VertexOutput1d {
29
+ let edge = edges_p1[edgeId];
30
+ var p: vec3<f32> = vec3<f32>(edge.p[3 * vertexId], edge.p[3 * vertexId + 1], edge.p[3 * vertexId + 2]);
31
+
32
+ var lam: f32 = 0.0;
33
+ if vertexId == 0 {
34
+ lam = 1.0;
35
+ }
36
+
37
+ var position = cameraMapPoint(p);
38
+ return VertexOutput1d(position, p, lam, edgeId);
39
+ }
40
+
41
+ fn calcTrig(p: array<vec3<f32>, 3>, vertexId: u32, trigId: u32) -> VertexOutput2d {
42
+ let subdivision = u_curvature_subdivision;
43
+ let h = 1.0 / f32(subdivision);
44
+
45
+ var lam = vec2f(0.0, 0.0);
46
+ if (vertexId % 3) < 2 {
47
+ lam[vertexId % 3] += h;
48
+ }
49
+
50
+ var position: vec3f;
51
+ var normal: vec3f;
52
+
53
+ if subdivision == 1 {
54
+ position = p[vertexId];
55
+ normal = cross(p[1] - p[0], p[2] - p[0]);
56
+ } else {
57
+ var subTrigId: u32 = vertexId / 3;
58
+ var ix = subTrigId % subdivision;
59
+ var iy = subTrigId / subdivision;
60
+ lam += h * vec2f(f32(ix), f32(iy));
61
+
62
+ if ix + iy >= subdivision {
63
+ lam[0] = 1.0 - lam[0];
64
+ lam[1] = 1.0 - lam[1];
65
+ }
66
+
67
+ let data = &u_curvature_values_2d;
68
+ var pos_and_gradients = evalTrigVec3Grad(data, trigId, lam);
69
+ if (u_deformation_values_2d[0] != -1.) {
70
+ pos_and_gradients += u_deformation_scale * evalTrigVec3Grad(&u_deformation_values_2d, trigId, lam);
71
+ }
72
+ position = pos_and_gradients[0];
73
+ normal = normalize(cross(pos_and_gradients[1], pos_and_gradients[2]));
74
+ }
75
+
76
+ let mapped_position = cameraMapPoint(position);
77
+
78
+ return VertexOutput2d(mapped_position, position, lam, trigId, normal);
79
+ }
80
+
81
+
82
+ @vertex
83
+ fn vertexTrigP1Indexed(@builtin(vertex_index) vertexId: u32, @builtin(instance_index) trigId: u32) -> VertexOutput2d {
84
+ var vid = 3 * vec3u(
85
+ trigs[4 * trigId + 0],
86
+ trigs[4 * trigId + 1],
87
+ trigs[4 * trigId + 2]
88
+ );
89
+
90
+ var p = array<vec3<f32>, 3>(
91
+ vec3<f32>(vertices[vid[0] ], vertices[vid[0] + 1], vertices[vid[0] + 2]),
92
+ vec3<f32>(vertices[vid[1] ], vertices[vid[1] + 1], vertices[vid[1] + 2]),
93
+ vec3<f32>(vertices[vid[2] ], vertices[vid[2] + 1], vertices[vid[2] + 2])
94
+ );
95
+ return calcTrig(p, vertexId, trigId);
96
+ }
97
+
98
+
99
+ @fragment
100
+ fn fragmentTrig(input: VertexOutput2d) -> @location(0) vec4<f32> {
101
+ checkClipping(input.p);
102
+ let p = &u_function_values_2d;
103
+ let value = evalTrig(p, input.id, u_function_component, input.lam);
104
+ return lightCalcColor(input.n, getColor(value));
105
+ }
106
+
107
+ @fragment
108
+ fn fragmentEdge(@location(0) p: vec3<f32>) -> @location(0) vec4<f32> {
109
+ checkClipping(p);
110
+ return vec4<f32>(0, 0, 0, 1.0);
111
+ }
@@ -0,0 +1,93 @@
1
+ // Uniforms are global variables that are constant for all invocations of a shader.
2
+ // They are used to store configuration data (no mesh etc.)
3
+ // Each uniform must have a unique binding group and number
4
+ // They are used to pass data from the CPU to the GPU (variable names are only relevant within the shader code)
5
+
6
+ // general uniforms
7
+ @group(0) @binding(14) var gBufferLam : texture_2d<f32>;
8
+
9
+ // legacy uniforms
10
+ @group(0) @binding(8) var<storage> edges_p1 : array<EdgeP1>;
11
+ @group(0) @binding(12) var<storage> vertices : array<f32>;
12
+ @group(0) @binding(13) var<storage> trigs : array<u32>;
13
+
14
+ // mesh uniforms
15
+ @group(0) @binding(20) var<uniform> u_mesh : MeshUniforms;
16
+ @group(0) @binding(21) var<storage> u_edges : array<Edge>;
17
+ @group(0) @binding(22) var<storage> u_segs : array<Seg>;
18
+ @group(0) @binding(23) var<storage> u_trigs : array<Trig>;
19
+ @group(0) @binding(24) var<storage> u_quads : array<Quad>;
20
+ @group(0) @binding(25) var<storage> u_tets : array<Tet>;
21
+ @group(0) @binding(26) var<storage> u_pyramids : array<Pyramid>;
22
+ @group(0) @binding(27) var<storage> u_prisms : array<Prism>;
23
+ @group(0) @binding(28) var<storage> u_hexes : array<Hex>;
24
+
25
+ // deformation uniforms
26
+ @group(0) @binding(30) var<storage> u_segs_deformation : array<f32>;
27
+ @group(0) @binding(31) var<storage> u_trigs_deformation : array<f32>;
28
+ @group(0) @binding(32) var<storage> u_quads_deformation : array<f32>;
29
+ @group(0) @binding(33) var<storage> u_tets_deformation : array<f32>;
30
+ @group(0) @binding(34) var<storage> u_pyramids_deformation : array<f32>;
31
+ @group(0) @binding(35) var<storage> u_prisms_deformation : array<f32>;
32
+ @group(0) @binding(36) var<storage> u_hexes_deformation : array<f32>;
33
+
34
+ // function uniforms
35
+ @group(0) @binding(30) var<storage> u_segs_function : array<f32>;
36
+ @group(0) @binding(31) var<storage> u_trigs_function : array<f32>;
37
+ @group(0) @binding(32) var<storage> u_quads_function : array<f32>;
38
+ @group(0) @binding(33) var<storage> u_tets_function : array<f32>;
39
+ @group(0) @binding(34) var<storage> u_pyramids_function : array<f32>;
40
+ @group(0) @binding(35) var<storage> u_prisms_function : array<f32>;
41
+ @group(0) @binding(36) var<storage> u_hexes_function : array<f32>;
42
+
43
+ // Line integral convolution
44
+ @group(0) @binding(40) var<uniform> u_line_integral_convolution : LineIntegralConvolutionUniforms;
45
+ @group(0) @binding(41) var u_line_integral_convolution_input: texture_2d<f32>;
46
+ @group(0) @binding(42) var u_line_integral_convolution_output: texture_storage_2d<r32float, write>;
47
+
48
+ // Create mesh
49
+ @group(0) @binding(50) var<storage, read_write> create_mesh_trigs_p1 : array<TrigP1>;
50
+ @group(0) @binding(51) var<storage, read_write> create_mesh_trig_function_values : array<f32>;
51
+ @group(0) @binding(52) var<storage, read_write> create_mesh_vertex_buffer : array<f32>;
52
+ @group(0) @binding(53) var<storage, read_write> create_mesh_index_buffer : array<u32>;
53
+
54
+ struct MeshUniforms {
55
+ subdivision: u32,
56
+ shrink: f32,
57
+
58
+ padding0: f32,
59
+ padding1: f32,
60
+ };
61
+
62
+ struct LineIntegralConvolutionUniforms {
63
+ width: u32, // canvas width
64
+ height: u32, // canvas height
65
+ kernel_length: u32,
66
+ oriented: u32, // 0: not oriented, 1: oriented
67
+ thickness: u32, // thickness of the lines (only used for oriented)
68
+
69
+ padding0: u32,
70
+ padding1: u32,
71
+ padding2: u32,
72
+ };
73
+ // Mesh element structures
74
+
75
+ struct Edge { p: array<u32, 2> }; // Inner edge, for wireframe
76
+ struct Seg { p: array<u32, 2>, nr: u32, index: u32 };
77
+ struct Trig { p: array<u32, 3>, nr: u32, index: u32 };
78
+ struct Quad { p: array<u32, 4>, nr: u32, index: u32 };
79
+ struct Tet { p: array<u32, 4>, nr: u32, index: u32 };
80
+ struct Pyramid { p: array<u32, 5>, nr: u32, index: u32 };
81
+ struct Prism { p: array<u32, 6>, nr: u32, index: u32 };
82
+ struct Hex { p: array<u32, 8>, nr: u32, index: u32 };
83
+
84
+
85
+ // legacy mesh structs
86
+ struct EdgeP1 { p: array<f32, 6> };
87
+ struct TrigP1 { p: array<f32, 9>, index: i32 }; // 3 vertices with 3 coordinates each, don't use vec3 due to 16 byte alignment
88
+ struct TrigP2 { p: array<f32, 18>, index: i32 };
89
+
90
+ struct ClippingTrig {
91
+ nr: u32, // volume element number
92
+ lam: array<f32, 9>, // 3 vertices with 3 barycentric coordinates each
93
+ };
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.4
2
+ Name: ngsolve_webgpu
3
+ Version: 0.0.1
4
+ Summary: WebGPU/Pyodide based rendering tools for Netgen/NGSolve
5
+ Author-email: Matthias Hochsteger <mhochsteger@cerbsim.com>, Christopher Lackner <clackner@cerbsim.com>
6
+ License-Expression: LGPL-2.1-or-later
7
+ Keywords: WebGPU,compute shaders,graphics,Python,NGSolve,FEM,Netgen
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Dynamic: license-file