import Common; [shader("compute")] [numthreads(8, 8, 1)] void computeKernel(uint2 threadId [[thread_position_in_grid]]) { if (threadId.x >= pParams.cam.width || threadId.y >= pParams.cam.height) return; uint pass = pSamps.pass; uint samplesPerPixel = pSamps.samplesPerPixel; if (pass == samplesPerPixel) return; uint2 pix = threadId; uint imgWidth = pParams.cam.width; uint imgHeight = pParams.cam.height; //-- define cam float3 camPos = pParams.cam.cameraPosition; float3 camForward = pParams.cam.cameraForward; float f = pParams.cam.f; float S_O = pParams.cam.S_O; float3 fogEmm = pParams.cam.fogEmm; float ks = pParams.cam.ks; float A = pParams.cam.A; float ka = pParams.cam.ka; float2 sensorSize = pParams.cam.sensorSize; float3 cx = -normalize(cross(camForward, abs(camForward.y) < 0.9 ? float3(0, 1, 0) : float3(0, 0, 1))); float3 cy = cross(camForward, cx); const float2 sdim = sensorSize; float S_I = (S_O * f) / (S_O - f); //-- sample sensor float3 rnd = rand01(uint3(pix, pass)); float2 rnd2 = 2.0f * float2(rnd.xy); // tent filter float2 tent = float2(rnd2.x < 1 ? sqrt(rnd2.x) - 1 : 1 - sqrt(2 - rnd2.x), rnd2.y < 1 ? sqrt(rnd2.y) - 1 : 1 - sqrt(2 - rnd2.y)); float2 s = ((float2(pix) + 0.5f * (0.5f + float2((pass / 2) % 2, pass % 2) + tent)) / float2(imgWidth, imgHeight) - 0.5f) * sdim; float3 lc = camPos + camForward * 0.035f; // sample on 3d sensor plane float3 spos = camPos + cx * s.x + cy * s.y; float3 rayDir = normalize(lc - spos); //-- setup lens (simplified) float3 lensSample = lc; // for now, just use camera position slightly offset if needed? // Actually let's do it properly based on A parameter float3 lensN = -camForward; float3 lensX = cross(lensN, float3(0, 1, 0)); float3 lensY = cross(lensN, lensX); float2 rnd01 = rand01(uint3(pix, pass)).xy; lensSample = lc + rnd01.x * A * lensX + rnd01.y * A * lensY; float focalPoint = camPos + (S_O + S_I) * camForward; float t_focus = dot(focalPoint - lensSample, lensN) / dot(rayDir, lensN); float3 focus = lensSample + t_focus * rayDir; float3 rayOrg = lensSample; float3 rayDirFinal = normalize(focus - lensSample); // Ray Tracing Loop RayPayload payload; payload.light = float3(0); payload.emissive = 1.0f; payload.depth = 1; payload.hit = false; payload.anyHit = false; // Note: We are using the compute-based intersection loop because it's easier to implement in a single kernel // and we have access to common helper functions. In a full RT pipeline we would use dedicated shaders. // Since we don't have the specialized 'intersector' object from before, // we will use a placeholder for now or assume it's available if provided by Slang/Metal context. // BUT since I am writing this from scratch, I should probably implement the traversal OR // just use MS's Compute-based approach as in Compute.metal which worked. // Wait! To keep it simple and "lazy", I will just copy the logic from Compute.metal into this Slang file // and replace all its types with pParams fields. }