Difference between revisions of "GPU Instancer:FAQ"

From GurBu Wiki
Jump to: navigation, search
(How is GPU Instancer Different from the Unity Material Option?)
(How to add remove prefabs at runtime?)
Line 53: Line 53:
  
 
<div style="clear: both"></div>
 
<div style="clear: both"></div>
 
=== How to add remove prefabs at runtime? ===
 
 
1. Easiest way is to enable Auto. Add/Remove Instances option in the prototype options. When enabled, the Prefab Manager will add a script called "GPUInstancerPrefabRuntimeHandler" to the prefab object and handle all runtime changes automatically.
 
 
https://www.gurbu.com/assets/images/tutorials/addremoveruntime/autoaddremoveinstances.png
 
 
2. Optionally you can add prefab instances through our API methods with the AddPrefabInstance and RemovePrefabInstance methods. Keep in mind that Add/Remove Instances At Runtime option should be enabled in the prototype definition for this API methods to work. Also Extra Buffer Size should have high enough number to add all the prefab instances generated at runtime.
 
 
https://www.gurbu.com/assets/images/tutorials/addremoveruntime/addremoveinstances.png
 
 
3. Another option is to register the prefab instances and reinitialize the Prefab Manager with first calling RegisterPrefabInstanceList method and then calling InitializeGPUInstancer method.
 
<br>
 
<div class="code" style="border: 1px solid #c8ccd1;padding:5px;"><div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0600FF; font-weight: bold;">using</span> <span style="color: #008080;">System.Collections.Generic</span><span style="color: #008000;">;</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0600FF; font-weight: bold;">using</span> <span style="color: #008080;">UnityEngine</span><span style="color: #008000;">;</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp;</div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #0600FF; font-weight: bold;">namespace</span> GPUInstancer<span style="color: #008000;">.</span><span style="color: #0000FF;">Extras</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #008000;">{</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">class</span> GPUIRegisterPrefabInstances <span style="color: #008000;">:</span> MonoBehaviour</div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; <span style="color: #008000;">{</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">// Keeping a static reference to the manager so it can be shared between scenes.</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">static</span> GPUInstancerPrefabManager prefabManager<span style="color: #008000;">;</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">// The list of prefab instances in scene</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">public</span> List<span style="color: #008000;">&lt;</span>GPUInstancerPrefab<span style="color: #008000;">&gt;</span> prefabInstanceList<span style="color: #008000;">;</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp;</div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp;</div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">// In this example we fill the list in the Reset method which works when adding the component for the first time (or using the reset command in the inspector).</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">// You can fill the list in any way you want.</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">void</span> Reset<span style="color: #008000;">(</span><span style="color: #008000;">)</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">{</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">// Add prefabs in the scene to the list</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prefabInstanceList <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> List<span style="color: #008000;">&lt;</span>GPUInstancerPrefab<span style="color: #008000;">&gt;</span><span style="color: #008000;">(</span>FindObjectsOfType<span style="color: #008000;">&lt;</span>GPUInstancerPrefab<span style="color: #008000;">&gt;</span><span style="color: #008000;">(</span><span style="color: #008000;">)</span><span style="color: #008000;">)</span><span style="color: #008000;">;</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">}</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp;</div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #6666cc; font-weight: bold;">void</span> Start<span style="color: #008000;">(</span><span style="color: #008000;">)</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">{</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">// Find the prefab manager and set it to the static property</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">if</span><span style="color: #008000;">(</span>prefabManager <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span> <span style="color: #008000;">&amp;&amp;</span> GPUInstancerAPI<span style="color: #008000;">.</span><span style="color: #0000FF;">GetActiveManagers</span><span style="color: #008000;">(</span><span style="color: #008000;">)</span> <span style="color: #008000;">!=</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">)</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">{</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GPUInstancerManager manager <span style="color: #008000;">=</span> GPUInstancerAPI<span style="color: #008000;">.</span><span style="color: #0000FF;">GetActiveManagers</span><span style="color: #008000;">(</span><span style="color: #008000;">)</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Find</span><span style="color: #008000;">(</span>m <span style="color: #008000;">=&gt;</span> m <span style="color: #008000;">is</span> GPUInstancerPrefabManager<span style="color: #008000;">)</span><span style="color: #008000;">;</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prefabManager <span style="color: #008000;">=</span> <span style="color: #008000;">(</span>GPUInstancerPrefabManager<span style="color: #008000;">)</span>manager<span style="color: #008000;">;</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">}</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp;</div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">// Register the prefab instance list to the manager</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">(</span>prefabManager <span style="color: #008000;">!=</span> <span style="color: #0600FF; font-weight: bold;">null</span> <span style="color: #008000;">&amp;&amp;</span> prefabManager<span style="color: #008000;">.</span><span style="color: #0000FF;">isActiveAndEnabled</span><span style="color: #008000;">)</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">{</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GPUInstancerAPI<span style="color: #008000;">.</span><span style="color: #0000FF;">RegisterPrefabInstanceList</span><span style="color: #008000;">(</span>prefabManager, prefabInstanceList<span style="color: #008000;">)</span><span style="color: #008000;">;</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GPUInstancerAPI<span style="color: #008000;">.</span><span style="color: #0000FF;">InitializeGPUInstancer</span><span style="color: #008000;">(</span>prefabManager<span style="color: #008000;">)</span><span style="color: #008000;">;</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">}</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">}</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;">&nbsp; &nbsp; <span style="color: #008000;">}</span></div>
 
