Costly 3D Mistakes to Avoid (Postmortem)


Since releasing GDSim, I have dedicated my development studies to becoming better at making games in 3D. There are several mistakes I can identify with my first effort, and I want to explain some, as a caution to other beginner indie developers making 3D games themselves.

Shader Compilation

One of the first things players may notice are that the game chokes and pauses when you start playing GDSim for the first time. This is when new shaders are being compiled for your graphics processor. For this project, I used mostly standard materials created by the Godot Engine editor, so those were the shaders being compiled. Every time a new material appears on-screen, the gameplay stops to complete this task. The more independent materials I used, the more times this happened.

☑️ Fix: Compile early and as few times as possible

Each shader only needs to be compiled once; there are only as many compile times as there are different materials. Cleverer uses of materials will reduce the total compile time. If compiling every shader at once does not take very long, it may be made into a process in a loading/intro screen, so that it hardly affects the experience at all.

Physics Waste

❌ Very high global physics tick rate

❌ Too many fixed-time (physics) calculations on every frame

As explained in the devlog post, Tires at Rest - A Deceptive Solution, I designed GDSim to operate at very high physics tick rates. This mitigated some precision errors in the simulation, at the expense of more CPU usage. In fact, a lot of processing time was spent calculating things that did not need to be updated that often; they only existed on the physics (fixed-time) loop for the sake of synchronization. This includes collision-checking for all physics objects in the scene...for as many as 360 times every second.

☑️ Fix (x2): Stiction, and early returns

The above-mentioned blog post describes a solution I've dubbed "stiction" that helps improve the behavior of the tire model at lower physics update rates. I will continue to refine the model for polish, but it is already functioning well locked at 144FPS. Additionally, I found that by counting physics frames, it is possible to skip over calculations that don't need to be ran every single frame, limiting the CPU load.

❌ High-poly auto-generated convex collision shapes

If you tell Godot Engine to generate multiple convex collision shapes from a detailed mesh, it can get very messy and expensive quickly. I created dedicated collision-shape meshes for cars, but they were not as simplified as they could be.

☑️ Fix: Import dedicated low-poly collision shape meshes for conversion

I have switched 3D modeling software and can easily create matching collision shapes much more quickly than before.

Graphics Waste

❌ Multiple viewport textures and extra cameras

❌ Advancing time-of-day redraws sky resource

To create the sky background in GDSim, I followed an example I read about on the internet that used a viewport texture in the background to draw the output from a duplicate camera. The duplicated camera rotates to match its matching "parent" camera, but peers around an independent scene, drawing what it sees to the texture. For split screen? There are four cameras. 😵‍💫

But wait, there's more! The rear view mirror is another camera and viewport texture. There's not a lot else you can do for such an effect, but there are a lot of cameras and viewports going on, and they add up. I had intended to add even more, for the side mirrors (optionally).

Even worse -- whenever time changes for the sky background, Godot is instructed to recalculate its built-in sky resource, which redraws a gradient texture. Then this new texture is mapped to the radiance map texture used by Godot's built-in materials. This happens on the CPU, not the GPU, and is so pointlessly slow I would not use it for an actual game. (I included warnings about its disappointing performance.)

☑️ Fix (x2): Avoid viewports unless necessary; use shaders

In the future, the sky background will be drawn using a custom shader that eliminates the need for viewport textures or extra cameras, and greatly simplifies the structure of the game.

❌ Triplanar texture mapping

I used this as a quick and dirty way to texture the environments, including the track surface, grass, and rock walls. It is an inefficient way to blend a texture over a 3D model, because it reads the texture three times, but it allowed me to map noise textures to all the surfaces quickly. It is a tool that should be used only when appropriate.

☑️ Fix: Appropriate UV mapping

I have improved my 3D modeling skills and can certainly utilize textures with more respect for the number of texture reads that occur. (:

❌ Tiny subpixel polygons everywhere

❌ Large map meshes are units; never culled

It turns out that little bitty single-pixel (or vanishingly small) polygons aren't just a regular waste of rendering time. They're an awful waste of rendering time. There are various places in GDSim where such shapes appear.

Also, for expediency, each type of surface on a map in GDSim is a mesh. Effectively, this means that the entire map is rendered all at once almost all the time. That is a terrible waste of basic frustum culling.

☑️ Fix: Use appropriate-LOD meshes and draw distances

☑️ Fix: Divide meshes into parts that can be frustum-culled

I have adopted an art style to mitigate such pitfalls, and I won't make the same mistakes again.

❌ Three spotlights per car, all with shadows

❌ Raycasts every frame to place graphics effects

❌ Alpha-blended shaded particles

This is just plain waste. During the development of this prototype, I was searching for an art style, trying out details. You might think that by using relatively low-poly models, you can get away with a lot more expensive effects, but flourishes like this still add up quickly.

With the raycast-based effects, again, I got caught up following examples online that were not written with performance in mind. ): It pays to be wary of this, especially for concepts packed into a YouTube video.

☑️ Fix (x3): Spend shadows, effects, & alpha blending wisely

Lovely visual touches are great, but always consider their value versus the impact they have on performance, especially if any are to be non-optional.

🏜 Explore With Care 🤠

Based on my experience and studies, 3D indie game development is still a wild frontier. There is unimaginable opportunity and bounty out there, waiting to be uncovered, but there are also quicksand traps, snake oil shops, false guides, and just the unforgiving terrain itself. There aren't many guardrails, and good help is rare. A lot of inside knowledge is shared just between "old cowboys".

For all this, since GDSim, unfortunately, some of my development time has been spent chasing dead ends. But it means coming up with better ideas.

Most advice about going into 3D indie game development solo is: "don't". To you, the intrepid explorer who happens to be reading this devlog, I hope my reflections may be of more use to you than that. 🙏

Get GDSim

Download NowName your own price

Leave a comment

Log in with itch.io to leave a comment.