UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

3 lines (2 loc) 2.83 kB
export const computeGsplatIntervalCullSource: "\n\nstruct Interval {\n workBufferBase: u32,\n splatCount: u32,\n boundsIndex: u32,\n pad: u32\n};\n\nstruct BoundsEntry {\n centerX: f32,\n centerY: f32,\n centerZ: f32,\n radius: f32,\n transformIndex: u32,\n pad0: u32,\n pad1: u32,\n pad2: u32\n};\n\nstruct CullUniforms {\n#ifdef GSPLAT_FISHEYE\n cameraWorldPos: vec3f,\n maxTheta: f32,\n cameraForward: vec3f,\n numIntervals: u32,\n#else\n frustumPlanes: array<vec4f, 6>,\n numIntervals: u32\n#endif\n};\n\n@group(0) @binding(0) var<uniform> uniforms: CullUniforms;\n\n@group(0) @binding(1) var<storage, read> intervals: array<Interval>;\n\n@group(0) @binding(2) var<storage, read_write> countBuffer: array<u32>;\n\n@group(0) @binding(3) var<storage, read> boundsBuffer: array<BoundsEntry>;\n@group(0) @binding(4) var<storage, read> transformsBuffer: array<vec4f>;\n\n@compute @workgroup_size({WORKGROUP_SIZE})\nfn main(@builtin(global_invocation_id) gid: vec3u) {\n let idx = gid.x;\n if (idx < uniforms.numIntervals) {\n let interval = intervals[idx];\n\n let entry = boundsBuffer[interval.boundsIndex];\n let localCenter = vec3f(entry.centerX, entry.centerY, entry.centerZ);\n let radius = entry.radius;\n\n let base = entry.transformIndex * 3u;\n let row0 = transformsBuffer[base];\n let row1 = transformsBuffer[base + 1u];\n let row2 = transformsBuffer[base + 2u];\n\n let worldCenter = vec3f(\n dot(vec4f(localCenter, 1.0), row0),\n dot(vec4f(localCenter, 1.0), row1),\n dot(vec4f(localCenter, 1.0), row2)\n );\n\n let worldRadius = radius * length(vec3f(row0.x, row1.x, row2.x));\n\n #ifdef GSPLAT_FISHEYE\n let v = worldCenter - uniforms.cameraWorldPos;\n let d = length(v);\n var visible = true;\n if (d > worldRadius) {\n let cosAngle = dot(v / d, uniforms.cameraForward);\n let theta = acos(clamp(cosAngle, -1.0, 1.0));\n let angularRadius = asin(min(worldRadius / d, 1.0));\n visible = (theta - angularRadius) < uniforms.maxTheta;\n }\n #else\n var visible = true;\n for (var p = 0; p < 6; p++) {\n let plane = uniforms.frustumPlanes[p];\n let dist = dot(plane.xyz, worldCenter) + plane.w;\n if (dist <= -worldRadius) {\n visible = false;\n break;\n }\n }\n #endif\n\n countBuffer[idx] = select(0u, interval.splatCount, visible);\n }\n\n // Thread 0 writes sentinel so prefixSum[numIntervals] = total visible count\n if (idx == 0u) {\n countBuffer[uniforms.numIntervals] = 0u;\n }\n}\n"; export default computeGsplatIntervalCullSource;