Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Unity 2017 Game Optimization
Unity 2017 Game Optimization

Unity 2017 Game Optimization: Optimize all aspects of Unity performance , Second Edition

eBook
€20.98 €29.99
Paperback
€36.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Table of content icon View table of contents Preview book icon Preview Book

Unity 2017 Game Optimization

Scripting Strategies

Since scripting will consume a great deal of our development time, it will be enormously beneficial to learn some best practices. Scripting is a very broad term, so we will try to limit our exposure in this chapter to situations that are very Unity specific, focusing on problems surrounding MonoBehaviours, GameObjects, and related functionality.

We will discuss the nuances and advanced topics of the C# language, .NET library, and Mono Framework in Chapter 8, Masterful Memory Management.

In this chapter, we will explore ways of applying performance enhancements to the following areas:

  • Accessing Components
  • Component callbacks (Update(), Awake(), and so on)
  • Coroutines
  • GameObject and Transform usage
  • Interobject communication
  • Mathematical calculations
  • Deserialization such as Scene and Prefab loading

Whether you have some specific problems in mind that you wish...

Obtain Components using the fastest method

There are several variations of the GetComponent() method, and they each have a different performance cost, so it becomes prudent to call the fastest possible version of this method. The three overloads available are GetComponent(string), GetComponent<T>(), and GetComponent(typeof(T)). It turns out that the fastest version depends on which version of Unity we are running since several optimizations have been made to these methods through the years; however, in all later versions of Unity 5 and the initial release of Unity 2017, it is best to use the GetComponent<T>() variant.

Let's prove this with some simple testing:

