As we approach the launch of Phase 2 of the Rooted alpha, we're excited to kick off this series of posts on our website to share our development journey, including the technical and artistic challenges we face. In summary, these posts will give you a glimpse into our daily life as developers, working on what excites us all: Rooted!
In this first post, I'll discuss managing the Open World.
Map Opening
Phase 2 of the Alpha allows us to include a large portion of the map in the build. Following a first Alpha session that was limited in scope (only the Monastery was available), you will now have the opportunity to explore and test the building system in a significantly larger area. Use this Alpha period to scout for the best spots for your future bases, but be cautious... there's no guarantee that a point of interest won't appear later, in the lead-up to Early Access!
Open World: Challenges and Technological Choices
Opting for an Open World for Rooted was a significant decision that comes with major challenges, necessitating critical technological choices.
World Partition and Server Streaming
Choosing Unreal Engine 5 plays a major role, especially due to the World Partition technology, which segments the map into a grid. All zones are loaded and unloaded dynamically based on players' locations, easing the load on players' PCs.
Implemented in Alpha 2, the tests are promising except for one issue: in the current version of Unreal Engine, the World Partition does not support Server Streaming. This means that the player hosting the game must load the entire map to manage player collisions in different cells.
With Unreal Engine 5.4 expected soon (announced at GDC 2024), Server Streaming will allow the server to load only the zones where players are located. We've tested this with a build version of the engine where we enabled Server Streaming, and the results are promising. We are eagerly awaiting UE 5.4 for our Alpha 2.0.
Developing Our Technology
To avoid being overly dependent on updates to Unreal Engine 5, we are collaborating with Victor Careil, developer of the successful Voxel Plugin for Unreal. This collaboration has led to a technology that manages the loading and display of all map environment props based on a Pool system.
In real time, a Pool of actors is updated to display all props near the player. These props include items like tables, chairs, pens, glasses, and PCs. For context, over 16,000 actors are involved in just the Monastery alone, amounting to several hundred thousand in the final game, displayed by only a few thousand actors making up our Pool. Essentially, this is a contingent of actors that we move around, dynamically assigning them appearances.
A major advantage of this solution is that it also functions in editor mode while we work on our map. In areas with a high density of props, this saves precious time and greatly enhances our comfort and efficiency in development.
Landscape and Vegetation Generation with PCG (Procedural Content Generation)
Landscape
Although our game is not a solo narrative type, we have created a Lore that allows us to forge a coherent environment, which we consider essential for offering a high-quality post-apocalyptic setting and atmosphere.
For this reason, we have naturally created our Landscape and then sculpt it in-engine to add layers from past civilizations, their stories, with buildings and road infrastructures.
For the Material Landscape, we use the RVT (runtime virtual texture), which provides natural transitions between the landscape and environment assets such as rocks, trees, and roads.
Foliage
However, procedural generation helps us create a rich world. This was already the case at the Monastery with our generator for walls, floors, and vaults, which, even on a small scale, allows for realistic results. For vegetation in Rooted, we use two technologies:
- PCG, which allows us to develop our own procedural logic to generate a consistent environment based on various factors (masks, terrain inclination, altitude, etc.). The size/age of trees, their density, and absence on roads are all meticulously managed through procedural generation. [/*]
- Grass Node, relating to foliage types such as grass, tall grasses, and ferns, communicates with our Landscape layers. Depending on what we define in the shader, specific types of plants and grasses are added to the environment. [/*]
I'll discuss how we manage the harvesting/farming of natural resources in a dedicated post.
Rendering Optimization
I mentioned challenges at the beginning of this post, and here is a significant one. We are developing Rooted to run on the average PC that will appear in Steam's statistics in a couple of years, with the goal of pushing technical limits further without reinventing what already exists. However, we are aware that many people are eager to participate in the alpha, and for this reason, we are making significant efforts to improve performance now.
Alpha 1 was very instructive in this regard. It's never simple with a major first title like Rooted, developed on a recent engine with new technologies and thus with limited feedback from other developers, to definitively validate all our workflow choices. And that's precisely why we decided to launch an alpha very early—to avoid realizing too late that some choices we had made were not the right ones.
Following this incredible initial testing period, we have revisited several points.
Materials
Our basic idea is simple: create and reuse as many generic materials (metal, wood, concrete) as possible to minimize the number of textures needed to avoid overloading your PCs. A low number of textures also allows us to opt for a higher initial resolution, thus achieving a truly beautiful rendering.
This is what we did at the Monastery: using instances of this material, with Material Layers we created to add layers of dirt, moss, and other imperfections. Think of Material Layers as effect layers in Photoshop. Unfortunately, this choice rests on the incompatibility of Vertex Painting on meshes using Nanite. Vertex Painting allows for painting instances of meshes present in the world, adding elements like moss or dirt, as we mentioned in an old tweet.
The feedback from the Alpha has been excellent in this respect, but from a performance standpoint, it's not feasible to rely solely on this workflow. The reason: the number of material instances the game must load at runtime to display all objects.
From a technical standpoint, Nanite performs a drawcall per different material, and the more materials there are, the more resource-intensive it is to generate a frame.
With the aim of reducing the number of drawcalls, we have begun to enrich our materials workflow by adding "real generic materials" and using trimsheets. Thus, a single simplified material with few instructions covers much more assets. The result is just as clean, with a substantial savings in drawcalls.
WPO, Triplanar
Among other technical points we have worked on, I can mention:
- World Position Offset: allows for movement of all vegetation based on wind or collision with a character. While the visual rendering is interesting and essential, it is nonetheless resource-intensive. We now control this element in Alpha 2, preventing movement on meshes too far from the character. [/*]
- Custom Triplanar: projects the texture into the world, especially on modular assets, to maintain visual coherence at the junctions, ensuring continuity of material rendering. There are no visible seams between walls. Its major disadvantage is its cost in resources. We have created for Rooted an optimized Triplanar, using only one texture sampling (versus three with the classical Triplanar), with specific UV calculations in the shader. Thanks to this, we have an optimized Triplanar that allows for a very nice visual rendering with a very low impact on performance. [/*]
Here are some of the points we wanted to share with you. If you're interested in this type of post, and would like even more detail on the technical aspects, don't hesitate to let us know on social media!
See you soon and thank you again for your support!
Mat