UNPKG

playcanvas

Version:

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

2 lines (1 loc) 2.52 kB
export const computeGsplatTileIntersectSource: "\n\nstruct SplatTileEval {\n radiusFactor: f32,\n splatMin: vec2f,\n splatMax: vec2f,\n}\n\nfn computeRadiusFactor(opacity: half, alphaClip: f32) -> f32 {\n return min(8.0, 2.0 * log(f32(opacity) / alphaClip));\n}\n\nfn computeSplatTileEval(\n screen: vec2f,\n cx: f32, cy: f32, cz: f32,\n opacity: half,\n viewportWidth: f32, viewportHeight: f32,\n alphaClip: f32\n) -> SplatTileEval {\n let K = cx * cz - cy * cy;\n let a = 4.0 * cz / K;\n let c = 4.0 * cx / K;\n let radiusFactor = computeRadiusFactor(opacity, alphaClip);\n let vmin = min(1024.0, min(viewportWidth, viewportHeight));\n let radius = vec2f(min(sqrt(2.0 * a), vmin), min(sqrt(2.0 * c), vmin));\n var result: SplatTileEval;\n result.radiusFactor = radiusFactor;\n result.splatMin = screen - radius;\n result.splatMax = screen + radius;\n return result;\n}\n\n// Tests if the quadratic a*t^2 + b*t + c = 0 has a root in the interval [l-d, r-d].\nfn segmentIntersectsEllipse(a: f32, b: f32, c: f32, d: f32, l: f32, r: f32) -> bool {\n let delta = b * b - 4.0 * a * c;\n let t1 = (l - d) * (2.0 * a) + b;\n let t2 = (r - d) * (2.0 * a) + b;\n return delta >= 0.0 && (t1 <= 0.0 || t1 * t1 <= delta) && (t2 >= 0.0 || t2 * t2 <= delta);\n}\n\n// Tests if the Gaussian cutoff ellipse intersects a tile rectangle.\n// Exact conic-edge intersection using positive-definite conic: cx*dx^2 + 2*cy*dx*dy + cz*dy^2 = w\nfn tileIntersectsEllipse(\n tileMin: vec2f, tileMax: vec2f, center: vec2f,\n cx: f32, cy: f32, cz: f32,\n radiusFactor: f32\n) -> bool {\n if (center.x >= tileMin.x && center.x <= tileMax.x &&\n center.y >= tileMin.y && center.y <= tileMax.y) {\n return true;\n }\n\n let w = radiusFactor;\n\n // Test closest horizontal edge\n var dx: f32;\n if (center.x * 2.0 < tileMin.x + tileMax.x) {\n dx = center.x - tileMin.x;\n } else {\n dx = center.x - tileMax.x;\n }\n if (segmentIntersectsEllipse(cz, -2.0 * cy * dx, cx * dx * dx - w, center.y, tileMin.y, tileMax.y)) {\n return true;\n }\n\n // Test closest vertical edge\n var dy: f32;\n if (center.y * 2.0 < tileMin.y + tileMax.y) {\n dy = center.y - tileMin.y;\n } else {\n dy = center.y - tileMax.y;\n }\n if (segmentIntersectsEllipse(cx, -2.0 * cy * dy, cz * dy * dy - w, center.x, tileMin.x, tileMax.x)) {\n return true;\n }\n\n return false;\n}\n";