Parameter | Description |
---|---|
accelerationStructure | The RayTracingAccelerationStructure to be generated. |
relativeOrigin | The relative origin of ray tracing instances. The default value is Vector3.zero. To use camera-relative ray-tracing, set this parameter to the position of the camera. |
buildSettings | The BuildSettings to use. |
Adds a command to build the RayTracingAccelerationStructure to be used in a ray tracing dispatch or when using inline ray tracing (ray queries).
To ensure that the acceleration structure is up to date, call this method before using the acceleration structure in ray tracing shaders (for example before a CommandBuffer.DispatchRays call) or when using inline ray tracing.
In the following example, the Update
method uses a compute shader dispatch to modify the vertex positions of a mesh instance, then the RayTracingAccelerationStructure is rebuilt.
using Unity.Collections; using UnityEngine; using UnityEngine.Rendering;
public class RayTracingInstanceManager : MonoBehaviour { public Material instanceMaterial; public ComputeShader vertexAnimationShader; public RayTracingShader rayTracingShader;
private RayTracingAccelerationStructure rtas; private CommandBuffer cmd; private RenderTexture rayTracingOutput; private uint cameraWidth = 0; private uint cameraHeight = 0; private uint meshResolution = 32; private Mesh instanceMesh;
void Start() { // Create command buffer cmd = new CommandBuffer(); cmd.name = "Ray Tracing Setup";
InitializeRayTracing(); }
private NativeArray<uint> CreateIndexArray(uint resolution) { uint indexCount = 2 * 3 * resolution * resolution; uint[] indices = new uint[indexCount];
int index = 0;
for (uint i = 0; i < resolution; i++) { for (uint j = 0; j < resolution; j++) { indices[index++] = i * (resolution + 1) + j; indices[index++] = (i + 1) * (resolution + 1) + j; indices[index++] = (i + 1) * (resolution + 1) + j + 1;
indices[index++] = i * (resolution + 1) + j; indices[index++] = (i + 1) * (resolution + 1) + j + 1; indices[index++] = i * (resolution + 1) + j + 1; } }
return new NativeArray<uint>(indices, Allocator.Persistent); }
struct Vertex { public Vector3 position; }
private NativeArray<Vertex> CreateVertexArray(uint resolution) { uint vertexCount = (resolution + 1) * (resolution + 1); Vertex[] vertices = new Vertex[vertexCount];
float invResolution = 1.0f / (float)resolution; float step = 2.0f * invResolution; int vertexIndex = 0; float posZ = -1.0f;
for (uint z = 0; z <= resolution; z++) { float posX = -1.0f;
for (uint x = 0; x <= resolution; x++) { vertices[vertexIndex].position = new Vector3(posX, 0, posZ);
vertexIndex++; posX += step; } posZ += step; }
return new NativeArray<Vertex>(vertices, Allocator.Temp); }
void InitializeRayTracing() { // Set up acceleration structure RayTracingAccelerationStructure.Settings settings = new RayTracingAccelerationStructure.Settings { managementMode = RayTracingAccelerationStructure.ManagementMode.Manual, layerMask = -1 }; rtas = new RayTracingAccelerationStructure(settings); // Create base mesh on GPU instanceMesh = new Mesh();
if (SystemInfo.supportsComputeShaders) { instanceMesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw; instanceMesh.indexBufferTarget |= GraphicsBuffer.Target.Raw; }
using (NativeArray<Vertex> varray = CreateVertexArray(meshResolution)) { instanceMesh.SetVertexBufferParams(varray.Length, new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3)); instanceMesh.SetVertexBufferData(varray, 0, 0, varray.Length); }
using (NativeArray<uint> iarray = CreateIndexArray(meshResolution)) { instanceMesh.SetIndexBufferParams(iarray.Length, IndexFormat.UInt32); instanceMesh.SetIndexBufferData(iarray, 0, 0, iarray.Length); instanceMesh.SetSubMesh(0, new SubMeshDescriptor(0, iarray.Length)); }
RayTracingMeshInstanceConfig gpuMeshInstance = new RayTracingMeshInstanceConfig(instanceMesh, 0, instanceMaterial);
// Make the acceleration structure update every time we call RayTracingAccelerationStructure.Build or CommandBuffer.BuildRayTracingAccelerationStructure. gpuMeshInstance.dynamicGeometry = true;
Matrix4x4 matrix = Matrix4x4.identity; matrix.SetTRS(new Vector3(0.0f, 0.0f, 0.0f), Quaternion.identity, Vector3.one);
rtas.AddInstance(gpuMeshInstance, matrix); }
void CreateResources() { 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; } }
void Update() { if (vertexAnimationShader == null) { Debug.LogError("Error: Compute shader is missing. Assign a compute shader to the vertexAnimationShader property."); return; }
GraphicsBuffer vertexBuffer = instanceMesh.GetVertexBuffer(0); cmd.SetComputeBufferParam(vertexAnimationShader, 0, "vertexBuffer", vertexBuffer);
cmd.SetComputeFloatParam(vertexAnimationShader, "realtimeSinceStartup", Time.realtimeSinceStartup); cmd.SetComputeIntParam(vertexAnimationShader, "vertexCount", vertexBuffer.count); cmd.SetComputeIntParam(vertexAnimationShader, "vertexSizeInBytes", vertexBuffer.stride);
if (vertexBuffer.stride % 4 != 0) Debug.Log("Vertex stride must be a multiple of 4.");
uint kernelGroupSizeX, kernelGroupSizeY, kernelGroupSizeZ; vertexAnimationShader.GetKernelThreadGroupSizes(0, out kernelGroupSizeX, out kernelGroupSizeY, out kernelGroupSizeZ);
int threadGroupsX = (int)(instanceMesh.vertexCount + kernelGroupSizeX - 1) / (int)kernelGroupSizeX; cmd.DispatchCompute(vertexAnimationShader, 0, threadGroupsX, 1, 1);
vertexBuffer.Dispose();
// Re-build acceleration to take into account modified mesh geometry. cmd.BuildRayTracingAccelerationStructure(rtas); // The command buffer will be executed in the next OnRenderImage }
[ImageEffectOpaque] void OnRenderImage(RenderTexture src, RenderTexture dest) { if (!SystemInfo.supportsRayTracing || !rayTracingShader) { Debug.LogWarning("Warning: The Ray Tracing API is not supported by this GPU or by the current graphics API."); Graphics.Blit(src, dest); return; } CreateResources(); cmd.SetRayTracingShaderPass(rayTracingShader, "Test"); // Input cmd.SetRayTracingAccelerationStructure(rayTracingShader, Shader.PropertyToID("g_AccelStruct"), rtas); cmd.SetRayTracingMatrixParam(rayTracingShader, Shader.PropertyToID("g_InvViewMatrix"), Camera.main.cameraToWorldMatrix); cmd.SetGlobalVector(Shader.PropertyToID("g_CameraPos"), Camera.main.transform.position); // Output cmd.SetRayTracingTextureParam(rayTracingShader, Shader.PropertyToID("g_Output"), rayTracingOutput); // Execute the raytracing shader cmd.DispatchRays(rayTracingShader, "MainRayGenShader", cameraWidth, cameraHeight, 1); // Execute command buffer Graphics.ExecuteCommandBuffer(cmd); cmd.Clear(); Graphics.Blit(rayTracingOutput, dest); }
void OnDisable() { // Cleanup if (rtas != null) { rtas.Dispose(); rtas = null; } if (instanceMesh != null) { DestroyImmediate(instanceMesh); instanceMesh = null; } if (cmd != null) { cmd.Release(); cmd = null; } if (rayTracingOutput != null) { rayTracingOutput.Release(); rayTracingOutput = null; } } }