int numTests = 1000000;
TestComponent test;
using (new CustomTimer("GetComponent(string)", numTests)) {
for (var i = 0; i < numTests; ++i) {
test = (TestComponent)GetComponent("TestComponent...

Remove empty callback definitions

The primary means of scripting in Unity is to write callback functions in classes derived from MonoBehaviour, which we know Unity will call when necessary. Perhaps the four most commonly used callbacks are Awake(), Start(), Update(), and FixedUpdate().

Awake() is called the moment a MonoBehaviour is first created, whether this occurs during Scene initialization or when a new GameObject containing the MonoBehaviour is instantiated at runtime from a Prefab. Start() will be called shortly after Awake() but before its first Update(). During Scene initialization, every MonoBehaviour Component's Awake() callback will be called before any of their Start() callbacks are.

After this, Update() will be called repeatedly, each time the Rendering Pipeline presents a new image. Update() will continue to be called provided the MonoBehaviour...

Cache Component references

Repeatedly recalculating a value is a common mistake when scripting in Unity, and particularly when it comes to the GetComponent() method. For example, the following script code is trying to check a creature's health value, and if its health goes below 0, it will disable a series of Components to prepare it for a death animation:

void TakeDamage() {

RigidBody rigidbody = GetComponent<RigidBody>();
Collider collider = GetComponent<Collider>();
AIControllerComponent ai = GetComponent<AIControllerComponent>();
Animator anim = GetComponent<Animator>();

if (GetComponent<HealthComponent>().health < 0) {
rigidbody.enabled = false;
collider.enabled = false;
ai.enabled = false;
anim.SetTrigger("death");
}
}

Each time this poorly optimized method executes, it will reacquire five different Component...

Share calculation output


Performance can be saved by having multiple objects share the result of some calculation; of course, this only works if all of them would generate the same result. Such situations are often easy to spot, but can be tricky to refactor, and so exploiting this would be very implementation dependent. 

Some examples might include finding an object in a Scene, reading data from a file, parsing data (such as XML or JSON), finding something in a big list or deep dictionary of information, calculating pathing for a group of Artificial Intelligence (AI) objects, complex mathematics-like trajectories, raycasting, and so on.

Think about each time an expensive operation is undertaken, and consider whether it is being called from multiple locations but always results in the same output. If this is the case, then it would be wise to restructure things so that the result is calculated once and then distributed to every object that needs it in order to minimize the amount of recalculation...

Update, Coroutines, and InvokeRepeating


Another habit that's easy to fall into is to call something repeatedly in an Update() callback way more often than is needed. For example, we may start with a situation like this:

void Update() {
  ProcessAI();
}

In this case, we're calling some custom ProcessAI() subroutine every single frame. This may be a complex task, requiring the AI system to check some grid system to figure out where it's meant to move or determine some fleet maneuvers for a group of spaceships or whatever our game needs for its AI.

If this activity is eating into our frame rate budget too much, and the task can be completed less frequently than every frame with no significant drawbacks, then a good trick to improve performance is to simply reduce the frequency that ProcessAI() gets called:

private float _aiProcessDelay = 0.2f;
private float _timer = 0.0f;

void Update() {
  _timer += Time.deltaTime;
  if (_timer > _aiProcessDelay) {
    ProcessAI();
    _timer -= _aiProcessDelay...

Faster GameObject null reference checks


It turns out that performing a null reference check against a GameObject will result in some unnecessary performance overhead. GameObjects and MonoBehaviours are special objects compared to a typical C# object in that they have two representations in memory: one exists within the memory managed by the same system managing the C# code we write (Managed code), whereas the other exists in a different memory space which is handled separately (Native code). Data can move between these two memory spaces, but each time this happens will result in some additional CPU overhead and possibly an extra memory allocation.

This effect is commonly referred to as crossing the Native-Managed Bridge. If this happens, it is likely to generate an additional memory allocation for an object’s data to get copied across the Bridge, which will require the Garbage Collector to eventually perform some automatic cleanup of memory for us. This subject will be explored in much more...

Avoid retrieving string properties from GameObjects


Ordinarily, retrieving a string property from an object is the same as retrieving any other reference type property in C#; it should be acquired with no additional memory cost. However, retrieving string properties from GameObjects is another subtle way of accidentally crossing over the Native-Managed Bridge.

The two properties of GameObject affected by this behavior are tag and name. Therefore, it is unwise to use either properties during gameplay, and you should only use them in performance-inconsequential areas, such as Editor Scripts. However, the Tag System is commonly used for runtime identification of objects, which can make this a significant problem for some teams.

For example, the following code would cause an additional memory allocation during every iteration of the loop:

for (int i = 0; i < listOfObjects.Count; ++i) {
  if (listOfObjects[i].tag == "Player") {
    // do something with this object
  }
}

It is often a better practice...

Use appropriate data structures


C# offers many different data structures in the System.Collections namespace and we shouldn't become too accustomed with using the same ones over and over again. A common performance problem in software development is making use of an inappropriate data structure for the problem we're trying to solve simply because its convenient. The two most commonly used are perhaps lists (List<T>), and dictionaries (Dictionary<K,V>).

If we want to iterate through a set of objects then a list is preferred, since it is effectively a dynamic array where the objects and/or references reside next to one another in memory, and therefore iteration causes minimal cache misses. Dictionaries are best used if two objects are associated with one-another and we wish to acquire, insert, or remove these associations quickly. For example, we might associate a level number with a particular Scene file, or an enum representing different body parts on a character, with Collider...

Avoid re-parenting Transforms at runtime


In earlier versions of Unity (version 5.3 and older), the references to Transform Components would be laid out in memory in a generally random order. This meant that iteration over multiple Transforms was fairly slow due to the likelihood of cache-misses. The upside was that re-parenting a GameObject to another one wouldn't really cause a significant performance hit since the Transforms operated a lot like a Heap data structure which tend to be relatively fast at insertion and deletion. This behaviour wasn't something we could control, and so we simply lived with it.

However, since Unity 5.4 and beyond, the Transform Component's memory layout has changed significantly. Since then, a Transform Component's parent-child relationships have operated more like dynamic arrays, whereby Unity attempts to store all Transforms that share the same parent sequentially in memory inside a pre-allocated memory buffer and are sorted by their depth in the Hierarchy...

Consider caching Transform changes


The Transform Component stores data only relative to its own parent. This means that accessing and modifying a Transform Component's positionrotation, and/or scale properties can potentially result in a lot of unanticipated matrix multiplication calculations to generate the correct Transform representation for the object through its parent Transforms. The deeper the object is in the Hierarchy window, the more calculations are needed to determine the final result. 

However, this also means that using localPositionlocalRotation, and localScale have a relatively trivial cost associated with them, since these are the values stored directly in the given Transform and can be retrieved without any additional matrix multiplication. Therefore, these local property values should be used whenever possible.

Unfortunately, changing our mathematical calculations from world-space to local-space can over-complicate what were originally simple (and solved) problems, so...

Avoid Find() and SendMessage() at runtime


The SendMessage() method and family of GameObject.Find() methods are notoriously expensive and should be avoided at all costs. The SendMessage() method is about 2,000 times slower than a simple function call, and the cost of the Find() method scales very poorly with Scene complexity since it must iterate through every GameObject in the Scene. It is sometimes forgivable to call Find() during initialization of a Scene, such as during an Awake() or Start() callback. Even in this case, it should only be used to acquire objects that we know for certain already exist in the Scene and for scenes that have only a handful of GameObjects in them. Regardless, using either of these methods for interobject communication at runtime is likely to generate a very noticeable overhead and potentially dropped frames.

Relying on Find() and SendMessage() is typically symptomatic of poor design, inexperience in programming with C# and Unity, or just plain laziness during...

Disable unused scripts and objects


Scenes can get pretty busy sometimes, especially when we're building large, open worlds. The more objects invoking code in an Update() callback, the worse things it will scale and the slower the game becomes. However, much of what is being processed may be completely unnecessary if it is outside of the player's view or simply too far away to matter. This may not be a possibility in large city-building simulation games, where the entire simulation must be processed at all times, but it is often possible in first-person and racing games since the player is wandering around a large expansive area, where non-visible objects can be temporarily disabled without having any noticeable effect on gameplay.

Disabling objects by visibility

Sometimes, we may want Components or GameObjects to be disabled when they're not visible. Unity comes with built-in rendering features to avoid rendering objects that are not visible to the player’s Camera view (through a technique...

Consider using distance-squared over distance


It is safe to say that CPUs are relatively good at multiplying floating-point numbers together, but relatively dreadful at calculating square-roots from them. Every time we ask a Vector3 to calculate a distance with the magnitude property or with the Distance() method, we're asking it to perform a square-root calculation (as per Pythagorean theorem), which can cost a lot of CPU overhead compared to many other types of vector math calculations.

However, the Vector3 class also offers a sqrMagnitude property, which provides the same result as distance, only the value is squared. This means that if we also square the value we wish to compare distance against, then we can perform essentially the same comparison without the cost of an expensive square-root calculation.

For example, consider the following code:

float distance = (transform.position – other.transform.position).Distance();
if (distance < targetDistance) {
  // do stuff
}

This can be replaced...

Minimize Deserialization behavior


Unity's Serialization system is mainly used for Scenes, Prefabs, ScriptableObjects and various Asset types (which tend to derive from ScriptableObject). When one of these object types is saved to disk, it is converted into a text file using the Yet Another Markup Language (YAML) format, which can be deserialized back into the original object type at a later time. All GameObjects and their properties get serialized when a Prefab or Scene is serialized, including private and protected fields, all of their Components as well as its child GameObjects and their Components, and so on.

When our application is built, this serialized data is bundled together in large binary data files internally called Serialized Files in Unity. Reading and deserializing this data from disk at runtime is an incredibly slow process (relatively speaking) and so all deserialization activity comes with a significant performance cost.

This kind of deserialization takes place any time we...

Load scenes additively and asynchronously


Scenes can be loaded either to replace the current Scene or can be loaded additively to add its contents to the current Scene without unloading the preceding one. This can be toggled via the LoadSceneMode argument of the SceneManager.LoadScene() family of functions. 

Another mode of Scene loading is to complete it either synchronously or asynchronously, and there are good reasons to use both. Synchronous loading is the typical means of loading a Scene by calling SceneManager.LoadScene() where the main thread will block until the given Scene completes loading. This normally results in a poor user experience, as the game appears to freeze as the contents are loaded in (whether as a replacement or additively). This is best used if we want to get the player into the action as soon as possible, or we have no time to wait for Scene objects to appear. This would normally be used if we’re loading into the first level of the game or returning to the main menu...

Create a custom Update() layer


Earlier in this chapter, in the 

Update, Coroutines and InvokeRepeating

 section, we discussed the relative pros and cons of using these Unity Engine features as a means of avoiding excessive CPU workload during most of our frames. Regardless of which of these approaches we might adopt, there is an additional risk of having lots of MonoBehaviours written to periodically call some function, which is having too many methods triggering in the same frame simultaneously.

Imagine thousands of MonoBehaviours that initialized together at the start of a Scene, each starting a Coroutine at the same time that will process their AI tasks every 500 milliseconds. It is highly likely that they would all trigger within the same frame, causing a huge spike in its CPU usage for a moment, which settles down temporarily and then spikes again a few moments later when the next round of AI processing is due. Ideally, we would want to spread these invocations out over time.

The following...

Summary


This chapter introduced you to many methods that improve your scripting practices in the Unity Engine, with the aim of improving performance if (and only if) you have already proven them to be the cause of a performance problem. Some of these techniques demand some forethought and profiling investigation before being implemented, since they often come with introducing additional risks or obfuscating our codebase for new developers. Workflow is often just as important as performance and design, so before you make any performance changes to the code, you should consider whether or not you're sacrificing too much on the altar of performance optimization.

We will investigate more advanced scripting improvement techniques later, in Chapter 8, Masterful Memory Management, but let's take a break from staring at code and explore some ways to improve graphics performance using a pair of built-in Unity features known as Dynamic Batching and Static Batching.

 

 

Left arrow icon Right arrow icon

Key benefits

  • Discover features and techniques to optimize Unity Engine's CPU cycles, memory usage, and the GPU throughput of any application
  • Explore multiple techniques to solve performance issues with your VR projects
  • Learn the best practices for project organization to save time through an improved workflow

Description

Unity is an awesome game development engine. Through its massive feature-set and ease-of-use, Unity helps put some of the best processing and rendering technology in the hands of hobbyists and professionals alike. This book shows you how to make your games fly with the recent version of Unity 2017, and demonstrates that high performance does not need to be limited to games with the biggest teams and budgets. Since nothing turns gamers away from a game faster than a poor user-experience, the book starts by explaining how to use the Unity Profiler to detect problems. You will learn how to use stopwatches, timers and logging methods to diagnose the problem. You will then explore techniques to improve performance through better programming practices. Moving on, you will then learn about Unity’s built-in batching processes; when they can be used to improve performance, and their limitations. Next, you will import your art assets using minimal space, CPU and memory at runtime, and discover some underused features and approaches for managing asset data. You will also improve graphics, particle system and shader performance with a series of tips and tricks to make the most of GPU parallel processing. You will then delve into the fundamental layers of the Unity3D engine to discuss some issues that may be difficult to understand without a strong knowledge of its inner-workings. The book also introduces you to the critical performance problems for VR projects and how to tackle them. By the end of the book, you will have learned to improve the development workflow by properly organizing assets and ways to instantiate assets as quickly and waste-free as possible via object pooling.

Who is this book for?

This book is intended for intermediate and advanced Unity developers who have experience with most of Unity's feature-set, and who want to maximize the performance of their game. Familiarity with the C# language will be needed.

What you will learn

  • • Use the Unity Profiler to find bottlenecks anywhere in your application, and discover how to resolve them
  • • Implement best practices for C# scripting to avoid common pitfalls
  • • Develop a solid understanding of the rendering pipeline, and maximize its performance by reducing draw calls and avoiding fill rate bottlenecks
  • • Enhance shaders in a way that is accessible to most developers, optimizing them through subtle yet effective performance tweaks
  • • Keep your scenes as dynamic as possible by making the most of the Physics engine
  • • Organize, filter, and compress your art assets to maximize performance while maintaining high quality
  • • Discover different kinds of performance problems that are critical for VR projects and how to tackle them
  • • Use the Mono Framework and C# to implement low-level enhancements that maximize memory usage and avoid garbage collection
  • • Get to know the best practices for project organization to save time through an improved workflow

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Nov 22, 2017
Length: 376 pages
Edition : 2nd
Language : English
ISBN-13 : 9781788472975
Vendor :
Unity Technologies
Languages :
Tools :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Product Details

Publication date : Nov 22, 2017
Length: 376 pages
Edition : 2nd
Language : English
ISBN-13 : 9781788472975
Vendor :
Unity Technologies
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 115.97
Mastering Unity 2017 Game Development with C#
€41.99
Unity 2017 Mobile Game Development
€36.99
Unity 2017 Game Optimization
€36.99
Total 115.97 Stars icon
Banner background image

Table of Contents

9 Chapters
Pursuing Performance Problems Chevron down icon Chevron up icon
Scripting Strategies Chevron down icon Chevron up icon
The Benefits of Batching Chevron down icon Chevron up icon
Kickstart Your Art Chevron down icon Chevron up icon
Faster Physics Chevron down icon Chevron up icon
Dynamic Graphics Chevron down icon Chevron up icon
Virtual Velocity and Augmented Acceleration Chevron down icon Chevron up icon
Masterful Memory Management Chevron down icon Chevron up icon
Tactical Tips and Tricks Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Full star icon Full star icon 5
(1 Ratings)
5 star 100%
4 star 0%
3 star 0%
2 star 0%
1 star 0%
Gregory Feb 02, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
The best book on performance optimization for Unity I've ever read. Unity development often provides similar ways to approach a function with drastically different performance implications, and this book guides you through dozens of everyday tools you can use to improve performance and memory optimization without sacrificing app complexity.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.