UNPKG

playcanvas

Version:

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

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