Turn CHAOS destructibles (Geometry Collection assets) into very performant GPU simulated destructible static meshes driven by Niagara particles.
Report Bug
·
Request Feature
This plugin allows you to take CHAOS destructibles (Geometry Collection assets) and process them into GPU simulated destructible static meshes driven by a Niagara Particle System. It's useful for creating cosmetic destructible props that are highly interactive but still very performant compared to CHAOS.
Under the hood the plugin uses a niagara system to simulate the physics of the fragments (bones) on the GPU, write their transforms to render targets, and finally a vertex shader to constrain the vertices of a specific fragment to its respective bone using the render targets. See more in Implementation Details below.
- 2025/03/29 - Version 0.9.0 released.
This project was tested with UE 5.5.4.
- Unreal Engine Project with C++ enabled.
- Recommended Engine Version 5.4 or above
- Drop the
NiagaraDestructionDriverinto your Game's/Pluginsdirectory. - Right click your
uprojectfile and use "Generate Visual Studio Project files". - Rebuild your project.
Using the plugin is hopefully pretty straightforward:
- Create a CHAOS Geometry Collection from any static mesh in your project. (remember to use the TinyGEO tool to remove tiny geometry).
- Add our custom MaterialFunction to any master shaders used in your static meshes.
- Use the custom editor action to turn the Geometry Collection into a Niagara Destruction Driver blueprint.
- Drop the blueprint in a level and the included function library in BP or C++ to intiate destruction force during gameplay.
Let's walk through it assuming you already have a CHAOS geometry collection:
STEP 1: On the master material you use for props that want to use with this plugin enable Use Material Attributes, and then add the MF_NiagaraDestructible Material Function and set it up with the NiagaraDestructionDriver_Enabled static switch as shown below:
STEP 2: Select a Geometry Collection in the editor. (NOTE: it should have only one level of geometry chunks due to current plugin limitations). Right Click and run Create Niagara Destruction Driver from the menu to generate the destruction driver blueprint and backing assets (destruction data asset, initial bone location texture, and the static mesh with custom UVs to drive the GPU simulation. More info in implementation details)
STEP 3: Drop the generated blueprint (subclass of ANiagaraDestructionDriverActor) into your level.
STEP 4: Add a Niagara Destruction Debugger (BP_DestructibleNiagaraRigDebugger) actor to your level. Simulate and drag around the debug actor to collide with the BP from step 2. to simulate "destruction force" on the actor.
Call UNiagaraDestructionDriverHelper::InitiateDestructionForce in C++ or blueprint and provide the origin, radius, and force parameters.
const FVector WorldPosition = this->GetActorLocation();
const float Radius = 250.f;
const float Force = 1.0f;
UNiagaraDestructionDriverHelper::InitiateDestructionForce(WorldPosition, Radius, Force);
You can do the same from a blueprint:
- Why do I need to add the material function? ... All of the destruction is driven by a shader vertex offset (WPO) so unfortunately you need to wire this up in the master prop material you plan to use in your game.
- Why do I need the
NiagaraDestructionDriver_Enabledstatic switch in my material? ... We don't need all the shader code to be active for all your props. This plugin generates Material Instance assets for the destructibles generated, and on those instances it sets the static switch to TRUE so the vertex shader code only runs for props that are processed by this plugin. - Is any of this replicated? ... No. For a poor man's solution just use and RPC and call
InitiateDestructionForceon all clients/servers/etc. - Can I generate destructibles at runtime? ... No. The underlying engine code required to process the geometry collection is editor only.
- Can you trace for collisions for the destroyed fragments? ... No. The fragments are animated using vertex offsets (WPO) in a shader. This system is intended for cosmetic destruction like wall surfaces and small props. In a future update we could allow this system to drive smaller chunks of a CPU driven chaos geometry collection where the larger chunks with collision etc. still work.
- What's the point? Just use CHAOS destruction. ... Niagara driven destructibles are more performant.
- Why did you make this? ... We developed a houdini driven prototype of this tech when I was CTO at Counterplay Games. Two very talented tech and VFX artists Milan Malata and James Sharpe (see acknowledgments) built that version. This is a clean room re-implementation of that system with a number of optimization and that does not require houdini.
- I'm getting weird floating pieces in my destructibles? ... Make sure to use the TinyGEO tool in Chaos Fracture tools to merge tiny geometry to it's neighbors.
| CVar | Console Variable | Value | Notes |
|---|---|---|---|
| CVarNDD_DebugCollisions | r.NDD.DebugCollisions |
[0 or 1] | set this to 1 to show a debug sphere wherever InitiateDestructionForce is happening. |
| CVarNDD_DebugMaterial | r.NDD.DebugMaterial |
[0 or 1] | use debug materials that show bones + don't need special material integration. |
Expand for more implementation details
- When using the destructible actor blueprint generated by this plugin, by default it shows proxy geometry (the static meshes used in the geometry collection) and hot swaps it for the destructible mesh with custom UVs only when destruction force actually overalps with this actor.
- To prevent occlusion culling the destroyed fragments when the mesh leaves view, we hack the mesh bounds in the destructible actor using
MeshComponent->SetBoundsScale(...)
The editor action that processes a Geometry Collection into all the relevant assets is implemented as one static function: UNiagaraDestructionDriverGeometryCollectionFunctions::GeometryCollectionToNiagaraDestructible and under the hood it does four things:
UNiagaraDestructionDriverGeometryCollectionFunctions::GeometryCollectionToStaticMeshtakes a geometry collection and generates a static mesh uasset with each vertex having a custom UV channel where the U value corresponds to the bone index that drives that vertex.UNiagaraDestructionDriverGeometryCollectionFunctions::SaveInitialBoneLocationsToTexturetakes a geometry collection and generates a texture uasset where each pixel is the XYZ coord initial bone location for each of the bones of the geometry collection in local space. Since RGB can't be negative, the ALPHA value is a bitmask that encodes the sign (positive/negative) of each of the RGB coords.- Creates a
UNiagaraDestructionDriverDataAssetData Asset that has references to all the generated assets in one convenient place. - Creates a blueprint instance of
ANiagaraDestructionDriverActorthat has all the logic to wire niagara + the static mesh up. It references the created Data Asset as well as contains stand-in proxy geometry (the original static meshes that were used to set up the geometry collection) and hot-swaps them for the Niagara Driven Destructible mesh when destruction actually occurs.
For more info, please refer to the Documentation
- Nanite support and testing.
- Have the custom UV channel index be a parameter instead of defaulting to index 1 (current limitation)
- Would be nice if PositionsTexture was DELTAs so it can be black / empty at resting state.
- Deal with motion blur by finishing the motion vector implementation in the VAT material function (needs RTs for previous frame bone position/rotation).
- Support for more than ONE level of chaos geometry collection.
- Support for internal structure connectivity graph to avoid "floating" pieces.
- Make the destructible actor and particle system movable.
- Make sure that fragments are not culled when original mesh is out of vision bounds. (did a bit of work here with
MeshComponent->SetBoundsScale)
See the open issues for a full list of proposed features (and known issues).
Any contributions you make are greatly appreciated. If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Distributed under the MIT License. See LICENSE for more information.
Emil Anticevic - @eanticev
Project Link: https://github.com/eanticev/niagara-destruction-driver
- James Sharpe -
x.com/_JamesSharpe_- github.com/UnconsciousObserver - As the VFX Lead at Counterplay Games in 2023, James architected and implemented the original iteration of this approach. - Milan Malata - github.com/mimalata. As the Principal Technical Artist at Counterplay Games in 2023, Milan built the Houdini fracture and VAT texture generation workflows for the original HDA based iteration of this approach.
- Alan Lee - As the technical art director at Counterplay Games, Alan put this system into production.
- Joshua Carlos - As a Senior Technical Artist at Counterplay Games in 2023, Joshua handled building python workflows to execute the HDAs on 1000s of props. The CHAOS mesh uasset generator is inspired by his work.