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