AddInstancesIndirect
Adds an array of ray tracing instances to the acceleration structure where the instance matrices are specified using a GraphicsBuffer.
Read time 24 minutesLast updated 12 days ago
Definition
- Type: Method
- Namespace: UnityEngine.Rendering
- Assembly: UnityEngine.CoreModule
AddInstancesIndirect(RayTracingMeshInstanceConfig, GraphicsBuffer, int, GraphicsBuffer, uint, uint)
Adds an array of ray tracing instances to the acceleration structure where the instance matrices are specified using a GraphicsBuffer.
public int AddInstancesIndirect(in RayTracingMeshInstanceConfig config, GraphicsBuffer instanceMatrices, int maxInstanceCount, GraphicsBuffer argsBuffer, uint argsOffset = 0, uint id = 4294967295)
Parameters
The common parameters that these ray tracing instances use.
The GraphicsBuffer to contain transformation matrices.
The maximum number of ray tracing instances to add to the acceleration structure.
The GraphicsBuffer containing 2 integer values at argsOffset byte offset: start instance and instance count.
The offset, in bytes, into argsBuffer where indirect arguments are stored.
An optional instance ID value that you can access in HLSL with the function. Unity assigns consecutive instance IDs to each mesh instance, starting with the value of .
InstanceID()idReturns
Type | Description |
|---|---|
| int | The value representing a handle that you can use to perform later actions (e.g. RayTracingAccelerationStructure.RemoveInstance), or 0 if the instances are not added successfully. |
Remarks
The function argument specifies the relevant source geometry and associated parameters for all ray tracing instances. The source geometry can be either specified using a Mesh or GraphicsBuffers containing vertex and index data.
configThe world transformation matrices for ray tracing instances are specified using the instanceMatrices function argument. Only 4x4 floating-point matrices are supported where the elements are stored using column-major layout (the same as Matrix4x4 layout). The buffer must be created using the GraphicsBuffer.Target.Structured or GraphicsBuffer.Target.Append flags. You can specify the contents of the buffer by simply calling instanceMatrices.SetData(Matrix4x4[]) or you can employ a more advanced algorithm where the matrix buffer is filled in a compute shader in a GPU-driven rendering pipeline, for example.
The argument is necessary to let Unity to allocate GPU memory for the acceleration structure (TLAS) used for ray tracing. The final number of valid ray tracing instances added to the acceleration structure depends on both the value and the values (start instance and instance count). An internal compute shader handles the process of adding instances. The compute shader is dispatched once for each call when the acceleration structure is built.
maxInstanceCountmaxInstanceCountargsBufferAddInstanceIndirectWhen is used, Unity enables the shader keyword. To declare the shader keyword in HLSL, add the line in the shader pass specified in RayTracingShader.SetShaderPass or CommandBuffer.SetRayTracingShaderPass. To access per-instance data relative to this array of ray tracing instances, use to generate a zero-based instance index in hit shaders.
AddInstancesIndirectINSTANCING_ON#pragma multi_compile _ INSTANCING_ONInstanceIndex() - unity_BaseInstanceIDWhen you have added all required instances, use RayTracingAccelerationStructure.Build or CommandBuffer.BuildRayTracingAccelerationStructure to build the acceleration structure on the GPU.
This functionality doesn't have any special hardware requirements in addition to ray tracing support requirements (SystemInfo.supportsRayTracing must be true). In DirectX Raytracing (DXR), this function causes all ray tracing instances in the array to use only one shader record from the shader table, which reduces the CPU overhead on the render thread for binding GPU resources to hit shaders.
This method returns a single instance handle which you can use later to perform actions that affect all ray tracing instances added using this method.
Additional Resources: RayTracingAccelerationStructure.RemoveInstance, RayTracingAccelerationStructure.Build, GraphicsBuffer.CopyCount.
AddInstancesIndirect(RayTracingGeometryInstanceConfig, GraphicsBuffer, int, GraphicsBuffer, uint, uint)
Adds an array of ray tracing instances to the acceleration structure where the instance matrices are specified using a GraphicsBuffer.
public int AddInstancesIndirect(in RayTracingGeometryInstanceConfig config, GraphicsBuffer instanceMatrices, int maxInstanceCount, GraphicsBuffer argsBuffer, uint argsOffset = 0, uint id = 4294967295)
Parameters
The common parameters that these ray tracing instances use.
The GraphicsBuffer to contain transformation matrices.
The maximum number of ray tracing instances to add to the acceleration structure.
The GraphicsBuffer containing 2 integer values at argsOffset byte offset: start instance and instance count.
The offset, in bytes, into argsBuffer where indirect arguments are stored.
An optional instance ID value that you can access in HLSL with the function. Unity assigns consecutive instance IDs to each mesh instance, starting with the value of .
InstanceID()idReturns
Type | Description |
|---|---|
| int | The value representing a handle that you can use to perform later actions (e.g. RayTracingAccelerationStructure.RemoveInstance), or 0 if the instances are not added successfully. |
Remarks
The function argument specifies the relevant source geometry and associated parameters for all ray tracing instances. The source geometry can be either specified using a Mesh or GraphicsBuffers containing vertex and index data.
configThe world transformation matrices for ray tracing instances are specified using the instanceMatrices function argument. Only 4x4 floating-point matrices are supported where the elements are stored using column-major layout (the same as Matrix4x4 layout). The buffer must be created using the GraphicsBuffer.Target.Structured or GraphicsBuffer.Target.Append flags. You can specify the contents of the buffer by simply calling instanceMatrices.SetData(Matrix4x4[]) or you can employ a more advanced algorithm where the matrix buffer is filled in a compute shader in a GPU-driven rendering pipeline, for example.
The argument is necessary to let Unity to allocate GPU memory for the acceleration structure (TLAS) used for ray tracing. The final number of valid ray tracing instances added to the acceleration structure depends on both the value and the values (start instance and instance count). An internal compute shader handles the process of adding instances. The compute shader is dispatched once for each call when the acceleration structure is built.
maxInstanceCountmaxInstanceCountargsBufferAddInstanceIndirectWhen is used, Unity enables the shader keyword. To declare the shader keyword in HLSL, add the line in the shader pass specified in RayTracingShader.SetShaderPass or CommandBuffer.SetRayTracingShaderPass. To access per-instance data relative to this array of ray tracing instances, use to generate a zero-based instance index in hit shaders.
AddInstancesIndirectINSTANCING_ON#pragma multi_compile _ INSTANCING_ONInstanceIndex() - unity_BaseInstanceIDWhen you have added all required instances, use RayTracingAccelerationStructure.Build or CommandBuffer.BuildRayTracingAccelerationStructure to build the acceleration structure on the GPU.
This functionality doesn't have any special hardware requirements in addition to ray tracing support requirements (SystemInfo.supportsRayTracing must be true). In DirectX Raytracing (DXR), this function causes all ray tracing instances in the array to use only one shader record from the shader table, which reduces the CPU overhead on the render thread for binding GPU resources to hit shaders.
This method returns a single instance handle which you can use later to perform actions that affect all ray tracing instances added using this method.
Additional Resources: RayTracingAccelerationStructure.RemoveInstance, RayTracingAccelerationStructure.Build, GraphicsBuffer.CopyCount.
AddInstancesIndirect(RayTracingMultiGeometryInstanceConfig, GraphicsBuffer, Type, GraphicsBuffer, int, GraphicsBuffer, uint, uint)
Adds an array of ray tracing instances to the acceleration structure where each instance can have a different transformation matrix, geometry and material.
public int AddInstancesIndirect(in RayTracingMultiGeometryInstanceConfig config, GraphicsBuffer instanceData, Type instanceType, GraphicsBuffer instanceIndices, int maxInstanceCount, GraphicsBuffer argsBuffer, uint argsOffset = 0, uint id = 4294967295)
Parameters
The common parameters that these ray tracing instances use.
The GraphicsBuffer to contain custom instance data.
A type that you define in your scripts to describe the instance data format.
An optional GraphicsBuffer that contains indices of ray tracing instances from instanceData to be added to the acceleration structure.
The maximum number of ray tracing instances to add to the acceleration structure.
The GraphicsBuffer containing 2 integer values at argsOffset byte offset: start instance and instance count.
The offset, in bytes, into argsBuffer where indirect arguments are stored.
An optional instance ID value that you can access in HLSL with the function. Unity assigns consecutive instance IDs to each mesh instance, starting with the value of .
InstanceID()idReturns
Type | Description |
|---|---|
| int | The value representing a handle that you can use to perform later actions (e.g. RayTracingAccelerationStructure.RemoveInstance), or 0 if the instances are not added successfully. |
Remarks
The function argument specifies the geometries, materials and other common parameters for all ray tracing instances. The source geometries can be specified using GraphicsBuffers containing vertex and index data. Use the array to specify where each geometry starts and ends in the vertex and index buffers. You can easily use Mesh data with this method by calling getter methods from the Mesh class to retrieve the vertex and index buffers and associated data. Use the array to store the materials to be used by ray tracing instances.
configconfig.subGeometriesconfig.materialsThe buffer contains custom instance data. Each instance must contain the following mandatory data: the instance transformation matrix, an index into to specify which geometry to use and an index into to specify which material to use. The transformation matrix must be a 4x4 floating-point matrix where the elements are stored using column-major layout (the same as Matrix4x4 layout). The geometry and material indices are represented using integer values. If the values are outside of their respective valid range, Unity clamps the values to the size of the and respectively.
instanceDataconfig.subGeometriesconfig.materialsconfig.subGeometriesconfig.materialsTo define the instance data format, pass a user-defined structure either as a generic type template argument or using the argument, for example by calling or the equivalent, using for the argument. The structure can have any name and format but it needs to contain the following mandatory named fields: , and . Unity throws an exception if any of these fields are not present in the structure that you provide.
instanceTypeAddInstancesIndirect<MyInstanceData>typeof(MyInstanceData)instanceTypeobjectToWorldgeometryIndexmaterialIndexThe buffer is optional and must be created using the GraphicsBuffer.Target.Structured or GraphicsBuffer.Target.Append flags. When using the buffer, the values in (startInstance and instanceCount) specify indices into this buffer instead of buffer. Use a GraphicsBuffer.Target.Append flag if you append instance indices from a compute shader into buffer. In this case, call CommandBuffer.CopyCounterValue or GraphicsBuffer.CopyCount to copy the final instance count from into . This way, you can control the amount of instances to be added to the acceleration structure from a compute shader, for example by culling some of the instances.
instanceIndicesinstanceIndicesargsBufferinstanceDatainstanceIndicesinstanceIndicesargsBufferThe argument is necessary to let Unity to allocate GPU memory for the acceleration structure (TLAS) used for ray tracing. The final number of valid ray tracing instances added to the acceleration structure depends on the value, the amount of indices in the buffer, and the values (start instance and instance count). An internal compute shader handles the process of adding instances. The compute shader is dispatched once for each call when the acceleration structure is built on the GPU.
maxInstanceCountmaxInstanceCountinstanceIndicesargsBufferAddInstancesIndirectWhen is used, Unity enables the shader keyword. To declare the shader keyword in HLSL, add the line in the shader pass specified in RayTracingShader.SetShaderPass or CommandBuffer.SetRayTracingShaderPass. To access per-instance data relative to the array of ray tracing instances added using a single call, use to generate a zero-based instance index in hit shaders. If you need to access additional per-instance data in hit shader, use to bind the data.
AddInstancesIndirectINSTANCING_ON#pragma multi_compile _ INSTANCING_ONAddInstancesIndirectInstanceIndex() - unity_BaseInstanceIDconfig.materialPropertiesRefer to the HLSL function from for more information about how to read vertex data from in hit shaders. For every geometry in the array, Unity prepares a entry into the built-in structured buffer. For every entry in array, Unity prepares a entry into the built-in structured buffer. and contain the basic information for reading vertex and index data in hit shaders.
GetMeshInfoUnityRayTracingMeshUtils.cgincconfig.vertexBufferconfig.subGeometriesMeshInfounity_MeshInfo_RTconfig.vertexAttributesVertexAttributeInfounity_MeshVertexDeclaration_RTMeshInfoVertexAttributesInfoWhen you have added all required instances, use RayTracingAccelerationStructure.Build or CommandBuffer.BuildRayTracingAccelerationStructure to build the acceleration structure on the GPU.
This functionality doesn't have any special hardware requirements in addition to ray tracing support requirements (SystemInfo.supportsRayTracing must be true). In DirectX Raytracing (DXR), this function causes Unity to set up one shader record for each Material provided in the array, which reduces the CPU overhead on the render thread for binding GPU resources to hit shaders.
config.materialsThis method returns a single instance handle which you can use later to perform actions that affect all ray tracing instances added using this method.
Additional Resources: RayTracingAccelerationStructure.RemoveInstance, RayTracingAccelerationStructure.Build, Mesh.GetVertexBuffer, Mesh.GetIndexBuffer, Mesh.GetVertexAttributes.
using System.Collections.Generic;using System.Runtime.InteropServices;using Unity.Collections;using UnityEngine;using UnityEngine.Rendering;[ExecuteInEditMode]public class MeshInstancing : MonoBehaviour{ [SerializeField] RayTracingShader rayTracingShader; [SerializeField] Material material1; [SerializeField] Material material2; private uint cameraWidth = 0; private uint cameraHeight = 0; private int instanceRows = 100; private int instanceColumns = 100; private RenderTexture rayTracingOutput; private RayTracingAccelerationStructure rtas; private GraphicsBuffer vertexBuffer; private GraphicsBuffer indexBuffer; private GraphicsBuffer instanceDataBuffer; private GraphicsBuffer indirectArgsBuffer; private void ReleaseResources() { cameraWidth = 0; cameraHeight = 0; if (rtas != null) rtas.Release(); if (rayTracingOutput != null) rayTracingOutput.Release(); if (vertexBuffer != null) vertexBuffer.Release(); if (indexBuffer != null) indexBuffer.Release(); if (instanceDataBuffer != null) instanceDataBuffer.Release(); if (indirectArgsBuffer != null) indirectArgsBuffer.Release(); rtas = null; rayTracingOutput = null; vertexBuffer = null; indexBuffer = null; instanceDataBuffer = null; indirectArgsBuffer = null; } struct Vertex { public Vertex(Vector3 pos, Vector3 n) { position = pos; normal = n; } public Vector3 position; public Vector3 normal; } // objectToWorld, materialIndex, and geometryIndex fields are mandatory. public struct RayTracingPerInstanceData { public Matrix4x4 objectToWorld; public int data1; public uint materialIndex; public uint geometryIndex; public float data2; public Vector4 data3; }; private void CreateResources() { if (rtas == null) { RayTracingAccelerationStructure.Settings settings = new RayTracingAccelerationStructure.Settings { managementMode = RayTracingAccelerationStructure.ManagementMode.Manual, rayTracingModeMask = RayTracingAccelerationStructure.RayTracingModeMask.Everything, layerMask = -1, buildFlagsStaticGeometries = RayTracingAccelerationStructureBuildFlags.PreferFastTrace | RayTracingAccelerationStructureBuildFlags.MinimizeMemory, enableCompaction = true }; rtas = new RayTracingAccelerationStructure(settings); } if (cameraWidth != Camera.main.pixelWidth || cameraHeight != Camera.main.pixelHeight) { if (rayTracingOutput != null) rayTracingOutput.Release(); rayTracingOutput = new RenderTexture(Camera.main.pixelWidth, Camera.main.pixelHeight, 0, RenderTextureFormat.ARGBHalf); rayTracingOutput.enableRandomWrite = true; rayTracingOutput.Create(); cameraWidth = (uint)Camera.main.pixelWidth; cameraHeight = (uint)Camera.main.pixelHeight; } // The vertex and index buffers for the source geometry will be specified in RayTracingMultiGeometryInstanceConfig.vertexBuffer and indexBuffer. // Setup a vertex buffer that contains a quad and a triangle. The vertex contains the position and the normal. if (vertexBuffer == null) { List<Vertex> vertices = new List<Vertex> { // Add a quad. new Vertex(new Vector3(1, 0, -1), new Vector3(0, 1, 0)), new Vertex(new Vector3(1, 0, 1), new Vector3(0, 1, 0)), new Vertex(new Vector3(-1, 0, 1), new Vector3(0, 1, 0)), new Vertex(new Vector3(-1, 0, -1), new Vector3(0, 1, 0)), // Add a triangle. new Vertex(new Vector3(1, 0, 0), new Vector3(0, 0, 1)), new Vertex(new Vector3(-1, 0, 0), new Vector3(0, 0, 1)), new Vertex(new Vector3(0, 3, 0), new Vector3(0, 0, 1)), }; vertexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Raw | GraphicsBuffer.Target.Vertex, vertices.Count, Marshal.SizeOf(typeof(Vertex))); vertexBuffer.SetData(vertices); } // The geometry sub-ranges will be specified in RayTracingMultiGeometryInstanceConfig.subGeometries. if (indexBuffer == null) { List<uint> indices = new List<uint>() { // 2 triangles for the quad. 0, 1, 2, 0, 2, 3, // 1 triangle. 4, 5, 6, }; indexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Raw | GraphicsBuffer.Target.Index, indices.Count, sizeof(uint)); indexBuffer.SetData(indices); } if (instanceDataBuffer == null) { int instanceCount = instanceRows * instanceColumns; // Generate a list of transformation matrices. NativeArray<Matrix4x4> matrices = new NativeArray<Matrix4x4>(instanceCount, Allocator.Temp); int index = 0; Matrix4x4 m = Matrix4x4.identity; float angle = 0; // Arrange the instances into a matrix. for (int row = 0; row < instanceRows; row++) { float z = row + 0.5f - instanceRows * 0.5f; for (int column = 0; column < instanceColumns; column++) { float x = column + 0.5f - instanceColumns * 0.5f; angle += 10.0f; Quaternion rotation = Quaternion.Euler(0, angle, 0); m.SetTRS(new Vector3(5.5f * x, 4.001f, 5.5f * z), rotation, new Vector3(2, 2, 2)); matrices[index] = m; index++; } } instanceDataBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Raw, instanceCount, Marshal.SizeOf(typeof(RayTracingPerInstanceData))); RayTracingPerInstanceData[] perInstanceData = new RayTracingPerInstanceData[instanceCount]; Random.InitState(12345); for (int i = 0; i < instanceCount; i++) { perInstanceData[i] = new RayTracingPerInstanceData { // Assign a random geometry and material to each instance. objectToWorld = matrices[i], materialIndex = (uint)Random.Range(0, 2), geometryIndex = (uint)Random.Range(0, 2), data1 = i, data2 = 3.14f, data3 = new Vector4(1, 2, 3, 4), }; } instanceDataBuffer.SetData(perInstanceData); } if (indirectArgsBuffer == null) { indirectArgsBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Raw, 1, 2 * sizeof(int)); int[] ints = new int[2] { 0, // instanceStart instanceRows * instanceColumns // instanceCount }; indirectArgsBuffer.SetData(ints); } } void OnDestroy() { ReleaseResources(); } void OnDisable() { ReleaseResources(); } [ImageEffectOpaque] void OnRenderImage(RenderTexture src, RenderTexture dest) { if (SystemInfo.supportsRayTracing == false) { Debug.Log("The Ray Tracing API is not supported by this GPU or by the current graphics API."); Graphics.Blit(src, dest); return; } if (rayTracingShader == null) { Debug.Log("Please set the RayTracingShader."); Graphics.Blit(src, dest); return; } CreateResources(); rtas.ClearInstances(); CommandBuffer cmdBuffer = new CommandBuffer(); Material[] materials = new Material[2]; materials[0] = material1; materials[1] = material2; VertexAttributeDescriptor[] vertexDescs = new VertexAttributeDescriptor[2]; vertexDescs[0] = new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3, 0); vertexDescs[1] = new VertexAttributeDescriptor(VertexAttribute.Normal, VertexAttributeFormat.Float32, 3, 0); RayTracingMultiGeometryInstanceConfig instances = new RayTracingMultiGeometryInstanceConfig(); instances.vertexBuffer = vertexBuffer; instances.vertexAttributes = vertexDescs; instances.indexBuffer = indexBuffer; instances.materials = materials; instances.rayTracingMode = UnityEngine.Experimental.Rendering.RayTracingMode.Static; // Configure the 2 geometries. // The geometries in this example are considered opaque. When cutout materials are used (for example foliage), use RayTracingSubMeshFlags.Enabled flag alone to enable any hit shaders. instances.subGeometries = new RayTracingSubGeometryDesc[2] { // The quad. new RayTracingSubGeometryDesc { indexStart = 0, indexCount = 2 * 3, flags = RayTracingSubMeshFlags.Enabled | RayTracingSubMeshFlags.ClosestHitOnly }, // The triangle is right after the quad in the vertex buffer. new RayTracingSubGeometryDesc() { indexStart = 2 * 3, indexCount = 3, flags = RayTracingSubMeshFlags.Enabled | RayTracingSubMeshFlags.ClosestHitOnly } }; // Not using instance indices in this example. // We add all the instances from instanceDataBuffer. rtas.AddInstancesIndirect<RayTracingPerInstanceData>(instances, instanceDataBuffer, null, -1, indirectArgsBuffer, 0); cmdBuffer.BuildRayTracingAccelerationStructure(rtas); cmdBuffer.SetRayTracingShaderPass(rayTracingShader, "Test"); // Input cmdBuffer.SetRayTracingAccelerationStructure(rayTracingShader, Shader.PropertyToID("g_AccelStruct"), rtas); cmdBuffer.SetRayTracingFloatParam(rayTracingShader, Shader.PropertyToID("g_Zoom"), Mathf.Tan(Mathf.Deg2Rad * Camera.main.fieldOfView * 0.5f)); // Output cmdBuffer.SetRayTracingTextureParam(rayTracingShader, Shader.PropertyToID("g_Output"), rayTracingOutput); cmdBuffer.DispatchRays(rayTracingShader, "MainRayGenShader", cameraWidth, cameraHeight, 1); Graphics.ExecuteCommandBuffer(cmdBuffer); cmdBuffer.Release(); Graphics.Blit(rayTracingOutput, dest); }}
The script in this example calls AddInstancesIndirect\<T\> to add a number of ray tracing instances using random geometries and materials to an acceleration structure.
AddInstancesIndirect<T>(RayTracingMultiGeometryInstanceConfig, GraphicsBuffer, GraphicsBuffer, int, GraphicsBuffer, uint, uint)
Adds an array of ray tracing instances to the acceleration structure where each instance can have a different transformation matrix, geometry and material.
public int AddInstancesIndirect<T>(in RayTracingMultiGeometryInstanceConfig config, GraphicsBuffer instanceData, GraphicsBuffer instanceIndices, int maxInstanceCount, GraphicsBuffer argsBuffer, uint argsOffset = 0, uint id = 4294967295)
Parameters
The common parameters that these ray tracing instances use.
The GraphicsBuffer to contain custom instance data.
An optional GraphicsBuffer that contains indices of ray tracing instances from instanceData to be added to the acceleration structure.
The maximum number of ray tracing instances to add to the acceleration structure.
The GraphicsBuffer containing 2 integer values at argsOffset byte offset: start instance and instance count.
The offset, in bytes, into argsBuffer where indirect arguments are stored.
An optional instance ID value that you can access in HLSL with the function. Unity assigns consecutive instance IDs to each mesh instance, starting with the value of .
InstanceID()idReturns
Type | Description |
|---|---|
| int | The value representing a handle that you can use to perform later actions (e.g. RayTracingAccelerationStructure.RemoveInstance), or 0 if the instances are not added successfully. |
Remarks
The function argument specifies the geometries, materials and other common parameters for all ray tracing instances. The source geometries can be specified using GraphicsBuffers containing vertex and index data. Use the array to specify where each geometry starts and ends in the vertex and index buffers. You can easily use Mesh data with this method by calling getter methods from the Mesh class to retrieve the vertex and index buffers and associated data. Use the array to store the materials to be used by ray tracing instances.
configconfig.subGeometriesconfig.materialsThe buffer contains custom instance data. Each instance must contain the following mandatory data: the instance transformation matrix, an index into to specify which geometry to use and an index into to specify which material to use. The transformation matrix must be a 4x4 floating-point matrix where the elements are stored using column-major layout (the same as Matrix4x4 layout). The geometry and material indices are represented using integer values. If the values are outside of their respective valid range, Unity clamps the values to the size of the and respectively.
instanceDataconfig.subGeometriesconfig.materialsconfig.subGeometriesconfig.materialsTo define the instance data format, pass a user-defined structure either as a generic type template argument or using the argument, for example by calling or the equivalent, using for the argument. The structure can have any name and format but it needs to contain the following mandatory named fields: , and . Unity throws an exception if any of these fields are not present in the structure that you provide.
instanceTypeAddInstancesIndirect<MyInstanceData>typeof(MyInstanceData)instanceTypeobjectToWorldgeometryIndexmaterialIndexThe buffer is optional and must be created using the GraphicsBuffer.Target.Structured or GraphicsBuffer.Target.Append flags. When using the buffer, the values in (startInstance and instanceCount) specify indices into this buffer instead of buffer. Use a GraphicsBuffer.Target.Append flag if you append instance indices from a compute shader into buffer. In this case, call CommandBuffer.CopyCounterValue or GraphicsBuffer.CopyCount to copy the final instance count from into . This way, you can control the amount of instances to be added to the acceleration structure from a compute shader, for example by culling some of the instances.
instanceIndicesinstanceIndicesargsBufferinstanceDatainstanceIndicesinstanceIndicesargsBufferThe argument is necessary to let Unity to allocate GPU memory for the acceleration structure (TLAS) used for ray tracing. The final number of valid ray tracing instances added to the acceleration structure depends on the value, the amount of indices in the buffer, and the values (start instance and instance count). An internal compute shader handles the process of adding instances. The compute shader is dispatched once for each call when the acceleration structure is built on the GPU.
maxInstanceCountmaxInstanceCountinstanceIndicesargsBufferAddInstancesIndirectWhen is used, Unity enables the shader keyword. To declare the shader keyword in HLSL, add the line in the shader pass specified in RayTracingShader.SetShaderPass or CommandBuffer.SetRayTracingShaderPass. To access per-instance data relative to the array of ray tracing instances added using a single call, use to generate a zero-based instance index in hit shaders. If you need to access additional per-instance data in hit shader, use to bind the data.
AddInstancesIndirectINSTANCING_ON#pragma multi_compile _ INSTANCING_ONAddInstancesIndirectInstanceIndex() - unity_BaseInstanceIDconfig.materialPropertiesRefer to the HLSL function from for more information about how to read vertex data from in hit shaders. For every geometry in the array, Unity prepares a entry into the built-in structured buffer. For every entry in array, Unity prepares a entry into the built-in structured buffer. and contain the basic information for reading vertex and index data in hit shaders.
GetMeshInfoUnityRayTracingMeshUtils.cgincconfig.vertexBufferconfig.subGeometriesMeshInfounity_MeshInfo_RTconfig.vertexAttributesVertexAttributeInfounity_MeshVertexDeclaration_RTMeshInfoVertexAttributesInfoWhen you have added all required instances, use RayTracingAccelerationStructure.Build or CommandBuffer.BuildRayTracingAccelerationStructure to build the acceleration structure on the GPU.
This functionality doesn't have any special hardware requirements in addition to ray tracing support requirements (SystemInfo.supportsRayTracing must be true). In DirectX Raytracing (DXR), this function causes Unity to set up one shader record for each Material provided in the array, which reduces the CPU overhead on the render thread for binding GPU resources to hit shaders.
config.materialsThis method returns a single instance handle which you can use later to perform actions that affect all ray tracing instances added using this method.
Additional Resources: RayTracingAccelerationStructure.RemoveInstance, RayTracingAccelerationStructure.Build, Mesh.GetVertexBuffer, Mesh.GetIndexBuffer, Mesh.GetVertexAttributes.
using System.Collections.Generic;using System.Runtime.InteropServices;using Unity.Collections;using UnityEngine;using UnityEngine.Rendering;[ExecuteInEditMode]public class MeshInstancing : MonoBehaviour{ [SerializeField] RayTracingShader rayTracingShader; [SerializeField] Material material1; [SerializeField] Material material2; private uint cameraWidth = 0; private uint cameraHeight = 0; private int instanceRows = 100; private int instanceColumns = 100; private RenderTexture rayTracingOutput; private RayTracingAccelerationStructure rtas; private GraphicsBuffer vertexBuffer; private GraphicsBuffer indexBuffer; private GraphicsBuffer instanceDataBuffer; private GraphicsBuffer indirectArgsBuffer; private void ReleaseResources() { cameraWidth = 0; cameraHeight = 0; if (rtas != null) rtas.Release(); if (rayTracingOutput != null) rayTracingOutput.Release(); if (vertexBuffer != null) vertexBuffer.Release(); if (indexBuffer != null) indexBuffer.Release(); if (instanceDataBuffer != null) instanceDataBuffer.Release(); if (indirectArgsBuffer != null) indirectArgsBuffer.Release(); rtas = null; rayTracingOutput = null; vertexBuffer = null; indexBuffer = null; instanceDataBuffer = null; indirectArgsBuffer = null; } struct Vertex { public Vertex(Vector3 pos, Vector3 n) { position = pos; normal = n; } public Vector3 position; public Vector3 normal; } // objectToWorld, materialIndex, and geometryIndex fields are mandatory. public struct RayTracingPerInstanceData { public Matrix4x4 objectToWorld; public int data1; public uint materialIndex; public uint geometryIndex; public float data2; public Vector4 data3; }; private void CreateResources() { if (rtas == null) { RayTracingAccelerationStructure.Settings settings = new RayTracingAccelerationStructure.Settings { managementMode = RayTracingAccelerationStructure.ManagementMode.Manual, rayTracingModeMask = RayTracingAccelerationStructure.RayTracingModeMask.Everything, layerMask = -1, buildFlagsStaticGeometries = RayTracingAccelerationStructureBuildFlags.PreferFastTrace | RayTracingAccelerationStructureBuildFlags.MinimizeMemory, enableCompaction = true }; rtas = new RayTracingAccelerationStructure(settings); } if (cameraWidth != Camera.main.pixelWidth || cameraHeight != Camera.main.pixelHeight) { if (rayTracingOutput != null) rayTracingOutput.Release(); rayTracingOutput = new RenderTexture(Camera.main.pixelWidth, Camera.main.pixelHeight, 0, RenderTextureFormat.ARGBHalf); rayTracingOutput.enableRandomWrite = true; rayTracingOutput.Create(); cameraWidth = (uint)Camera.main.pixelWidth; cameraHeight = (uint)Camera.main.pixelHeight; } // The vertex and index buffers for the source geometry will be specified in RayTracingMultiGeometryInstanceConfig.vertexBuffer and indexBuffer. // Setup a vertex buffer that contains a quad and a triangle. The vertex contains the position and the normal. if (vertexBuffer == null) { List<Vertex> vertices = new List<Vertex> { // Add a quad. new Vertex(new Vector3(1, 0, -1), new Vector3(0, 1, 0)), new Vertex(new Vector3(1, 0, 1), new Vector3(0, 1, 0)), new Vertex(new Vector3(-1, 0, 1), new Vector3(0, 1, 0)), new Vertex(new Vector3(-1, 0, -1), new Vector3(0, 1, 0)), // Add a triangle. new Vertex(new Vector3(1, 0, 0), new Vector3(0, 0, 1)), new Vertex(new Vector3(-1, 0, 0), new Vector3(0, 0, 1)), new Vertex(new Vector3(0, 3, 0), new Vector3(0, 0, 1)), }; vertexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Raw | GraphicsBuffer.Target.Vertex, vertices.Count, Marshal.SizeOf(typeof(Vertex))); vertexBuffer.SetData(vertices); } // The geometry sub-ranges will be specified in RayTracingMultiGeometryInstanceConfig.subGeometries. if (indexBuffer == null) { List<uint> indices = new List<uint>() { // 2 triangles for the quad. 0, 1, 2, 0, 2, 3, // 1 triangle. 4, 5, 6, }; indexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Raw | GraphicsBuffer.Target.Index, indices.Count, sizeof(uint)); indexBuffer.SetData(indices); } if (instanceDataBuffer == null) { int instanceCount = instanceRows * instanceColumns; // Generate a list of transformation matrices. NativeArray<Matrix4x4> matrices = new NativeArray<Matrix4x4>(instanceCount, Allocator.Temp); int index = 0; Matrix4x4 m = Matrix4x4.identity; float angle = 0; // Arrange the instances into a matrix. for (int row = 0; row < instanceRows; row++) { float z = row + 0.5f - instanceRows * 0.5f; for (int column = 0; column < instanceColumns; column++) { float x = column + 0.5f - instanceColumns * 0.5f; angle += 10.0f; Quaternion rotation = Quaternion.Euler(0, angle, 0); m.SetTRS(new Vector3(5.5f * x, 4.001f, 5.5f * z), rotation, new Vector3(2, 2, 2)); matrices[index] = m; index++; } } instanceDataBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Raw, instanceCount, Marshal.SizeOf(typeof(RayTracingPerInstanceData))); RayTracingPerInstanceData[] perInstanceData = new RayTracingPerInstanceData[instanceCount]; Random.InitState(12345); for (int i = 0; i < instanceCount; i++) { perInstanceData[i] = new RayTracingPerInstanceData { // Assign a random geometry and material to each instance. objectToWorld = matrices[i], materialIndex = (uint)Random.Range(0, 2), geometryIndex = (uint)Random.Range(0, 2), data1 = i, data2 = 3.14f, data3 = new Vector4(1, 2, 3, 4), }; } instanceDataBuffer.SetData(perInstanceData); } if (indirectArgsBuffer == null) { indirectArgsBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Raw, 1, 2 * sizeof(int)); int[] ints = new int[2] { 0, // instanceStart instanceRows * instanceColumns // instanceCount }; indirectArgsBuffer.SetData(ints); } } void OnDestroy() { ReleaseResources(); } void OnDisable() { ReleaseResources(); } [ImageEffectOpaque] void OnRenderImage(RenderTexture src, RenderTexture dest) { if (SystemInfo.supportsRayTracing == false) { Debug.Log("The Ray Tracing API is not supported by this GPU or by the current graphics API."); Graphics.Blit(src, dest); return; } if (rayTracingShader == null) { Debug.Log("Please set the RayTracingShader."); Graphics.Blit(src, dest); return; } CreateResources(); rtas.ClearInstances(); CommandBuffer cmdBuffer = new CommandBuffer(); Material[] materials = new Material[2]; materials[0] = material1; materials[1] = material2; VertexAttributeDescriptor[] vertexDescs = new VertexAttributeDescriptor[2]; vertexDescs[0] = new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3, 0); vertexDescs[1] = new VertexAttributeDescriptor(VertexAttribute.Normal, VertexAttributeFormat.Float32, 3, 0); RayTracingMultiGeometryInstanceConfig instances = new RayTracingMultiGeometryInstanceConfig(); instances.vertexBuffer = vertexBuffer; instances.vertexAttributes = vertexDescs; instances.indexBuffer = indexBuffer; instances.materials = materials; instances.rayTracingMode = UnityEngine.Experimental.Rendering.RayTracingMode.Static; // Configure the 2 geometries. // The geometries in this example are considered opaque. When cutout materials are used (for example foliage), use RayTracingSubMeshFlags.Enabled flag alone to enable any hit shaders. instances.subGeometries = new RayTracingSubGeometryDesc[2] { // The quad. new RayTracingSubGeometryDesc { indexStart = 0, indexCount = 2 * 3, flags = RayTracingSubMeshFlags.Enabled | RayTracingSubMeshFlags.ClosestHitOnly }, // The triangle is right after the quad in the vertex buffer. new RayTracingSubGeometryDesc() { indexStart = 2 * 3, indexCount = 3, flags = RayTracingSubMeshFlags.Enabled | RayTracingSubMeshFlags.ClosestHitOnly } }; // Not using instance indices in this example. // We add all the instances from instanceDataBuffer. rtas.AddInstancesIndirect<RayTracingPerInstanceData>(instances, instanceDataBuffer, null, -1, indirectArgsBuffer, 0); cmdBuffer.BuildRayTracingAccelerationStructure(rtas); cmdBuffer.SetRayTracingShaderPass(rayTracingShader, "Test"); // Input cmdBuffer.SetRayTracingAccelerationStructure(rayTracingShader, Shader.PropertyToID("g_AccelStruct"), rtas); cmdBuffer.SetRayTracingFloatParam(rayTracingShader, Shader.PropertyToID("g_Zoom"), Mathf.Tan(Mathf.Deg2Rad * Camera.main.fieldOfView * 0.5f)); // Output cmdBuffer.SetRayTracingTextureParam(rayTracingShader, Shader.PropertyToID("g_Output"), rayTracingOutput); cmdBuffer.DispatchRays(rayTracingShader, "MainRayGenShader", cameraWidth, cameraHeight, 1); Graphics.ExecuteCommandBuffer(cmdBuffer); cmdBuffer.Release(); Graphics.Blit(rayTracingOutput, dest); }}
The script in this example calls AddInstancesIndirect\<T\> to add a number of ray tracing instances using random geometries and materials to an acceleration structure.