using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Events;
namespace GPUInstancer
{
public static class GPUInstancerAPI
{
#region Global
///
/// Main GPU Instancer initialization Method. Generates the necessary GPUInstancer runtime data from predifined
/// GPU Instancer prototypes that are registered in the manager, and generates all necessary GPU buffers for instancing.
/// Use this as the final step after you setup a GPU Instancer manager and all its prototypes.
/// Note that you can also use this to re-initialize the GPU Instancer prototypes that are registered in the manager at runtime.
///
/// The manager that defines the prototypes you want to GPU instance.
/// If set to false the manager will not run initialization if it was already initialized before
public static void InitializeGPUInstancer(GPUInstancerManager manager, bool forceNew = true)
{
manager.InitializeRuntimeDataAndBuffers(forceNew);
}
///
/// Sets the active camera for a specific manager. This camera is used by GPU Instancer for various calculations (including culling operations).
/// Use this right after you add or change your camera at runtime.
///
/// The manager that defines the prototypes you want to GPU instance.
/// The camera that GPU Instancer will use.
public static void SetCamera(GPUInstancerManager manager, Camera camera)
{
manager.SetCamera(camera);
}
///
/// Sets the active camera for all managers. This camera is used by GPU Instancer for various calculations (including culling operations).
/// Use this right after you add or change your camera at runtime.
///
/// The camera that GPU Instancer will use.
public static void SetCamera(Camera camera)
{
if (GPUInstancerManager.activeManagerList != null)
GPUInstancerManager.activeManagerList.ForEach(m => m.SetCamera(camera));
}
///
/// Returns a list of active managers. Use this if you want to access the managers at runtime.
///
/// The List of active managers. Null if no active managers present.
public static List GetActiveManagers()
{
return GPUInstancerManager.activeManagerList == null ? null : GPUInstancerManager.activeManagerList.ToList();
}
///
/// Starts listening the specified process and runs the given callback function when it finishes.
/// GPU Instancer does not lock Unity updates when initializing instances and instead, does this in a background process.
/// Each prototype will show on the terrain upon its own initialization. Use this method to get notified when all prototypes are initialized.
/// The most common usage for this is to show a loading bar. For an example, see:
///
/// The event type that will be listened for callback
/// The callback function to run upon initialization completion. Can be any function that doesn't take any parameters.
public static void StartListeningGPUIEvent(GPUInstancerEventType eventType, UnityAction callback)
{
GPUInstancerUtility.StartListening(eventType, callback);
}
///
/// Stops listening the specified process and unregisters the given callback function that was registered with .
/// Use this in your callback function to unregister it (e.g. after hiding the loading bar).
/// For an example, see:
///
/// The event type that was registered with
/// The callback function that was registered with
public static void StopListeningGPUIEvent(GPUInstancerEventType eventType, UnityAction callback)
{
GPUInstancerUtility.StopListening(eventType, callback);
}
///
/// Updates all transform values in GPU memory with the given offset position.
///
/// GPUI Manager to apply the offset
/// Offset Position
public static void SetGlobalPositionOffset(GPUInstancerManager manager, Vector3 offsetPosition)
{
GPUInstancerUtility.SetGlobalPositionOffset(manager, offsetPosition);
}
///
/// Updates all transform values in GPU memory with the given offset matrix.
///
/// GPUI Manager to apply the offset
/// Offset Matrix
public static void SetGlobalMatrixOffset(GPUInstancerManager manager, Matrix4x4 offsetMatrix)
{
GPUInstancerUtility.SetGlobalMatrixOffset(manager, offsetMatrix);
}
///
/// Removes the instances in GPU memory that are inside bounds.
///
/// GPUI Manager to remove the instances from
/// Bounds that define the area that the instances will be removed
/// Adds an offset around the area that the instances will be removed
/// If prototypeFilter parameter is given, only the instances of the given prototypes will be removed.
public static void RemoveInstancesInsideBounds(GPUInstancerManager manager, Bounds bounds, float offset = 0, List prototypeFilter = null)
{
manager.RemoveInstancesInsideBounds(bounds, offset, prototypeFilter);
}
///
/// Removes the instances in GPU memory that are inside collider.
///
/// GPUI Manager to remove the instances from
/// Collider that define the area that the instances will be removed
/// Adds an offset around the area that the instances will be removed
/// If prototypeFilter parameter is given, only the instances of the given prototypes will be removed.
public static void RemoveInstancesInsideCollider(GPUInstancerManager manager, Collider collider, float offset = 0, List prototypeFilter = null)
{
manager.RemoveInstancesInsideCollider(collider, offset, prototypeFilter);
}
///
/// [For Advanced Users Only] Returns the float4x4 ComputeBuffer that store the localToWorldMatrix for each instance in GPU memory. This buffer can be used to make
/// modifications in GPU memory before the rendering process.
///
/// GPUI Manager to get the buffer from
/// Prototype that the buffer belongs to
///
public static ComputeBuffer GetTransformDataBuffer(GPUInstancerManager manager, GPUInstancerPrototype prototype)
{
return manager.GetTransformDataBuffer(prototype);
}
///
/// Changes the LODBias with the given value. Values lower than the LODBias in your Quality Settings will result in higher quality
/// but less performance (e.g. more instances will use LOD0), values higher than the LODBias in your Quality Settings will
/// reduce the quality but increase performance (e.g. less instances will use LOD0)
///
/// GPUI Manager to adjust the LOD sizes
/// New LODBias value
/// If prototypeFilter parameter is given, only the LODBiases of the given prototypes will be changed.
public static void SetLODBias(GPUInstancerManager manager, float newLODBias, List prototypeFilter = null)
{
manager.SetLODBias(newLODBias, prototypeFilter);
}
///
/// Can be used to change the material of a prototype at runtime
///
/// GPUI Manager
/// GPUI Prototype
/// New material to set on the renderer
/// LOD level
/// Renderer index on the LOD level
/// Submesh index of the renderer
public static void ChangeMaterial(GPUInstancerManager manager, GPUInstancerPrototype prototype, Material material, int lodLevel = 0, int rendererIndex = 0, int subMeshIndex = 0)
{
GPUInstancerRuntimeData runtimeData = manager.GetRuntimeData(prototype, true);
if (runtimeData == null)
return;
GPUInstancerRenderer gpuiRenderer = runtimeData.instanceLODs[lodLevel].renderers[rendererIndex];
// Generate proxy GO with a Mesh Renderer to get material property blocks
GameObject proxyGameObject = new GameObject("ProxyGO");
MeshFilter meshFilter = proxyGameObject.AddComponent();
MeshRenderer proxyRenderer = proxyGameObject.AddComponent();
proxyRenderer.materials = new Material[gpuiRenderer.materials.Count];
// Set mesh to proxy GO
meshFilter.mesh = gpuiRenderer.mesh;
// Set new material to runtime data
gpuiRenderer.materials[subMeshIndex] = GPUInstancerConstants.gpuiSettings.shaderBindings.GetInstancedMaterial(material);
// Set new material to proxy GO
proxyRenderer.materials[subMeshIndex] = material;
// Get material property blocks
proxyRenderer.GetPropertyBlock(gpuiRenderer.mpb);
if (gpuiRenderer.shadowMPB != null)
proxyRenderer.GetPropertyBlock(gpuiRenderer.shadowMPB);
// Destroy proxy GO
GameObject.Destroy(proxyGameObject);
// Setup new materials for instancing
GPUInstancerUtility.SetAppendBuffers(runtimeData);
}
///
/// Can be used to change the mesh of a prototype at runtime
///
/// GPUI Manager
/// GPUI Prototype
/// New mesh to set on the renderer
/// LOD level
/// Renderer index on the LOD level
/// Submesh index of the renderer
public static void ChangeMesh(GPUInstancerManager manager, GPUInstancerPrototype prototype, Mesh mesh, int lodLevel = 0, int rendererIndex = 0, int subMeshIndex = 0)
{
GPUInstancerRuntimeData runtimeData = manager.GetRuntimeData(prototype, true);
if (runtimeData == null)
return;
GPUInstancerRenderer gpuiRenderer = runtimeData.instanceLODs[lodLevel].renderers[rendererIndex];
if (gpuiRenderer.mesh.subMeshCount != mesh.subMeshCount)
{
Debug.LogError("ChangeMesh method can not be used with a mesh that has different amount of submeshes than the original mesh.");
return;
}
if (gpuiRenderer.mesh.vertexCount != mesh.vertexCount)
{
int argsLastIndex = gpuiRenderer.argsBufferOffset;
// Setup the indirect renderer buffer:
for (int j = 0; j < gpuiRenderer.mesh.subMeshCount; j++)
{
runtimeData.args[argsLastIndex++] = gpuiRenderer.mesh.GetIndexCount(j); // index count per instance
runtimeData.args[argsLastIndex++] = 0;// (uint)runtimeData.bufferSize;
runtimeData.args[argsLastIndex++] = gpuiRenderer.mesh.GetIndexStart(j); // start index location
runtimeData.args[argsLastIndex++] = 0; // base vertex location
runtimeData.args[argsLastIndex++] = 0; // start instance location
}
runtimeData.argsBuffer.SetData(runtimeData.args);
}
gpuiRenderer.mesh = mesh;
}
///
/// SetInstanceCount can be used to discard instances that are indexed higher than the given index count
///
/// GPUI Manager
/// GPUI Prototype
/// New instance count to set on the runtime data
public static void SetInstanceCount(GPUInstancerManager manager, GPUInstancerPrototype prototype, int instanceCount)
{
GPUInstancerRuntimeData runtimeData = manager.GetRuntimeData(prototype, true);
if (runtimeData == null)
return;
if (instanceCount > runtimeData.bufferSize)
{
Debug.LogError("Instance count can not be higher than the buffer size.");
return;
}
runtimeData.instanceCount = instanceCount;
}
///
/// [OBSOLETE]
///
[Obsolete("GetInstanceDataArray method is obsolete. Use GetInstanceDataNativeArray instead.", true)]
public static Matrix4x4[] GetInstanceDataArray(GPUInstancerManager manager, GPUInstancerPrototype prototype)
{
return null;
}
///
/// Returns the native array that stores the transform data of the instances
///
/// GPUI Manager
/// GPUI Prototype
/// Instance data array
public static NativeArray GetInstanceDataNativeArray(GPUInstancerManager manager, GPUInstancerPrototype prototype)
{
GPUInstancerRuntimeData runtimeData = manager.GetRuntimeData(prototype, true);
if (runtimeData == null)
throw new Exception("GetInstanceDataNativeArray API method must be used after manager is initialized.");
runtimeData.dependentJob.Complete();
return runtimeData.instanceDataNativeArray;
}
///
/// Returns the prototype list of the given GPUI manager
///
/// GPUI Manager
/// Prototype List
public static List GetPrototypeList(GPUInstancerManager manager)
{
return manager.prototypeList.ToList();
}
///
/// Changes prototype's shadow LOD setting
///
/// GPUI Prototype
/// LOD level to change the shadow setting
/// True if LOD level is shadow casting
/// (Optional) Provide an LOD level that shadows will be rendered from
public static void ChangeLODShadow(GPUInstancerPrototype prototype, int lodLevel, bool isShadowCasting, int shadowLOD = -1)
{
int lodIndex = lodLevel * 4;
if (lodLevel >= 4)
lodIndex = (lodLevel - 4) * 4 + 1;
if (isShadowCasting)
prototype.shadowLODMap[lodIndex] = shadowLOD >= 0 ? shadowLOD : lodLevel;
else
prototype.shadowLODMap[lodIndex] = 9;
}
///
/// Releases Compute Buffers for all prototypes defined on the manager
///
///
public static void ReleaseInstanceBuffers(GPUInstancerManager manager)
{
if (manager != null)
GPUInstancerUtility.ReleaseInstanceBuffers(manager.runtimeDataList);
}
///
/// Releases Compute Buffers for the given prototype
///
///
public static void ReleaseInstanceBuffers(GPUInstancerManager manager, GPUInstancerPrototype prototype)
{
if (manager != null)
GPUInstancerUtility.ReleaseInstanceBuffers(manager.GetRuntimeData(prototype));
}
#endregion Global
#region Prefab Instancing
///
/// Registers a list of prefab instances with GPU Instancer. You must use after registering these prefabs for final initialization.
/// The prefabs of the instances in this list must be previously defined in the given manager (either at runtime or editor time).
///
/// The manager that defines the prototypes you want to GPU instance.
/// The list of prefabs instances to GPU instance.
public static void RegisterPrefabInstanceList(GPUInstancerPrefabManager manager, IEnumerable prefabInstanceList)
{
manager.RegisterPrefabInstanceList(prefabInstanceList);
}
///
/// Unregisters a list of prefab instances from GPU Instancer. You must use after unregistering these prefabs for final initialization.
/// The prefabs of the instances in this list must be previously defined in the given manager (either at runtime or editor time).
///
/// The manager that defines the prototypes you want to GPU instance.
/// The list of prefabs instances to be removed from GPU instancer.
public static void UnregisterPrefabInstanceList(GPUInstancerPrefabManager manager, IEnumerable prefabInstanceList)
{
manager.UnregisterPrefabInstanceList(prefabInstanceList);
}
///
/// Clears the registered prefab instances from the prefab manager.
///
/// The manager that defines the prototypes you want to GPU instance.
public static void ClearRegisteredPrefabInstances(GPUInstancerPrefabManager manager)
{
manager.ClearRegisteredPrefabInstances();
}
///
/// Clears the registered prefab instances from the prefab manager for a specific prototype.
///
/// The manager that defines the prototypes you want to GPU instance.
/// The prototype to clear registered instances for.
public static void ClearRegisteredPrefabInstances(GPUInstancerPrefabManager manager, GPUInstancerPrototype prototype)
{
manager.ClearRegisteredPrefabInstances(prototype);
}
///
/// Adds a new prefab instance for GPU instancing to an already initialized list of registered instances.
/// Use this if you want to add another instance of a prefab after you have initialized a list of prefabs with .
/// The prefab of this instance must be previously defined in the given manager (either at runtime or editor time).
/// Note that the prefab must be enabled for adding and removal in the manager in order for this to work (for performance reasons).
/// Also note that the number of total instances is limited by the count of already initialized instances plus the extra amount you define in the manager.
///
/// The manager that defines the prototypes you want to GPU instance.
/// The prefab instance to add.
/// (Optional) When true, buffer size designated for the prototype will automatically increase when there is not enough space for adding a new instance
public static void AddPrefabInstance(GPUInstancerPrefabManager manager, GPUInstancerPrefab prefabInstance, bool autoIncreaseBufferSize = false)
{
manager.AddPrefabInstance(prefabInstance, autoIncreaseBufferSize);
}
///
/// Removes a prefab instance from an already initialized list of registered instances.
/// Use this if you want to remove a prefab instance after you have initialized a list of prefabs with
/// (usually before destroying the GameObject).
/// The prefab of this instance must be previously defined in the given manager (either at runtime or editor time).
/// Note that the prefab must be enabled for adding and removal in the manager in order for this to work (for performance reasons).
///
/// The manager that defines the prototypes you want to GPU instance.
/// The prefab instance to remove.
/// If set to false Mesh Renderer components will not be enabled after removing prefab instance which will make the
/// instance invisible.
public static void RemovePrefabInstance(GPUInstancerPrefabManager manager, GPUInstancerPrefab prefabInstance, bool setRenderersEnabled = true)
{
manager.RemovePrefabInstance(prefabInstance, setRenderersEnabled);
}
///
/// Disables GPU instancing and enables Unity renderers for the given prefab instance without removing it from the list of registerd prefabs.
/// Use this if you want to pause GPU Instancing for a prefab (e.g. to enable physics).
/// Note that the prefab must be enabled for runtime modifications in the manager in order for this to work (for performance reasons).
/// Also note that you can also add to a game object to use its collider to automatically
/// enable/disable instancing when a prefab instance enters/exits its collider.
///
/// The manager that defines the prototypes you want to GPU instance.
/// The prefab instance to disable the GPU Instancing of.
/// If set to false Mesh Renderer components will not be enabled after disabling instancing which will make the
/// instance invisible.
public static void DisableIntancingForInstance(GPUInstancerPrefabManager manager, GPUInstancerPrefab prefabInstance, bool setRenderersEnabled = true)
{
manager.DisableIntancingForInstance(prefabInstance, setRenderersEnabled);
}
///
/// Enables GPU instancing and disables Unity renderers for the given prefab instance without re-adding it to the list of registerd prefabs.
/// Use this if you want to unpause GPU Instancing for a prefab.
/// Note that the prefab must be enabled for runtime modifications in the manager in order for this to work (for performance reasons).
/// Also note that you can also add to a game object to use its collider to automatically
/// enable/disable instancing when a prefab instance enters/exits its collider.
///
/// The manager that defines the prototypes you want to GPU instance.
/// The prefab instance to enable the GPU Instancing of.
/// If set to false Mesh Renderer components will not be disabled after enabling instancing. Should be used only for instances
/// that have already disabled mesh renderers to speed up the process.
public static void EnableInstancingForInstance(GPUInstancerPrefabManager manager, GPUInstancerPrefab prefabInstance, bool setRenderersDisabled = true)
{
manager.EnableInstancingForInstance(prefabInstance, setRenderersDisabled);
}
///
/// Updates and synchronizes the GPU Instancer transform data (position, rotation and scale) for the given prefab instance.
/// Use this if you want to update, rotate, and/or scale prefab instances after initialization.
/// The updated values are taken directly from the transformation operations made beforehand on the instance's Unity transform component.
/// (These operations will not reflect on the GPU Instanced prefab automatically unless you use this method).
///
/// The manager that defines the prototypes you want to GPU instance.
/// The prefab instance to update the transform values of. The instance's Unity transform component must be updated beforehand.
public static void UpdateTransformDataForInstance(GPUInstancerPrefabManager manager, GPUInstancerPrefab prefabInstance)
{
manager.UpdateTransformDataForInstance(prefabInstance);
}
///
/// Specifies a variation buffer for a GPU Instancer prototype that is defined in the prefab's shader. Required to use
/// Use this if you want any type of variation between this prototype's instances.
/// To define the buffer necessary for this variation in your shader, you need to create a StructuredBuffer field of the relevant type in that shader.
/// You can then access this buffer with "gpui_InstanceID"
/// see and its demo scene for an example
///
///
///
/// This sample shows how to use the variation buffer in your shader:
///
/// colorBuffer;
/// #endif
/// ...
/// void surf (Input IN, inout SurfaceOutputStandard o) {
/// ...
/// #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
/// col = colorBuffer[gpui_InstanceID];
/// #else
/// col = _Color;
/// #endif
/// ...
/// }
/// ]]>
///
/// See "GPUInstancer/ColorVariationShader" for the full example.
///
///
///
/// The type of variation buffer. Must be defined in the instance prototype's shader
/// The manager that defines the prototypes you want to GPU instance.
/// The GPU Instancer prototype to define variations.
/// The name of the variation buffer in the prototype's shader.
public static void DefinePrototypeVariationBuffer(GPUInstancerPrefabManager manager, GPUInstancerPrefabPrototype prototype, string bufferName)
{
manager.DefinePrototypeVariationBuffer(prototype, bufferName);
}
///
/// Sets the variation value for this prefab instance. The variation buffer for the prototype must be defined
/// with before using this.
///
/// The type of variation buffer. Must be defined in the instance prototype's shader.
/// The prefab instance to add the variation to.
/// The name of the variation buffer in the prototype's shader.
/// The value of the variation.
public static void AddVariation(GPUInstancerPrefab prefabInstance, string bufferName, T value)
{
prefabInstance.AddVariation(bufferName, value);
}
///
/// Updates the variation value for this prefab instance. The variation buffer for the prototype must be defined
/// with before using this.
///
/// The type of variation buffer. Must be defined in the instance prototype's shader.
/// The manager that defines the prototypes you want to GPU instance.
/// The prefab instance to update the variation at.
/// The name of the variation buffer in the prototype's shader.
/// The value of the variation.
public static void UpdateVariation(GPUInstancerPrefabManager manager, GPUInstancerPrefab prefabInstance, string bufferName, T value)
{
prefabInstance.AddVariation(bufferName, value);
manager.UpdateVariationData(prefabInstance, bufferName, value);
}
///
/// Specifies a variation buffer for a GPU Instancer prototype that is defined in the prefab's shader. And sets the variation values for the given array.
///
/// The type of variation buffer. Must be defined in the instance prototype's shader
/// The manager that defines the prototypes you want to GPU instance.
/// The GPU Instancer prototype to define variations.
/// The name of the variation buffer in the prototype's shader.
/// The array that stores the variation information.
public static PrefabVariationData DefineAndAddVariationFromArray(GPUInstancerPrefabManager manager, GPUInstancerPrefabPrototype prototype, string bufferName, T[] variationArray)
{
return manager.DefineAndAddVariationFromArray(prototype, bufferName, variationArray);
}
///
/// Specifies a variation buffer for a GPU Instancer prototype that is defined in the prefab's shader. And sets the variation values for the given array.
///
/// The type of variation buffer. Must be defined in the instance prototype's shader
/// The manager that defines the prototypes you want to GPU instance.
/// The GPU Instancer prototype to define variations.
/// The name of the variation buffer in the prototype's shader.
/// The array that stores the variation information.
public static PrefabVariationData DefineAndAddVariationFromArray(GPUInstancerPrefabManager manager, GPUInstancerPrefabPrototype prototype, string bufferName, NativeArray variationArray) where T : struct
{
return manager.DefineAndAddVariationFromArray(prototype, bufferName, variationArray);
}
///
/// Updates the variation values for the given array for the specified prototype and buffer.
///
/// The type of variation buffer. Must be defined in the instance prototype's shader
/// The manager that defines the prototypes you want to GPU instance.
/// The GPU Instancer prototype to define variations.
/// The name of the variation buffer in the prototype's shader.
/// The array that stores the variation information.
/// Start index of the given array that the data will be uploaded to the buffer
/// Start index of the buffer to set the data from the array
/// Total number of variation data to set to the buffer from the array
public static void UpdateVariationFromArray(GPUInstancerPrefabManager manager, GPUInstancerPrefabPrototype prototype, string bufferName, T[] variationArray, int arrayStartIndex = 0, int bufferStartIndex = 0, int count = 0)
{
manager.UpdateVariationsFromArray(prototype, bufferName, variationArray, arrayStartIndex, bufferStartIndex, count);
}
///
/// Updates the variation values for the given array for the specified prototype and buffer.
///
/// The type of variation buffer. Must be defined in the instance prototype's shader
/// The manager that defines the prototypes you want to GPU instance.
/// The GPU Instancer prototype to define variations.
/// The name of the variation buffer in the prototype's shader.
/// The array that stores the variation information.
/// Start index of the given array that the data will be uploaded to the buffer
/// Start index of the buffer to set the data from the array
/// Total number of variation data to set to the buffer from the array
public static void UpdateVariationFromArray(GPUInstancerPrefabManager manager, GPUInstancerPrefabPrototype prototype, string bufferName, NativeArray variationArray, int arrayStartIndex = 0, int bufferStartIndex = 0, int count = 0) where T : struct
{
manager.UpdateVariationsFromArray(prototype, bufferName, variationArray, arrayStartIndex, bufferStartIndex, count);
}
///
/// Returns the ComputeBuffer that is created for the variation. Please note that the Compute Shader will be destroyed and recreated when the buffer size changes or the manager is reinitialized.
///
/// The manager that defines the prototypes you want to GPU instance.
/// The GPU Instancer prototype to define variations.
/// The name of the variation buffer in the prototype's shader.
/// Variation ComputeBuffer
public static ComputeBuffer GetVariationBuffer(GPUInstancerPrefabManager manager, GPUInstancerPrefabPrototype prototype, string bufferName)
{
return manager.GetVariationBuffer(prototype, bufferName);
}
///
/// Use this method to create prefab instances with the given transform information without creating GameObjects.
///
/// The GPUI Prefab Manager that the prefab prototype is defined on
/// GPUI Prefab Prototype
/// Array of Matrix4x4 that store the transform data of prefab instances
public static void InitializeWithMatrix4x4Array(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prototype, Matrix4x4[] matrix4x4Array)
{
GPUInstancerUtility.InitializeWithMatrix4x4Array(prefabManager, prototype, matrix4x4Array);
}
///
/// Use this method to initialize buffers for the given prototype and set the buffer data later with UpdateVisibilityBuffer API methods. Please note that you will
/// need to provide a positive integer buffer size to initialize the buffers successfully.
///
/// The GPUI Prefab Manager that the prefab prototype is defined on
/// GPUI Prefab Prototype
/// Size of the buffer to allocate in GPU memory
/// (Optional) Initial instance count to render. Can also be set later with SetInstanceCount API method
public static void InitializePrototype(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prototype, int bufferSize, int instanceCount = 0)
{
GPUInstancerUtility.InitializePrototype(prefabManager, prototype, bufferSize, instanceCount);
}
///
/// Use this method to update transform data of all prefab instances with a Matrix4x4 array. By default all the data from the array will be
/// uploaded to the GPU. You can make partial uploads by setting the arrayStartIndex, bufferStartIndex, and count parameters.
///
/// The GPUI Prefab Manager that the prefab prototype is defined on
/// GPUI Prefab Prototype
/// Array of Matrix4x4 that store the transform data of prefab instances
/// Start index of the given array that the data will be uploaded to the buffer
/// Start index of the buffer to set the data from the array
/// Total number of matrices to set to the buffer from the array
public static void UpdateVisibilityBufferWithMatrix4x4Array(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prototype, Matrix4x4[] matrix4x4Array,
int arrayStartIndex = 0, int bufferStartIndex = 0, int count = 0)
{
GPUInstancerUtility.UpdateVisibilityBufferWithMatrix4x4Array(prefabManager, prototype, matrix4x4Array, arrayStartIndex, bufferStartIndex, count);
}
#if UNITY_2019_1_OR_NEWER
///
/// Use this method to update transform data of all prefab instances with a float4x4 native array. By default all the data from the array will be
/// uploaded to the GPU. You can make partial uploads by setting the arrayStartIndex, bufferStartIndex, and count parameters.
///
/// The GPUI Prefab Manager that the prefab prototype is defined on
/// GPUI Prefab Prototype
/// Array of float4x4 that store the transform data of prefab instances. Struct reference is not forced so you can use any float4x4 struct (e.g. Matrix4x4 or float4x4 from Mathematics package)
/// (Optional) Start index of the given array that the data will be uploaded to the buffer
/// (Optional) Start index of the buffer to set the data from the array
/// (Optional) Total number of matrices to set to the buffer from the array
public static void UpdateVisibilityBufferWithNativeArray(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prototype, NativeArray float4x4Array,
int arrayStartIndex = 0, int bufferStartIndex = 0, int count = 0) where T : struct
{
GPUInstancerUtility.UpdateVisibilityBufferWithNativeArray(prefabManager, prototype, float4x4Array, arrayStartIndex, bufferStartIndex, count);
}
#endif
///
/// Use this method to define Prefab Prototypes at runtime for procedurally generated GameObjects
///
/// The GPUI Prefab Manager that the prefab prototype will be defined on
/// GameObject to use as reference for the prototype
/// (Optional) If false, GPUI will not add the GPUInstancerPrefab component on the prototypeGameObject
///
public static GPUInstancerPrefabPrototype DefineGameObjectAsPrefabPrototypeAtRuntime(GPUInstancerPrefabManager prefabManager, GameObject prototypeGameObject, bool attachScript = true)
{
return prefabManager.DefineGameObjectAsPrefabPrototypeAtRuntime(prototypeGameObject, attachScript);
}
///
/// Initialize single prefab prototype for preparing runtime data and buffers for instanced rendering
///
/// The GPUI Prefab Manager that the prefab prototype is defined on
/// GPUI Prefab Prototype
///
public static GPUInstancerRuntimeData InitializeGPUInstancer(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prototype)
{
// initialize PrefabManager if it is not already initialized
prefabManager.InitializeRuntimeDataAndBuffers(false);
// generate and return prototype runtime data
return prefabManager.InitializeRuntimeDataForPrefabPrototype(prototype);
}
///
/// Use this method to add new instances to prototype when you do not use prefabs (Ex: when you create a prototype with DefineGameObjectAsPrefabPrototypeAtRuntime API method)
///
/// The GPUI Prefab Manager that the prefab prototype is defined on
/// GPUI Prefab Prototype
/// List of GameObjects to register on the manager
public static void AddInstancesToPrefabPrototypeAtRuntime(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prefabPrototype, IEnumerable instances)
{
prefabManager.AddInstancesToPrefabPrototypeAtRuntime(prefabPrototype, instances);
}
///
/// Use this method to remove a prototype definition at runtime
///
/// The GPUI Prefab Manager that the prefab prototype is defined on
/// GPUI Prefab Prototype to remove from the manager
public static void RemovePrototypeAtRuntime(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prefabPrototype)
{
prefabManager.RemovePrototypeAtRuntime(prefabPrototype);
}
///
/// Creates a copy of the given prototype. After the changes you want to make to the prototype are completed, you need call InitializePrototype or InitializeWithMatrix4x4Array to create the runtimeData for this prototype
///
/// The GPUI Prefab Manager that the prefab prototype is defined on
/// Prototype to copy from
///
public static GPUInstancerPrefabPrototype ClonePrototypeAtRuntime(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype originalPrototype)
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
Debug.LogError("ClonePrototypeAtRuntime metod can not be called at edit mode.");
return null;
}
#endif
GPUInstancerPrefabPrototype clone = ScriptableObject.Instantiate(originalPrototype);
prefabManager.prototypeList.Add(clone);
return clone;
}
///
/// Adds a pre-defined prototype to the Prefab Manager. When called at runtime, you need to initialize the runtimedata for this prototype (e.g. by using the InitializePrototype API method).
///
/// The GPUI Prefab Manager that the prefab prototype will be defined on
/// Prototype to add
public static void AddPrototoypeToManager(GPUInstancerPrefabManager prefabManager, GPUInstancerPrefabPrototype prototype)
{
if (prefabManager.prototypeList.Contains(prototype))
{
Debug.LogError("Prefab Manager already contains prototype: " + prototype, prototype);
return;
}
prefabManager.prototypeList.Add(prototype);
prefabManager.prefabList.Add(prototype.prefabObject);
}
#endregion Prefab Instancing
#region Detail & Tree Instancing
///
/// Sets the Unity terrain to the GPU Instancer manager and generates the instance prototypes from Unity detail
/// prototypes that are defined on the given Unity terrain component.
/// Use this to initialize the GPU Instancer detail manager if you want to generate your terrain at runtime.
/// See and its demo scene for an example.
///
/// The manager that defines the prototypes you want to GPU instance.
///
public static void SetupManagerWithTerrain(GPUInstancerTerrainManager manager, Terrain terrain)
{
manager.SetupManagerWithTerrain(terrain);
}
#endregion Detail & Tree Instancing
#region Detail Instancing
///
/// Updates and synchronizes the GPU Instancer detail prototypes with the modifications made in the manager at runtime.
/// Use this if you want to make changes to the detail prototypes at runtime. Prototypes in the manager must be modified before using this.
/// For example usages, see: and
///
/// The manager that defines the prototypes you want to GPU instance.
/// Whether GPU Instancer should also update meshes. Send this value as "true" if you change properties
/// related to cross quadding, noise spread and/or detail scales
public static void UpdateDetailInstances(GPUInstancerDetailManager manager, bool updateMeshes = false)
{
GPUInstancerUtility.UpdateDetailInstanceRuntimeDataList(manager.runtimeDataList, manager.terrainSettings, updateMeshes, manager.detailLayer);
}
///
/// Returns a list of 2D array of detail object density for the all the prototypes of the manager.
///
///
///
public static List GetDetailMapData(GPUInstancerDetailManager manager)
{
return manager.GetDetailMapData();
}
///
/// Returns a 2D array of detail object density for the given layer.
///
///
///
///
public static int[,] GetDetailLayer(GPUInstancerDetailManager manager, int layerIndex)
{
return manager.GetDetailLayer(layerIndex);
}
///
/// Can be used to set the Detail Map Data to the Detail Manager before initialization.
///
///
///
public static void SetDetailMapData(GPUInstancerDetailManager manager, List detailMapData)
{
manager.SetDetailMapData(detailMapData);
}
#endregion
#region Tree Instancing
///
/// Use this method to add new terrains to Tree Manager at runtime
///
/// The GPUI Tree Manager to add the new terrain
/// New terrain to render the trees
public static void AddTerrainToManager(GPUInstancerTreeManager manager, Terrain terrain)
{
manager.AddTerrain(terrain);
}
///
/// Use this method to remove terrains from Tree Manager at runtime
///
/// The GPUI Tree Manager to remove the terrain
/// Terrain to remove
public static void RemoveTerrainFromManager(GPUInstancerTreeManager manager, Terrain terrain)
{
manager.RemoveTerrain(terrain);
}
#endregion Tree Instancing
#region Editor Only
#if UNITY_EDITOR
///
/// [EDITOR-ONLY] Shader auto-conversion can be run with this method without using a GPUI Manager
///
/// Shader to convert
/// True if successful
public static bool SetupShaderForGPUI(Shader shader)
{
if (shader == null || shader.name == GPUInstancerConstants.SHADER_UNITY_INTERNAL_ERROR)
{
Debug.LogError("Can not find shader! Please make sure that the material has a shader assigned.");
return false;
}
GPUInstancerConstants.gpuiSettings.shaderBindings.ClearEmptyShaderInstances();
if (!GPUInstancerConstants.gpuiSettings.shaderBindings.IsShadersInstancedVersionExists(shader.name))
{
if (GPUInstancerUtility.IsShaderInstanced(shader))
{
GPUInstancerConstants.gpuiSettings.shaderBindings.AddShaderInstance(shader.name, shader, true);
Debug.Log("Shader setup for GPUI has been successfully completed.");
return true;
}
else
{
Shader instancedShader = GPUInstancerUtility.CreateInstancedShader(shader);
if (instancedShader != null)
{
GPUInstancerConstants.gpuiSettings.shaderBindings.AddShaderInstance(shader.name, instancedShader);
return true;
}
else
{
string originalAssetPath = UnityEditor.AssetDatabase.GetAssetPath(shader);
if (originalAssetPath.ToLower().EndsWith(".shadergraph"))
Debug.LogError(string.Format(GPUInstancerConstants.ERRORTEXT_shaderGraph, shader.name));
else
Debug.LogError("Can not create instanced version for shader: " + shader.name + ".");
return false;
}
}
}
else
{
Debug.Log(shader.name + " shader has already been setup for GPUI.");
return true;
}
}
///
/// [EDITOR-ONLY] Adds the shader variant used in the given material to the GPUIShaderVariantCollection. This collection is used to include the shader variants with GPUI support in your builds.
/// Normally GPUI Managers makes this automatically, but if you generate your managers at runtime, this method can be usefull to add these shader variants manually.
///
///
public static void AddShaderVariantToCollection(Material material)
{
GPUInstancerConstants.gpuiSettings.AddShaderVariantToCollection(material);
}
///
/// [EDITOR-ONLY] Starts rendering GPUI instances for the given manager in editor mode. The simulation can be stopped using the StopEditorSimulation method.
/// It will automatically stop when entering Play mode.
/// It is usefull to render instances in Editor Mode while using no-GameObject workflow.
///
/// GPUI manager to start simulation for
public static void StartEditorSimulation(GPUInstancerManager manager)
{
if (!Application.isPlaying && manager.gpuiSimulator != null)
manager.gpuiSimulator.StartSimulation();
}
///
/// [EDITOR-ONLY] Stops rendering GPUI instances for the given manager in editor mode. Can be used after StartEditorSimulation method to disable rendering.
///
/// GPUI manager to stop simulation for
public static void StopEditorSimulation(GPUInstancerManager manager)
{
if (!Application.isPlaying && manager.gpuiSimulator != null)
manager.gpuiSimulator.StopSimulation();
}
#endif
#endregion Editor Only
}
}