Intro to 3D Character Performance on the Web
The Golden Age
The year is 2001, and six-year-old me is doing important business: eating sand and running from ghosts in my grandpa’s barn at dawn. Meanwhile, a small German game was released that year, making a significant mark in the history of immersive characters: Gothic. Along with the first Harry Potter games for PC, it was one of my earliest memories of virtual avatars that looked and behaved convincingly for the time. But what does that have to do with performance in 2024 — 23 years later?
To some degree, old techniques from the early 2000s have resurfaced as valuable tools for getting the most out of today’s platforms, especially for barrierless 3D experiences on the web. The web has transformed from merely displaying your local pizzeria’s menu to a medium where you can preview your new glasses projected right onto your nose in real-time.
However, technically speaking, it’s still not the holy grail where you can “just make it work”™. Some considerations and understanding are needed before building the next Fortnite on your uncle’s iPhone 6.
In this blog post, I’ll introduce some tech art insights to help you create great-looking and high-performing 3D characters targeting the web, especially for medium to low-end devices.
In the Beginning, There Was the User
And hopefully, they’re not using an iPhone 6 anymore. But in reality, some slow devices are still out there. It doesn’t need to be an old phone; it could be a cost-effective office laptop that large companies send out in bulk to employees for spreadsheet work.
So, step number one: know your target devices. This will most of the time be a moving target when talking about the web, but it’s best to align on a minimum spec that includes:
- CPU and GPU processing speed
- RAM and VRAM size (sometimes shared)
- Supported browsers and versions
Share these technical specifications within your team and adhere to them. This will help you support design and art development, also when communicating with product teams and clients.
One could write multiple posts just about target hardware and system limits of WebGL and various libraries, but focusing on high-level agreements will already take you a long way.
A Bag Full of Bottlenecks
A modern 3D character consists of multiple components that are directly related to the technical considerations mentioned earlier:
- Geometry that defines the form
- Materials and textures that add the paint
- An armature with joints driven by animation
Keeping files small when transmitting them over the magical net we call the World Wide Web is usually a good idea. From experience, textures can be compressed or resized to be quite small by finding the sweet spot for quality based on the channel and camera distance.
For geometry, optimizing the poly count is highly important, and so is quantizing the different attribute data types for position, normals, and skinning data. Libraries like gltf-transform offer easy ways to apply these optimizations out of the box, proven in production, while staying in the ecosystem of web adherent technologies.
On the artist’s side, further techniques can boost quality when you understand your limitations. Mirroring symmetric textures, for example, can dramatically increase texture resolution without increasing file sizes — if the design allows for it. Using trim sheets to optimize the last piece of UV space can also help achieve your goals.
Margin sizes should be as precise as possible for the target resolution to avoid wasting any pixels. A specific detail for squeezing out the last bit of quality from textures is how artists, or their software, fill the space between UV islands. The usual flood-fill method stretches textures at the borders, leading to unnecessary high-frequency details—especially for normal maps. Simpler approaches, like smaller fill margins, blurs, or default colors around the edges, allow for better texture quality after compression.
Also keep an eye on detail sizes surving compression and how art direction can collaborate with those limits instead of playing into them.
With your perfectly optimized geometry, textures, and materials, you sail into the sunset of the smoothest integration known to man. All metrics are met, the VRAM footprint is small, and transfer times are blazing fast due to smaller file sizes. But wait—there’s trouble in the water ahead.
Animations!
While we’ve discussed optimized attributes, it’s important to realize that joints and their skinning data take up space, as do blend shapes, which can drive facial animations and body proportions. Compression can help, but setting clear targets from the beginning will reduce file sizes and also reduce CPU and GPU load. This is especially important on slower devices, which can be bottlenecked by pose calculations. I suggest aligning on at least the following:
- Maximum joint count
- Maximum animation lengths and frame rate
- Splitting objects to keep morph shapes (e.g., only on the head)
Conclusion
Without diving into spreadsheets and red-string conspiracy boards, you can already imagine that spec lists are crucial for preventing your project’s performance from spiraling downward. In the era of AAAA games, where poly counts seem to be a thing of the past (Nanite, cough), we as engineers are not only responsible for building the technology but also for explaining why we sometimes need to return to these seemingly “old-school” methods.
I hope this overview provides a solid introduction for the technically interested to understand some key strategies for staying sane in the age of metaverse and Web3 games, which under the hood are still driven by our good old friend OpenGL ES3. Until Safari and all devices support WebGPU in 2042, these methods are here to stay, I guess.
Obviously, there are more factors to consider in client land, such as shader complexity, atlasing and draw calls, transparency, device and asset tiering, imposters, different file formats and delivery, wasm workers … the list goes on.
I’d love to hear your thoughts and insights on these topics on social media. Thank you for reading my first blog post!
— Eric
Connect with me: