Difference between revisions of "GPU Instancer:FAQ"

From GurBu Wiki
Jump to: navigation, search
(What are the Known Limitations?)
(When Using HDRP, I cannot See the Occlusion Culling Feature Working)
Line 924: Line 924:
  
 
In short, the occlusion culling feature is working in HDRP and as expected - however it is currently not possible to confirm it with a side by side comparison of game and scene views. Hopefully Unity will fix this in a future version.
 
In short, the occlusion culling feature is working in HDRP and as expected - however it is currently not possible to confirm it with a side by side comparison of game and scene views. Hopefully Unity will fix this in a future version.
 +
 +
<div style="clear: both"></div>
 +
<br>
 +
 +
 +
=== Why is Oculus Quest (any version) not supported and will it be supported in the future? ===
 +
----
 +
 +
 +
While GPU Instancer supports VR, OpenGL ES 3.1 and Vulkan, we encountered graphical issues specific to Oculus Quest while using it with GPUI in some cases. We are guessing that there are unspecified GPU limitations or bugs on some Unity versions, however we were not able to confirm these.
 +
So while some are currently using GPUI with Quest without issues, it is not guaranteed that it will work in every case. That is why Oculus Quest is not supported.
 +
It is currently not in our roadmap to support Oculus Quest and we will not accept refund requests or look into bug reports related to it.
  
 
<div style="clear: both"></div>
 
<div style="clear: both"></div>

Revision as of 12:40, 13 June 2022

About | Crowd Animations | Features | Getting Started | Terminology | Best Practices | API Documentation | F.A.Q.


Contents

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)
  • 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, PS5, Xbox One)

Note: Oculus Quest (any version) is not supported.

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


Crowd Animations Requirements

Requirements for the Crowd Animations Extension are the same with GPU Instancer, however please note that mobile platforms support is currently at an experimental stage for Crowd Animations.


What are the Known Limitations?


There are certain limitations that are introduced by the way Indirect GPU instancing works and/or how Unity handles it. Below you can find a list of the known limitations.


Lighting Limitations:

  • Baked Global Illumination is not supported for instanced prototypes (baked lighting data will be ignored for GPUI instances, but you can use it for the rest of the scene objects)
  • Light Probes are not supported (all the instances share the same probe value).
  • Only for Unity versions prior to 2018.2.0f2:' In forward rendering mode, only directional and ambient lights are supported for instanced prototypes. (This limitation does not apply to deferred rendering mode.)
  • Reflection probes: instanced prototypes with reflective surfaces do not show reflections in forward rendering mode. This limitation does not apply to deferred rendering mode. Also, instanced prototypes still appear on other reflective surfaces in forward rendering mode - they just don't show reflections themselves. Please also note that URP only uses forward rendering currently - so this also applies to URP.


Shader Limitations:

  • Geometry shaders are not supported.
  • Tesselation shaders are not supported


Android Limitations:

  • It requires special care to decide what you can render when targeting Android Devices. Android platforms have inherent GPU limitations and target devices must both support GPU instancing and fare good with it. For example the amount of objects possible to render would be lower than a desktop platform - where the maximum number of instances and prototypes might vary depending on the devices' GPU limitations. Therefore, you must make sure that the number of prototypes and instances per those prototypes do not exceed the target devices' GPU limitations.


Miscellaneous Limitations:

  • Negative scaling on GameObjects is not supported.


How can I make a Support Request?


For your support requests, please write an e-mail to support@gurbu.com with the following information:

  • Your invoice number(s) (except for pre-purchase questions)
  • Your Unity version number
  • Target platform(s)
  • Packages in use with version numbers (especially render pipelines)


For issues or bug reports, please also include:

  • Any console log related to GPU Instancer
  • Screenshots of the GPUI managers in use
  • Detailed description of the problem and how to recreate it
  • Screenshots and/or videos related to the issue
  • A sample project (e.g. a scene with minimum amount of content to show the problem)


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 GPU 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. Since GPUI automatically generates a copy of the original shader of the material that it configures to work with itself, you are also not limited to using the Standard and Surface shaders and can use most custom shaders out of the box with it.


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 can I convert shaders manually to support GPU Instancer?



GPUI has a system that automatically generates a converted version of most shaders to work with itself. This system keeps track of shader changes and handles re-conversions automatically as well. This includes 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. GPUI detects if a shader is compatible with it and will not generate a separate shader if that is the case. Here is the information you need to manually edit your shaders to support GPUI.


Surface Shaders


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


