Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement particle groups, enabling simple particle trails. #296

Merged
merged 7 commits into from
Mar 10, 2024

Conversation

pcwalton
Copy link
Contributor

@pcwalton pcwalton commented Mar 5, 2024

This commit essentially allows multiple effects to share the same underlying buffer. Such sub-effects are known as particle groups. An effect may have up to 32 particle groups, each with its own capacity. Every modifier specifies which particle groups it affects. Spawners always spawn into particle group 0; this restriction was implemented for simplicity and can be lifted later.

A new modifier has been added, CloneModifier. This allows particles to be duplicated into a group on a fixed rate. By cloning particles into a group, particle trails can be created.

It's intended that a node graph can be layered on top of particle groups in the future. Particle groups are the most efficient way I can think of to implement node graphs in any case, so this seems to me to be a step toward a node-based editor.

Currently, init modifiers don't run on cloned particles. Their age is, however, reset to 0 if present, as this is typically the most useful behavior.

Internally, each particle group receives its own update and render invocation. This reduces branching in both shaders, simplifies much of the bookkeeping, and enables ribbon rendering for trails in the future (needed for weapon effects, etc.)

The new worms example illustrates how trails can be produced with this groups feature.

This PR obsoletes #288. Feedback is very welcome!

@pcwalton
Copy link
Contributor Author

pcwalton commented Mar 5, 2024

Here's what the example looks like:

Screenshot 2024-03-05 020706

@pcwalton
Copy link
Contributor Author

pcwalton commented Mar 5, 2024

Oh, that limit of 4 dynamic offsets is terribly annoying. I'll have to think of how to work around it.

@djeedai
Copy link
Owner

djeedai commented Mar 5, 2024

Oh, that limit of 4 dynamic offsets is terribly annoying. I'll have to think of how to work around it.

This is if I remember the default for "downlevel" in wgpu, and therefore is expected to be a conservative value for Web. I don't know how many users we'd lose (especially on Web) by raising that limit, but if possible I'd really like to avoid doing so. Let me know if I can help (discussion, review, ...) find a solution.

@pcwalton pcwalton force-pushed the groups branch 7 times, most recently from 16c0ba9 to 0c49f95 Compare March 6, 2024 00:16
This commit essentially allows multiple effects to share the same
underlying buffer. Such sub-effects are known as *particle groups*. An
effect may have up to 32 particle groups, each with its own capacity.
Every modifier specifies which particle groups it affects. Spawners
always spawn into particle group 0; this restriction was implemented for
simplicity and can be lifted later.

A new modifier has been added, `CloneModifier`. This allows particles to
be duplicated into a group on a fixed rate. By cloning particles into a
group, particle trails can be created.

It's intended that a node graph can be layered on top of particle groups
in the future. Particle groups are the most efficient way I can think of
to implement node graphs in any case, so this seems to me to be a step
toward a node-based editor.

Currently, init modifiers don't run on cloned particles. Their age is,
however, reset to 0 if present, as this is typically the most useful
behavior.

Internally, each particle group receives its own update and render
invocation. This reduces branching in both shaders, simplifies much of
the bookkeeping, and enables ribbon rendering for trails in the future
(needed for weapon effects, etc.)

The new `worms` example illustrates how trails can be produced with this
groups feature.
@pcwalton
Copy link
Contributor Author

pcwalton commented Mar 6, 2024

CI looks good now. I worked around the dynamic offsets limit by switching to separate per-effect bind groups for init and update. This is a bit unfortunate, but shouldn't affect performance much since we aren't batching anyhow.

Copy link
Owner

@djeedai djeedai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't finish, and most comments are minor in the grand scheme of things ;) but I took the worms example and added a loop around it, to spawn 2 similar worms effects, except one has double the particle size (so we can see which is which). Unfortunately, the second effect has no trail, so there's a bug. See how the bigger head particles have no trail.

image

src/modifier/clone.rs Outdated Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
src/asset.rs Show resolved Hide resolved
src/asset.rs Show resolved Hide resolved
src/asset.rs Show resolved Hide resolved
src/render/mod.rs Show resolved Hide resolved
src/render/mod.rs Show resolved Hide resolved
src/render/vfx_common.wgsl Show resolved Hide resolved
src/render/mod.rs Outdated Show resolved Hide resolved
src/render/vfx_indirect.wgsl Outdated Show resolved Hide resolved
djeedai and others added 3 commits March 9, 2024 15:59
Fix the rendering of multiple effects, which was broken due to the use
of a `HashMap<>` keyed by the cached render pipeline ID, which is not
unique by definition (the cache is here to prevent duplicates, and reuse
a shader across effects and groups if the code is the same).

The core issue comes from the fact `EffectBatch` used to drive
rendering, mapping 1:1 with entities spawned in the render world to emit
draw calls. With the grouping of multiple draw calls per
`EffectBatches` (renamed from `EffectBatch`), each draw call of a group
inside an effect shares the same `EffectBatches` so has lost access to
its own unique group index.

To solve this, add a new `EffectDrawBatch` component, unique per draw
call, and containing the group index. For simplicity, this new component
references the existing `EffectBatches`, so we don't need to change
everything and we can share the data across groups. This adds one level
of indirection in the draw call, but hopefully ECS is fast enough for
the low number of calls we typically have. We can revisit later.
@pcwalton
Copy link
Contributor Author

Addressed review comments.

Copy link
Owner

@djeedai djeedai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merging as is, we can refine later if needed. Thanks a lot, this is an awesome change! 🥳

src/asset.rs Outdated Show resolved Hide resolved
@djeedai djeedai added C - enhancement New feature or request A - internal Internal change on a core system A - modifiers Change related to modifiers C - breaking change A breaking API or behavior change labels Mar 10, 2024
@djeedai djeedai merged commit 4bb95a4 into djeedai:main Mar 10, 2024
16 of 17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A - internal Internal change on a core system A - modifiers Change related to modifiers C - breaking change A breaking API or behavior change C - enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants