Skip to content

Commit 68a00d2

Browse files
committed
Optimize performance with instanced rendering and concurrent spatial grid, and fix WASM simulation panic
1 parent 5fa544b commit 68a00d2

File tree

6 files changed

+361
-378
lines changed

6 files changed

+361
-378
lines changed

Cargo.lock

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ rayon = "1.8"
1919
rand = { version = "0.8", features = ["getrandom"] }
2020
getrandom = { version = "0.2", features = ["js"] }
2121
indexmap = "=2.2.6" # Pin version to avoid E0658 with our toolchain
22+
dashmap = "5.5"
2223

2324
# Graphics - match galacto version
2425
wgpu = { version = "24.0", features = ["webgl"] }
@@ -44,6 +45,10 @@ serde-wasm-bindgen = "0.6"
4445
console_error_panic_hook = "0.1"
4546
raw-window-handle = { version = "0.6", features = ["wasm-bindgen-0-2"] }
4647

48+
[target.'cfg(target_arch = "wasm32")'.dependencies]
49+
parking_lot = { version = "0.12", features = ["nightly"] }
50+
instant = { version = "0.1", features = ["wasm-bindgen"] }
51+
4752
[profile.release]
4853
opt-level = 3
4954
lto = true

src/shader.wgsl

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,66 @@
1-
struct VertexInput {
2-
@location(0) position: vec2<f32>,
3-
@location(1) color: vec3<f32>,
4-
@location(2) center: vec2<f32>,
5-
@location(3) radius: f32,
1+
// Instance data: position (xy), radius, color (rgb)
2+
struct InstanceInput {
3+
@location(0) pos_radius: vec4<f32>, // xy = position, z = radius, w = unused
4+
@location(1) color: vec4<f32>, // rgb = color, a = unused
65
}
76

87
struct VertexOutput {
98
@builtin(position) position: vec4<f32>,
109
@location(0) color: vec3<f32>,
11-
@location(1) center: vec2<f32>,
12-
@location(2) radius: f32,
13-
@location(3) uv: vec2<f32>,
10+
@location(1) uv: vec2<f32>,
1411
}
1512

13+
// Quad vertices (generated in shader)
14+
const QUAD_VERTICES: array<vec2<f32>, 6> = array<vec2<f32>, 6>(
15+
vec2<f32>(-1.0, -1.0),
16+
vec2<f32>(1.0, -1.0),
17+
vec2<f32>(-1.0, 1.0),
18+
vec2<f32>(1.0, -1.0),
19+
vec2<f32>(1.0, 1.0),
20+
vec2<f32>(-1.0, 1.0),
21+
);
22+
1623
@vertex
17-
fn vs_main(vertex: VertexInput) -> VertexOutput {
24+
fn vs_main(
25+
instance: InstanceInput,
26+
@builtin(vertex_index) vertex_index: u32,
27+
) -> VertexOutput {
1828
var out: VertexOutput;
19-
out.position = vec4<f32>(vertex.position, 0.0, 1.0);
20-
out.color = vertex.color;
21-
out.center = vertex.center;
22-
out.radius = vertex.radius;
23-
24-
// Calculate UV coordinates relative to the ball's center
25-
out.uv = (vertex.position - vertex.center) / vertex.radius;
29+
30+
let quad_pos = QUAD_VERTICES[vertex_index];
31+
let screen_pos = instance.pos_radius.xy;
32+
let radius = instance.pos_radius.z;
2633

34+
// Expand quad by radius with glow extension
35+
let glow_extension = radius * 0.5;
36+
let quad_size = radius + glow_extension;
37+
38+
out.position = vec4<f32>(screen_pos + quad_pos * quad_size, 0.0, 1.0);
39+
out.color = instance.color.rgb;
40+
out.uv = quad_pos; // -1 to 1 range
41+
2742
return out;
2843
}
2944

3045
@fragment
3146
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
32-
// Calculate distance from center of the ball
47+
// Distance from center (uv is -1 to 1)
3348
let dist = length(in.uv);
3449

35-
// Create a proper circular shape with smooth falloff
36-
let circle = smoothstep(1.0, 0.0, dist);
37-
38-
// Create a more pronounced glowing effect with multiple layers
39-
let core = smoothstep(1.0, 0.0, dist * 2.0); // Bright core
40-
let glow_inner = smoothstep(1.0, 0.0, dist * 1.5) * 0.9; // Inner glow
41-
let glow_middle = smoothstep(1.0, 0.0, dist * 1.2) * 0.7; // Middle glow
42-
let glow_outer = smoothstep(1.0, 0.0, dist * 0.8) * 0.5; // Outer glow
43-
let glow_far = smoothstep(1.0, 0.0, dist * 0.5) * 0.3; // Far glow
44-
45-
// Combine all glow layers for a more intense effect
50+
// Create glowing ball effect
51+
let core = smoothstep(1.0, 0.0, dist * 2.0);
52+
let glow_inner = smoothstep(1.0, 0.0, dist * 1.5) * 0.9;
53+
let glow_middle = smoothstep(1.0, 0.0, dist * 1.2) * 0.7;
54+
let glow_outer = smoothstep(1.0, 0.0, dist * 0.8) * 0.5;
55+
let glow_far = smoothstep(1.0, 0.0, dist * 0.5) * 0.3;
56+
4657
let glow = core + glow_inner + glow_middle + glow_outer + glow_far;
47-
48-
// Create the final color with transparency
49-
let alpha = glow * 0.95; // More opaque for better visibility
58+
let alpha = glow * 0.95;
5059
let final_color = in.color * glow;
5160

52-
// Add a subtle white glow around the edges for better definition
61+
// White glow for definition
5362
let white_glow = smoothstep(1.0, 0.0, dist * 0.4) * 0.2;
5463
let final_color_with_glow = final_color + vec3<f32>(white_glow);
55-
64+
5665
return vec4<f32>(final_color_with_glow, alpha);
57-
}
66+
}

src/simulation/mod.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,19 +154,14 @@ impl Simulation {
154154
fn rebuild_spatial_grid(&mut self) {
155155
self.grid.clear();
156156

157-
// Use parallel processing for grid building
158-
let grid_entities: Vec<_> = self
159-
.world
157+
// Parallel inserts directly into DashMap (thread-safe)
158+
self.world
160159
.query::<(&Position,)>()
161160
.iter()
162161
.par_bridge()
163-
.map(|(entity, (pos,))| (entity, pos.x, pos.y))
164-
.collect();
165-
166-
// Insert entities into grid (this part needs to be sequential due to HashMap)
167-
for (entity, x, y) in grid_entities {
168-
self.grid.insert(entity, x, y);
169-
}
162+
.for_each(|(entity, (pos,))| {
163+
self.grid.insert(entity, pos.x, pos.y);
164+
});
170165
}
171166

172167
fn process_entities_parallel(&self) -> Vec<EntityUpdate> {

0 commit comments

Comments
 (0)