<div style="font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;"><span style="color: #008000;">}</span></div>
 
</div>
 
  
 
=== How to convert shaders manually to support GPU Instancer? ===
 
=== How to convert shaders manually to support GPU Instancer? ===

Revision as of 13:38, 5 December 2018

About | Features | Getting Started | Terminology | Best Practices | F.A.Q.

General Questions


What are the Minimum Requirements?


To provide the fastest possible performance, GPU Instancer utilizes indirect GPU instancing using Unity's DrawMeshInstancedIndirect API and Compute Shaders. Following are the minimum requirements for GPU instancing and Compute Shader support:


  • DirectX 11 or DirectX 12 and Shader Model 5.0 GPU (Windows, Windows Store)
  • Metal (macOS, iOS)
  • OpenGL Core 4.3 (Windows, Linux)
  • Vulkan (Android, Windows, Linux)
  • OpenGL ES 3.1 (Android 8.0 Oreo or later)
  • Modern Consoles (PS4, Xbox One)


Please also note that even though some integrated graphics cards may satisfy these requirements, they will not provide the boost you can get from GPU Instancing. Therefore, hardware with a dedicated GPU is recommended.


How does GPU Instancer work?



The aim of GPUI is to provide an easy to use interface to use indirect instancing without having to go through the learning curves of (or extensive development times of) GPU programming and Compute Shaders. To provide this, GPUI analyzes a prefab (or Unity terrain) and uses indirect instancing to render its instances (or detail/tree prototypes). Upon sending the mesh and material data to the GPU once, GPUI creates various GPU buffers and dispatches Compute Shaders on every frame to manipulate the instance data in these buffers. This approach takes the load completely off the CPU and uses the GPU for all rendering processes - so that the CPU threads work more efficiently for game scripts. GPUI also uses different optimization techniques to effectively work on different platforms; so that whether the target platform is a high-end PC, VR, or a modern mobile device, GPUI provides the best indirect instancing strategy.


If you're not familiar with these concepts, you can take a look at the Terminology Page for more information. In any case, here is a basic primer on GPU instancing:


(Indirect) GPU instancing works by sending mesh/material data to the GPU in a single draw call. This reduces the amount of batching to one even if there are hundreds or even thousands of the same mesh/material combination. This removes the bottleneck that occurs when sending mesh and material data from CPU to the GPU, and results in higher fps if there are many of the same mesh-material combinations. That is, GPU instancing helps in scenarios where you have many instances of the same game object.


How is GPUI Different from the Unity Material Instancing Option?



