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.
- ngsolve_webgpu/__init__.py +0 -0
- ngsolve_webgpu/_version.py +21 -0
- ngsolve_webgpu/animate.py +76 -0
- ngsolve_webgpu/cf.py +369 -0
- ngsolve_webgpu/clipping.py +155 -0
- ngsolve_webgpu/geometry.py +376 -0
- ngsolve_webgpu/isosurface.py +101 -0
- ngsolve_webgpu/jupyter.py +168 -0
- ngsolve_webgpu/lic.py +115 -0
- ngsolve_webgpu/mesh.py +424 -0
- ngsolve_webgpu/shaders/clipping/common.wgsl +120 -0
- ngsolve_webgpu/shaders/clipping/compute.wgsl +30 -0
- ngsolve_webgpu/shaders/clipping/render.wgsl +37 -0
- ngsolve_webgpu/shaders/compute.wgsl +59 -0
- ngsolve_webgpu/shaders/elements3d.wgsl +83 -0
- ngsolve_webgpu/shaders/eval/common.wgsl +14 -0
- ngsolve_webgpu/shaders/eval/seg.wgsl +30 -0
- ngsolve_webgpu/shaders/eval/tet.wgsl +61 -0
- ngsolve_webgpu/shaders/eval/trig.wgsl +121 -0
- ngsolve_webgpu/shaders/eval.wgsl +0 -0
- ngsolve_webgpu/shaders/geo_edge.wgsl +55 -0
- ngsolve_webgpu/shaders/geo_face.wgsl +47 -0
- ngsolve_webgpu/shaders/geo_vertex.wgsl +71 -0
- ngsolve_webgpu/shaders/isosurface/compute.wgsl +63 -0
- ngsolve_webgpu/shaders/isosurface/negative_clipping.wgsl +13 -0
- ngsolve_webgpu/shaders/isosurface/negative_surface.wgsl +15 -0
- ngsolve_webgpu/shaders/isosurface/render.wgsl +50 -0
- ngsolve_webgpu/shaders/line_integral_convolution.wgsl +100 -0
- ngsolve_webgpu/shaders/mesh.wgsl +296 -0
- ngsolve_webgpu/shaders/numbers.wgsl +40 -0
- ngsolve_webgpu/shaders/shader.wgsl +111 -0
- ngsolve_webgpu/shaders/uniforms.wgsl +93 -0
- ngsolve_webgpu-0.0.1.dist-info/METADATA +13 -0
- ngsolve_webgpu-0.0.1.dist-info/RECORD +37 -0
- ngsolve_webgpu-0.0.1.dist-info/WHEEL +5 -0
- ngsolve_webgpu-0.0.1.dist-info/licenses/LICENSE +504 -0
- 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
|