Back to Index Page Articles


Parts of the article might not be correcly converted. For best experience, go to the Tor site.
http://ttauyzmy4kbm5yxpujpnahy7uxwnb32hh3dja7uda64vefpkomf3s4yd.onion




Dani's Race Franzo Livestream Report

October 06, 2024


Yesterday ( 5th October 2024 ) Franzo from opensource_gaming did a livestream of a game I am developing called Dani's Race.



This article will be my observation of things working in the game, and things that need urgent attention. Among them the highest priority are: Optimization and User-experience.





Optimization Struggles and UPBGE engine




According to this youtube video which tested 3 popular Free Software game engines ( UPBGE, Armory and Godot ) and compared them to one another, UPBGE ( the engine used for Dani's Race ) scores the highest in the looks department. Making good looking graphics in it appears to be very easy. But on the other hand, it is the one with the slowest performance.

A lot of people might jump to conclusions that BGE ( the previous incarnation of the engine ) was kind of a bad engine to begin with. And yes, it seems like BGE always was a little more demanding than any other engine at the time. BGE in itself is not necessarily the problem here, though.

Main criticism of BGE ( performance-wise ) was that it used ( and still uses ) python for the scripting. Which is assumed to be very slow. And that could pretty much be the case for games like Yo Frankie! made almost 20 years ago. When computers were much slower and python was a terrible decision for something that had to run fast.

The reality is, python is only used for the optional scripting and only to send messages to the internal game engine, written primarily on C++. Yes, with bad code it could be a rather significant blow to performance, but in the case of Dani's Race, execution of logic ( python included ) only amounts to something along the lines of 2%.

The 2 heaviest elements in Dani's Race ( according to the engine's profiler ) are:

- Rasteriser 30%
- Depsgraph 60%

Rasterisation is the process of converting vector data into a pixel-based image. Basically the rendering of the frame itself. This is the part that GPU is doing. To optimize for the Rasterisation, the scene fed into it should be simpler. Less geometry, less texture resolution, less shader complexity.

The main difference between UPBGE to something like the BGE from Blender 2.79 is the way shaders are handled. BGE used standard OpenGL SL materials. As far as I know Godot and similar game engines use the same approach to shaders. UPBGE instead uses EEVEE which GLSL only on the surface, but in reality is a completely different beast.





Cycles Render and how it made UPBGE slower




Both BGE and UPBGE are basically just Blender, but used to make games. But Blender is not just a game engine. It is in fact a whole 3D pipeline suit, made into one handy program with tons of very cool features.

For the longest time Blender had a regular rasteriser rendering engine simply called "Blender Internal" which looked a bit better than the GLSL materials, by providing additional function that are not easily calculate-able, like refraction, reflection, ambient occlusion and such. Which was used primarily to make films and not games, since rendering frames with all these options would take a very long time.

At some point after version 2.5 a new rendering engine was introduced. This time not a typical rasteriser, but a true path-tracer called Cycles. Which works by sending "rays" from the camera and bouncing them around the scene to estimate light and color values. This by itself already removed a need to calculate ambient occlusions separately. And made refractions, reflections and even light bounces work much better. People jumped on Cycles as soon as it came out. And by Blender 2.8 "Blender Internal" was removed entirely for lack of use.

One more thing cycles did was to introduce a concept of instant update to Blender. When blender only had Blender Internal, if you wanted to change something about a material, you would render it. Then change something. Then render it again. Cycles, because it used rays, and could make a very noisy approximation of the scene relatively fast ( only the final image was slow, because you have to render a lot of samples to make the noise disappear ), you could update the scene almost in real time. Allowing the artist to dial in the material just right and see immediate change in the 3D viewport.

That concept later was developed further. At first you had to slide your slider and release the mouse, for the update to happen. But then the developers decided that it will be better for the artists to see the changes in real time as they are sliding their sliders.

This made it so Blender now had to be extremely dynamic. And made it so now the developers were forced to rewrite the old scene-graph ( a system handling updates ) and replace it with a new, much more complicated dependency graph ( depsgraph ). Which allowed smarter, real-time updates of pretty much everything. Resulting subsequently in developments like the Geometry Nodes that takes this concept to the max.

