-
Notifications
You must be signed in to change notification settings - Fork 163
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
The definitive Particle Effect rework #6465
Open
BMagnu
wants to merge
65
commits into
scp-fs2open:master
Choose a base branch
from
BMagnu:particle_cleanup
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Conflicts: # code/globalincs/type_traits.h
BMagnu
added
enhancement
A new feature or upgrade of an existing feature to add additional functionality.
cleanup
A modification or rewrite of code to make it more understandable or easier to maintain.
fix
A fix for bugs, not-a-bugs, and/or regressions.
refactor
A cleanup/restructure of a feature for speed, simplicity, and/or maintainability
particles
An item related to the particle system
labels
Dec 16, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
cleanup
A modification or rewrite of code to make it more understandable or easier to maintain.
enhancement
A new feature or upgrade of an existing feature to add additional functionality.
fix
A fix for bugs, not-a-bugs, and/or regressions.
particles
An item related to the particle system
refactor
A cleanup/restructure of a feature for speed, simplicity, and/or maintainability
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The definitive Particle Effect rework
Okay, frankly the particle spawning system has some issues. This is my attempt to clean it up once and for all, in a way that is at least more future proof than the current system.
Many thanks also to @Kestrellius, for helping me testing and debugging this PR.
For whoever might be reviewing this: I recommend looking at the following files as if they were entirely new instead of trying to dig through the not-very-helpful diff:
code/particle/ParticleEffect.h
code/particle/ParticleSource.cpp
code/particle/ParticleSource.h
The current state and its problems
To understand both the need for this PR and the design goals, let's first discuss the issues I see with the current system, both from a maintainance and code extending standpoint, as well as from a user-facing standpoint.
Needless separation of Effect Types
Currently, particle effects tabled through
-part.tbm
files need to be one of 5 different types:This is suboptimal from both a code perspective, as well as from a user perspective. From a code perspective, this constitutes a lot of duplicated code, since large parts of the handling of these types is identical between them. After all, a Single-type particle is effectively identical to a Sphere-type particle with radius 0. Furthermore, Composite-type particles especially are a pain-point in the current system, as they behave sufficiently different from all other types to need special handling in many places. While most of these types are currently handled as polymorphic, Composite alone needs to be checked against in many places, defeating the purpose of using polymorphism for effect types.
Furthermore, adding new features to particles typically requires a similar if not the same change in all effect types, adding unnecessary maintainance overhead.
From a user perspective, the main drawback originating from the seperated effect types is missing flexibility. Right now, a lot of particle effect options are mutually exclusive. An example of this would be the velocity pattern of the Cone-type effect with the particle's themselves spawning in a spherical volume as would be the case in a Volume-type effect. Fundamentally, the only thing that is causing this mutual exclusivity is the type separation. There is no inherent cause why a particle effect could not have both of these properties. As such, the given type separation significantly reduces flexibility and possible applications for users.
Layers and layers of Particle Effect systems
Another highly significant issue for both maintainability and usability is the current layering of the particle system. To give a quick overview, currently, the following layers exist:
As is evident, there is a significant stack of legacy particle handling in various states of modernization, all concurrently maintained and adding to the code bloat of the overall system.
Additionally, which layer any given particle is in has a significant effect on usability, both causing overall confusion to users, and reducing usability for the less capable types.
Layer 0 is mostly a backend layer which all other systems implicitly rely on, however there are a few things that directly create particles in layer 0, notably scripting and pspews.
Layer 1 mostly contains very old particles tabled directly in the ships or weapons table, such as ship split particles, damage spew, thruster particles, and so on. Notably, most of the layer 1 particles that have not been converted to layer 2 seem to be modified per-frame dependent on the current gameplay state. This is what I presume to be the reason for these particles not to be updated to layer 2 handling, as that requires a static particle effect.
Layer 2 is primarily two different wrappers around the layer 1 code (and thus also requires the level 1 code to be present and maintained). The main difference is that it adheres to the static effects of the modern particle effect system. This also allows this type of particle effect to be replaced by a modern layer 3 particle effect if tabled properly.
Layer 3 is the modern particle effects which are read from
-part.tbm
files, and are handled by the modern particle code which only relies on layer 0.Not only are these different layers confusing, but the inability to use
-part.tbm
particle effects for layer 1 (and layer 0) particles strongly diminishes their usefulness.In addition, the interdependence of the layers on one another makes maintainance fairly hard and painful.
Code redundancy
Perhaps due to the organic growth of the system, several bits of code (even outside the different particle effect types) are strongly redundant.
Especially for calculating the position and orientation of particle effect sources, global as well as local to potential parents, there is lot of duplicate code.
In addition, the submodel stack of a given model that spawns particles is potentially traversed multiple times for various different computational steps, when once would have been sufficient.
Furthermore, everything that could be queried from something that spawns particles is currently handled in its own function, with a large switch-case statement, repeating all possible particle source hosts every time instead of using polymorphism to properly abstract this.
Because of the complexity of this code, a few possible combinations of global/local coordinates in either in- and/or output are simply broken and will yield incorrect particles.
Insufficient separation of code responsibilities
Big parts of the particle code are stateful. That, in and of itself, is not a problem. However, these states tend to be modified as side effects of functions in very different parts of the code.
This makes understanding the code as well as maintaining the code very difficult. Things modifying the state of their callers in insufficiently documented side-effects is a common feature in the current particle code, which should be reduced for better code readability.
The approach for a redesign
Now that the issues with the existing system are discussed, we can get into the four core redesign aspects I have identified and implemented.
One Effect Type to rule them all
The core improvement over the existing system is the introduction of a new particle type. This "Omni" particle type is effectively a superset of all previously existing particle type.
This includes the tableable particle types, as well as legacy particles handled in layer 1 and 2. This has a few critical advantages:
First, all existing particle types can be removed. Since all particle types, such as the Sphere-type, only have a subset of the features of the new Omni-type, all existing effects can be specified as an Omni-type effect. In fact, this is what the parsing code for the
-part.tbm
does with this PR. Instead of parsing them as before, it will now use the parsed data to construct an Omni-type effect instead. This allows handling the new particle system as a replacement to layer 3, instead of as an additional fourth layer.The same thing applies to layer 1 and layer 2 particles. The Omni-effect has all necessary configuartion options to represent all existing particle spawning methods used in layer 1 and 2. As such, the parsing code for these particles is similarly changed to construct Omni-type effects instead of the legacy effects. This allows us to entirely remove layers 1 to 3 of the current particle system, instead of just building on top of them. The problem of dynamic adaption of effects to the current gameplay situation is resolved by adding modular curves to particles, such that the adaption to gameplay can be handled as data instead of as hardcoded behaviour.
Overall, this new Omni-effect is thus able to completely eliminate the redundant code between effect types, and is able to significantly declutter the rest of the particle spawning system.
Furthermore, since one effect type is now able to handle everything, a user tabling this new effect is now able to combine all behaviours instead of having to decide between multiple mutually exclusive types.
The only prior effect type not directly handleable through this Omni-type effect is the composite effect. As the composite effect itself was handled very differently prior to this PR as well, it felt sensible to just properly differentiate the behaviour of "multiple effects per source" from just tabling different effects.
As a result, this PR now handles all effects as composites. Any effect ID which can be used to create a particle spawner now refers to a vector of particle effects instead of a singular effect.
As such, a non-composite effect is simply a composite containing one effect, and the code always expects that a given effect ID could imply any number of effects being spawned from a given particle source.
Abstracting Volumes
In order to facilitate the Omni-type effect, it is required to be able to specifiy volumes, both for the velocities of prior effect types like the Sphere or Cone-type, as well as for the particle positions of the Volume-type. As such, this PR now abstracts the concept of "Volume for particles" independent of how they are used. Currently, three types of volumes are known to the system:
Abstracting Effect Hosts
This PR also rips out the multitude of switch-case statements for various effect hosts (like object / existing particle / just a free floating vector) and replaces it with polymorphism.
This allows code maintainer to just create a new class instead of having to search for many switch-case statements to edit, some of which need to be closely matched to one another.
It also fixes some bugs where this exact matching wasn't done properly in some cases. Unlike the volumes, which need particle specific code to facilitate some of the modular curves, the effect hosts are sufficiently generic that they could be easily adapted to work for other things that are attached to objects or the like.
General decluttering
Additionally, this PR tidys up some of the more egregious issues as well as remove a lot of unnecessary boilerplate. Notably, this results in a clear hierarchy and process:
The notable change to before is that the only thing that has a modifiable state is the particle source.
And the only thing that modifies this state is the particle source itself. Neither does the particle spawning in 4. change the timing state (as it did before), nor does the result of 4. have any effect on whether the particle source will continue to spawn particles in the future. This is all managed by the particle source in one single function, greatly improving code readability, reducing complexity, and fixing some long-standing bugs.
Effective changes with this PR
The overall result from the previously discussed points is fourfold. Less code (around 1000 lines), even though a lot of functionality was added and the new parsing code and hardcoded definitions to adapt legacy particles takes up a lot of lines (even if simple ones). Less complexity and a lot better maintainability. More functionality, as will be discussed later. And finally, several bugfixes, as will also be discussed later.
Added User-Facing Functionality
To get this out of the way first, even with the new parsing options and significant changes, all existing tables work and will continue to work with no significant behavioural change.
-part.tbm
. This notably includes thruster particles, damage spew, impact spew, and ship split particles, among others.Fixed Bugs
Outstanding TODO's and future enhancements
In decreasing order of importance