Behind the Scenes with: The Infinity Engine
The tips, tricks and secrets of Decentraland’s creators revealed
Our official launch on February 20 opened the gates to the general public for the very first time, allowing them to experience the virtual world in all its glory.
Providing these thousands of newcomers with their first taste of the Metaverse were creations from some of our long-serving and most prolific scene makers.
We’ll be profiling their work, their techniques and secrets in a series of blog posts. In this first post, we take a look at The Infinity Engine by creator Bence Varga.
The Infinity Engine is essentially two things: a licensable game engine inside Decentraland and its own first demo application. Players must mine for loot underground and then take a train across the desert to sell the loot – all while defending the train from bandits on horseback.
Bence created an engine that acts as a kind of simulator. The entire content of the estate can be moved in any direction, which allows infinite travel within the boundaries. His plan is to offer the technology of the Infinity Engine to other creators in exchange for MANA, for which Bence would customize the engine based on their needs.
In discussion with Decentraland’s Nico Earnshaw and Sam Hamilton, Bence talks us through the development of The Infinity Engine, in particular his approach to using objects in scenes and the finer points of optimization.
How do you store info about the terrain that’s not visible to the player and then determine what objects they see? Or is this randomly generated?
I have set up both procedural and ‘world fixed’ objects in the scene, as my plan was to include and store a whole village that is completely off-scene at the beginning. To store the off-scene objects I defined a “shapeManager’’ entity type, that has a component that stores the object type (essentially the GLTF reference) and a large-world position. These shape manager entities update the large-world positions every frame – whether the object is visible or not – and check if this position is inside the scene boundaries (with some object radius thresholds). If the large-world position is inside the boundaries then the specific object type is spawned at the position and from then on the position is also copied to the spawned entity as well. Conversely, when the position reaches the scene boundary the ‘managed’ shape gets removed. An example of this would be the parts of the mine entrance upstairs, which obviously have to be in the exact same position every time the train returns.
For procedural objects, I have two methods as well. The first is just spawning objects in zones along the edges in the direction the train is heading. The more performant version is the one where I don’t need to spawn anything new, I just move the objects that leave the scene to a new location further on in the scene. The biggest problem I had was avoiding generating anything on the train tracks, as distance measurements can be quite a burden on performance.
Your game is very well optimized and plays very smoothly. What optimization techniques had the greatest impacts on performance?
My two biggest optimization goals were:
-
Keeping the polygon count down (also because black outlines essentially double the count). The whole scene has only 4MB of models
-
Minimizing texture resolution
- My whole textures folder is less than 0.6 MB!
- I used mostly 256x256 and 128x128 textures
- I turned off texture sampling (which sadly didn’t work in the deployed scene)
Other than these I would say optimization was more about navigating the capabilities of the current SDK and platform. During beta testing my biggest challenge was anything involving moving platforms and moving the player. I was lucky with this scene as the player and the train don’t actually move, so there is much less chance of the player falling out, or having jaggy camera movement.
I also avoided objects that follow the player. Using them currently causes huge delays and makes the scene practically unusable. I switched for screen-space weapons early on. I was planning on changing the gun image from idle to shooting (with nozzle flash), but when I tested the game on a slower laptop it became evident that I should minimize UI update usage. When I was clicking too much, the game essentially slowed down to a stop.
For the bandit models I used one single animation loop that plays on forever, rather than adding animators and animation switching. I knew there could be a lot of enemies on the screen at once so I had to optimize these a lot. One bandit+horse model is around 900 tris (1800 tris with black outline) The most important optimization tip actually came from my wife. When a player was upstairs, I removed everything downstairs. And while the player was mining underground, all of the upstairs desert and systems were removed. This gave me a significant performance gain.
Stay tuned for future posts with more of Decentraland’s scene stars, including behind the scenes looks at projects like Block Runner, Dragon Race, Salmonomicon and more.