This new Blender depsgraph is taking 60% of the time it takes one frame to render in Dani's Race. Old BGE scenegraph would be almost insignificant in comparison.

But it is not the only thing cycles did to slow down UPBGE. Cycles as opposed to Blender Internal or GLSL materials is way more flexible. By default cycles materials are node based. Which means people can go nuts and make all kind of complicated procedural behemoth-shaders. It's not a simple material that takes a few texture maps as inputs. It's a whole playground where you can design your own shaders. And decide what controls what. Which in itself seems like a much more complex system to get right. But Cycles is a path-tracer and cannot be ( at least in the near future ) reliably used to render a game, which has to run many tens of times a second.

Enter EEVEE.

EEVEE was conceived as a replacement of sorts, of the old Blender Internal engine. Inspired heavily by both Cycles and the Unreal Engine ( as evident from early presentations of the engine ). EEVEE's whole idea was to render cycles materials as faithfully as possible, while remaining a real-time rasteriser engine. It could help, for example, work on materials a lot faster, since you don't need to wait for cycles to clear up the noise everytime you move a slider. And it could be used for animations where quality of ray-tracing is not as needed. But a lot of people also saw a huge potential of EEVEE to be used for BGE. As a replacement to the limited GLSL materials. But in the same version where EEVEE was introduced ( Blender 2.8 ) BGE was deleted. Making a lot of people very disappointed.

UPBGE ( which originally started as a fork of the regular BGE ) decided to gamble on this disappointment and make a version of Blender 2.8+ with EEVEE and BGE working together as people wanted.

Therefor Rasterisation is slow due to EEVEE trying to faithfully render extremely complex cycles materials. And Depsgraph is slow due it trying to accommodate all possible dynamic changes in the scene which were not possible before with earlier versions of BGE. Resulting in a very powerful but very slow game engine.





The optimization in the game itself




When it was evident from an early ( unrecorded ) testing of the game on Franzo's computer ( some weeks before the stream ) that the game is poorly optimized for anything but the latest hardware, a hunt for optimization tricks began.

Originally Depsgraph and Rasteriser were taking roughly the same amount of time. But as evident, those optimization efforts payed off to reduce something like half of the strain from the GPU.

First was the optimization of materials themselves. The game file was very messy and contained a lot of duplicate materials. For example a glass material which is used on building and cars had like 5 or 6 copies in the final game. All these copies were reduced to links of the same ( if it's possible ) material, for almost the entire game. This boosted the performance a little bit. Empty material slots and unused materials were removed entirely. Reducing the game's size by a few tens of MB.

Then was the geometry optimization. The game, as you maybe know, is a sequel to a movie I made a year or so ago called Moria's Race from which I copied a lot of assets. One of which, Neonspeedster ( the hero car ) contained a lot of geometry to look smooth in the film. Geometry that for some reason I failed to realize was a bit much for a game.

( Probably due to my computer being too strong ).

I reduced triangles on Neonspeedster from 300+ thousand, to below 20 thousand. By re-rigging most of its outer shell from the source files of the film. And when I liked the result of that, I proceeded to reduce geometry where-ever possible on the rest of the cars.

For depsgraph, the best strategy is to have less stuff. Less objects ( if you can connect something into one object, do it ). Less modifiers. If you can apply a modifier, do it. This was done relatively early in development. And maintained relatively well.

Also you have to limit creating and disappearing of objects. Since this tends to create the strongest spikes of activity in the depsgraph for some reason. So despawing and spawning cars is actually more expensive than keeping them in for longer. But what was done about it is to instead reuse everything as much as possible, by just teleporting things around. If there is no car in-front of the camera. And a car that the player cannot see, this car could be moved where it would be "spawed" in the normal engine. And in the same time, this constitutes a "despawn" of that same car from that place where the player doesn't see it.

Still with all these tricks in place, moving the cars or fences or whatever around too often would also result in a, way less, but a constant strain on the depsgraph. So executing of those scene updates should be infrequent enough to keep the FPS high. For which the game now has a function calculating how often one such update can happen.

The things I just listed were already implemented in the version Franzo used for the stream. And yet with all this insane optimization, the game still ran like a piece of poo on his machine. So more has to be done.

Perhaps reducing unnecessary geometry from the location meshes could help reduce Rasterisation a bit more.





The optimization in the engine




The engine ( UPBGE ) is not the smartest engine out there. Even though it is expected to be slower for all those features that it has.

For example, depsgraph doesn't need to run on every single frame for every single object as evident by this pull request. And removing static object from trying to update all of their internals all the time, could boost the game's performance a lot. Which is something I'm trying to investigate, by trying to get a working version of this specific branch of the engine. So far unsuccessfully ( it doesn't compile ).

Also there is the elephant in the room. Depsgraph is being updated on the CPU, while Rasteriser is working on the GPU. Therefor in theory they could work in parallel increasing the performance almost to 200%. At this point the Depsgraph has to finish its half of the calculation, for then the GPU to start its part. Meaning even though the game runs slow, both CPU and GPU don't run at their full capacity. It's good for when you want to have other things open with the game. But terrible for the game's FPS. I already filed an issue on that.

It is probable, that since there is not a lot of active development on the engine itself, I will have to fork the engine and implement all those changes myself, to boost the performance of the game. But hopefully the devs will wake up.





User experience




According to the experience of Franzo playing the game itself, apart from the optimization, which we already discussed, a few other things were problematic.





Controls




The game appears to be confusing with its controls on many levels. First of all the combination of WASD for walking and Arrow keys for driving ( as a default configuration ) was met with a lot of confusion from a lot of people including Franzo. Something perhaps has to be done about it. And the vast majority of people suggest just making cars control with WASD by default too. Since people who prefer arrow keys can just change the settings.

Speaking about the settings, a few times during the stream Franzo changed the controls in such a way that one key controlled two functions, since there was no warning of it in the settings dialog. This is a relatively easy thing to fix. And it's already on my list.

Other control related confusion stems from not knowing how to operate with something, or that this something can be operated with a key. Like for example the elevator in the garage. Which you have to press L to call to yourself. But 1 to get it up. There is a blink-and-you-miss-it message about the elevator controls first time you come close to them. But they are insufficient. And nobody pays attention. Therefor a better system to know that something can be operated on should be designed.

Cars, according to Franzo, accelerate a bit too fast, which could be just some part of the code still sensitive to FPS changes.





Music




According to Franzo ( which some players disagree with ) the current state of the music in the game is very repetitive. And has to have more variation to be exciting.





Shaky Cam




The game is simulating the Adrenalin level of the protagonist and tries to induce it in the player by shaking the camera more violently, the more pumped up with Adrenalin Dani is. This works well for me ( I like good tension if film and love when it's getting harder to drive because you are going fast or hitting things ). But apparently I have different tolerances for this kind of effect.

I guess a smart way to fix this problem would be to introduce a setting which allows you to set how violently the camera shakes. Which could be set to zero for those especially vulnerable to the effect.





Un-patched areas




There is an area in the game which I underdeveloped, since it is a road going out of the city that is barely visible in the movie. There is no indication that this is not a place you want to drive to. And the road model itself is broken. So Franzo fell into the hole in the road and got stuck, needing to restart the game.





Good things




It seems like Franzo enjoyed the concept and potential of the game. And liked that it has a story. It was perhaps really fun for him to be able to just go where ever he wanted. Even though at times he was in pain for needing to walk somewhere because he didn't have a car. Also it seems he really liked the way you fix cars in the game.

People in the chat said that the game looks good ( even though it was very graphically reduced to be somewhat playable ). I guess those people need to see it on high settings.





Conclusion




It seems like I chose a strangely advanced engine for new hardware to make a game that is actually kind of cool. But the game is struggling immensely because it is very hard to optimize it. And therefor I have less testers and therefor I know less about what people are confused about.

Happy Hacking!!!