Skip to main content

dynamis_soft/
lib.rs

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}