Since the #pragma multi_compile_instancing directive is automatically added to the generated code from surface shaders, you do not need to include it. However, if you have a additional passes (such as a shadowcaster pass), you need to add support to these passes as well (see Vertex/fragment Shaders below)

Please also note that if your shadows are not showing correctly (e.g. they show on camera position), you can add the addshadow option to your surface pragma directive to have your surface shader generate a shadow pass for you. This will make sure that your shadow pass is also setup for GPUI. If you do not define the addshadow option, and if your surface shader also does not have a shadow pass, Unity will use the shadow pass from the defined fallback shader, and this shader may not be setup for GPUI.

Vertex/fragment Shaders

For all passes:


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


You also need to add instancing setup to your input structs and vertex functions if you don't already have it:


struct appdata_custom
{
    ...
    UNITY_VERTEX_INPUT_INSTANCE_ID
}


v2f vert( appdata_custom v )
{
    v2f o;
    UNITY_SETUP_INSTANCE_ID(v);
    ...
    return o;
}


URP Shaders

For all passes, you need to include the multi_compile_instancing and the instancing_options procedural:setupGPUI pragma directives. Please note that the GPUInstancerInclude.cginc must be included after the URP include files:


...
Pass {
    ...
    HLSLPROGRAM
    ...
    #pragma multi_compile_instancing
    #pragma instancing_options procedural:setupGPUI
    ...
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
 
    #include "GPUInstancer/Shaders/Include/GPUInstancerInclude.cginc"
 
    ...
    ENDHLSL
}
...


Same as with other vertex/fragment shaders above, you also need to add instancing setup to your input struct and vertex function if you don't already have it.


For the vertex input struct:

struct VertexInput
{
    ...
    UNITY_VERTEX_INPUT_INSTANCE_ID
}


For the vertex output struct:

struct VertexOutput
{
    ...
    UNITY_VERTEX_INPUT_INSTANCE_ID
}


The vertex function:

VertexOutputvert(VertexInput v)
{
    VertexOutput o;
    UNITY_SETUP_INSTANCE_ID(v);
    ...
    return o;
}


And the fragment function:

half4 frag(VertexOutput IN)
{
    UNITY_SETUP_INSTANCE_ID(IN);
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
    ...
    return o;
}


HDRP Shaders

Same as with URP shaders. For all passes, you need to include the multi_compile_instancing and the instancing_options procedural:setupGPUI pragma directives. Please note that the GPUInstancerInclude.cginc must be included after the HDRP include files:


...
Pass {
    ...
    HLSLPROGRAM
    ...
    #pragma multi_compile_instancing
    #pragma instancing_options procedural:setupGPUI
    ...
    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/NormalSurfaceGradient.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/FragInputs.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl"
    ...
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/BuiltinUtilities.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialUtilities.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Decal/DecalUtilities.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDecalData.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderGraphFunctions.hlsl"
 
    #include "GPUInstancer/Shaders/Include/GPUInstancerInclude.cginc"
 
    ...
    ENDHLSL
}
...


Same as with other vertex/fragment shaders above, you also need to add instancing setup to your input struct and vertex function if you don't already have it.


For the vertex input struct:

struct AttributesMesh
{
    ...
    UNITY_VERTEX_INPUT_INSTANCE_ID
}


For the vertex output struct:

struct PackedVaryingsMeshToPS
{
    ...
    UNITY_VERTEX_INPUT_INSTANCE_ID
}


The vertex function:

PackedVaryingsMeshToPSVert(AttributesMesh inputMesh)
{
    PackedVaryingsMeshToPS outputPackedVaryingsMeshToPS;
    UNITY_SETUP_INSTANCE_ID(inputMesh);
    UNITY_TRANSFER_INSTANCE_ID(inputMesh, outputPackedVaryingsMeshToPS);
    ...
    return outputPackedVaryingsMeshToPS;
}


And the fragment function:

