Search Unity

Instanced GPU Rendering doesn't work reliably.

Discussion in 'General Graphics' started by djarcas, Jul 30, 2016.

  1. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    246
  2. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    246
    When it works, it works great:

    upload_2016-8-2_12-57-26.png

    But it appears to collect up items based on... being near eachother? Based on draw order? Touched by a certain combination of lights? (Deferred)

    I have potentially many thousands of the same object (You can see I've many 'BarTin' in that view that don't use Instancing yet) and I would like to absolutely maximise the amount of instancing and reduce the number of draw calls!
     
  3. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    246
    And because I don't like being ALL doom and gloom, the last day of work has seen my drawcalls drop from 9600 to 2000 in this test scene.

     
    Last edited: Aug 2, 2016
  4. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    505
    I see voxels... Are you using instancing to draw voxels?
     
  5. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    246
    No, those meshes don't move around and are baked on another thread before being handed off to Unity. Most the meshes in the game are now instanced - conveyor belts, ingots, mass storage, storage hoppers, vegetation, etc.
     
  6. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    246
    All of these ingots are the same material and mesh, no scaling applied. They're broken a number of sub-batches, but are rendering between 1 and 200 per instance. I don't think I've seen anything hit the current cap of 500. Still wanting to have many more instances in a batch and reduce the number of drawcalls. Help plz nice unity ppl.

    Instanced Bars.jpg
     
  7. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    246
    So... any one else actually using this headline feature, or is it just me trying to squeeze the most out of it?
     
  8. DenisM

    DenisM

    Joined:
    Dec 6, 2013
    Posts:
    62
  9. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    246
    mowax74 likes this.
  10. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I can't think of a project more suited to instancing. Which developer is currently working on it? probably best to @ ping them for more discussion. I know you are annoyed :/ some developers I spoke to were outright failing with it.

    I do know that anything transparent queue will break in all sorts of ways (z sorting) and maybe at a guess dynamic batching is interfering.
     
  11. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    246
    Uh, me, I'm the developer on this game.
     
  12. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    246
    Seeing things instance a whole 'twice' with no clue why not. I take it that the Unity Devs don't actually read these forums at all? Is there a better way to get support?

    upload_2016-8-23_13-13-34.png
     
    laurentlavigne likes this.
  13. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,325
    @Peter77 shared this in the 5.4 beta forum http://www.console-dev.de/bin/Unity5_Example_Coins.zip
    Seems that GPU instancing in 5.4 is crap so combining meshes and applying animated texture is the way. I'd say for And now is sumemr vacation in Denmark so wait a week - then go thermonuclear on them :D
    (because 2008 tech in 2016 - and it doesn't work - is a bit much)
     
  14. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    246
    Combining meshes really isn't an option for me. I can't begin to imagine doing that every frame for all those moving bars. I understand there are 'things I can do to increase the chances of dynamic rendering batching them together', and I would just really like to know what those things are!
     
  15. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,325
    Oh no the idea isn't to combine the mesh at runtime but to combine a quad textured with the animated gold moving on the belt. The gold won't be full 3d but there are shader tricks for that.
     
  16. ShilohGames

    ShilohGames

    Joined:
    Mar 24, 2014
    Posts:
    3,020
    djarcas: I have been trying to get GPU instancing to work better in my game, but I have been seeing a similar problem. In my game, there are thousands of identical projectiles (with identical meshes and identical materials) flying around in the scene, but Unity cannot instance all of them. It would be extremely helpful if Unity added a debugging feature to help explain why instancing is not working as expected.
     
  17. ShilohGames

    ShilohGames

    Joined:
    Mar 24, 2014
    Posts:
    3,020


    Unity chose to instance the selected mesh only 2 times, even though there were over a thousand identical clones of that mesh in the scene. And there are a bunch of clones that Unity chose not to instance at all. For GPU Instancing to be useful, Unity should instance as many as it can. If it cannot handle a thousand in one instance call, then it should break that up into a few hundred per call.

    What is the secret to getting the GPU Instancing feature working effectively?
     
  18. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    246
    I have to say, I have a horrible feeling I know the answer - are you in deferred? I was trying with an unrelated project, which is forward rendered, and I saw the most incredibly large batches happening. I suspect batches are split down by the selection of lights they're touched by? Just a guess, this is all a bit black box. It's dynamic batching all over again *sour look*
     
  19. zeroyao

    zeroyao

    Unity Technologies

    Joined:
    Mar 28, 2013
    Posts:
    169
    Hey,

    There are many factors that may break batches, and the current approach of instancing complies with the rendering order given by the renderloop. Sorting on depth bucket is one of them. While manually calling DrawMeshInstanced API, or explicit control of rendering order (by specifying Queue tag in the shader) could solve part of the problem, we are actively developing new ways to alter the rendering order so that instancing can be more efficient automatically. It will take some time as there are many measurements to be done on many platforms.
     
  20. ShilohGames

    ShilohGames

    Joined:
    Mar 24, 2014
    Posts:
    3,020
    djarcas: Yes, I am using deferred.
     
    Last edited: Sep 12, 2016
  21. ShilohGames

    ShilohGames

    Joined:
    Mar 24, 2014
    Posts:
    3,020
    zeroyao: Is the current rendering order causing instancing to break into really small groups? I have scenes with a thousand identical clones (simple quad mesh based projectiles), where Unity is instancing in groups of 2 to 4. I thought Unity was supposed to be able to instance hundreds of items together.
     
  22. ShilohGames

    ShilohGames

    Joined:
    Mar 24, 2014
    Posts:
    3,020
    I created a new project today to test the simplest situation. I set up an empty scene, wrote a script to instantiate 1000 identical clones of an object, and then checked the stats and frame debugger to see how well Unity could instance in this ultra simple test. Even in this simple case, Unity was only instancing a couple quads together at a time.

    I did test with both forward and with deferred. Both rendering modes had the same results.

    In this example, my prefab had three quad meshes, two of which were identical. So for 1000 clones of the prefab, there were 2000 clones of one mesh and material in the scene and 1000 clones of another mesh and material in the scene. In this example there are 3000 quads, but only two unique meshes and materials.

    With GPU Instancing, there are 973-1057 SetPass Calls. The number of SetPass Calls varies each time I load the scene, because the random placement of the prefabs in the scene affects the dynamic batching.

     
  23. ShilohGames

    ShilohGames

    Joined:
    Mar 24, 2014
    Posts:
    3,020
    BTW, I tried to submit my tiny instancing test project to Unity Tech Support, and the web browser says "oops. We're sorry, but something went wrong." I tried twice, and received that response both time.

    Update: The submission was successful even though the page said "oops." Both support submissions are listed in the "My requests" queue in the Unity site. (#61809 and #61810)
     
    Last edited: Sep 12, 2016
  24. ShilohGames

    ShilohGames

    Joined:
    Mar 24, 2014
    Posts:
    3,020
    djarcas: Did you submit a test project to Unity regarding the problems you are seeing with GPU Instancing? If so, did anybody from Unity have any ideas for get GPU Instancing to work better? I submitted an instancing test project to Unity over 24 hours ago, but have not received any feedback yet.
     
  25. zeroyao

    zeroyao

    Unity Technologies

    Joined:
    Mar 28, 2013
    Posts:
    169
    Heya @ShilohGames

    It's strange that with your simple settings instancing can't work efficiently. I can find your cases though (61809 and 61810), and the numbers don't seem right (these days it should be 6 digits starting with 8 or 9 even). You can also DM me with a download link to your project.
     
  26. ShilohGames

    ShilohGames

    Joined:
    Mar 24, 2014
    Posts:
    3,020
    zeroyao: I can share it with you using DropBox. I sent you a PM.
     
  27. ShilohGames

    ShilohGames

    Joined:
    Mar 24, 2014
    Posts:
    3,020
    Thanks to some feedback from zeroyao, I have able to get a massive improvement to GPU Instancing in my project. In the Instancing Test scene I posted about previously, I made 1000 clones of a laser projectile prefab in an otherwise empty scene.

    Previously, the prefab contained three quads and two textures. I refactored the prefab using Mesh Baker today to reduce the Laser projectile prefab to one mesh and one texture. Using the same 1000 clone test scene, I reduced the DrawCalls/SetPassCalls from about 1000 to merely 5. Additionally, instancing groups dramatically improved from a previous 2 to now 500.

    Here are new images showing the improvement in the test scene:



    Anyway, I wanted to pass this information on to anybody who is struggling to get GPU Instancing to work. Unity's batching and instancing options seem to only work if a prefab has only one texture. By combining the meshes and textures, I was able to get the prefab's texture count down to one.
     
  28. MalcolmSmith

    MalcolmSmith

    Joined:
    Mar 25, 2017
    Posts:
    1
    I was seeing the same problem on a project I'm working on.

    The hint here from zeroyao was was that the instancing batches based on the rendering order and non-instanced objects will break batches. My instanced objects were mixed in with non-instanced objects which broke the batching.

    Give your instanced shader a custom depth on the render queue and you get all the instanced objects batched up together. I'm now seeing perfect instancing. :)
     
  29. VLukianenko

    VLukianenko

    Joined:
    Mar 27, 2017
    Posts:
    30
    Setting custom depth on the render queue helps indeed!
     
  30. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    DUUUUUDE!!! I was getting mad!!! THANK YOU!!! 2018.2.0F2 and this is still happening!!! omg!! I had sooo many drawcalls on a map full of atlased prefabs with gpu instancing enabled and I was nuts.

    Is unity aware of this?!!
     
  31. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Yeah, but that's just par the course for any rendering pipeline in any engine. It's more of a case of "is the user aware of how to really drive a car"

    Anyone doing 2D in unity no doubt learned this a long time ago. Unity can't force a behaviour where it all goes to one render queue because then it would break anyone's game where the author wants things to be rendered in between.

    So if people want to make sure something is batched, don't render things in between, or draw the batch manually or set the pass for it so it won't get split.
     
  32. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    OK, lets switch the question. How the hell this is not in the docs, in black capital letters? :D
    https://docs.unity3d.com/Manual/GPUInstancing.html
    I find to having to switch to debug to tweak the standard shader is bit annoying, but hey, minor fault given the benefit. thanks again!
     
  33. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I agree that would be helpful for a lot of people. But batching (and instancing) is vulnerable (if automatic) to depth sorting and draw queues.

    This just the safe automatic option, so it will draw batches out of order in transparent queues in order to sort them. This is the same for any transparent queue, really, and should change as you rotate the camera. It's all down to GPU architecture.
     
  34. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    I may be getting a bit lost.
    Look this is my harbour scene. There are many many objects that are duplicated, they're prefabs. Containers, Lightposts, fences, cranes etc...
    upload_2018-9-2_23-14-23.png

    What would be way to make gpu instancing work.

    Like I should put all the opaque GPU instantiatable meshes to an specific renderqueue and transparent ones to another specific renderqueue? Won´t this make the Frame debug display the message saying that could not batch because mesh have different materials (of cours its a different object so it has its own material). Is then GPU instancing limited in teh number of different objects that can GPU instantiate? if I puf different renderqueeues to many materials won´t the rendering totally mess up?
     
  35. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    Ok one aditional probably sounds silly but... do theese GPU instantiatable objects need to actually be instantiated in runtime? if so, here is the issue because I've the mal already modeled in editor.

    If so, I should fin a way for existing objects to be instantiated and the ones present get dissabled or destroyed... May be I should create an script editor that surfs the scnee looking for prefabs and builds up a dictionary with teh prefab name and values of the transform.... for later on instantiate async. Not sure atm if the load scene async will wait for the instantiate async of each prefab to finish or they'll load on teh go one scen estarted.

    Please enlight me ! :D
     
  36. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    I managed it to work
    upload_2018-9-3_0-46-51.png

    Performance wise is in pair with dynamic batching. I guess there are other benefits like GPU instancing supports lightmaping, to me this is a big pro, but the need to instance is a big con. Also GPU instancing is ultrasensitive to teh fact that if a non GPU instanced obj is in teh same render queue it breaks, somewhat silently. Now I've to manage to pass the lightmap coord from the source obj to the instanced one before destorying teh old.
     
  37. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    I moved the prefabs to Resources/GPU
    and used this script on each
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class GPU_Instancer_Test : MonoBehaviour
    4. {
    5.  
    6.     string StuffToInstantiate;
    7.     //public int instanTiateTimes;
    8.  
    9.     // Use this for initialization
    10.     void Start()
    11.     {
    12.         StuffToInstantiate = transform.name;
    13.  
    14.         // GameObject instance = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>(StuffToInstantiate), new Vector3(Random.Range(0,100), Random.Range(0, 100), Random.Range(0, 100)),Quaternion.identity);
    15.         if (Resources.Load<GameObject>("GPU/" + StuffToInstantiate) != null)
    16.         {
    17.             GameObject instance = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("GPU/" + StuffToInstantiate), transform.position, transform.rotation);
    18.      
    19.             Destroy(gameObject);
    20.         }
    21.  
    22.     }
    23. }
    Sure there is more elegant way but a bunch started to instance unlike without the script. I got improvement, still not dramatic, I'll re read this thread.
     
  38. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    Hi, I've updated the script so the lightmaped dynamic objects can be gpu instanced.
    In the harbour scene I've many prefabs like cranes that are lightmaped yet some are static some destructable so, seeing I've to instantiate theese and I wanted to keep lightmaping...

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class GPU_Instancer_Test : MonoBehaviour
    6. {
    7.     Renderer[] sourceRenderers;
    8.  
    9.     string StuffToInstantiate;
    10.     //public int instanTiateTimes;
    11.     private void Awake()
    12.     {
    13.         sourceRenderers=transform.GetComponentsInChildren<Renderer>(true);
    14.     }
    15.  
    16.  
    17.     void Start()
    18.     {
    19.         StuffToInstantiate = transform.name;
    20.  
    21.         // GameObject instance = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>(StuffToInstantiate), new Vector3(Random.Range(0,100), Random.Range(0, 100), Random.Range(0, 100)),Quaternion.identity);
    22.         if (Resources.Load<GameObject>("GPU/" + StuffToInstantiate) != null)
    23.         {
    24.             GameObject instance = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("GPU/" + StuffToInstantiate), transform.position, transform.rotation);
    25.             Renderer[] targetRenderers = instance.GetComponentsInChildren<Renderer>(true);
    26.  
    27.             Debug.Log("targetRenderers.Length" + targetRenderers.Length);
    28.  
    29.             for (int i=0; i<targetRenderers.Length;i++) {
    30.                 //Debug.Log(targetRenderers[i].name +" <> "+ sourceRenderers[i].name);
    31.                 targetRenderers[i].lightmapIndex        = sourceRenderers[i].lightmapIndex;
    32.                 targetRenderers[i].lightmapScaleOffset  = sourceRenderers[i].lightmapScaleOffset;
    33.             }
    34.  
    35.             //renderqueue can not be changed in runtime without doing some major material swaps. you should create a new mat that is a clone of the actual and change renderqueeu to that new mat and assign it.
    36.             /*
    37.               Material[] tempMats = targetRenderer.sharedMaterials;
    38.               foreach (Material m in tempMats) {
    39.                   m.shader.renderQueue = m.shader.renderQueue + 1;
    40.               }
    41.           */
    42.             Destroy(gameObject);
    43.         }
    44.  
    45.     }
    46. }
    I tried to change renderqueue but thath needs to be done in a more fashined way creating a material on the fly and passing properties of original to the newly created one plus I think I did not find the "gpu instance" bool publickly accesible. So far most of my non instancing geometries now are unique geometries that are needing atlassing in order to reduce drawcalls.
    But if anyone whants to suggest a way to change renderquee in runtime I'm all ears.

    I tried to GPU instance vegetation by enabling GPU instance on the "optimized" material, I did duplicate the mats within the prefab and then you can edit them and then I reasigned them with no visible benefits. So I assinged an nature bark shader instead and that seemed to be working so I did so for the rest of vegetation but once there are more than 1 trees looking to be gpu instanced things don´t work, plus you lose billboard lod. Anyone suceeded doing so?
     
    Last edited: Sep 10, 2018
  39. ristophonics

    ristophonics

    Joined:
    May 23, 2014
    Posts:
    32
    With you! I think instancing breaks down with LODs as well as on objects with different lighting information...
    If the object is reflecting (even baked information) it counts as a pass.. and if another instanced object is receiving a different reflection then ..... broken... well kind of... Unity seems batch as many as possible given they shared the same properties. Ports....
     

    Attached Files:

  40. theforgot3n1

    theforgot3n1

    Joined:
    Sep 26, 2018
    Posts:
    205
    LODs should be fine. I have a scene with 5 levels of LOD (6 including cull) and it works fine for me.