GPU Instancer:FAQ

From GurBu Wiki
Revision as of 00:06, 2 December 2018 by GurBu Admin (talk | contribs) (Batch counts are higher than without GPUI)
Jump to: navigation, search

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 method 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)

How does GPU Instancer work?


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.

GPU Instancer further builds on this concept by applying various culling and LOD operations directly in the GPU and rendering only the relevant instances on the screen. This is why frustum and occlusion culling systems included with GPU Instancer are designed to work with GPU instancing only. What they do is to reduce the number of objects drawn for each prototype that are defined on the GPUI Managers. So let's say you have 1000 instances of a prefab - to draw these, GPU Instancer makes only 1 draw call with the count 1000 (this count is stored in GPU memory). When you use frustum and/or occlusion culling, this count is modified in GPU according to culling results. So it makes 1 draw call with a count less than 1000 - and rendering speed up further because there are less objects that are actually rendered.

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.

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.

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.

using System.Collections.Generic;
using UnityEngine;
 
namespace GPUInstancer.Extras
{
    public class GPUIRegisterPrefabInstances : MonoBehaviour
    {
        // Keeping a static reference to the manager so it can be shared between scenes.
        public static GPUInstancerPrefabManager prefabManager;
        // The list of prefab instances in scene
        public List<GPUInstancerPrefab> prefabInstanceList;
 
 
        // 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).
        // You can fill the list in any way you want.
        public void Reset()
        {
            // Add prefabs in the scene to the list
            prefabInstanceList = new List<GPUInstancerPrefab>(FindObjectsOfType<GPUInstancerPrefab>());
        }
 
        void Start()
        {
            // Find the prefab manager and set it to the static property
            if(prefabManager == null && GPUInstancerAPI.GetActiveManagers() != null)
            {
                GPUInstancerManager manager = GPUInstancerAPI.GetActiveManagers().Find(m => m is GPUInstancerPrefabManager);
                prefabManager = (GPUInstancerPrefabManager)manager;
            }
 
            // Register the prefab instance list to the manager
            if (prefabManager != null && prefabManager.isActiveAndEnabled)
            {
                GPUInstancerAPI.RegisterPrefabInstanceList(prefabManager, prefabInstanceList);
                GPUInstancerAPI.InitializeGPUInstancer(prefabManager);
            }
        }
    }
}

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);
            }
        }
    }
     

Troubleshooting

Batch counts are higher than without GPUI

Increased batch counts usually means that there are prototypes with very few instance counts. GPUI works best with prefabs that have high instance counts. Most commonly made mistake is to render everything with GPUI even while some prefabs have very few instance counts.

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 this, 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)