1mod capacity;
2mod domain;
3mod streams;
4
5pub use capacity::{SoftCapacity, SoftInputs, capacity, floor, plan};
6pub use domain::{SoftDomain, SoftWork};
7pub use streams::{SoftDemand, SoftStream, SoftStreams};
8
9use dynamis_abi::{Count, StepParamsRecord};
10use dynamis_broadphase::BroadphaseStream;
11use dynamis_gpu::GpuContext;
12use dynamis_gpu::Resources;
13use dynamis_pass::{Schedule, Stage, domain_passes};
14use dynamis_shader::{CORE, rows};
15use dynamis_state::StateStream;
16
17const PARTICLE_SHAPE: &[&str] = &[include_str!("../shaders/particle_shape.wgsl")];
18const PARTICLE_REACH: &[&str] = &[include_str!("../shaders/particle_reach.wgsl")];
19const ELEMENT_SAMPLE: &[&str] = &[include_str!("../shaders/element_sample.wgsl")];
20const SOFT_REACTION: &[&str] = &[include_str!("../shaders/soft_reaction.wgsl")];
21const SOFT_ANCHOR: &[&str] = &[include_str!("../shaders/soft_anchor.wgsl")];
22const SOFT_ATTACH: &[&str] = &[
23 include_str!("../shaders/soft_reaction.wgsl"),
24 include_str!("../shaders/soft_anchor.wgsl"),
25];
26
27fn particle_index() -> Vec<&'static str> {
28 let mut fragments = dynamis_shader::GRID_INDEX.to_vec();
29 fragments.extend_from_slice(PARTICLE_SHAPE);
30 fragments
31}
32
33fn particle_reach_index() -> Vec<&'static str> {
34 let mut fragments = dynamis_shader::GRID_INDEX.to_vec();
35 fragments.extend_from_slice(PARTICLE_REACH);
36 fragments
37}
38
39fn particle_collide_index() -> Vec<&'static str> {
40 let mut fragments = dynamis_shader::GEOMETRY_INDEX.to_vec();
41 fragments.extend_from_slice(PARTICLE_REACH);
42 fragments
43}
44
45fn particle_wake_index() -> Vec<&'static str> {
46 let mut fragments = dynamis_shader::GRID_INDEX.to_vec();
47 fragments.extend_from_slice(PARTICLE_REACH);
48 fragments
49}
50
51domain_passes!(
52 SoftPasses,
53 soft_bounds => &[],
54 soft_entries => &["soft_bounds", "prepare"],
55 soft_settle => &["ccd_apply"],
56 soft_substeps => &["soft_settle"],
57 soft_apply => &["soft_substeps"],
58);
59
60#[derive(Clone, Copy, Debug)]
61pub struct SoftFrame {
62 pub params: StepParamsRecord,
63 pub simulating: bool,
64 pub material: bool,
65}
66
67pub struct Soft {
68 passes: SoftPasses,
69 bounds: Stage,
70 entries: Stage,
71 activity: Stage,
72 wake: Stage,
73 attach_wake: Stage,
74 rest: Stage,
75 integrate: Stage,
76 reset: Stage,
77 elements: Stage,
78 gather: Stage,
79 attachment: Stage,
80 density: Stage,
81 pressure: Stage,
82 detect: Stage,
83 resolve: Stage,
84 material: Stage,
85 apply: Stage,
86}
87
88impl Soft {
89 pub fn new(context: &GpuContext, streams: &impl Resources, passes: SoftPasses) -> Self {
90 let particles = SoftStream::Particles;
91 let bodies = SoftStream::BodyStates;
92 let index = particle_index();
93 let reach = particle_reach_index();
94 let collide = particle_collide_index();
95 let wake_fragments = particle_wake_index();
96 Self {
97 passes,
98 bounds: Stage::build(
99 context,
100 "soft_bounds",
101 rows(
102 context,
103 include_str!("../shaders/particle_bounds.wgsl"),
104 PARTICLE_SHAPE,
105 Count::Particles.field(),
106 ),
107 streams,
108 &[
109 ("counters", StateStream::Counters.whole()),
110 ("params", StateStream::Params.whole()),
111 ("particles", particles.whole()),
112 ],
113 &[],
114 ),
115 entries: Stage::build(
116 context,
117 "soft_entries",
118 rows(
119 context,
120 include_str!("../shaders/particle_entries.wgsl"),
121 &index,
122 Count::Particles.field(),
123 ),
124 streams,
125 &[
126 ("params", StateStream::Params.whole()),
127 ("particles", particles.whole()),
128 ("entry_keys", BroadphaseStream::EntryKeys.whole()),
129 ("entry_order", BroadphaseStream::EntryOrder.whole()),
130 ("entries", BroadphaseStream::Entries.whole()),
131 ("counters", StateStream::Counters.whole()),
132 ],
133 &[],
134 ),
135 activity: Stage::build(
136 context,
137 "soft_activity",
138 rows(
139 context,
140 include_str!("../shaders/soft_activity.wgsl"),
141 CORE,
142 Count::Particles.field(),
143 ),
144 streams,
145 &[
146 ("params", StateStream::Params.whole()),
147 ("particles", particles.whole()),
148 ("bodies", bodies.whole()),
149 ],
150 &[],
151 ),
152 wake: Stage::build(
153 context,
154 "soft_wake",
155 rows(
156 context,
157 include_str!("../shaders/soft_wake.wgsl"),
158 &wake_fragments,
159 Count::Particles.field(),
160 ),
161 streams,
162 &[
163 ("params", StateStream::Params.whole()),
164 ("particles", particles.whole()),
165 ("bodies", bodies.whole()),
166 ("body_states", StateStream::BodyStates.whole()),
167 ("body_descs", StateStream::BodyDescriptors.whole()),
168 ("colliders", StateStream::Colliders.whole()),
169 ("entry_keys", BroadphaseStream::EntryKeys.whole()),
170 ("entry_order", BroadphaseStream::EntryOrder.whole()),
171 ("entries", BroadphaseStream::Entries.whole()),
172 ("counters", StateStream::Counters.whole()),
173 ],
174 &[],
175 ),
176 attach_wake: Stage::build(
177 context,
178 "soft_attach_wake",
179 rows(
180 context,
181 include_str!("../shaders/soft_attach_wake.wgsl"),
182 SOFT_ANCHOR,
183 Count::Attachments.field(),
184 ),
185 streams,
186 &[
187 ("params", StateStream::Params.whole()),
188 ("attachments", SoftStream::Attachments.whole()),
189 ("particles", particles.whole()),
190 ("body_states", StateStream::BodyStates.whole()),
191 ("body_descs", StateStream::BodyDescriptors.whole()),
192 ("row_of_body", StateStream::BodyRowOfId.whole()),
193 ("bodies", bodies.whole()),
194 ],
195 &[],
196 ),
197 rest: Stage::build(
198 context,
199 "soft_rest",
200 rows(
201 context,
202 include_str!("../shaders/soft_rest.wgsl"),
203 CORE,
204 Count::SoftBodies.field(),
205 ),
206 streams,
207 &[
208 ("params", StateStream::Params.whole()),
209 ("bodies", bodies.whole()),
210 ("counters", StateStream::Counters.whole()),
211 ],
212 &[],
213 ),
214 integrate: Stage::build(
215 context,
216 "soft_integrate",
217 rows(
218 context,
219 include_str!("../shaders/soft_integrate.wgsl"),
220 CORE,
221 Count::Particles.field(),
222 ),
223 streams,
224 &[
225 ("params", StateStream::Params.whole()),
226 ("particles", particles.whole()),
227 ("bodies", bodies.whole()),
228 ],
229 &[],
230 ),
231 reset: Stage::build(
232 context,
233 "soft_reset",
234 rows(
235 context,
236 include_str!("../shaders/soft_reset.wgsl"),
237 CORE,
238 Count::Elements.field(),
239 ),
240 streams,
241 &[
242 ("params", StateStream::Params.whole()),
243 ("elements", SoftStream::Elements.whole()),
244 ],
245 &[],
246 ),
247 elements: Stage::build(
248 context,
249 "soft_elements",
250 rows(
251 context,
252 include_str!("../shaders/soft_elements.wgsl"),
253 ELEMENT_SAMPLE,
254 Count::Elements.field(),
255 ),
256 streams,
257 &[
258 ("params", StateStream::Params.whole()),
259 ("particles", particles.whole()),
260 ("elements", SoftStream::Elements.whole()),
261 ("contributions", SoftStream::Contributions.whole()),
262 ("bodies", bodies.whole()),
263 ],
264 &[],
265 ),
266 gather: Stage::build(
267 context,
268 "soft_gather",
269 rows(
270 context,
271 include_str!("../shaders/soft_gather.wgsl"),
272 CORE,
273 Count::Particles.field(),
274 ),
275 streams,
276 &[
277 ("params", StateStream::Params.whole()),
278 ("particles", particles.whole()),
279 ("contributions", SoftStream::Contributions.whole()),
280 ("adjacency", SoftStream::Adjacency.whole()),
281 ("elements", SoftStream::Elements.whole()),
282 ("bodies", bodies.whole()),
283 ],
284 &[],
285 ),
286 attachment: Stage::build(
287 context,
288 "soft_attach",
289 rows(
290 context,
291 include_str!("../shaders/soft_attach.wgsl"),
292 SOFT_ATTACH,
293 Count::Attachments.field(),
294 ),
295 streams,
296 &[
297 ("params", StateStream::Params.whole()),
298 ("attachments", SoftStream::Attachments.whole()),
299 ("particles", particles.whole()),
300 ("body_states", StateStream::BodyStates.whole()),
301 ("body_descs", StateStream::BodyDescriptors.whole()),
302 ("row_of_body", StateStream::BodyRowOfId.whole()),
303 ("reactions", SoftStream::Reactions.whole()),
304 ("bodies", bodies.whole()),
305 ],
306 &[],
307 ),
308 density: Stage::build(
309 context,
310 "soft_density",
311 rows(
312 context,
313 include_str!("../shaders/soft_density.wgsl"),
314 &reach,
315 Count::Particles.field(),
316 ),
317 streams,
318 &[
319 ("params", StateStream::Params.whole()),
320 ("particles", particles.whole()),
321 ("pressure", SoftStream::Pressure.whole()),
322 ("bodies", bodies.whole()),
323 ("entry_keys", BroadphaseStream::EntryKeys.whole()),
324 ("entry_order", BroadphaseStream::EntryOrder.whole()),
325 ("entries", BroadphaseStream::Entries.whole()),
326 ("counters", StateStream::Counters.whole()),
327 ],
328 &[],
329 ),
330 pressure: Stage::build(
331 context,
332 "soft_pressure",
333 rows(
334 context,
335 include_str!("../shaders/soft_pressure.wgsl"),
336 &reach,
337 Count::Particles.field(),
338 ),
339 streams,
340 &[
341 ("params", StateStream::Params.whole()),
342 ("particles", particles.whole()),
343 ("pressure", SoftStream::Pressure.whole()),
344 ("bodies", bodies.whole()),
345 ("entry_keys", BroadphaseStream::EntryKeys.whole()),
346 ("entry_order", BroadphaseStream::EntryOrder.whole()),
347 ("entries", BroadphaseStream::Entries.whole()),
348 ("counters", StateStream::Counters.whole()),
349 ],
350 &[],
351 ),
352 detect: Stage::build(
353 context,
354 "soft_collide_detect",
355 rows(
356 context,
357 include_str!("../shaders/soft_collide_detect.wgsl"),
358 &collide,
359 Count::Particles.field(),
360 ),
361 streams,
362 &[
363 ("params", StateStream::Params.whole()),
364 ("particles", particles.whole()),
365 ("body_states", StateStream::BodyStates.whole()),
366 ("body_descs", StateStream::BodyDescriptors.whole()),
367 ("colliders", StateStream::Colliders.whole()),
368 ("elements", SoftStream::Elements.whole()),
369 ("adjacency", SoftStream::Adjacency.whole()),
370 ("contacts", SoftStream::Contacts.whole()),
371 ("entry_keys", BroadphaseStream::EntryKeys.whole()),
372 ("entry_order", BroadphaseStream::EntryOrder.whole()),
373 ("entries", BroadphaseStream::Entries.whole()),
374 ("counters", StateStream::Counters.whole()),
375 ("bodies", bodies.whole()),
376 ],
377 &dynamis_state::shape_resources(),
378 ),
379 resolve: Stage::build(
380 context,
381 "soft_collide_resolve",
382 rows(
383 context,
384 include_str!("../shaders/soft_collide_resolve.wgsl"),
385 SOFT_REACTION,
386 Count::Particles.field(),
387 ),
388 streams,
389 &[
390 ("params", StateStream::Params.whole()),
391 ("particles", particles.whole()),
392 ("body_states", StateStream::BodyStates.whole()),
393 ("body_descs", StateStream::BodyDescriptors.whole()),
394 ("contacts", SoftStream::Contacts.whole()),
395 ("reactions", SoftStream::Reactions.whole()),
396 ("bodies", bodies.whole()),
397 ],
398 &[],
399 ),
400 material: Stage::build(
401 context,
402 "soft_material",
403 rows(
404 context,
405 include_str!("../shaders/soft_material.wgsl"),
406 ELEMENT_SAMPLE,
407 Count::Elements.field(),
408 ),
409 streams,
410 &[
411 ("params", StateStream::Params.whole()),
412 ("particles", particles.whole()),
413 ("elements", SoftStream::Elements.whole()),
414 ("bodies", bodies.whole()),
415 ],
416 &[],
417 ),
418 apply: Stage::build(
419 context,
420 "soft_apply",
421 rows(
422 context,
423 include_str!("../shaders/soft_apply.wgsl"),
424 CORE,
425 Count::Bodies.field(),
426 ),
427 streams,
428 &[
429 ("params", StateStream::Params.whole()),
430 ("body_states", StateStream::BodyStates.whole()),
431 ("reactions", SoftStream::Reactions.whole()),
432 ("wake_flags", StateStream::WakeFlags.whole()),
433 (
434 "woke_count",
435 dynamis_state::counter(dynamis_abi::COUNTER_WOKE),
436 ),
437 (
438 "deferred_woke_count",
439 dynamis_state::counter(dynamis_abi::COUNTER_WOKE_DEFERRED),
440 ),
441 ],
442 &[],
443 ),
444 }
445 }
446
447 pub fn record(
448 &self,
449 pass: u32,
450 schedule: &mut Schedule,
451 encoder: &mut wgpu::CommandEncoder,
452 streams: &impl Resources,
453 frame: &SoftFrame,
454 ) {
455 if !frame.simulating {
456 return;
457 }
458 let particles = Count::Particles.rows(&frame.params);
459 let elements = Count::Elements.rows(&frame.params);
460 let bodies = Count::SoftBodies.rows(&frame.params);
461 let attachments = Count::Attachments.rows(&frame.params);
462 if pass == self.passes.soft_bounds {
463 let mut bounds = schedule.open(encoder, pass);
464 self.bounds.record_rows(&mut bounds, streams, particles);
465 drop(bounds);
466 } else if pass == self.passes.soft_entries {
467 let mut entries = schedule.open(encoder, pass);
468 self.entries.record_rows(&mut entries, streams, particles);
469 drop(entries);
470 } else if pass == self.passes.soft_settle {
471 let mut settle = schedule.open(encoder, pass);
472 self.activity.record_rows(&mut settle, streams, particles);
473 self.wake.record_rows(&mut settle, streams, particles);
474 self.attach_wake
475 .record_rows(&mut settle, streams, attachments);
476 self.rest.record_rows(&mut settle, streams, bodies);
477 drop(settle);
478 } else if pass == self.passes.soft_substeps {
479 let mut substeps = schedule.open(encoder, pass);
480 for _ in 0..frame.params.soft_substeps {
481 self.reset.record_rows(&mut substeps, streams, elements);
482 self.integrate
483 .record_rows(&mut substeps, streams, particles);
484 for _ in 0..frame.params.soft_iterations {
485 self.elements.record_rows(&mut substeps, streams, elements);
486 self.gather.record_rows(&mut substeps, streams, particles);
487 self.density.record_rows(&mut substeps, streams, particles);
488 self.pressure.record_rows(&mut substeps, streams, particles);
489 }
490 self.attachment
491 .record_rows(&mut substeps, streams, attachments);
492 self.detect.record_rows(&mut substeps, streams, particles);
493 self.resolve.record_rows(&mut substeps, streams, particles);
494 if frame.material {
495 self.material.record_rows(&mut substeps, streams, elements);
496 }
497 }
498 drop(substeps);
499 } else if pass == self.passes.soft_apply {
500 let mut apply = schedule.open(encoder, pass);
501 self.apply
502 .record_rows(&mut apply, streams, Count::Bodies.rows(&frame.params));
503 drop(apply);
504 }
505 }
506}