Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by AzzyDude24601 · Nov 23, 2017 at 03:04 PM · transform.parent

Need help improving the performance of Transform.SetParent for 5000+ objects

I've been experiencing some severe performance issues using Transform.SetParent for many objects. From reading this blog post I've determined that this is not an unusual issue to encounter in Unity.

However the blog post hasn't really helped me figure out how to re-write my code in a more efficient manner. Basically what I currently have looks something like this...

  GameObject myContainer = GameObject.Find("My Container");
  foreach (var item in items)                                       // can be 5000+ items
 {
     GameObject myPrefab = Instantiate(myPrefab) as GameObject;
     myPrefab.transform.SetParent(myContainer.transform, false); 
     myPrefab.transform.localPosition = new Vector3(x, y, z);       // x,y,z change in each iteration
 }


...so what would be the correct way to write this in C# for the best performance? (Right now this can take over 10 seconds for 3-5k items.

Comment
Add comment · Show 16
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Nov 23, 2017 at 03:31 PM 0
Share

Are you sure that the delay comes from SetParent? Instantiate is a rather slow process and depending on how complex the object is you instantiate it can take quite some time. For example if the prefab has colliders and / or a rigidbody component there's a lot additional processing.

Are you sure you need 5000+ instances at the same time? Your code seems to be pseudocode. What's item and how is it related to the prefabs you instantiate? What actual purpose do those instances have? What do they represent? Are they UI objects or something else?

avatar image AzzyDude24601 Bunny83 · Nov 23, 2017 at 03:41 PM 0
Share

$$anonymous$$y instantiated objects are primitive cubes with a box collider on them. If I comment out Transform.SetParent(), the code executes in half the time. Before I come up with ways around using 5000+ instances, I'd rather know if there are any simple (relatively) ways to improve performance.

avatar image Dray AzzyDude24601 · Nov 24, 2017 at 12:27 PM 1
Share

$$anonymous$$aybe it helps a bit to pass the parent transform to the Instantiate function?

  GameObject myPrefab = Instantiate(myPrefab, myContainer.transform) as GameObject;

I got to agree with Bunny83 though, > 5000 instances of anything are quite a lot, you need to figure some way to organize them. In any case you're going to have some precalculation time, you won't get around this that easy.

Here's some thaughts:

  • A good way to manage a huge amount of objects in 3d space is using Octrees but if this can help you depends on what you are trying to achieve.

  • If not all blocks are required to spawn right away, implement some kind of "lazy" loading where you only load what's close to the player.

  • If you want to remove and create new blocks, consider reusing the old ones ins$$anonymous$$d of reinstantiating, this will save you a lot of performance.

$$anonymous$$aybe you can provide a little more information, what all these cubes meant to do? Do they move all the time? Are you creating these only when your game starts or more often?

Show more comments
Show more comments
avatar image JedBeryll · Nov 24, 2017 at 12:16 PM 0
Share

First i would use something other than GameObject.FInd, maybe find with tag but it would be even better with a reference.

Since u use C# you could use the Instantiate<GameObject>(myPrefab); overload (maybe it doesn't matter but i guess it's there for a reason)

Do the instantiated objects have rigidbodies? As far as i know instantiating static colliders makes the physics engine rebuild it's data, maybe it does this after every iteration? Working from here, an object pool may speed things up.

avatar image AzzyDude24601 JedBeryll · Nov 24, 2017 at 12:48 PM 0
Share

I only use GameObject.Find once at the start to find the container. It's not in the loop.

avatar image Bunny83 JedBeryll · Nov 24, 2017 at 12:50 PM 0
Share

Actually the single GameObject.Find call will only take milliseconds (probably even micro seconds). So that's not really relevant.


The generic version of Instantiate is usually automatically choosen. You don't need to specify the generic type manually. Since the source parameter of the generic instantiate is of type "T" the compiler automatically uses the type of the parameter.

 Transform prefab;
 
 var inst = Instantiate(prefab);

"inst" should have the type Transform in this case. So this should also compile without error:

 Transform inst = Instantiate(prefab);
avatar image JedBeryll JedBeryll · Nov 24, 2017 at 12:56 PM 0
Share

Ok so what about the rigidbody thing?

avatar image AzzyDude24601 JedBeryll · Nov 24, 2017 at 01:03 PM 0
Share

There is one rigidbody on the parent container, then all the children have one collider.

Show more comments
Show more comments

2 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by JedBeryll · Nov 24, 2017 at 01:28 PM

Instantiating split into several frames: Note that i haven't checked it so it may have issues. Let me know if it does and you can't figure out what's wrong.

usage: StartCoroutine(InstantiateInFrames(original, parent, 5000, 10));

 public IEnumerator InstantiateInFrames(GameObject original, Transform parent, int instanceAmount, int framesUsed) {
         int instancesPerFrame = Mathf.CeilToInt(instanceAmount / framesUsed);
 
         int current = 0;
 
         for (int i = 0; i < instanceAmount; i++) {
             GameObject instance = Instantiate(original, parent);
             //whatever else you need to do
 
             current++;
             if (current >= instancesPerFrame) {
                 current = 0;
                 yield return null;
             }
         }
     }
Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image AzzyDude24601 · Nov 24, 2017 at 01:32 PM 0
Share

No, unfortunately this just kept crashing Unity. I tried a few different approaches, but couldn't get it working.

avatar image Multirezonator AzzyDude24601 · Nov 28, 2017 at 02:01 PM 0
Share

@AzzyDude24601 Too many objects, Unity normally works with 200-300 objects, 5k is too much, you need to seriously think about the optimization.

avatar image AzzyDude24601 Multirezonator · Nov 28, 2017 at 02:22 PM 0
Share

In this forum post the Unity representative, Joachim_Ante, talks about large hierarchies in the >5000 range so it doesn't seem to be completely unheard of.

avatar image Buckslice AzzyDude24601 · Nov 30, 2017 at 12:13 AM 0
Share

This code works perfectly fine for me... what errors are you getting?

I would check out the Unity Profiler if you haven't, it may help narrow down the cause of the slowdowns.

avatar image XenoRo · Dec 03, 2017 at 04:48 AM 0
Share

Instantiating split into several frames

That does not help solve the core of the issue; only masks it behind a buffer of frames. In fact, due to overhead, it slightly increases the problem.


@$$anonymous$$ultirezonator - 5k is not too much. There is no too much. It depends entirely on the combination of per-object optimization and strategy regarding the total of objects. You could have 1,000,000 objects on screen at one time if you wanted; and you could set the transform parent for each of them in a few frames; maybe even a single frame, depending on how you do it.

avatar image
0

Answer by XenoRo · Dec 03, 2017 at 05:39 AM

Your problem is not with SetParent. It's the code in general. With all due respect; it's horrendously slow, to the point where it would be fair to call it "anti-optimized".


GameObject myContainer = GameObject.Find("My Container");

I don't know where this is written, but it's probably in the wrong place. It should be done in Awake(), like all reference-setups/dependency-injections (all Find calls or stuff doing the same as Find calls).

Find has the potential of having to traverse every object in your scene before it finds what you're looking for. It should only be done once, whenever possible. To keep a reference to the object you would be finding indefinitely (for as long as you need it), you cache it; meaning you store it in a field of the class. (there are other ways to do it, but this is the main one;specially for a beginner)


GameObject myPrefab = Instantiate(myPrefab) as GameObject;

If you are dealing with large amount os objects (as low as 10 or as high as 100, depending on the "weight" of the object's initialization [speaking in simplified terms: how much stuff the objects' type has/defines]), you want pooling. Instantiation is slow; reusing objects is fast; so unless you're creating 5000+ "useless" objects, you want to do pooling so that you don't have to instantiate any of those "a second time".

Also, I'm pretty sure you don't need the as; because myContainer is already a GameObject, and/or Find can only find GameObjects anyways.


myPrefab.transform.SetParent(myContainer.transform, false);

Since you're going to set a new position to the objects anyway, you can and should set the parent field**, instead of calling the SetParent method. This avoids the overhead related to handling the worldPositionStays parameter (the false you're calling the method with), and just changes the Transform's parent reference directly.


myPrefab.transform.localPosition = new Vector3(x, y, z);

I don't know what iteration you're talking about when you say that "x, y and z change every iteration", but it ain't in the foreach-loop. But even if that's the case, the new Vector3 part is bad. Vector3 is a struct, therefore a value-type, therefore a pass-by-value, therefore "immutable"; but it's "immutable" across assignments and as a method parameter; not in a local scope. You could, and should, totally cache that vector outside of the loop, and simply use vector.Set(x, y, z) for each iteration (if it's really even necessary in the first place), instead of creating a new one for every item/iteration.


If after these optimizations you still get a noticeable hit in the game when doing this operation, then you can start thinking about splitting the job across multiple frames, and/or across multiple threads...

...nvm the second one, you're too beginner for multi-threading yet, trust me; give yourself a few projects and a couple of years of experience with "normal" unity before you even start messing with multi-threading in unity; it's full of caveats and gotchas, and you will regret it if you try to deal with it now... Multi-threading is powerful, but you need to learn to walk before you learn to run; otherwise you will stumble, fall, and probably break your neck; you have been warned.


Even after that, other improvements are likely doable (such as avoiding having objects with "inappropriate children", as was the case in the blog post you referenced), but would need more specific details about how your project is currently setup/organized, and/or your source-code.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image AzzyDude24601 · Dec 03, 2017 at 06:43 PM 0
Share

Okay, well first off, thank you for all the information and taking the time to answer. I should point out the code is pseudo-typed, so my GameObject.Find is in my awake. I only wrote it to illustrate my usage of SetParent. As for what the code is actually doing...

In essence I am creating an image browser for virtual reality. The parent object is actually an empty game object serving as an interactable wall that the user can swipe left and right with their motion controller to scroll through all the images, which are my 1-10k instantiated objects.

Inside the loop, I call another function not written here which returns x, y and z integer based on the current count of the foreach loop. This is what controls the pattern the images appear in the wall (e.g. interlocking rows of 3 or 2, etc, etc - basically things I can't do with the standard grid layout component). I think you are correct in that I can re-write this code to have less overhead in setting the position and parent of the objects.

To conclude, your bold text introducing the concept of multi-threading, only to immediately retract the idea due to your assumption of my skill level, to me, seems to serve no purpose. Not that it matters, but I've actually been successfully mult-threading in Unity for the past 2 years, despite it not being thread safe. If you genuinely thought I was too inexperienced for multi-threading, why even broach the subject?

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

78 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Setparent function dont work properly 0 Answers

Instantantiate relative to parents position 1 Answer

Problems with transform.parent in unity 4.6 2 Answers

How do I go up from child to parent? 1 Answer

Lag on set transform.parent 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges