This is a Unity/HLSL port of the excellent Annotated Realtime Raytracing blog post by Kevin Fung.
The original GLSL shader runs live in a web browser on ShaderToy. Unity looks the same but at 138fps (Intel HD GPU).
This was much easier than I thought it would be. Here are the changes I made:
- Added HLSL kernel (
CSMain) that calls the GLSL fragment shader (mainImage) - Added
iGlobalTimeandiResolutionshader variables - Replaced
vec2withfloat2 - Replaced
vec3withfloat3 - Replaced
vec4withfloat4 - Expand constructors with 1 argument to n, e.g.
vec3(1.0)->float3(1.0,1.0,1.0) - Change
consttostatic const - Change struct initializer syntax, e.g.
Material(vec3(0.0,0.2,1.0),1.0,0.0)->{ float3(0.0,0.2,1.0),1.0,0.0 }
I learnt about Unity Compute Shaders from Coxlin's Blog. This article just multiplies 4 integers by 2.0 in a Computer Shader and prints the results to the console. Everything you need to know to get started.
Understanding the relationship between the [numthreads(x,y,z)] attribute in the shader, and the shader.Dispatch(kernelIndex, gx,gy,gz) call in C#, is fundamental. The kernel CSMain is executed (x*y*z) * (gx*gy*gz) times and the id passed into the kernel ranges from (0,0,0) to (x*gx, y*gy, z*gz).
Here is how the kernel is evaluated for each thread in pseudocode:
const int numThreadsX, numThreadsY, numThreadsZ;
static void kernel(int x, int y, int z) { }
static void Dispatch(int threadGroupsX, int threadGroupsY, int threadGroupsZ) {
for (var gx = 0; gx < threadGroupsX; gx++) {
for (var gy = 0; gy < threadGroupsY; gy++) {
for (var gz = 0; gz < threadGroupsZ; gz++) {
// Dispatch group
for (var x = 0; x < numThreadsX; x++) {
for (var y = 0; y < numThreadsY; y++) {
for (var z = 0; z < numThreadsZ; z++) {
kernel(
gx * numThreadsX + x,
gy * numThreadsY + y,
gz * numThreadsZ + z
);
}
}
}
}
}
}
}
