14
\$\begingroup\$

When I am making a model for a 3D game what should I take as a measure in my budget Polygons (triangles) or vertices? I have made an experiment with two sets 40000 cubes one with 8 vertices and 12 triangles, another with 24 vertices and 12 triangles. All was done in Unity and both of those were generated procedurally. To my surprise, both sets performed almost the same there was a very small difference between them.

Does it mean I should not worry about vertices count and only look at triangles count?

EDIT: I have made another experiment I have created a plane with 19602 triangles and 10000 vertices and another one with same ammount of tirangles but 39204 vertices. I have generated 4000 of both. Now less vertices won 14 fps to 19 fps. So I guess generally less is better, but only in large differences.

\$\endgroup\$
1
  • 9
    \$\begingroup\$ Write your game and fix issues as they arise. This kind of issue may never come up and you're wasting your time :P \$\endgroup\$
    – Vaillancourt
    Sep 8, 2017 at 12:25

3 Answers 3

17
\$\begingroup\$

Let's imagine a big grid mesh, like one we might use for terrain. We'll render n triangles worth of it, covering say half our 1080p screen, in a single draw call.

If we weld all of our vertices and have no smoothing/texturing seams, then each triangle has 3 vertices and each vertex is shared by 6 triangles, so we have n/2 vertices.

To render this we need to:

  • Run the vertex shader at least n/2 times

    ("at least" because our cache for vertex results is only so big. Sometimes we'll end up evicting a vertex we already transformed, then need it again for a later triangle that shares it and so re-run the vertex shader on it. So we don't get quite as much savings as it looks like on paper)

  • Clip & cull n triangles.

  • Rasterize & interpolate over at least 1920x1080/2 or about 1 million pixels of the frame buffer (since we said our terrain covers about half the screen).

    ("at least" because of the way GPUs work on quads of pixels, some fragments just outside the edges of polygons still get rasterized but then masked, meaning we process fragments twice. For a bumpy mesh we'll also get overdraw anywhere the mesh occludes itself, if we're not lucky enough to draw the frontmost polygon into the depth buffer first)

  • Run the fragment shader for all those >= 1 million fragments.

  • Blend ~ 1 million results into the frame & depth buffers.

Okay, now let's unweld all of our vertices so now we have 3n vertices to render, six times more than before! Our steps are...

  • Run the vertex shader 3n times.

    (No asterisks due to caching since every vertex is used only once, though this means the cache can't save us any time)

  • Clip & cull n triangles.

  • Rasterize & interpolate over at least 1920x1080/2 or about 1 million pixels of the frame buffer.

  • Run the fragment shader for all those >= 1 million fragments.

  • Blend ~ 1 million results into the frame & depth buffers.

...wait, every step except the first one is the same! So most of the work that the GPU does in a typical draw call is not directly related to the number of vertices used. The amount of screen coverage, overdraw, and total triangle count make up much more of the cost.

That doesn't mean vertices are completely free. If you share vertices when you can you get some modest savings from caching, especially if your vertex shaders are complicated or your hardware's vertex pipeline is weak (as was the case on some older consoles). But given that vertex count tracks proportional to triangle count plus or minus a constant factor, it's usually not as interesting a metric of overall mesh cost.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ What about the cost of sending those vertices to memory? \$\endgroup\$ Sep 8, 2017 at 13:30
  • 8
    \$\begingroup\$ Unless you're changing your vertex buffer every frame, you pay that upload cost once. Your textures and frame buffer are likely the bigger hogs of video memory and bandwidth within any given frame. It still means vertices certainly aren't free, and it's better to share them when practical, but unshared vertices will rarely if ever be the reason a game performs poorly. \$\endgroup\$
    – DMGregory
    Sep 8, 2017 at 13:42
  • \$\begingroup\$ Will add to this, as I am doing forests etc in my game. When I started, I was initially using draw calls (I use my own engine, this may not completely align with your question) to draw models with verts only, this in itself was ok, performance was fine. But, when I started using indexing, I did get a performance improvement because some verts were shared and so cached, so some calculations weren't done twice. What the bottom line is, that raw test of verts alone is not the best indicator verts vs tri counts. Your pipeline can be affected by too many of either. As other answers allude to. \$\endgroup\$
    – ErnieDingo
    May 16, 2018 at 21:46
2
\$\begingroup\$

Neither.

Unless you're talking truly massive numbers of tris (millions), what you care about is:

  • Number of rendered pixels
  • Cost of fragment shader
  • Number of draw calls (with the limit strongly depending on the device).

24 vertices times 4000 cubes gives 96'000 vertices.

640x380 pixels gives 243'200 fragments, and most devices support considerably larger resolutions.

You could re-run your experiment with 1'000'000 cubes, batched to avoid the draw call bottleneck(1 single model for 1'000 cubes).

\$\endgroup\$
1
  • 2
    \$\begingroup\$ This very much depends on the scene and how you're rendering. If you have a scene that naturally has relatively little overdraw, vertex processing certainly can dominate your performance. Also, the number of draw calls is not the issue (for some APIs) so much as state changes between draw calls. \$\endgroup\$ Sep 8, 2017 at 20:49
1
\$\begingroup\$

Worth noting that if you're doing a WebGL application, vertex count quickly becomes a bottleneck in terms of file size for users to download. Same number of triangles but often 2-3 times more vertices than shown in DCC software. Better unwrapping can help a lot in this case by having less seams.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .