Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Changing Objects To/From Static at Runtime

Discussion in 'Scripting' started by John-B, Oct 28, 2018.

  1. John-B

    John-B

    Joined:
    Nov 14, 2009
    Posts:
    1,259
    I have LOTS of objects in this scene that need to be static most of the time, except during a set-up phase where scenery objects can be instantiated and deleted, moved and rotated. When set up is done and the action starts, all those scenery objects are fixed and don't change again until action is paused and changes are again made in the scene. Having all those non-static objects in the scene starts to affect performance, especially when there are more than a few.

    I see the StaticBatchingUtility has a Combine function that can be used at runtime to prepare non-static objects to take advantage of static batching. That's just what I need. But I don't see a way to undo this so the objects can once again be modified. I need the objects to be non-static when paused, but static when playing. Is there any way to get the performance benefits of static batching, but still be able to modify the objects?
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,514
    Marking things static is really an editor time thing.

    And if you click the little drop arrow you'll see all the optimization tricks unity may try to do with it (and opt out of if you want) when the GO is marked static.

    One of which is the static batching like you mentioned. Which is where the mesh's of static objects are joined together to make one giant mesh used by all (reducing the number of draw calls).

    Others are occlussion, lightmaps, navigation, and others.

    The reason it is editor only (technically, though you do see the StaticBatchingUtility), is that a lot of these are not exactly easily reversible.

    Mainly because reversing it requires regenerating said optimizations all over again. Rebuilding whatever optimization used. Such as in the case of the static mesh, it requires throwing out the batched mesh and then recalculating a whole new mesh based on the meshes minus the one you want to remove from it.

    ...

    This OF COURSE implies you need to store references to ALL those meshes still so you can rebuild it. Basically forcing you to increase memory usage since you'll have each unique mesh AND the batched mesh, even though the unique ones don't have draw calls performed on them.

    This technically can be done.

    When you build your batched mesh you essentially store a table of all the meshes that went into and where they got used. And when you need to remove an object from the batch you'd give it back its original mesh, and then you'd recalc the mesh for everything else.

    Though I'll say... this is going to be SLOW. And probably shouldn't be done all to frequently. And I could not tell you what side effects might occur (especially with say lighting or something).

    TLDR;

    Basically... if an object needs to EVER move, may it only be infrequent. Don't mark it static. Cause it's not static, it's dynamic.
     
    eyupunity, Bunny83 and Joe-Censored like this.
  3. John-B

    John-B

    Joined:
    Nov 14, 2009
    Posts:
    1,259
    Thanks for the very informative response.

    Maybe a better approach is to instantiate all objects as static, then instantiate a temporary, non-static copy of just one individual object when it needs to be modified. Then when the editing is done, instantiate a new static object and delete the temporary copy. Or something like that. I get that it takes some time to recalculate the batch mesh and instantiate/delete game objects, but it would only happen occasionally. The performance drop with too many non-static objects in the scene is continuous. I've learned that it doesn't take too many non-static objects in a scene before FPS starts to drop noticeably.
     
    Last edited: Oct 28, 2018
  4. John-B

    John-B

    Joined:
    Nov 14, 2009
    Posts:
    1,259
    Playing around with this, I've discovered that making one or just a few objects in the scene static has no effect on SetPass Calls or batches or FPS (as shown in the Editor Statistics panel). However, making many objects static, around 20 or more, does increase FPS and batches, no effect on SetPass Calls. It might depend on which objects, how complex they are, though all use only a single material, and many share the same material.
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,514
    Lets say you have 100 objects in scene.

    That is 100 draw calls.

    If you set 1 static... that's still 100 draw calls.

    If you set 2 static... that now only 99 draw calls (98 dynamic, and 1 batched).

    If you set 3 static... 98.

    ... and so on.

    Furthermore the 'batched' call has the vertex count of all the messhes batched together. So the complexity of the single draw call goes up.

    Think of it like this... when batching, you can think of it like a job having 3 main parts.

    1) setup/prep to begin the task
    2) the task
    3) cleanup

    Like say you had to wash dishes.

    1) fill the sink with water and soap
    2) wash dishes
    3) drain sink and wipe up area

    1 & 3 don't take that long relative to the actual dish washing. But lets say that every time you did the job you had to do all 3 steps.

    Well that's what individual draw calls are. You have to do all 3 steps with each call. Setup, perform, cleanup.

    So if you can batch multiple objects together, step 2 balloons linearly. If you can wash 5 dishes per minute, and you pile on 100 dishes, no matter what order you do them in you're going to take 20 minutes to wash them.

    BUT if it takes you 1 minute to setup and 1 minute tear down. Then doing that for every 5 dishes means 20 minutes of setup (for each batch of 5) and 20 minutes of teardown (for each batch of 5). That's 60 minutes.

    But if we batched them all together. Then it's 1 minute setup, 1 minute teardown, and 20 minutes of work. 22 minutes.

    For small amounts of batching you don't really see this. If we only batched 3 of those dish jobs. We'd still have 20 minutes of washing, but 17 minutes of setup and 17 minutes of teardown. 54 minutes.

    Thing to consider here is the setup/teardown of draw calls is significantly shorter than the actual draw (going through all the verts). Nevermind that the processing time is in the nanoseconds imperceptible to humans. So the gains are even smaller at first until you have a LOT of them.

    So yeah... you only see the payoffs with the more you batch.

    ...

    The idea being if you have a world, like say a town. A lot of things don't move. Houses/buildings, the ground, various props from street signs to lamp posts, etc. This could easily be half of your scene, if not more. So you batch them all together.

    That is unless you are creating a 'dynamic or destructible' world. In which... yeah, batching doesn't get you much because you don't have a lot of static things. This is why not but a few years ago the idea of fully destructable worlds was a 'novel' idea! From a technological perspective it has a lot of processing overhead. Way back when, that was the big selling point of 'Red Faction' for instance.
     
    Last edited: Oct 29, 2018
    eyupunity and ThermalFusion like this.
  6. John-B

    John-B

    Joined:
    Nov 14, 2009
    Posts:
    1,259
    After a bit more experimenting, I think I've discovered something that prevents my idea of static and non-static copies from working, or of even just static objects working. When I was testing for batching effects, I was starting with a particular set of objects already in the scene (my test set). Whether or not those objects are static makes a difference, as I mentioned. BUT, if the objects are instantiated at run time, it doesn't appear to make any difference at all if they're static. Instantiating static and non-static objects at runtime adds the same number of SetPass Calls and batches. Does that mean that the batch is not being recalculated when new static objects are added? If that's the case, then it doesn't matter if the objects in the scene are static or not if they're added at runtime.

    I don't think I'm doing a "dynamic" world. It's a level editor, nothing new. When not in the editor, everything is fixed and immovable. In the editor you can add, delete, and position scenery and terrain objects. It's entirely possible the level could contain hundreds of objects, so I've been trying different things to get and keep the frame rate up.
     
    Last edited: Jan 4, 2019
  7. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    At least when it comes to static batching, only ever objects that are already in a scene at build time and marked static will be batched. If you instantiate something marked as batching static in runtime the clone may or may not be marked as such, but it will not build new batches or join existing ones.
    You'll need to batch your things yourself after you're done manipulating them, either by StaticBatchingUtility mentioned above, or just combining your mesh data yourself.
     
  8. John-B

    John-B

    Joined:
    Nov 14, 2009
    Posts:
    1,259
    I started thinking about this issue again, though I've not had the chance to try anything. The StaticBatchingUtility prepares an object for static batching, so it would be the same as if that object was in the scene at build time and marked static. Does that mean that batching for the entire scene is re-calculated, as it is at build time? If so, if there were other newly-instantiated static objects in the scene, would they be included in the new batches as a result of just that one call to StaticBatchingUtility? Sounds too good to be true.
     
    Last edited: Jan 4, 2019
  9. steveh2112

    steveh2112

    Joined:
    Aug 30, 2015
    Posts:
    314
    hi john-b, did you ever make any progress with this?

    i'm making a game builder game, scenes will be loaded from external files at runtime and are editable and savable by the user.

    i'd like for the user to be able to generate a performance (not editable) verson when they are ready for production, to do that i guess need to be able to run the batching system at runtime like unity does on build.

    it sounds like you are doing a similar thing so i'm interested to hear more about your progress. thanks
     
  10. John-B

    John-B

    Joined:
    Nov 14, 2009
    Posts:
    1,259
    No success. I played around a bit with baking light maps, but never got that to work right. Seems to be possible, but I couldn't figure it out. Sounds like you have a similar situation, so please post anything you learn.
     
  11. steveh2112

    steveh2112

    Joined:
    Aug 30, 2015
    Posts:
    314
    will do, but my thought right now is a bit of a cop out. i'd have players send their scene to me and i build a standalone version in unity editor and publish it for them on my site. i don't plan to release my entire unity project of course because it has all my IP in there and some 3rd party assets.
     
  12. John-B

    John-B

    Joined:
    Nov 14, 2009
    Posts:
    1,259
    I'm still working on that project, but I'm (reasonably) satisfied that performance will be acceptable. I did every other optimization I know of, including using texture atlases, GUI atlases, combining meshes, LOD (wrote my own), dynamic batching, no shadows or antialiasing, and a few others I can't think of right now. It might not've been enough a few years ago, but I've been pleasantly surprised by performance on current iOS hardware.
     
  13. Eugenio

    Eugenio

    Joined:
    Mar 21, 2013
    Posts:
    197
    Hello !! :)

    I don't know if it could be of any use, but you can manually combine meshes at runtime.
    Please, take a look at https://forum.unity.com/threads/tiled-unity-quad-meshcombiner-to-save-draw-calls.962049/ as an example of how you can achieve this.

    Obviously I use that in a build level loading phase of the game. It takes time and you really need to be able to clean everything up properly, but in terms of drawcalls it really pays off.
    I currently have something like 1300 tiles to build a terrain and it would be impossible to get good performances from this approach without combining the mesh. Combining, I go from over 1000 drawcalls to 3... pretty convenient, isn't it? ;)
     
  14. Giannisimic

    Giannisimic

    Joined:
    Aug 18, 2017
    Posts:
    2
    Put this in a script on the parent gameobject. Should work

    GameObject newThing = this.gameObject;
    newThing.isStatic = true;
    newThing.transform.parent = transform;
    StaticBatchingUtility.Combine(gameObject);
     
  15. ryanmillerca

    ryanmillerca

    Joined:
    Aug 12, 2012
    Posts:
    143
    Thank you, this is the best answer!
     
  16. OzgurGurbuz

    OzgurGurbuz

    Joined:
    Jun 18, 2019
    Posts:
    37
    I didn't think that I can reach an answer this quick. Thanks a lot, I appreciate it!