void Frag(PackedVaryingsMeshToPS packedInput, OUTPUT_GBUFFER(outGBuffer) #ifdef _DEPTHOFFSET_ON, out float outputDepth : SV_Depth #endif)
{
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(packedInput);
    UNITY_SETUP_INSTANCE_ID(packedInput);
    ...
}


Amplify Shader Editor directives

Amplify Shader Editor Directives for GPUI

It is important to add support from the ASE window rather than the code since ASE would overwrite your changes if you save the shader again. You can use the additional directives as shown in the picture. Since the GPUInstancerInclude.cginc include directive is path relative, it is recommended to use the direct file reference feature of ASE for this file as shown in the picture. You can find the file to reference under GPUInstancer/Shaders/Include


Please note, however, when using ASE's SRP templates (LWRP or HDRP), the injected GPUI pragmas are generated above the LWRP or HDRP includes. You either need to manually edit the generated shader code to put them below the SRP includes or omit this step altogether to have GPUI auto-convert the shader to work with itself.



ShaderGraph Setup


GPUI ShaderGraph v4.x Node
GPUI ShaderGraph v5.x (and later) Node


You can find two packages that contain two versions of the ShaderGraph GPUI setup node when you download GPU Instancer. For ShaderGraph versions 4.x, you can extract the package:


GPUInstancer/Extras/GPUI_ShaderGraph_v4.x_Node.unitypackage


For ShaderGraph 5.x and above, you can extract the package:


GPUInstancer/Extras/GPUI_ShaderGraph_v5.x_or_Later_Node.unitypackage


After importing the package that corresponds to your ShaderGraph version, GPU Instancer will add a ShaderGraph node in your project:

  • You can find the ShaderGraph 4.x node under the GPU Instancer category with the name GPU Instancer Setup.
  • You can find the ShaderGraph 5.x (and later) node under the Sub Graphs category with the name GPU Instancer Setup.


Both of these nodes work as pass-through nodes and they take any position nodes as input, so that you can add it as the final step of your (vertex) position node network.


You can connect the ShaderGraph 4.x node to the Position output and the ShaderGraph 5.x (and later) node to the Vertex Position output of your graphs to enable GPUI support for your shaders.



Better Shaders Setup


Better Shaders Setup


To add GPUI support to Better Shaders, simply add the Stackable_GPUInstancer to the Shader List on your stacked shader file.



Crowd Animations Shaders Setup


Setting up your shaders to work with Crowd Animations requires a few additional / different steps. For more information on this, you can take a look at this wiki article.


What are the Build Settings for Android platforms?



Build Settings for Android


GPUI relies heavily on Compute Shaders for its operations in the GPU. In mobile platforms, Compute Shaders are usually supported by the higher-end devices. The requirement for Compute Shaders in the Android systems is at least Open GL ES 3.1 or the Vulkan API.


GPUI does not need any additional settings when targeting Vulkan; however, you need to enable Open GL ES 3.1 support when targeting the Open GL ES API.


To do this, you can simply enable the Require ES3.1 checkbox under:

Edit->Project Settings->Player->Other Settings.


Otherwise Unity will disable the Compute Shaders and your build will run without GPUI enabled.


Please also note that older versions of Unity have some bugs for some of the GPU models on Android devices. If you're working on an Android game, it is recommended to use the latest Unity LTS version.


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 GPUI settings window: Edit -> Preferences -> GPU Instancer


How can I Setup my Instances to have Material Variations on them?



Material Variations on Instances of a Single Prototype


GPU Instancing works by drawing a single mesh and material combination multiple times on the screen. This is why GPUI creates its prototypes from Prefab definitions where it uses the mesh and material information for each renderer the Prefab has and issues drawcalls for them seperately. Thus, out of the box, there would not be any variations for the materials of the prefab instances. However, GPUI offers a solution for having material variations through the GPU Instancer API. The included demo scene ColorVariationsDemo is intended as an example usage of this, so you can take a look at it to get started. Please note, however, that this is an advanced feature and will require you to do some scripting and shader editing.


To setup instance based variations, you basically need to define a buffer, register this buffer to the GPUI prototype instances (and the Prefab Manager) and modify your shader to accept this buffer. The contents of the buffer (variations) can then be set and updated during runtime. Therefore, the setup has a C# scripting part and a shader scripting part.


If you are using Amplify Shader Editor, you can skip steps 1 and 2 and follow the dedicated section for this below.



1. On the MonoBehaviour Script:


Here you can define the buffer and register it to the GPUI instances and a Prefab Manager. You can then update the instances through the GPU Instancer API to make GPUI use this buffer for variations of the instance material. The following example generates a number of GPUI prototype instances, defines a color variations buffer and registers it to the GPUI instances in the Start method. It then updates the buffer with random colors in the Update method, making the generated instances change to a random color every update without breaking instancing. The required references are to the GPUI Prototype (the Prefab itself can be assigned for this since the GPUI prototype component lives on the Prefab) and the active Prefab Manager in the scene.


  1.  
  2.     public class ColorVariations : MonoBehaviour
  3.     {
  4.         // The reference to the Prototype (the prefab itself can be assigned here since the GPUI Prototype component lives on the Prefab).
  5.         public GPUInstancerPrefab prefab;
  6.         // The reference to the active Prefab Manager in the scene.
  7.         public GPUInstancerPrefabManager prefabManager;
  8.         // The count of instances that will be generated.
  9.         public int instances = 1000;
  10.         // The name of the buffer. Must be the same with the StructuredBuffer in the shader that the Mateiral will use. See: "ColorVariationShader_GPUI.shader".
  11.         private string bufferName = "colorBuffer";
  12.         // The List to hold the instances that will be generated.
  13.         private List<GPUInstancerPrefab> goList;
  14.         void Start()
  15.         {
  16.             goList = new List<GPUInstancerPrefab>();
  17.             // Define the buffer to the Prefab Manager.
  18.             if (prefabManager != null && prefabManager.isActiveAndEnabled)
  19.             {
  20.                 GPUInstancerAPI.DefinePrototypeVariationBuffer<Vector4>(prefabManager, prefab.prefabPrototype, bufferName);
  21.             }
  22.             // Generate instances inside a radius.
  23.             for (int i = 0; i < instances; i++)
  24.             {
  25.                 GPUInstancerPrefab prefabInstance = Instantiate(prefab);
  26.                 prefabInstance.transform.localPosition = Random.insideUnitSphere * 20;
  27.                 prefabInstance.transform.SetParent(transform);
  28.                 goList.Add(prefabInstance);
  29.                 // Register the variation buffer for this instance.
  30.                 prefabInstance.AddVariation(bufferName, (Vector4)Random.ColorHSV());
  31.             }
  32.             // Register the generated instances to the manager and initialize the manager.
  33.             if (prefabManager != null && prefabManager.isActiveAndEnabled)
  34.             {
  35.                 GPUInstancerAPI.RegisterPrefabInstanceList(prefabManager, goList);
  36.                 GPUInstancerAPI.InitializeGPUInstancer(prefabManager);
  37.             }
  38.         }
  39.         void Update()
  40.         {
  41.             // Update the variation buffer with a random set of colors every frame, thus changing instance colors per instance every frame.
  42.             GPUInstancerAPI.UpdateVariation(prefabManager, goList[Random.Range(0, goList.Count)], bufferName, (Vector4)Random.ColorHSV());
  43.         }
  44.     }
  45.  


The important parts are as follows:


Defining the name of the varitation buffer (it is important to notice that the name of this buffer must match the StructuredBuffer on the shader exactly):

        private string bufferName = "colorBuffer";


Defining the variation buffer to the Prefab Manager. Please note that you define which type of variation you will use while defining the prototype variation buffer to the manager. In this example, we use a Vector4 since we are using color variation. This is a generic method and you can read more on it from its API documentation.

        GPUInstancerAPI.DefinePrototypeVariationBuffer<Vector4>(prefabManager, prefab.prefabPrototype, bufferName);


Registering the variation buffer per instance:

        prefabInstance.AddVariation(bufferName, (Vector4)Random.ColorHSV());


And updating the variation buffer later on if you wish:

        GPUInstancerAPI.UpdateVariation(prefabManager, goList[Random.Range(0, goList.Count)], bufferName, (Vector4)Random.ColorHSV());


2. On the Material's Shader:


For this setup to work, you also need the shader that the material will use to recognize the buffer you have defined above. This can be achieved by defining a StructuredBuffer property in the shader with exactly the same name as you defined the buffer in the MonoBehaviour script.


You can define the structured buffer among the shader properties as such:

  1.         #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED       
  2.             StructuredBuffer<float4> colorBuffer;
  3.         #endif
  4.  


And then use it as you wish by referencing the instance by using gpui_InstanceID. This is variable stores the instance index on the variation buffer. The following example, in line with the color variations example, modifies the Albedo of the surface shader with the variations buffer. In this example we set the color property in the vertex function (colorVariationVert) and pass it to the surface function (surf) to modify the final color:


The input struct:

  1.  
  2.         struct Input {
  3.             float2 uv_MainTex;
  4.             float4 colorVariation;
  5.         };
  6.  


We use the variation buffer to modify the colorVariation property of the input struct in the vertex function:

  1.  
  2.          void colorVariationVert (inout appdata_full v, out Input o) {
  3.              UNITY_INITIALIZE_OUTPUT(Input, o);
  4.              o.colorVariation = _Color;
  5.              #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
  6.                 
  7.                 o.colorVariation = colorBuffer[gpui_InstanceID];
  8.             #endif
  9.          }
  10.  


And use that colorVariation property to modify the final Albedo in the surface function:

  1.  
  2.         void surf (Input IN, inout SurfaceOutputStandard o) {
  3.             // Albedo comes from a texture tinted by color
  4.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * saturate(IN.colorVariation);
  5.             o.Albedo = c.rgb;
  6.             // Metallic and smoothness come from slider variables
  7.             o.Metallic = _Metallic;
  8.             o.Smoothness = _Glossiness;
  9.             o.Alpha = c.a;
  10.         }
  11.  


The important part here is getting the variation buffer index of the instance by accessing the GPUI instance id with the gpui_InstanceID. And using that index to access the variation in the buffer:

                o.colorVariation = colorBuffer[gpui_InstanceID];


You can find this example shader and the corresponding demo scene included in the package under GPUInstancer/Demos/ColorVariations


Using Variations with Amplify Shader Editor

You can download and example shader that shows how to use a variations node for Amplify Shader Editor from this link.


You can follow the following three steps to do this:


1. Firstly, we need to define the StructuredBuffer we will be using for variations. Create a cginc file containing only this StructuredBuffer definition. In this example we are naming this file as GPUIVariationDefinition.cginc:

  1.         #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED       
  2.             StructuredBuffer<float4> colorBuffer;
  3.         #endif
  4.  


2. Then, include this file in the Additional Directives section of the Amplify Shader Editor as such:

Ase-variations-node-1.png


Note that the other directives in this image are also required for setting up GPUI with ASE as described in this article.


3. Finally, create a custom expression node in Amplify Shader Editor that will output this buffer (as shown in the example below):

Ase-variations-node-2.png


The contents of this custom expression node essentially use the buffer based on instance id as such:

  1. #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
  2.     return colorBuffer[gpui_InstanceID];
  3. #else
  4.     return color;
  5. #endif


How Can I (Automatically) Add/Remove Prototype Instances



GPU Instancer allows you to add and remove instances during runtime. This can be done automatically without writing any additional code, in which case GPUI will keep track of new instantiations (or destroying) of the prefab instances and will handle the prototype GPU buffers accordingly. For more control, you can also use the API to handle this yourself - or completely register and initialize the managers with exactly the instances you want. You can see below how to use each option:


The Auto. Add/Remove Instances Option


1. The easiest way to add/remove instances at runtime is to enable Auto. Add/Remove Instances option under the Runtime Settings.


When this is enabled, the Prefab Manager will add a component called GPUInstancerPrefabRuntimeHandler on the prefab object and will handle all runtime changes automatically when new instances are instantiated or existing ones are destroyed.


The Add/Remove Instances at Runtime Option


2. Optionally, you can add prefab instances through the GPU Instancer API methods AddPrefabInstance and RemovePrefabInstance.


Please keep in mind that the 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 a high enough number to add all the prefab instances generated at runtime.


3. Alternatively, you can use the GPU Instancer API to register the prefab instances and reinitialize the Prefab Manager for complete control. This can be done by first calling the RegisterPrefabInstanceList method and then calling the InitializeGPUInstancer method.


The following code demonstrates how this can be done:


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 Can I Use a no-GameObject Workflow?



GPU Instancer allows you to work with a no-GameObject workflow to maximize your scene performance. By using this workflow, you can render prefab instances without instantiating GameObjects and therefore not using any CPU time for them. Please not that this is an advanced feature and requires a good understanding of Transformation Matrices and GPU Instancing.


The basic idea behind this workflow is supplying an array of Matrix4x4s to the GPU Instancer API to initialize the instances. The included demo scene PrefabsWithoutGameObjects is designed to demonstrate an example usage of this workflow, so it can be a good starting point.


The below script is also is an example that demonstrates a basic usage. What this script does is to first initialize the GPU Instancer Prefab Manager with matrix data that represents transforms at random positions inside a radius of 15 units in the Awake method. Then, if a key is pressed, it updates the matrices with new random positions:



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 Change the Camera at Runtime?


GPUI keeps a reference to the scene camera, and auto-detects the cameras with the "Main Camera" tag. You can also specify a specific camera for use with a given manager. However, if you wish to switch cameras at runtime, you need to call the SetCamera API method from your script right after you enable/instantiate your new camera.


Alternatively, you can add the included GPUInstancerCameraHandler Component on your cameras to have GPUI automatically handle this for you.


How Can I use WindZones with TreeCreator trees?



GPUI would use the WindZone that exists in your scenes for wind effects on TreeCreator trees out of the box. However, if you add a WindZone or make changes to your WindZone at runtime, you need to use the following line of code right after adding/modifying your WindZone:


Shader.SetGlobalVector("_Wind", GPUInstancerManager.GetWindVector());


Please note that this is only necessary for TreeCreator trees. SpeedTrees and other custom trees would work out of the box as expected.


When Using HDRP, I cannot See the Occlusion Culling Feature Working



When using HDRP, if you use the scene view and the game view side by side, Unity uses the camera preview's depth texture on the scene and game views. This is a Unity bug; the result being the depth texture is a downscaled version of the expected depth texture. The following screenshots illustrate this problem:


OcclusionCullingHDRP-1.png


This screenshot uses the GPUI Hi-Z occlusion Generator in debug mode. This mode overlays the depth texture so you can inspect it. You can see that, on the upper (game) view, the depth texture being used is small and does not scale over the window. Since GPUI uses the information from this texture to do occlusion culling, this results in objects not being culled when these two views are put side by side. However, occlusion culling in HDRP actually works; and here is how you can test it: You can add the GPU Instancer GUI Info component on a game object, and enable the Show Rendered Amount option on it. Please note that this is for debug purposes only and would slow down the performance of GPUI.


When you run the game and have only the game window showing with this, you will see the instances are being culled since the rendered amounts will be decreasing when camera is behind occluders.


In short, the occlusion culling feature is working in HDRP and as expected - however it is currently not possible to confirm it with a side by side comparison of game and scene views. Hopefully Unity will fix this in a future version.



Why is Oculus Quest (any version) not supported and will it be supported in the future?



While GPU Instancer supports VR, OpenGL ES 3.1 and Vulkan, we encountered graphical issues specific to Oculus Quest while using it with GPUI in some cases. We are guessing that there are unspecified GPU limitations or bugs on some Unity versions, however we were not able to confirm these. So while some are currently using GPUI with Quest without issues, it is not guaranteed that it will work in every case. That is why Oculus Quest is not supported. It is currently not in our roadmap to support Oculus Quest and we will not accept refund requests or look into bug reports related to it.


Crowd Animations Questions


How Can I Setup a Custom Shader to Work with Crowd Animations?



The Crowd Animations Extension works out of the box with materials using the Standard, Standard (Specular) and Autodesk Interactive shaders. However, if you wish to use a custom shader with CA, you need to manually setup the shader for work with it. Please note that this requires a working knowledge of shaders.


You can find all the necessary information on setting up a shader to work with Crowd Animations in the this section of the Getting Started wiki page.


Troubleshooting


I See Artifacts / Instances don't Show / Show at Incorrect Locations when Using a Custom Shader



If you are using a custom vertex/fragment shader, the shader needs to be setup for instancing. GPUI sets shaders up for working with itself, but cannot automate general instancing setup since there is no good way to generalize this.


If you are using a custom shader on your instances, or if you are using an asset from the Asset Store, this will most likely be the reason why your instances do not show correctly. To setup your shaders with GPUI in this case, you can take a look at setting vertex/fragment shaders up manually to work with GPU Instancer.


Shadows on the Prefab Instances Look Blocky/Wrong



Using the Shadow Pass of the Original Shader


By default, GPUI uses a custom, lightweight "shadows only" shader to render the shadows of the prototypes that are defined on a Prefab Manager. Using this shader helps increase the shadow performance slightly more; especially if the original shader is using a shadow pass generated by a surface shader (using the addshadow directive). In most cases this shader is enough to render the prototype flawlessly; however, if the original shader uses vertex animation and/or alpha cutoff, then the shadows might not look right. Typical cases of this are when adding tree prefabs. In these cases you can enable the Shadow with Original Shader option under the Shadow settings for the prototype (in the Prefab Manager). This will use the shadow pass of the original shaders of the prefab and the shadows should then look right.



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.


GPUI not working while targeting Android platforms



Disabling OpenGL ES 3.0 Emulation in Android Projects

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.


If you leave the Emulation mode on, and if you try running your scene with a GPUI manager in it, Unity will throw the following error in the console and GPUI will be deactivated:


Target Graphics API does not support Compute Shaders. Please refer to Minimum Requirements on GPUInstancer/ReadMe.txt for detailed information.


In order to solve this, you can use Unity Editor in No Emulation mode as shown in the picture to the right and make your mobile tests with a build. The editor will then run in the original mode of your operating system (e.g. Direct3D 11 on Windows).


Please also note that Unity switches back to the emulation mode regularly, so you might need to switch back often.


For information on how to use build settings for Android devices you can look at this section.



With Projectors in my Scene, I see Artifacts/Performance Hit


Unity Projectors can cause a performance hit and/or artifacts on the screen when using GPU Instancer. The reason for this is related to how Unity handles projectors internally. There is, however, a very easy solution to workaround this by using Layers. The steps are as follows:


Creating a Layer for GPUI

1) You can start by creating a new Layer (e.g. GPUIRenderingLayer)

Defining the Rendering Layer for Prefabs

2) Setting this Layer to the prefabs are enough for prefab instancing with Prefab Manager, Tree Manager and for the prefab type prototypes in the Detail Manager.

Defining the Rendering Layer in the Manager

3) For the Detail Textures, you can set this new Layer to the Detail Texture Layer of the Detail Manager.

Ignoring the GPUI Rendering Layer in the Projector

4) You can then set the projector to ignore the GPUI Rendering Layer as shown in the picture to the left.


Transperent Materials Look Inside-Out/Back-to-Front when Used on Prototypes


Materials with transparency can result in unexpected behavior when used with GPU Instancer. Since GPU instancing works by treating all instances as the same, the GPU draws one mesh multiple times without any regard to draw ordering. This will result in wrong draw orders while using transparency, and the typical result would be inside-out or back-to-front looking prototype instances. This can be solved by implementing a form of OIT approximation. Please note, however, that GPUI currently does not include such an implementation so if you are willing to use transparent objects with GPUI, you should manually implement an OIT solution.


Screen Space Post Processing Effects (e.g. Ambient Occlusion) Look Wrong



Graphics Settings Custom Depth Shader Setup

If you are having issues with some post processing effects (like Ambient Occlusion) in Forward Rendering mode, you can use the included custom depth-normals shader instead of the built in one to solve these issues. You can find this shader in:


