July 2024

General

The July dev blog was released late, at the same time as the August dev blog.

Slime On Digestive System

During August I continued the integration of Slime and filaments and the digestive system scripts.

 

This time the placement is semi-procedural, so I can add groups of points with procedural parameters and add links manually.

 

I mainly use a curve to define the areas where I want to add the most points, based on the surface area.

SlimePointSpawnProbability.pngSlimePointSpawnResult.png

 

It allows me to populate an area quite easily and keep control over it.

 

Search and dev one particle system for multiple instances

In an Engine, particle effects are managed via Niagara. I'm not familiar with using Niagara FX in an Unreal Engine, so I did a bit of research and development to understand what was possible and what wasn't, especially when a simple particle system is used for several different instances.

 

Let me explain: for good optimization, it's easier to have a single particle system handling 100 different particles than to have 100 particle systems each handling one particle. This is the case for the Slime, which will manage several filaments at once, or the interaction system, which will display interaction notifications in the game space.

 

During this research and development, I concentrated for 2 days on interactions, which I felt was easier to manage.

Here's what I posted in the game's WIP:

 

----------------

First, I started to review and redo the interaction notify FX I created for when you are close to an interaction. In the previous version, each particle used its execution index to choose the target data (Location, Interaction type, color, and more) and the FX system managed the number of particles to show.

This works but contains some problems. When a particle is removed or a data index changed, every particle using a higher index has to reassign its data. This causes the particles to move to the new location with an ugly motion blur. Also, I can't use animations since the interactions change particles with new state data.

 

In the game that less visible because in the most of because you see a way less interactions at the same time.

In the new FX version, each particle is assigned to a specific interaction and removed when the interaction is removed from the data. It was very complicated to find how to assign the correct data to each particle.

Avoiding multiple particles assigning data at spawn was very tricky. When several particles spawn in the same frame, it is not possible for a particle to check the other particles that spawn at the same time, but I can know how many particles spawn at the same time and the particles that have already spawned.

So, I check all spawned particles to find the last unique ID, and then check the particle ID to find the offset from the last spawned particle. I also check the number of spawned particles, and with that I can find the data selection offset.

I can now spawn several particles at same time without conflict. This take me so MANY hours and that was not finished.

 

The code I did work for FX GPU simulation, but on my side, I need a CPU simulation. And the CPU integration of HLSL code seem to be broken. I lost more hours trying to Debug and understand what I did wrong before understand that the code do not manage basic stuff as loop or arrays. More detail here: https://forums.unrealengine.com/t/issue-with-loop-behavior-in-niagara-hlsl-with-cpu-particles/1927567

 

And now I have another issue: When an Interaction is removed from the data the particle assigned to his data should be remove himself after a time and not immediately. The particle set a bool variable as invalid and start the despawn animation.

 

In my FX I need determine the number of particles to spawn at frame and for that I need read all particles data to know how many particles is valid.

And this is impossible. The particles can read the data of the other particles but the emmiter that spawn the particles can't read it. I did not find other way to do that.

 

In the newt video, I spawn interactions with random locations and remove them after a delay. When an interaction is spawned, the FX spawns a new particle, and when the interaction is removed, the particle sets itself as invalid and despawn. For the debug, it just turns red and do not despawn.

As you can see, the spawning stops creating new particles because it counts invalid ones as valid, and the number of particles continue to match with the number of interactions.

 

This issue is blocking because in case of a particle get removed at same time another one spawn the whole index offset system that I did with HLSL get break because the offset will be wrong on all next following particles.

 

So that works but that not stable and a way to complex to do.

----------------

 

Later I managed to simplify the operation and make it stable. And I'm finally using it with Slime filaments, but not for interactions.

 

I'll talk a bit more about that below.

 

Interaction Particle System

 

Following research and development, I decided that it was simpler to use a particle system for each interaction.

So I reworked the particle system and added new animations based on the interaction data.

 

I've removed the E logo and reworked the rendering of the basic states with animations between each state.

 

In addition, the interaction code now follows the character scale.

 

Slime Particle System

For the Slime filament particle system, I first worked on the possibility of having a single filament with all the basic interactions and parameters.

The filament will get crush or thicken according to the distance of the points to keep a coherent volume and simulate gravity. With certain parameters such as length, color, etc.

 

To simulate gravity at first, I wanted to use a hyperbolic curve to make a Catenary curve.

 

The chain curve is physically correct for simulating the position of points along a string as a function of gravity.

 

But after a few hours of work I couldn't figure out the mathematical formulas and get it to work.

So I used a parabolic curve. It's not physically correct, but it works very well and can be modified in the future if needed.

 

From here on I tried to use a particle system for each Slime filament, which as expected was not optimized at all.

 

So I did some more research and development and managed to stabilize the blocking problem from last time.

 

Here's what I posted in the game's WIP:

 

----------------

My optimization is over 9000 :>

 

Since my last post, I have done many tests and redone the slime interaction and FX several times.

 

Regarding the FX, I started with one FX per slime tread, like I finally did for the button interactions. However, in this case, the resources used to manage every FX were too heavy. I optimized by using a deformable mesh with a Render Target texture to manage the deformations in the shader, but the optimization was still not good.

SlimeFX_MeshTest.png

 

And in the end, I reworked what I had done in my FX dev and search:

One FX to manage several slime treads, and this time it was way more stable, and I achieved superb GPU optimization.

SlimeFX_StableMultiInstance.png

 

On the CPU side I also did nice progress on the optimization using many caches do transfer all data and avoid useless recalculations.

Now, I can run 2 x 10000 points in runtime at 90fps.

Do you remember when I was at 10fps with 2 x 25 points?

 

In the game, I will never use more than 1000 points at the same time, so I will not optimize more the slime treads for the moment.

----------------

 

I remove the debugger, add the gravity curve, a Shader and here's the result:

 

It will look even better when I understand how to use hyperbolic curves.

 

It will also be possible to add physics with swinging filaments and add animations when a link is created or broken without it consuming much more performance.

 

For the moment, I don't intend to touch the FX, but I'll certainly be making improvements after the Vore update.

 

Finally, I also ran several tests on shader rendering.

And some VR tests

 

Common Optimizations

At that point I was still having optimization problems with the rendering and animation in the digestive system in VR.

 

To compensate and continue optimizing the rest of the game, I made small progress in a few areas.

 

Here, for example, I've done a pass on hand and finger tracking in VR.

I used to average 600 µs per CPU frame, but I've managed to get it down to 60 µs.

VRFingers_Before.png VRFingers_After.png

 

It's funny to see that now the game is more optimized than previous versions, with more content to deal with.

 

Digestive System CPU Optimization

I did a pass on optimization and how modifiers are handled on the CPU side.

 

 

 

Data is set up and modified only when necessary, and the various parts of the digestive system will use only the modifiers they need.

 

This is particularly useful for filtering the data to be sent to the GPU, which will calculate the animation.

 

The modifiers' animation is now deterministic, making it easier to debug and synchronize in multiplayer.

 

Deterministic means I'll always get the same result depending on the data sent.

 

Now, on the CPU side, the collision update is the most power-hungry part.

I can't optimize this part because it's handled in the source code by the physics engine.

 

Collision updating will take up more resources for the host player and dedicated servers as they need to update collisions for everyone, whereas the client needs to update only the collisions it uses.

 

The collision update frame rate is not synchronized to the game and will depend on the context, allowing most machines to play the game at 60 frames per second.

ClientVsServerColExec.png

 

Here's the result in game :