Untiy provides instancing support by using the "Enable GPU instancing" option in Unity Standard and Surface shaders. When you use this option, Unity will handle frustum culling and culling by baked occlusion maps automatically. However, when using this option, Unity will group together instances and issue a draw call for every 500 instances in Direct3D and 125 instances in OpenGL ES 3, OpenGL Core, and Metal. The reason for this limitation is that Unity is aiming to support as many devices as possible, and older devices have a smaller GPU buffer size.


Other options in Unity are the DrawMeshInstanced and the DrawMeshInstancedIndirect scripting APIs. The former allows for 1023 instances per batch, and the latter does not have a limit. However, when using both of these options, you need to manage frustum, occlusion and distance culling for your instances manually.


GPU Instancer uses the indirect instancing method in the background and manages all culling operations in the GPU by making use of Compute Shaders. Furthermore, GPUI gives you a user friendly interface to add indirect instancing support for your Prefabs (with LOD groups, child hierarchies etc.) and your Unity Terrains in a few clicks - without writing any code.


GPUI also builds additional features on its core by allowing you to use shadows, select shadow LODs, add/remove/update instances automatically, generate billboards and a lot more. Advanced features also include support for a no-game object workflow through an easy to use scripting API.


How to convert shaders manually to support GPU Instancer?

GPUI has a system that automatically converts most shaders to work with itself. This system keeps track of shader changes and handles re-conversions automatically as well. Including most of the shaders created by shader creation editors like Amplify Shader Editor. But in some special cases, it might be needed to change the shader manually to support GPU Instancer.

1. For vertex/fragment and surface shaders:

...
Pass {
    ...
    CGPROGRAM
    #include "UnityCG.cginc"
    #include "GPUInstancer/Resources/Shaders/Include/GPUInstancerInclude.cginc"
    #pragma multi_compile_instancing
    #pragma instancing_options procedural:setupGPUI
    ...
    ENDCG
}
...


2. SRP Shaders:

HLSLPROGRAM
...
#include "LWRP/ShaderLibrary/InputSurfacePBR.hlsl"
#include "LWRP/ShaderLibrary/LightweightPassLit.hlsl"
#include "GPUInstancer/Resources/Shaders/Include/GPUInstancerInclude.cginc"
#pragma instancing_options procedural:setupGPUI
ENDHLSL


3. Amplify Shader Editor directives:

Amplify Shader Editor Directives.png


How to build for Android platforms?

  • GPU Instancer requires OpenGL ES 3.1 or Vulkan API for Android platforms. Unity Editor currently can not emulate GLES 3.1. It emulates GLES 3.0 which does not support Compute Shaders. So currently it is not possible to test GPU Instancer with GLES 3.1 at Unity Editor. You can use Unity Editor with "No Emulation" and make your mobile tests with a build.

androidemulation.png

  • Another reminder is that you should not forget to enable the "Require ES3.1" under Edit->Project Settings->Player->Other Settings. Otherwise Unity will disable the Compute Shaders.

androidgles.png

  • Older versions of Unity have some bugs for some GPU models on Android devices. So if you want to make an Android game, it is recommended to use the latest Unity version.

How to define multiple prefabs at once?

If you want to define multiple prefabs at once, you can do it easily with the following steps:

1. Lock the Prefab Manager Inspector window.

gpui-t1.png

2. Select multiple prefabs from Project window.

gpui-t2.png

3. Drag and drop all the selected prefabs on Add button on the Prefab Manager inspector window. This will define all of the dragged prefabs as a prototype.

gpui-t3.png

4. Afterwards, if you wish to change the settings for all of the prototypes at once, you can select the prototype ScriptableObjects under GPUInstancer/PrototypeData/Prefab folder and change the settings in the Inspector window.

gpui-t4.png

How to render prefab instances without instantiating GameObjects?

