1
\$\begingroup\$

I want to know how to minimize draw calls when rendering multiple customized characters onscreen, presumably with 3-4 materials apiece. Is there a better way to achieve custom color configurations than instancing/duplicating materials? Am I overthinking the problem?

Our game is a frenetic, goofy arena fighter, made in Unity. We plan to publish on mobile, first. I am tasked with creating an art pipeline which allows for customizable additions and color changes to the player's avatar. I'm trying to look ahead to when this character creator will be a part of the game and consider the performance implications of this kind of system. A character creator could potentially serve us in the generation of random NPCs at launch, and will feature heavily when we move to multiplayer.

My concern is with the number of draw calls on mobile. Currently, we have a bunch of identical characters, all creating instances of the main material on spawn to differentiate by random color. Since draw calls are directly linked to the number of materials onscreen, this process concerns me. Before complicating the issue with variations in mesh and texture on a per-object basis, having 1 material per character already limits us to a certain number of NPCs onscreen.

I delivered a material solution which allows changing one color to differentiate from other characters. Now the director is asking about the feasibility of breaking each character into multiple materials to allow for player customization. With 4 materials per character (1 shared), draw calls would increase geometrically per spawn. I've heard mobile platforms tend to be limited to about 20-120 draw calls between low and high end devices. That would make for 5-35 characters allowed onscreen at once, assuming we could get the environment down to around 5 draw calls.

I would be especially interested in any material masking techniques people are aware of. Having a need for around 4 customizable aspects would seem to point towards using some sort of RGBA texturing and masking solution, but I have no idea how to make Unity do that.

\$\endgroup\$
1
\$\begingroup\$

While it's true that draw calls are expensive and we'll generally want to minimize them, we don't need to go full Highlander "There Can Be Only One" on it. ;)

Having one draw call for each character is not unreasonable - especially since character models often have enough vertex data / skinned animation that they don't dynamically batch together anyway.

But there are some ways you can minimize draw calls within a single customizable character, or minimize the impact of multiple draw calls:

  • You can use Vertex Colours to tint parts of the mesh, rather than splitting each off into its own mesh/submesh/material.

  • You can specify a multi-colour palette for the character in its material, and select a colour from this palette within your shader using either vertex attributes or a paint-by-numbers texture map. That way you can independently change multiple colours on a mesh in a single material.

  • Material Property Blocks let you apply variations to a material in a somewhat lighter-weight fashion than instantiating a new unique material. It still generates additional draw calls, but the state changes are optimized to reduce the impact.

  • Texture Atlases can let you assign unique texture content to several different character parts and render them all with a single material.

  • Mesh.CombineMeshes will let you stitch multiple disparate mesh parts together into a single mesh for rendering.

\$\endgroup\$
  • \$\begingroup\$ Thank you so much, [Dungeon Master] Gregory. I was concerned I was being paranoid about draw calls. I needed to know where the limits were. I will be discussing these options for minimizing draw calls with my team. This will help immensely to inform how we implement our character creation system, or at least how we randomize NPCs. Having never used the process, I have a question about using vertex colors to tint. Can that be done on top of detailed texture maps? Or does all of our texturing come through per vertex, as with vertex lighting? \$\endgroup\$ – reversetrio Mar 23 '17 at 15:19
  • \$\begingroup\$ Similar to vertex lighting (which uses the same data channels), vertex colours are interpolated between vertices. You can multiply that with a texture you've sampled in your fragment shader to still get per-pixel detail layered with this tint - but variation in the tint component will be limited to the density of your mesh. \$\endgroup\$ – DMGregory Mar 23 '17 at 16:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.