GPUInstancer/Shaders/Internal-DepthNormalsTexture_GPUI.shader


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.



Instances Close to the Camera Flicker or Disappear when using Occlusion Culling


If you are having issues where your instances that are close to the camera are flickering and/or disappearing, this might be caused by the occlusion culling feature. This issue is more likely to happen especially with large instances when they are near the camera. To solve this, you can first try disabling occlusion culling on the manager to test this. If the problem is solved when you do that, you can turn occlusion culling back on and try increasing the Occlusion Cull Offset and Occlusion Cull Accuracy settings under the Culling section. If the problem persists, you can still keep using occlusion culling by adjusting the minimum distance where any kind of culling will happen. You can do this by increasing the Min. Culling Distance setting until the flickering/disappearing does not happen any longer.


When Using the Detail Manager, My Grass Looks Different than It does on the Unity Terrain



The default foliage shader that GPUI uses is based on the Standard Lighting Model (as opposed to the Lambert that Unity uses on the terrain details in the Standard Pipeline). This might result in different looks of detail prototypes than without GPUI. If tweaking the Foliage Shader Properties is not working out for you, you can use the Lambert version of the Foliage shader in the project instead (or any other material with a third party shader).


If you are using the Standard Pipeline and if you wish to use the Lambert version of the Foliage Shader for all your details, you can create a custom material with the GPUInstancer/FoliageLambert shader for each of your texture type detail prototypes and use it as a custom material in the Detail Manager for the corresponding prototypes.


Flares don't Show up with Occlusion Culling on


GPU Instancer Preferences

This issue is related to how Unity renders its Flare components, and can be solved by changing GPUI's preferred occlusion culling method. You can use the GPU Instancer Preferences to do this; simply change the Occlusion Culling Type to Compute Shader as seen in the picture.



Compatibility with Other Assets

GPU Instancer works out of the box together with most other Unity Asset Store assets (or requires minimal effort to set up). With some assets, however, it will simply not work together because of the nature of the two assets. Assets that rely on Mesh Combining or their own rendering solutions fall into this latter category.


As GurBu Technologies, we are always up for integration with other assets. If you are an Asset Store developer, please contact us and we can investigate possible integrations.


In this section, you can find a list of some commonly used assets that are already known to work or not with GPUI.


Amplify Shader Editor

GPUI works out of the box with ASE shaders. GPUI creates a copy of your ASE shader and configures it to work with itself. Any updates will also be reflected on the created shader. At runtime, GPUI use this converted shader for its prototypes where the material has the original shader. However, if you don't want your shader to be duplicated, you can also check the above description to see how you can manually use the directives necessary for GPUI in your ASE shaders.


Please note, however, that Unity does not support tessellation and GPU instancing at the same time, so tessellated ASE shaders won't work with GPUI as well.


Amplify Impostors

Using a Custom Billboard (Amplify Impostors)


GPUI works out of the box with Amplify Impostors. You can define any Impostor Prefab as a GPUI prototype. GPUI will also use the impostor if it is an a LOD level of the prefab.


Alternatively, you can use the Use Custom Billboard option under the Billboard Settings in all managers and assign the mesh and material that you can generate with Amplify Impostors. This will allow you to keep using GPUI's billboard settings for the selected prototype but render the billboard with Amplify Impostors.


Please note that in order for imposter shadows to work properly, you need to enable the Shadow with Original Shader setting in the manager.

Amplify Occlusion

GPUI works out of the box with Amplify Occlusion in Deferred rendering mode. In Forward rendering, you can use the included custom depth-normals shader instead of the Unity built-in one. This setup is described here.


MapMagic World Generator

GPUI - MapMagic Integration

GPU Instancer has a built-in integration with MapMagic World Generator. For more information on using GPUI with your MapMagic Terrains, you can refer to this wiki aricle


AQUAS

AQUAS works out of the box with GPU Instancer. However, the AQUAS water planes use two Projectors for water caustics - and these projectors cause a performance hit when using GPU Instancer. There is a very easy solution to overcome this; the steps are as follows:


Creating a Layer for GPUI

1) GPUI includes a feature where you can define a layer that you wish to use for the texture details in the Detail Manager. So you can create a new Layer first (e.g. GPUIRenderingLayer)

Defining the Rendering Layer in the Manager

2) Then set this new Layer to the Detail Texture Layer of the Detail Manager. For all prefabs, GPUI uses the layer of the prefab for this purpose.

Aquas Caustics Projectors

3) Finally, you can set this as the Ignore Layer for the AQUAS caustic projectors. There are two of them under the Aquas Water Plane object.

Ignoring the GPUI Rendering Layer in the Projector

4) You can set ignore the GPUI Rendering Layer as shown in the picture to the left.


Vegetation Studio / Vegetation Studio (Pro)

Since Vegetation Studio uses its own rendering system, it is not possible for GPUI and VS to work on the same objects. However, if you wish to use VS and GPUI together, you can still use GPUI for prefabs that you do not define in VS.


Nature Manufacture - Meadow Environment

Material settings in the inspector

Nature Manufacture's Meadow Environment asset works out of the box with GPUI. However, when detail prototypes are used as prefabs, a setting in the materials of these prefabs can cause unexpected distance culling. If your prefab type prototypes are culled before the Max Culling distance that you set in the manager, you can increase the CullFarStart property in the prefab's material:


Custom Tree Importer (CTI)


In general, assets created with CTI (such as Tropical Forest Pack) mostly work out of the box with GPUI. In the Built in (Standard) Render Pipeline, both forward and deferred rendering modes work as expected without any additional setup necessary for the bark and leaf materials that use the corresponding CTI shaders. This also includes all CTI shader features such as wind and translucency.


There are, however two issues that needs to be addressed. The first of these is that some assets created with CTI use the tessellated version of the shaders. These will not work with GPUI since Unity does not support Tesselation and GPU Instancing together.


The second issue is that the billboard LODs for the trees use Unity's Billboard Renderer. This renderer is by default ignored by GPUI; however to render a billboard LOD for the tree prototypes it is enough to simply enable the Generate Billboard option in the Billboard Settings section of the manager and click on the Generate Billboard button:


Manager Billboard Settings


Here is an example tree billboard from the Tropical Forest Pack:


GPUI Generated Billboard


Please also note that when using trees with CTI shaders, you should enable the Shadow with Original Shader option in the manager for each prototype if you will render your prototypes with shadows. Since CTI shaders have features such as wind and alpha testing, this is important to make the shadows look right:


CTI-ShadowWithOriginalShader.png


Finally, if you wish to use CTI shaders in a Scriptable Render Pipeline (such as HDRP or URP) with GPUI, you need to add the GPU Instancer Setup Node to the CTI ShaderGraph.


Below is a screenshot from HDRP using this technique and the Cupuacu Tree from the Tropical Forest Pack:


A tree with a CTI shader rendered with GPUI in HDRP