{"id":1018,"date":"2026-09-08T22:37:41","date_gmt":"2026-09-08T22:37:41","guid":{"rendered":"https:\/\/x.sheep-mine.ts.net\/index.php\/rendering-at-scale-efficient-strategies-for-massive-object-counts\/"},"modified":"2026-09-08T22:37:41","modified_gmt":"2026-09-08T22:37:41","slug":"rendering-at-scale-efficient-strategies-for-massive-object-counts","status":"publish","type":"post","link":"https:\/\/x.sheep-mine.ts.net\/index.php\/rendering-at-scale-efficient-strategies-for-massive-object-counts\/","title":{"rendered":"Rendering at scale: Efficient strategies for massive object counts"},"content":{"rendered":"<p><br \/>\n<\/p>\n<div>\n<h2>Investigate what\u2019s causing rendering issues and then optimize<\/h2>\n<p>Rendering is a collaboration between your CPU and GPU.<\/p>\n<p>\u201cThe CPU is the coach, and the GPU is the athlete. The CPU calls the play and the GPU carries them out,\u201d says Liam Dudas, optimization engineer on <em>Backyard Baseball.<\/em><\/p>\n<p>Sometimes the work the GPU has to do is more time-consuming than other tasks. Complex meshes, shaders, and lighting can cause slowdowns, and the best way to improve performance is to reduce their complexity by asking the artist to optimize these assets.<\/p>\n<p>Other times, it\u2019s not <em>what <\/em>the CPU asks the GPU to do, but <em>how it asks it<\/em>.<\/p>\n<p>Is the CPU executing its instructions optimally? Is it taking a long time to figure out what to draw, making the CPU twirl its thumbs instead of getting the rest of the game to run? Is the CPU providing information redundantly? A good coach can inspire an unexpected comeback from his team, but when it comes to optimization, we can\u2019t just get these systems to \u201ctry harder.\u201d It\u2019s all about understanding the information they\u2019re dealing with and how they communicate it.<\/p>\n<p>This comes down to optimizing the draw calls the CPU passes to the GPU. The more work we can pack into one call, the better, especially when there are tens of thousands of objects to render.<\/p>\n<p>There are plenty of tricks to achieve this \u2013 but a word of caution before you do.<\/p>\n<p>Don\u2019t just optimize willy-nilly, for nothing more than the thrill of clever code. Always benchmark first. Find where your project is suffering the most. The first question you should always ask: Is your bottleneck in the CPU or the GPU?<\/p>\n<p>Some of the solutions in this post increase CPU speed, others GPU speed. You don\u2019t want to get carried away optimizing one processor when the other one is actually the source of your frame spikes. Once you decide whether your game is CPU- or GPU-bound, investigate which procedure is taking the longest, then optimize that. <a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/unity.com\/how-to\/best-practices-for-profiling-game-performance\">Unity\u2019s profiling best practices guide<\/a>\u00a0is a great place to start, which includes a handy flowchart that provides guidance on the often mysterious process of profiling.<\/p>\n<p>\u201cI have to do a lot of profiling,\u201d says Liam. \u201cI can tell when the CPU is doing a lot, and the GPU isn&#8217;t, and vice versa. Really, our worst bottleneck has been both of them at different times.\u201d<\/p>\n<p>We included a slew of our favorite resources at the end of this post to help you on your own profiling journey.<\/p>\n<p>And with that disclaimer out of the way, let\u2019s explore optimizations.<\/p>\n<h2>Simplifying and culling<\/h2>\n<p>When rendering, we need to determine which meshes to render and where.<\/p>\n<p>The more meshes we have and the more draw calls we need, the more the CPU has to keep figuring out what to do while the GPU waits for its next job.<\/p>\n<p>We could speed up the process by rendering fewer meshes. For example, you could swap complex meshes with imposters, billboards, or low-poly versions; or you could break up a sprawling world into smaller levels with less to render at once. These are tried-and-true solutions you should use when you can, but they limit the level of detail in your environments.<\/p>\n<p>One optimization that avoids this, and is simple to implement, is occlusion culling, where the camera checks what\u2019s within its field of view and avoids rendering what the player can\u2019t see. This saves time at the cost of increased memory usage, but it\u2019s often worth it in environments with many stationary meshes, like detailed rooms in an office building. This optimization is an industry standard, but it\u2019s often not enough on its own.<\/p>\n<h2>Static batching<\/h2>\n<p>Another way we can limit the number of meshes we render without sacrificing variety is by combining them into a single mesh.<\/p>\n<p>You can do this yourself manually. Or, so long as the meshes share the same material, Unity can do this for you in a process called batching. Set a game object to static, and Unity will automatically batch all of the meshes with the same material together to cut down the draw calls. Use this option on anything that stays static, like trees and walls.<\/p>\n<p>This drastically reduces RAM usage and CPU overhead, allowing the GPU to render more content at once. But keep in mind, more GPU memory will be used to store the combined meshes.<\/p>\n<p>Static batching is often our #1 key optimization process, particularly for <em>Backyard Baseball<\/em>. Using URP\u2019s batching system is simple, so the most challenging part is figuring out how to use as few materials as possible across as many models as possible. That balancing act is why we have some of the most creative cats on our optimization and art teams.<\/p>\n<h2>GPU instancing<\/h2>\n<p>This is a good time to start distinguishing between a thing\u2026 versus an instance of that thing.<\/p>\n<p>Let\u2019s say you have a mesh. A mesh is an asset. And its material is an asset. They are single files that exist in your file structure. For every object with a 3D appearance in your game, a mesh describes its shape, and then a material describes how its surface looks.<\/p>\n<p>But because Unity simplifies its details, some developers don\u2019t realize that when their game is running, they actually have multiple copies of these things instantiated into their game world. When your player explores a forest, they\u2019re moving through many copies of that one tree stored as an asset in their game\u2019s files.<\/p>\n<p>This is why we used GPU instancing for the foliage in <em>Backyard Baseball<\/em>. Instead of rendering each copy of the tree with unique calls to the GPU, the CPU instead asks the GPU to render all identical models at once. If you\u2019re not careful, this could result in every tree in the forest looking identical. But, with some effective parameters in the material\u2019s shader, for example, a value to customize the color of the leaves, you can pass to the GPU one model and material, along with the unique colors for each tree, rather than asking for each tree individually.<\/p>\n<\/div>\n<p><br \/>\n<br \/><a href=\"https:\/\/unity.com\/blog\/rendering-at-scale-efficient-strategies-for-massive-object-counts\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Investigate what\u2019s causing rendering issues and then optimize Rendering is a collaboration between your CPU&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1018","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/posts\/1018","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/comments?post=1018"}],"version-history":[{"count":0,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/posts\/1018\/revisions"}],"wp:attachment":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/media?parent=1018"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/categories?post=1018"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/tags?post=1018"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}