Search Unity

[RELEASED] GPU Instancer

Discussion in 'Assets and Asset Store' started by LouskRad, May 3, 2018.

  1. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,

    One thing to watch out when using multiple terrains would be to use a reasonable detail distance. GPUI allows you to increase the draw distance a lot more than the Unity terrain, but if you have extreme max view distances, it would mean that GPUI will draw the details on other terrains as well.

    Also, when there are multiple terrains, the Tree and Detail managers are duplicated for each terrain. This results in more draw calls and so it would be better not to use very small chunks with GPUI.

    As for the spikes you mentioned, we have investigated this issue, and it looks like this issue is not related to GPUI. Apparently, the issue is caused when you don't have generated light map data in your scene whether GPUI is enabled or not.
     
    jeromeWork likes this.
  2. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,

    When you have an active manager in your scene, it will initialize OnEnable() when you enter play mode. When you use the InitializeGPUInstancer API method, it will initialize a second time - but GPUI also uses various threading code during its initialization which could cause unexpected issued.

    The safest thing to do would be to have the manager disabled in your scene and enable it after you resize your terrain at runtime. That way, you do not need to run the InitializeGPUInstancer API method since GPUI will do it when enabling.
     
    MTandi likes this.
  3. strongbox3d

    strongbox3d

    Joined:
    May 8, 2012
    Posts:
    860
    Hello,

    I am looking into buying your asset. I am working on Unity 2018.3.7f1 and HDRP. Do you have a lit/translucent shader with wind to use with your asset? My game is on Xbox One.

    Regards,
    Carlos
     
  4. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,
    and thank you for your interest in GPUI.

    Currently GPUI does not come with included HDRP shaders, but can auto-generate a convert copy of most shaders to work with itself. We have documentation that shows how to manually make the shader compatible if the auto conversion does not work for some reason.

    For use with terrains, you can set a custom material with a custom shader to use for texture type terrain details, and for prefab types GPUI simply uses the shader on the prefab.
     
  5. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi everyone,

    GPUI version 1.1.0 is released on the asset store. This update includes bug fixes, new features and some changes as usual.

    Firstly, with this version GPUI now provides its GPU Occlusion Culling support for VR platforms as well. This support is provided for both Single Pass and Multi Pass rendering modes.

    Here is a screenshot of the debug view:

    GPUI_v1.1.0_OC_VR_Debug.png

    Please note that the rendering mode will be auto-detected in Unity versions 2018.3 and up, but for previous versions, you will need to select the mode you are using from the Edit -> Prefences ->GPU Instancer window:

    GPUI_v1.1.0_VR_Occlusion_Mode.png

    We have also added a custom depth-normals shader with this version. If you are having issues with some post processing effects (like Ambient Occlusion) in Forward Rendering mode, you can use this shader instead of the built in depth normals shader to solve these issues.

    GPUI_v1.1.0_Custom_Depth_Shader.png

    Here is the comparison of the Ambient Occlusion Effect from the Post-Processing Stack in Forward Rendering and debug mode:

    Without the custom depth shader:
    GPUI_v1.1.0_Custom_Depth_Shader_Without.png

    With the custom depth shader:
    GPUI_v1.1.0_Custom_Depth_Shader_With.png

    Please note that this is only necessary in Forward Rendering mode. This shader is almost the the same with the built in version of the Unity depth-normals shader, and only includes the GPUI setup additionally. You can thus safely use this shader without effecting anything else.

    Next up, we added a new option to choose whether to disable scaling on the trees of the Terrain Manager and also a new API method to change the LOD Bias values for prototypes at runtime.

    GPUI now also supports version control systems like Perforce, and supports file checkout operations on read-only files on the background.

    We have also added support for biomes for the MapMagic World Generator integration.

    We hope you enjoy the new update!

    The full v1.1.0 changelog is as follows:

    New: Occlusion culling VR support (both single pass and multi pass)
    New: API method to change LOD Bias values for prototypes at runtime
    New: Setting to edit instancing bounds size
    New: Integration to version control systems like Perforce which uses readonly files
    New: Options to disable scaling on Tree prototypes
    New: Added custom depth normals shader
    New: MapMagic integration Biome support

    Changed: Modified foliage shader to use the custom depth normals shader

    Fixed: GLES shadow rendering error
    Fixed: Occlusion culling disabling DepthNormals on the camera
    Fixed: Null pointer error when Prefab Manager manager is disabled with Auto. Add/Remove Instances enabled
    Fixed: Prefab Manager not creating Proxy for SpeedTree8
    Fixed: Map Magic integration GameObject not being saved in scene when imported
    Fixed: Detail Manager not finalizing initialization when the activeThreads list is not cleared
     
    ftejada, jeromeWork and Rewaken like this.
  6. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    Hello, I have a terrible prefab that I would never use in production that I am using for a prototype that makes GPUInstancer crashing. I don't care to make it work, but I attach the prefab in case it can be interesting for you to debug it.
     

    Attached Files:

    • Grid.zip
      File size:
      20.9 KB
      Views:
      370
  7. SingularitySystems

    SingularitySystems

    Joined:
    Feb 10, 2014
    Posts:
    48
  8. torvald-mgt

    torvald-mgt

    Joined:
    Jun 14, 2015
    Posts:
    8
    Hey. Is it possible to correct the display of prefabs with a negative scale? During the construction of buildings, it is often convenient to mirror the details along one of the axes. In the inspector, everything looks good. But when using GPUI normals are inverted.
     
  9. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,
    and thank you for the feedback.

    We have made a fix that would prevent prefabs like this to throw the error you have seen, and will include this fix in the next update. You can simply edit the following lines in the GPUInstancerUtility.cs to apply the fix yourself:

    Line 108:
    Code (CSharp):
    1. runtimeData.argsBuffer = new ComputeBuffer(1, runtimeData.args.Length * sizeof(uint), ComputeBufferType.IndirectArguments);
    into:
    Code (CSharp):
    1. runtimeData.argsBuffer = new ComputeBuffer(runtimeData.args.Length, sizeof(uint), ComputeBufferType.IndirectArguments);
    and Line 118:
    Code (CSharp):
    1. runtimeData.shadowArgsBuffer = new ComputeBuffer(1, runtimeData.args.Length * sizeof(uint),
    2.                         ComputeBufferType.IndirectArguments);
    into:
    Code (CSharp):
    1. runtimeData.shadowArgsBuffer = new ComputeBuffer(runtimeData.args.Length, sizeof(uint),
    2.                         ComputeBufferType.IndirectArguments);
    That should fix the error. However, as you said, the prefab can be optimized - but if you will use this prefab like this, it would be better to define the "quad" children objects as a prefab and define that to GPUI as the prototype instead. For more information on container prefabs such as this, you can take a look at this wiki document.
     
  10. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,

    ComputeShader.Dispatch() is not supposed to take any time at all, since it just queues the compute operations to run in the GPU. Do you get any errors in the console? And what is the target platform and the Unity version you are using?

    It would help us identify this problem if you can also send us a sample test project where we can see this issue. You can mail us at support@gurbu.com.
     
  11. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,

    GPUI does not support negative scaling. Since most of the operations GPUI executes in the GPU use the transform matrix data, even if the visible mesh and its normals were to show correctly, the culling, LODs, etc. would not work as intended.
     
  12. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    @LouskRad I need some advices:

    I can see why you took some design decision with the API, it's clear, however these decisions make the API a bit awkward to use in a data oriented scenario. For DO scenario I don't mean UnityECS as you know I have my own solution.

    Hence a list of questions, just to be sure I am getting it right:

    1) if I have N prefab and I have to instance these prefabs multiple times, it seems that I have to call GPUInstancerAPI.UpdateVisibilityBufferWithMatrix4x4Array(prefabManager, prefab.prefabPrototype, _matrix4x4Array); for each prefab where the size of the matrix array is equivalent to the number of instances for that prefab

    2) How does this scenario work when instances are created and removed in run time? It seems that I need to use the Add/Remove Instances At Runtime flag, but then I am not sure what size I should set the Extra Buffer Size too, does the size matter (some time this number can be big)?

    3) in a DOD scenario, what is the best way to get hold of the GpuInstancePrefabManager and why there shouldn't be more than one? For me it would be really useful if the API wasn't so Monobehaviour dependent (for example it would be useful to be totally code driven, with me newing a GPUInstancePrefabManager when needed without GO/MB involved.

    4) How does GPUInstancer work with GPU Instancing? I see you have this option, I am not sure when to use it though (
    EnableInstancingForInstance/UpdateTransformDataForInstance)

    5) why should I need multiple GPUInstanceManagers?

    6) Are the prototype registered inside the GPUInstancePrefabManager considered like prefab that I can instance multiple times? If so, how can I get to the prototype reference to instantiate if I don't use gameobject/monobehaviours at all?

    sorry for all these questions, but I think this is all I need for now.

    Edit: I am checking the demos, so far the closest thing to what I need it seems to be the
    AddRuntimeCreatedGameObjects demo. I really do not want to use references (drag and dropped prefabs ect), at least this demo shows me that I can load a prefab with the addressable system and register a GPUInstancePrefabPrototype. Still I need a reference to the GPUInstancerPrefabManager in the scene tho.

    it would be awesome if the GPUInstancerPrefabPrototype was a struct instead of a class, so that I could store it in my ECS components

    I am still not sure what's the point of the prototypes inside the GPUIPM, in my mind I see them as a prefab I can instance, but I can't see how.
     
    Last edited: Mar 26, 2019
  13. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    Some progresses, but it doesn't work and I am still quite confused, I would like to show you what I would like to achieve:

    Code (CSharp):
    1.  public static class ECSResourceManager
    2.     {
    3.        //to be used only once per prefab, I was expecting I could use the prototype to
    4. //then build instances in run time, but I can't find how!
    5.         public static IEnumerator<TaskContract> RegisterPrefab(string prefab)
    6.         {
    7.             var prototypeGameObject = Addressables.LoadAsset<GameObject>(prefab);
    8.  
    9.             while (prototypeGameObject.IsDone == false) yield return Yield.It;
    10.  
    11.             var prototype =
    12.                 GPUInstancerAPI.DefineGameObjectAsPrefabPrototypeAtRuntime(prefabManager, prototypeGameObject.Result);
    13.  
    14.             _prefabs.Add(index, prototype);
    15.  
    16. //later on can I do
    17. //GPUInstancerAPI.InitializeWithMatrix4x4Array(prefabManager, prototype, new[] {Matrix4x4.identity});
    18. //?
    19.  
    20.             yield return index++;
    21.         }
    22.  
    23.         static ECSResourceManager()
    24.         {
    25.             if(prefabManager == null && GPUInstancerAPI.GetActiveManagers() != null)
    26.             {
    27.                 GPUInstancerManager manager =
    28.                     GPUInstancerAPI.GetActiveManagers().Find(m => m is GPUInstancerPrefabManager);
    29.                 prefabManager = (GPUInstancerPrefabManager) manager;
    30.             }
    31.         }
    32.     }
    Or Maybe

    Code (CSharp):
    1. public static IEnumerator<TaskContract> RegisterPrefab(string prefab)
    2.         {
    3.             var prototypeGameObject = Addressables.LoadAsset<GameObject>(prefab);
    4.  
    5.             while (prototypeGameObject.IsDone == false) yield return Yield.It;
    6.  
    7.             var prefabi = prototypeGameObject.Result.AddComponent<GPUInstancerPrefab>();
    8.        
    9.             //prefabi.gpuInstancerID what is this for?
    10.  
    11.             GPUInstancerAPI.AddPrefabInstance(prefabManager, prefabi);
    12.        
    13.             _prefabs.Add(index, null);
    14.        
    15.             yield return index++;
    16.         }
    This works under conditions:
    Code (CSharp):
    1.             var prototypeGameObject = Addressables.LoadAsset<GameObject>(prefab);
    2.  
    3.             while (prototypeGameObject.IsDone == false) yield return Yield.It;
    4.          
    5.             var prefabi = prototypeGameObject.Result.GetComponent<GPUInstancerPrefab>();
    6.          
    7.             GPUInstancerAPI.InitializeWithMatrix4x4Array(prefabManager, prefabi.prefabPrototype, new[] {Matrix4x4.identity});
    8.  
    This works, but is it good?

    Code (CSharp):
    1.  
    2.             while (prototypeGameObject.IsDone == false) yield return Yield.It;
    3.            
    4.             var prototype =
    5.             GPUInstancerAPI.DefineGameObjectAsPrefabPrototypeAtRuntime(prefabManager, prototypeGameObject.Result);
    6.             prefabManager.InitializeRuntimeDataAndBuffers();  
    7.             GPUInstancerAPI.InitializeWithMatrix4x4Array(prefabManager, prototype, new[] {Matrix4x4.identity});
    so the idea would be to register something in the GPUInstancerAPI so that later on I can create an instance out of it. However I may getting this totally wrong, in the sense that there isn't such a concept like a GPUInstancerPrefab or GPUInstancePrototype that I can carry around to create new instance out of them, but this is what I would like to have some how. Leads?

    Right now I would get this when I use InitializeWithMatrix4x4Array with the prototype created n that way

    Can not find runtime data for prototype: 1_Cube. Please check if the prototype was added to the Prefab Manager.

    AddInstancesToPrefabPrototypeAtRuntime doesn't make much sense to me as it needs gameobjects that I don't want to create to start with

    The second code doesn't work either and I wonder what prefabi.gpuInstancerID is used for.

    The third case works, but only if I pre-register the prefab in the GPUIPM, I hoped I could that in run-time

    the fourth case does exactly what I need, but what happens if I call it multiple times (one per prefab?)
     
    Last edited: Mar 26, 2019
  14. GurhanH

    GurhanH

    Joined:
    Apr 24, 2017
    Posts:
    539
    Hi @sebas77

    First of all, before diving into the code, I would recommend to read the wiki documentations and especially No-GameObject workflow for your use case, which was recently updated with some more explanation on the API methods and an explanation about the best practice on how to add/remove instances while using Matrix4x4 arrays. And also check the PrefabsWithoutGameObjects and AddRuntimeCreatedGameObjects demos thoroughly to see example codes about how to implement an integration using low level API methods.

    As for your questions:

    If you want to use a No-GameObject workflow, it is enough to call the InitializeWithMatrix4x4Array API method once for each prefab at start. You need to call the UpdateVisibilityBufferWithMatrix4x4Array method only when you make a change in the array data.

    When you use the No-GameObject workflow, you are managing all the instances through this array and there is no connection to actual GameObjects, so you do not need to enable any Runtime Settings.

    Rendering calls requires to be be queued on every frame, and MonoBehaviours are the best way to do this. There are also many other variables (e.g ComputeBuffers) that are generated and modified at runtime which are required for the Compute Shader operations and the draw calls, and these are also stored for fast and easy access inside the Managers.
    If we were to make an API method that takes all these variables as a parameter, it would be very hard for users to figure out what to set to these parameters, and most of the updates to GPUI would break the integrations.

    For an explanation on GPU Instancing and how GPUI implements it, you can have a look at this wiki documentation.
    If you want to use Matrix4x4 arrays, you have no need for these API methods, since you will be handling which instances will be rendering, or where they will be rendered, through the arrays.

    It is the users' design decision, how they want to setup their managers. You can have a single one where you define all your prototypes, or multiple ones where you can load from different scenes or enable/disable different ones according to your use case at runtime.

    By design prototypes require a GameObject reference which is used as a template to collect information (e.g mesh, material, LOD, transform data, etc.) to setup the rendering process. But this does not mean you have to have a prefab to define a prototype, or save the prototype as an asset. You can use a runtime generated GameObject and a runtime generated prototype by calling DefineGameObjectAsPrefabPrototypeAtRuntime method as in AddRuntimeCreatedGameObjects demo scene.

    GPUInstancerPrefabPrototypes are ScriptableObjects that store GPUI settings for each prefab and they are stored as assets in Unity (if not generated at runtime). ScriptableObjects are a safe and multipurpose way to store information. And because they are also Unity assets they can just be dragged and dropped on a Monobehaviour component as a parameter for example.
     
  15. GurhanH

    GurhanH

    Joined:
    Apr 24, 2017
    Posts:
    539
    I attached an example scene with a script showing how you can accomplish this.
     

    Attached Files:

    FlightOfOne and sebas77 like this.
  16. jeromeWork

    jeromeWork

    Joined:
    Sep 1, 2015
    Posts:
    429
    Super helpful and informative, as always. I'm very grateful for the lightmap tip (which turns out is totally unrelated to GPUI!) Thanks for taking the time.
     
  17. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    @GurhanHazinedar thank you a lot for your time and patient to answer all my questions, I think the last solution will work I need the time to test it.

    Edit: my current worry is about how to layout this data. To have maximum efficency my entities should be grouped by prototype which maybe a bit restrictive
     
    Last edited: Mar 28, 2019
  18. jeromeWork

    jeromeWork

    Joined:
    Sep 1, 2015
    Posts:
    429
    @LouskRad / @GurhanHazinedar Your advice on multi-terrain is working really well (and you were spot on re. missing light data causing spikes :rolleyes:)

    - Can I ask for guidance on using "Use Floating Origin" in the manager's Scene Settings?
    I don't see it mentioned anywhere in the wiki.

    I'm using World Streamer to loop terrain tiles, it resets world position after a set distance to stop problems with floating point errors. How would that work with the GPU Instancer setting?

    Thanks, as always
     
  19. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    @GurhanHazinedar

    do you think it would be possible to have a version of InitializeWithMatrix4x4Array and UpdateVisibilityBufferWithMatrix4x4Array that use a start and end index from the passed array instead to assume that I need to use it all?
    It seems possible as I see that Unity has
    public unsafe void SetData<T>(
    NativeArray<T> data,
    int nativeBufferStartIndex,
    int computeBufferStartIndex,
    int count)
    and similar, so it should be doable for you to add the function (I will add myself meanwhile) (these overloads are useful in the ECS scenario)

    I assume that these two functions are the most efficient way to update transforms in GPUI although prefabManager.runtimeDataList.Find(rd => rd.prototype == prototype); worries me (as it's a linear search and could become expensive over time).
    I understood the that number of instances must be preallocated, this is fine to me. Still not sure if to preallocate a small number and reinitialize every now and then or preallocate just a big number (which is just a problem in case I don't know how many prototypes I am going to have)

    All that said, do you have advices in case I want to handle dynamic meshes (changing vertices every frame)?
     
    Last edited: Mar 28, 2019
  20. GurhanH

    GurhanH

    Joined:
    Apr 24, 2017
    Posts:
    539
    It should work when you just enable "Use Floating Origin" option on the Manager.
     
  21. GurhanH

    GurhanH

    Joined:
    Apr 24, 2017
    Posts:
    539
    If you need to very frequently and/or partially update the matrix data, you can get access to the ComputeBuffer buffer and call SetData on this by keeping a reference to it from the result of GPUInstancerAPI.GetTransformDataBuffer method.

    You can change the mesh vertices as long as they have the same submesh and vertex counts. Otherwise it wouldn't work, you would need to reinitilaize.
     
    sebas77 likes this.
  22. jeromeWork

    jeromeWork

    Joined:
    Sep 1, 2015
    Posts:
    429
    Thanks @GurhanHazinedar ... I guess I was wondering what it's doing under the hood :)

    - for anyone interested, even without knowing how, I can confirm that it does work just great on an infinite looping multi-tiled terrain.

    Super impressed with this asset, and the support from its developers.
     
    LouskRad and GurhanH like this.
  23. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    Thank you again! At the moment I update all the matrices once a frame, but I can optimize it for sure. I will investigate all the possibilities, so far it looks very promising and I am pushing to see it used in the final product!
     
    LouskRad and GurhanH like this.
  24. GurhanH

    GurhanH

    Joined:
    Apr 24, 2017
    Posts:
    539
    Thanks! Happy to hear everything is working out :)
    If you wish to know about the floating origin option, when enabled, it attaches the GPUInstancerFloatingOriginHandler script on the terrain with a reference to the manager. This script checks for position changes on the terrain and when it happens, it dispatches a compute shader that moves all the instance positions in GPU memory.
     
    jeromeWork likes this.
  25. Rewaken

    Rewaken

    Joined:
    Mar 24, 2015
    Posts:
    128
    Yup support is awesome but assets design is also fantastic that's why even after I am using my own solution for animation instancing with custom made animator I am waiting for their solution to use in my game.
     
    jeromeWork, LouskRad and GurhanH like this.
  26. Bamfax

    Bamfax

    Joined:
    Jun 12, 2016
    Posts:
    52
    Hi,

    let me say many thanks for GPUInstancer. I just started toying with it, thinking what the concepts need to be for integrating it in my project.

    What I am not quite clear yet is how to address the (prefab) manager and keep track of the instances. If I understood correctly, it is possible to run multiple managers, but only have each prototype once over all managers in the scene.

    The project setup here is multiple independent 'simulations' using the same prefabs in each of them. To stick with the boids demo analogy, think of it as multiple aquariums with similar fish swarms. Computeshaders update the boids/fish positions. Instances are added and removed during runtime. The computeshaders calculate positions per swarm, while the GPUI manager arranges the matrices via prototype. Seeing the gpuInstancerID on the GPUInstancerPrefab, this looks like a nice way to keep track of which instance has which index on its prototype array. This is definitely a way to go when using MonoBehaviours.

    Would a similar approach (thinking of tracking instance indexes) be possible without using MonoBehaviours? Ideally the instances would not be instantiated as GameObjects and instead go directly into the GPUInstancer world. As GPUInstancerPrefab seems pretty lightweight, would it be feasible if I have it inherit from SerializedObject instead? Thinking of how to get access to gpuInstancerID without requiring GameObjects. Or how about building an Interface which exposes gpuInstancerID (along with other GPUInstancerPrefab features) and implement that in my instance class (having to adapt GPUI API, manager, etc.)? Alternatively, if there's already an approach coming of this in the ECS direction (GPUInstancerPrefab becoming a component?), I am not there yet, but I guess this could also work out fine here.

    Thank you for your recommendations.
     
    Last edited: Mar 31, 2019
  27. Bamfax

    Bamfax

    Joined:
    Jun 12, 2016
    Posts:
    52
    Allow me yet another question: Thinking about the boids CS demo, how would I handle the TRS matrices when having two or more types of boids? Let's assume the main computeshader kernel can handle all types of boid and is operating on a single TRS matrix, while the prototypes/prefabs have a TRS matrix per type (if I am not mistaken). What would be the best approach to split out the single TRS matrix into matrices per prototype? Would it make sense to dispatch additional computeshaders after the main computeshader which then separate the single large matrix into matrices per prototype? I guess the occlusion culling is also computeshader based and is run per prototype TRS matrix? So for occlusion culling I would need to make sure the prototype TRS matrices are populated as expected beforehand.

    Again, thank you for your time.
     
  28. RomBinDaHouse

    RomBinDaHouse

    Joined:
    Mar 18, 2015
    Posts:
    13
    Hi LouskRad,

    We dont use map magic, but we also need optimization for "multiple terrain - multiple managers" case. Is it possible to use (or reuse) one set of detail or trees prototypes (or one manager for details, one for trees) for whole scene containing several terrains? For example in best case: one prototype of grass -> one draw call regardless of the number of terrains in the frame.

    I have a couple more questions:
    - we need grass details rendering on long distance but it seems not optimal for shadow pass, could we use "Use Custom Shadow Distance" parameter for grass details? For example "Max Distance" = 300, but "Shadow Distance" = 30. It seems this parameter not working for grass even if we use prefab with LODs and LODs' shadows is disabled.

    - there's high overdraw when rendering far grass, is it possible to lower "Detail Density" by distance somehow?
     
  29. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,
    and thank you for supporting GPUI.

    You can define the same prototypes in multiple Prefab Managers, but it is not recommended; since each manager will issue draw calls for its prototypes separately.

    When using the no game object workflow, the gpuInstancerID on the prototype instances become irrelevant, since there is no game object reference and this property is not set. If you want to keep track of your instances when using this workflow, you can use the indices of the Matrix4x4 array you are using for instance ids. Internally, the indices of the array you will be using will be exactly the same with the indices of the instances in the compute buffer. Thus when using such a workflow, you will have complete control over your instances. You can track your instances from their indices in the matrix array and from there, you can have your own design according to your needs.

    If you are programming the movement of your instances in a compute shader, and if you don't need that data in the CPU side, you don't actually need to get back that data.

    Suppose you have 10 types of fish, and 100 instances of each; so 1000 fish in total.

    You can start by initializing your fish instances (just like in the boids demo); 10 prototypes for the fish types and 100 instances per each prototype. You will also need a separate buffer that will contain all these instances, with the size of 1000.

    Then in each update, (1) you can dispatch your own compute shader that will work on this buffer of 1000 instances and do your boid calculations on each instance, (2) then you can dispatch another compute shader that copies data from the first one to the GPUI compute buffer. You could do this in the first compute shader as well, but it is up to you.

    Doing it this way, GPUI will use the buffer you have modified for visibility calculations as well, so you don't have to do anything extra for occlusion culling.
     
  30. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,

    Currently, an optimization for "multiple terrains", along with various other features which will redefine how GPUI handles Unity terrains is indeed among our plans. However, these require fundamental changes to the core GPUI code as far as detail and tree instancing goes and thus will require a relatively major update - potentially one in which we will deprecate the Detail and Tree Managers and GPUI will use a single manager to handle everything related to the Unity terrain(s). However, our priority right now is the skinned mesh extension, so at this point I cannot give you concrete information on when and in what form these changes will be implemented.

    About custom shadow distances for grass details, we will add this to our roadmap and will make that feature available soon. Thank you for your feedback.

    As for "Detail Density" by distance, this is not supported but you can achieve a similar effect by using "tuft" prefab prototypes for your grass and using LODs on them. In fact, you can take a look at this wiki article for a similar suggestion and build on it by using sparser meshes as LODs.
     
    RomBinDaHouse likes this.
  31. RomBinDaHouse

    RomBinDaHouse

    Joined:
    Mar 18, 2015
    Posts:
    13
    Sounds good!

    Thank you, we will wait for this feature

    Ok, will try this way.
    The only disadvantage is that big grass tufts do not conforms the terrain heightmap as well as small separate planes \ billboards. For this case maybe we need to pass heightmap texture to vertex shader and shift vertices pos in worldspace according to difference between pivotY and heightmap.
    and wind animation also doesn't working
     
    Last edited: Apr 1, 2019
  32. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    going back to the gameobjectless topic, I have a little problem with the pattern that assumes that I know all the prefabs before hand. I dynamically load resources on demand, this means that I can have new prototypes at run time, which means that every time I have to call

    GPUInstancerAPI.InitializeGPUInstancer(prefabManager);

    I suspect this is not going to work, alternatives?

    p.S.: it did work, I am not sure about the performance consequences though.

    Edit: I also will need to change material on the instanced cube, how can I do this in the current scenario? Should I use the material variations?

    Edit2: I read that transparency is not supported, is this true? Should I fall back on normal unity rendering for transparent stuff?
     
    Last edited: Apr 1, 2019
  33. Ardinius

    Ardinius

    Joined:
    Oct 4, 2015
    Posts:
    57
    Hi,
    Thank you for this great asset, as well as the great support and the promise of future features. (Skinned mesh any updates?)

    I just want to ensure i am doing best practice, I am rendering 150,000 trees. (these are .fbx models and normal prefabs not unity trees).
    I did test the non game object work flow but it didn't give me any better performance.
    Presently i can get around 100fps,
    I attempted adding a LOD to the tree prefab to as to use billboards but i cannot get GPUI to generate a billboard for the object, does GPUI support billboard generation of normal models?
     
  34. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,

    it would indeed work by initializing the manager, but to increase performance in that scenario, you are right that a prototype based initialization method would be better. Thank you for the feedback, we will look into adding this method to the GPUI API.

    For changing material properties, if you need the changes instance based, you can use a variation buffer. You can take a look at the ColorVariationsDemo scene for an example.

    As for transparency, they are not supported out of the box and the problem is with handling the sorting of transparent objects with GPU Instancing. You can take a look at this wiki section for an explanation.
     
  35. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,
    and thanks, we will keep improving GPUI with the feedback we get from you.

    As for the skinned mesh support, we are actively working on it as our priority. We have currently achieved the basic GPU Skinning functionality for this, and it is integrated to the GPUI core. Right now we are testing its code base and we hope to have an early version available in the near future. If you haven't seen the related announcement about it, the skinned mesh support will be released as a beta version in the form of an extension asset to GPU Instancer. We will be posting more on the technical details and the package contents in the upcoming days.

    About the no game object workflow, there could be a number of factors effecting the final performance result you see. One good way to determine these would be to use the profiler to see what is taking up the most resources. For example if you see that you are being GPU bound while rendering your instances, a no game object workflow would indeed not help get better FPS since it would mean that the system is capped while rendering the geometry.

    To use billboards as LODs on your trees with the Prefab Managers, you do not need to manually add an LOD group or billboard LOD level to your prefab. All you need to do is to check Generate Billboard on your manager, and GPUI will handle the creation of the billboard LOD and its grouping automatically (whether the original prefab has an LOD Group or not). You can choose the options under the Billboard Settings section as you see fit.
     
  36. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    I read already that part of the wiki and worried me a bit, as historically OIT techniques were really hard to develop (unless you talk about multiplication/addition :p) and obviously you are saying that there is no way to sort the triangles. Luckily we don't need transparency that much, but my question is, can we fall back to Unity/UnityECS render for transparency?

    Edit: some OIT cool stuff from github https://github.com/candycat1992/OIT_Lab, but I don't know these techniques at all
     
  37. GurhanH

    GurhanH

    Joined:
    Apr 24, 2017
    Posts:
    539
    There is no automatic fallback system, but you can simply not define transparent objects as GPUI prototypes, since they will not work correctly.

    We made a quick test with this project. Seems like, you can use it for transparency support by adding GPUI setup to the replacement shaders.
     
  38. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    manual fallback is fine to me, but I still want to know if the two rendering pipelien will be compatible (it seems so)

    this sounds very cool
     
  39. Bamfax

    Bamfax

    Joined:
    Jun 12, 2016
    Posts:
    52
    I just toyed around with the boids CS and had (supposedly) the second normalize() in the kernel go indefinite if two (or more) boids are sharing the same position e.g. at spawn time (which does not happen in the demo, as they are spawned on random positions).

    Hacky fix (at line 80):
    // Calculates a rotation from the vectors.
    float3 aggrDirection = separation + alignment + cohesion;
    float3 direction = float3(0.0f, 0.0f, 0.0f);
    if (length(aggrDirection) > 0.0000001f)
    direction = normalize(aggrDirection);
     
    Last edited: Apr 2, 2019
    LouskRad likes this.
  40. PicturesInDark

    PicturesInDark

    Joined:
    Jun 13, 2013
    Posts:
    89
    One simple cuestion, I think is strange and it must to have an explanation: If I add GPU instancer with GPUI MapMagic Integration to MapMagic DemoScene (that one that comes with the asset MapMagic with no changes) I have the same FPSs and performance that without GPU Instancer. Why? How to increase the performance?
     
  41. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,

    When using GPUI with terrain details in general, it is important to note that the Detail Manager (or in the case of MapMagic, the integration) serves both functions of improving visual quality and performance. The default settings that the manager comes with is intended to be at a balanced point for most scenarios, but would not be the best for all. You can take a look at this wiki document for the best practices of using terrain details with GPUI.

    Also, please take further notice that the GPUI Tree Manager generates billboards for the trees that do not show in the MapMagic scene by default (which also limits max mesh trees to 150).

    In short, as far as the MapMagic demo scene is concerned, more geometry is rendered with GPUI. GPUI also uses a higher quality shader for terrain details, which would compromise the performance gain for better visual quality - resulting in similar FPS.
     
  42. farzaan090

    farzaan090

    Joined:
    Jul 23, 2018
    Posts:
    15
    Is there any way to use the GPUI Modification Collider to cause tree instances in the tree manager to be replaced with prefabs of the tree that run the scripts from the prefab of the tree?

    Would there be any performance lost if I manually placed trees on the terrain and used the prefab manager versus using the unity terrain system plus the tree manager?
     
    Last edited: Apr 4, 2019
  43. LouskRad

    LouskRad

    Joined:
    Feb 18, 2014
    Posts:
    904
    Hi there,

    The GPUI Modification Collider is designed for use with the Prefab Manager only. You should be able to use the Prefab Manager instead of the Tree Manager for your trees without compromising performance; however, memory consumption can increase a bit since you will have GameObjects in scene.
     
    farzaan090 likes this.
  44. Monorio1

    Monorio1

    Joined:
    Dec 10, 2018
    Posts:
    17
    So my grass turns black whenever the models get swapped with the instanced one. The alpha cuttout is present but the rest of it is black. The shader is made using Amplify shader, I have added the required dependency as per the wiki. upload_2019-4-4_14-50-57.png
    The shader does have vertex local offset, but I can't figure where to add what I'm guessing is missing. I.E.
    UNITY_VERTEX_INPUT_INSTANCE_ID
    if the instancing_options procedural:setupGPUI isn't there the model displays correctly but is floating above the camera.

    With the line:
    upload_2019-4-4_14-54-10.png

    Thanks
     

    Attached Files:

  45. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    is there a way to disable GPUI and fallback to normal GOs rendering without removing the plugin and leaving the project intact? (So I can switch between the two for debugging purposes)

    edit: something is currently driving me crazy, if I use false here:

    Code (CSharp):
    1.  prototype = GPUInstancerAPI.DefineGameObjectAsPrefabPrototypeAtRuntime(prefabManager,
    2.                                                                                        prototypeGameObject.Result);
    3.              
    4.                 GPUInstancerAPI.InitializeGPUInstancer(prefabManager, false); //<----
    5.                 GPUInstancerAPI.InitializeWithMatrix4x4Array(prefabManager, prototype,
    6.                                                              new Matrix4x4[maxNumberOfInstances]);
    the game crashes immediately at the first
    UpdateVisibilityBufferWithMatrix4x4Array.


    if I put true, it works as long as this is called once. If I called a second time with another gameobject, the update visibility crashes because the
    transformationMatrixVisibilityBuffer is null

    Edit2: ok the following works, but awkward!

    Code (CSharp):
    1. prototype = GPUInstancerAPI.DefineGameObjectAsPrefabPrototypeAtRuntime(prefabManager,
    2.                                                                                        prototypeGameObject.Result);
    3.              
    4.                 GPUInstancerAPI.InitializeGPUInstancer(prefabManager, true);
    5.              
    6.                 foreach (var prefabI in _prefabs)
    7.                 GPUInstancerAPI.InitializeWithMatrix4x4Array(prefabManager, prefabI.Value.GPUIprototype,
    8.                                                              new Matrix4x4[maxNumberOfInstances]);
     
    Last edited: Apr 5, 2019
  46. Bamfax

    Bamfax

    Joined:
    Jun 12, 2016
    Posts:
    52
    Regarding defining prototypes from prefabs and runtime, I also experienced some errors I did not really yet understand. Let me follow up on that this evening.

    > is there a way to disable GPUI and fallback to normal GOs rendering without removing the plugin and leaving the project intact? (So I can switch between the two for debugging purposes)

    GPUInstancer is based on DMII, so I would guess options are limited if no GOs are available. Previously I was instantiating Gameobjects, and switching between Unity standard renderer and DMII by batch switching between meshrenderers and DMII rendering. If the transforms ceased to exist on the classic side, then this of course needs a pipe to exchange transforms between both sides (e.g. ComputerBuffer.GetData()).
    For now, working with a gameobjectless workflow, I still define from prefab, never instantiate gameobjects, just do rendering via GPUI (by spawning from non-monobehaviour class instances) and could, if really needed, instantiate from prefabs based on the some class instances (which are lightweight (non-)gameobject instances, also kept around for referencing to GPUI instances) for debugging.
     
  47. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    oh yeah, I didn't mean that GPUI would handle the NOGO scenario, I would switch code my self to enable the two scenarios, but when I disable GPUI I would be sure that nothing is running with it. Not entirely necessary though
     
  48. GurhanH

    GurhanH

    Joined:
    Apr 24, 2017
    Posts:
    539
    Hi @Monorio1

    It looks like a lighting problem. But I can not say the exact reason without more information.

    One possibility is that, if you are using Forward rendering and your Unity version is older than 2018.2.0f2, only one directional light will be applied to the instances. Because Unity did not run the ForwardAdd passes in Forward rendering for indirect instancing prior to 2018.2. You can test this by changing the Rendering Path to Deferred at your camera settings, or by changing the intensity of the directional light in your scene. If this is the case, you can either switch to Deferred rendering, or update your Unity version.

    If this does not help, please send us an e-mail with detailed information about your Unity version, target platform, scene lighting, camera rendering path and shader setup, or if possible a sample project so that we can see the problem firsthand.
     
  49. GurhanH

    GurhanH

    Joined:
    Apr 24, 2017
    Posts:
    539
    Hi @sebas77

    As @Bamfax mentioned, it wouldn't work with a no-GO scenario. But with GOs, GPUI enables MeshRenderers on the GOs and clears buffers when the manager is disabled/destroyed. So it would fallback to normal rendering. Only thing you would need to do manually if the occlusion culling is enabled, is to destroy the GPUInstancerHiZOcclusionGenerator script that is attached to the main camera on initialization. This runs independent from managers, so it is not destroyed when a manager is disabled.

    The optional boolean parameter forceNew, when set to false, checks if the manager was initialized before, and if it did, it does not run the initialization again (we will add more explanation to the description to clear possible misunderstandings). In this case you need to set it to true, since there has been a change in prototype definitions and it requires reinitialization.

    To comment on this, I need to see how you make the update visibility call. There is probably a missing initialization call. It would also help if you can send us a sample project, so that we can better understand your use case.

    If prefabI are prefab instances, this is not a correct use. But when it works like this, it is possible that there was a prototype that was not initialized before. You should make sure that you call InitializeWithMatrix4x4Array for each prototype before calling UpdateVisibilityBufferWithMatrix4x4Array.
     
  50. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,642
    sorry I forgot to update the code, the correct code is:

    Code (CSharp):
    1.  GPUInstancerPrefabPrototype prototype = GPUInstancerAPI.DefineGameObjectAsPrefabPrototypeAtRuntime(prefabManager,
    2.                                                                                        prototypeGameObject.Result);
    3.  
    4.                 _prefabs.Add(prefabID, new RXResource
    5.                 {
    6.                     GPUIprototype = prototype, unityEntity = uECSEntity,
    7.                     maxInstance = maxNumberOfInstances
    8.                 });
    9.            
    10.                 GPUInstancerAPI.InitializeGPUInstancer(prefabManager, true);
    11.            
    12.                 foreach (var prefabI in _prefabs)
    13.                 GPUInstancerAPI.InitializeWithMatrix4x4Array(prefabManager, prefabI.Value.GPUIprototype,
    14.                                                              new Matrix4x4[prefabI.Value.maxInstance]);
    Edit: what is this error about?

    ArgumentException: ComputeBuffer.SetData() : Accessing 65408 bytes at offset 0 for Compute Buffer of size 64000 bytes is not possible.
    UnityEngine.ComputeBuffer.SetData (System.Array data) (at C:/buildslave/unity/build/Runtime/Export/Shaders/ComputeShader.bindings.cs:128)
     
    Last edited: Apr 5, 2019