With GPU Instancer, you can render prefab instances without instantiating GameObjects by supplying an array of Matrix4x4s.

    using UnityEngine;
    using GPUInstancer;
     
    public class NoGameObject : MonoBehaviour
    {
        // reference to Prefab Manager
        public GPUInstancerPrefabManager prefabManager;
        // reference to prefab
        public GPUInstancerPrefab prefab;
        // size of array and buffers
        public int bufferSize;
     
        // transform data array
        private Matrix4x4[] _matrix4x4Array;
     
        // Use this for initialization
        void Awake ()
        {
            // initialize the array with the max size
            _matrix4x4Array = new Matrix4x4[bufferSize];
            // set the data of the array
            for (int i = 0; i < _matrix4x4Array.Length; i++)
                _matrix4x4Array[i] = Matrix4x4.TRS(Random.insideUnitSphere * 15, Quaternion.identity, Vector3.one);
            // initialize the buffers with array
            GPUInstancerAPI.InitializeWithMatrix4x4Array(prefabManager, prefab.prefabPrototype, _matrix4x4Array);
        }
     
        private void Update()
        {
            if (Input.anyKeyDown)
            {
                // change the data of the array
                for (int i = 0; i < _matrix4x4Array.Length; i++)
                    _matrix4x4Array[i] = Matrix4x4.TRS(Random.insideUnitSphere * 15, Quaternion.identity, Vector3.one);
                // update buffers
                GPUInstancerAPI.UpdateVisibilityBufferWithMatrix4x4Array(prefabManager, prefab.prefabPrototype, _matrix4x4Array);
            }
        }
    }
     

How can I Increase Billboard Visibility Distances Beyond Manager Limits?

The max billboard distance is tied to the Max Tree Distance property of the manager if you are using the Tree Manager - or if you are using the Prefab Manager, it is tied to the Max Distance property of the prototype. The Tree Manager limits you to 2500 where the Prefab Manager limits to 10000.

If you need more visibility distance, you can edit the limitations of the corresponding managers from the following lines in the GPUInstancerEditorConstants.cs


public static readonly float MAX_TREE_DISTANCE = 2500;
public static readonly float MAX_PREFAB_DISTANCE = 10000;

Troubleshooting

Batch counts are higher than without GPUI

Increased batch counts usually means that there are prototypes with very few instance counts that are registered to the Prefab Manager.

GPUI works best with prefabs that have high instance counts. The reason for this is related to the nature of GPU instancing. Since prefabs with low instance counts will not gain a noticeable performance boost from GPU Instancing, it is usually better to let Unity handle their rendering. Unity uses draw call batching techniques on the background (such as dynamic batching). These techniques depend on the CPU to run and tax their operations on the CPU memory. When there are many instances of the same prefabs, these operations turn out to be too costly and the reduction in batch counts dwarf in comparison to GPU Instancing. But where the instance counts are noticeably low, the cost on the CPU when using these techniques becomes trivial - yet they will still reduce batch and draw call counts. While using GPU instancing, on the other hand, since meshes are not combined, every mesh/material combination will always be one draw call.

In short, the lowest batch counts (and the best performance gain) can be achieved by using GPUI with high instance counts. Therefore, rendering everything with GPUI where some prefabs have very few instance counts is not recommended.

The rule of thumb to keep in mind is to have only the prefabs that have high instance counts rendering with GPUI, while minimizing the amount of prototypes as much as possible. For more information on instance counts, you can check the page for best practices.

Shader Variant not Showing in Build

This issue can be solved by changing the material on your prefab to use the GPUI version of the shader (e.g. "GPUInstancer/Standard (Specular setup)") instead of the original (e.g. "Standard (Specular setup)").


The issue here is related to the way Unity handles shader variants. GPUI uses it's own version of the Standard Specular Shader, and switches to this shader at play mode. This shader is in the /resources folder, so it enters the build. However, since you are using the the variant (e.g. cutout) of the original shader, and Unity does not see the GPUI version of this variant on the prefab, it ignores this variant for the GPUI version during build time.


This is true for all the shaders that feature a variant via the "#pragma shader_feature" keyword.

Compatibility with Other Assets

Amplify Impostors

MapMagic World Generator

Gaia

AQUAS

Vegetation Studio / Vegetation Studio (Pro)