Optimizing Assets for Cities Skylines
Hello there! I'm “ComradeIntense”, and I'm here to share some insights and best
practices for enhancing the performance of your Cities Skylines assets.
The subsequent sections will unveil the wisdom I've gathered during my time exploring this domain,
lessons I've learned from experts (particularly from my teacher, Ronyx69), and from
my professional experience. My intention is to pass on this accumulated knowledge. Should you find any
discrepancies or have suggestions, please reach out; I'm always on the learning curve.
While this guide is tailored for those who have a foundational understanding of asset creation (a
helpful starting point would be: https://cslmodding.info), it will delve deeper into the implications of your design choices on the game's performance and how to
mitigate any negative impacts.
While I aim to be concise, there'll be instances where we'll delve into the technicalities. These are
crucial for a comprehensive understanding, so I'd recommend thorough reading without skimming over any part.
Part I
1) Definition of Draw Calls
A draw call is a command where the (CPU) directs the (GPU) to render an object on the screen. The process begins when a mesh is loaded. The CPU then calculates the
positions of each vertex in the mesh relative to the world space, as well as the associated materials.
It then instructs the GPU to display the mesh on the screen by providing the location of each vertex
and the materials to be applied. The efficiency of this process is influenced by the number of vertices and draw
calls.
A discrepancy in the performance capacities of the CPU and GPU can result in a bottleneck. If a CPU
lags in processing the instructions, the GPU may remain idle, waiting for further directives.
2) The Role of Triangles (Tris) in Graphics
Understanding the relevance of draw calls provides context to the significance of triangle count in gaming
graphics. A triangle is formed by three vertices. The GPU calculates the position of these vertices.
Therefore, a reduction in the number of triangles corresponds to fewer vertices for the GPU to
process, leading to enhanced performance. Modern GPUs can handle a large number of
triangles effectively.
Nonetheless, it's essential for developers to be judicious in the use of triangles. Using more triangles than needed can impact overall game performance, especially when multiple assets are
displayed on the screen simultaneously.
3) Comparative Analysis: Cities Skylines vs. Other Games
Different games employ various techniques to optimize graphics rendering. A central query in optimization is
whether it's more efficient to render one large mesh or multiple smaller meshes. Typically, rendering a single
large mesh requires fewer draw calls than multiple smaller meshes.
Many game developers combine smaller meshes to create a single, larger mesh to boost performance.
Additionally, developers often employ strategies like using higher triangle counts for objects near the player or
camera and fewer triangles for distant objects. Some even use detailed images on flat surfaces to simulate
intricate details without additional triangles.
In the game "Cities Skylines", the optimization process is distinct.
Players have the autonomy to add numerous objects to their game scenes, which can result in non-optimized graphics
rendering due to the vast array of assets. Each added mesh requires the CPU to execute draw calls, consuming more
processing power.
While it's crucial to be conscious of triangle and vertex counts,
achieving a balance between detail and performance is equally essential. Developers should discern what requires
intricate modeling and what can be represented using simpler graphics tools, such as normal maps or diffuse
techniques.
Part II
1) Understanding Vertex Precision Loss
In games, there exists a central reference point, known as the world origin, identified by coordinates x,y,z =
0,0,0. All vertices of meshes are computed relative to this world origin. Some game developers might calculate
vertex positions in relation to the camera or might shift the world origin.
When a draw call is initiated for a mesh, each vertex's location in world space, or its relative
position to the world origin (0,0,0), is determined and relayed to the GPU for rendering on the screen.
Vertex position data is stored in a format known as a 32-bit floating point. Floating points provide
precision up to a certain extent. The greater the distance a vertex is from the world origin, the higher the
chance for computational errors. Vertices distant from the world origin can begin to display inaccuracies in their
calculated positions.
In cases where a vertex in the middle of a mesh isn't linked to another vertex, inaccuracies in
position calculations become apparent. This can lead to visible glitches in
rendering:
To address this, it's essential that a mesh remains "closed." For instance, the problematic vertex
should be connected as displayed:
Alternatively, if connecting isn't feasible, the vertex can slightly overlap an adjacent face:
This approach isn't perfect and should be utilized if the textures match, preventing Z-fighting or
display flickering.
Vertices should ideally remain connected, even if it necessitates more triangles. Additionally,
merging vertices can be beneficial. An illustrative video that demonstrates the importance of maintaining vertex
precision can be found here:
Minecraft video
2) Overdraw and Its Impact
Overdraw in gaming can have a significant impact on performance. Essentially, overdraw occurs when the GPU renders
pixels that overlap, which can be resource-intensive.
To elucidate, consider a rendered scene featuring two characters in the background and glasses in the
foreground. The GPU would have to render both the characters and the overlapping area of the glasses' lens,
consuming additional resources.
A building comprised of two intersecting shapes illustrates this concept further:
In the above example, the areas marked in red and blue denote overdraw. To optimize performance, these
areas should be trimmed:
Another example involves a sword image with transparent areas:
Between Fig1 and Fig2, the latter is preferred due to reduced overdraw, even with a higher triangle
count. While transparent pixels might seem negligible, the GPU processes them, using unnecessary resources.
3) The Concept of Overshading
Overshading, akin to Overdraw, affects game performance. It results from the presence of slender triangles in a
rendered image. The GPU processes pixels in 2x2 blocks. If a tiny section of a triangle touches a single pixel
within such a block, the GPU processes the entire block. This leads to wastage as up to 75% of the processed data
might be discarded.
For instance, consider a building with an intricate design:
To improve the design and reduce overshading, a few additional cuts and connections can be introduced:
While contemporary GPUs are adept at handling such computations, optimizing topology to reduce long,
thin triangles is recommended for efficient performance.
Part III
1) Texture Ratios and Power of 2
The topic of texture sizes and the significance of sticking to powers of 2, namely, 32 (smallest), 64, 128, 256,
512, 1024, 2048, and 4096 (largest), has been under constant discussion. While it's true that textures can come in
any ratio and aren't confined to being square (for instance, 256x2048 is entirely acceptable), one cardinal rule
is not to utilize textures that deviate from the powers of 2.
You might argue, “I've never encountered issues without adhering to this.” However, two aspects
warrant consideration:
A) Compression:
Upon saving your texture, launching the asset editor will trigger the game engine to transform your texture to the DXT format, a compressed texture format, DXT being the compression methodology. This compression cannot transpire if your texture isn't divisible by 32. Hence, it's imperative to adhere to the previously mentioned dimensions.
B) MipMaps:
Mip maps come into play when the game engine is loading the textures. They serve as the equivalent of LODs for
textures. These are lower resolution duplicates of your primary texture that activate based on the mesh's distance
from the camera. As the mesh recedes, a lower-resolution texture is applied, with this resolution diminishing
progressively as you pan out. As you zoom in, the resolution incrementally reverts to its original size.
Here's an illustrative chain of a mip map:
This mechanism is automated and doesn't require any manual adjustments.
Now, aligning this with the power of 2 concept: Deviating from power of 2 textures can lead to
compression-induced texture corruption, most noticeable from a distance or at
certain angles. While the texture will still function and display on your model, underlying problems exist.
Furthermore, some game engines, like Unreal Engine, don't even support mip mapping without power of 2
textures. However, Unity (employed by Cities Skylines) offers an alternative approach. While Unity allows
non-power of 2 textures, they consume more memory and exhibit slower GPU read times. This is due to the engine
enforcing mip maps, scaling, and padding your texture to the succeeding power of 2. Therefore, for optimal
performance, consistently use power of 2 resolutions.
2) Texture Size: A Critical Aspect
Concluding this segment, let's delve into texture sizes. Larger image resolutions demand more memory (specifically
VRAM in your GPU) during rendering.
Here's a revelation: The file size of textures saved as PNGs on your
device is not the prime concern, as in-game importing compresses them via DXT. Notably, memory consumption isn't a
reflection of texture intricacy but is solely dependent on resolution size. Therefore, it's crucial to maintain a
balance between resolution and detail retention.
In Cities Skylines, DXT compression manifests in the following sequence:
_diffuse
_alpha + _color + _illumination collectively (ACI)
_normal + _specular in tandem (XYS)
Ronyx69 crafted a comprehensive chart detailing the sizes of these compressed textures:
(Keep in mind that the final asset size isn't solely due to textures, but they constitute a
significant portion.)
What's the next step? Simply put, avoid superfluous texture sizes. Although it might seem evident,
achieving this requires experience. Regrettably, many asset creators take shortcuts, leading to oversized textures.The industry needs a shift from the mundane cycle of replicating these flawed methods. The focus should be on
maximizing texture efficiency, reusing sections, and reducing resolution size without compromising on quality.
While this guide emphasizes performance-oriented aspects, remember: not everything has to be
intricately modeled, and most assets don't necessitate a texture resolution exceeding 2048.