- Home /
Instantiating 20K gameobjects performance issue
Hi!
I'm working on a project in which I have, as a requirement, 20K gameobjects instantiated that are always moving. Each gameobject has a script attached in which I can change its color, size, etc. Obviously, I get a poor performance. I've read that with Graphics.DrawMeshInstancedIndirect I can get a performance boost, but it only instantiate a mesh, not a prefab. Is there any other alternative so I can get a performance boost? The code I'm using right now to instantiate is the following one:
public GameObject gameObjectPrefab;
public int numberOfInstances;
private void Start()
{
for (int i = 0; i < numberOfInstances; i++)
{
Vector3 randomPosition = new Vector3(Random.Range(-5000, 5000), Random.Range(-5000, 5000), Random.Range(-5000, 5000));
Instantiate(gameObjectPrefab, randomPosition , Quaternion.identity, transform);
}
}
I attach one screenshot taken from the profiler
I don't suppose this is what you want to hear but I think the best alternative would be to redesign in a way that doesn't require 20,000 moving gameobjects.
Where does the spike exactly come from that gives you poor performance? Have you taken a look in the profiler, to see exactly what is causing the performance degradation? Perhaps in the physics calculation, collision calculation etc? You should try to show some images of the profiler when spikes happen.
Hi @ShadyProductions. Thanks for your reply. I've attached a screenshot of the profiler so maybe you can help me
If you're bumping into a performance issue and there's no way to get around that large object requirement, then you might want to start looking into ECS / DOTS.
Are your objects all on-screen at the same time?
Hi @TreyH Thanks for your reply. I have attached a screenshot of the profiler to the question. Is ECS/DOTS compatible with Unity 2018.2.18f? Are bothof them still in preview?
Answer by unity_ek98vnTRplGj8Q · Feb 25, 2020 at 04:22 PM
I know you disagreed with @logicandchaos but if you are just changing color, position, and size you should be able to do this from a manager script without the need for a script on each object... in fact I'm having trouble thinking of much functionality that requires you to have a script on each game object, usually its done for convenience / organizational sake. But if you want 20k objects I really recommend trying to come up with a solution that only uses one script instance. AT THE VERY LEAST if your scripts have update functions (which I see that they do), call them from a manager script instead of having unity call them for you. This can result in a pretty significant performance boost by itself. Taking this a step further, this seems like the kind of thing that Unity's DOTS system is perfect for. There is a bit of a learning curve, but it can really have incredible results, even with several hundred thousand entities.
If you post a screenshot of the script breakdown in the profiler (we can only see the top bit of it in the screenshot you posted) as well as the code in your update functions we could probably help you identify issues there as well.
Came to suggest DOTS as well. Here's a good tutorial, with benchmarks that show just how much faster you can make things: https://software.intel.com/en-us/articles/get-started-with-the-unity-entity-component-system-ecs-c-sharp-job-system-and-burst-compiler
Hi @Fragsteel! Thanks for your reply! I've taken a look to the website but I'm finding it tricky. I mean, I've tried the "moving transform" methods in a new project which I'm using for test purposes and it worked (although in my project I just move the parent of the 20k objects), but I'm having issues to change my current methods (change color, size, etc) to DOTS. Any suggestions like other websites or videos?
Hi @unity_ek98vnTRplGj8Q Thanks for your answer. I did the manager script so I can get rid of having and update function inside every script and in fact I have a performance boost of around 5-7 fps. I'll like to try DOTS, but I'm finding it tricky to get methods (change color, scale, etc) that can be called from other scripts. Do you know any good tutorial/website?
You shouldn't necessarily keep pushing at one aspect for performance. If you look at your profiler output the blue scripts bit is relatively small so there will be di$$anonymous$$ishing returns if you only attack that side of things. Rendering for example is taking up most of the CPU time. Without knowing more about your set-up it's hard to say more but, for example, LODing can make a big difference. You're unlikely to need to be drawing 20$$anonymous$$ objects at full res.
Looking at the graph, there is a ton of garbage created constantly. It's not that much compared to rendering, but garbage can be easier to get rid of, so I would start with that.
Answer by logicandchaos · Feb 25, 2020 at 01:10 PM
If you create one script that manages all the objects it will be more efficient than each object having a script on it, especially if the script has an update on it.
Hi @logicandchaos. Thanks for your reply. Currently, due to project requirements, I need to have a script attached to each gameobject so I can choose which one changes its color, size, etc.
yes you can have a script on each object, but no update call, that is the heaviest part. You can set up a singleton GameObject$$anonymous$$anager and it has an Update() method, and a list of all the objects you want to check and do things with. I have a script for this that I'm trying to get approved on the asset store.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// This is my Update $$anonymous$$anager script it's a singleton designed to handle all updates from a single update call.
/// Should increase efficiency and allow functions called of non monobehaviour objects on update.
/// by logicandchaos
/// </summary>
public class Update$$anonymous$$anager : $$anonymous$$onoBehaviour {
//make singleton
public static Update$$anonymous$$anager Instance { get; private set; }
private void Awake()
{
if (Instance == null)
Instance = this;
else
Destroy(gameObject);//don't allow multiple instances
}
//list of actions to execute in Update();
private List<System.Action> updates = new List<System.Action>();
public void AddActionToUpdate(System.Action p_action)
{
if (!updates.Contains(p_action))
{
updates.Add(p_action);
}
}
public void RemoveActionFromUpdate(System.Action p_action)
{
if (updates.Contains(p_action))
{
updates.Remove(p_action);
}
}
void Update()
{
//for each action in list
foreach (System.Action action in updates)
{
//run action
action();
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Example00 : $$anonymous$$onoBehaviour
{
private void OnEnable()
{
if (Update$$anonymous$$anager.Instance != null)
Update$$anonymous$$anager.Instance.AddActionToUpdate(ExampleUpdate);
}
private void OnDisable()
{
if (Update$$anonymous$$anager.Instance != null)
Update$$anonymous$$anager.Instance.RemoveActionFromUpdate(ExampleUpdate);
}
public void ExampleUpdate()
{
//code to execute in Update$$anonymous$$anager.Update()
}
}
Answer by Stoycho3xs · Mar 04, 2020 at 11:00 AM
@ratchetunity I have struggled with this problem in the past. What I do was to save the prefabs in "Inactive" so when i instantiate them Unity does it really fast. When all prefab are ready I make them "Active" and that's all. Hope it helps.