UNPKG

playcanvas

Version:

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

167 lines (166 loc) 4.79 kB
const computeGsplatCommonSource = ` #include "halfTypesCS" const TILE_SIZE: u32 = 16u; fn quatToMat3(r: half4) -> half3x3 { let r2: half4 = r + r; let x: half = r2.x * r.w; let y: half4 = r2.y * r; let z: half4 = r2.z * r; let w: half = r2.w * r.w; return half3x3( half(1.0) - z.z - w, y.z + x, y.w - z.x, y.z - x, half(1.0) - y.y - w, z.w + y.x, y.w + z.x, z.w - y.x, half(1.0) - y.y - z.z ); } struct SplatCov2D { screen: vec2f, a: f32, b: f32, c: f32, viewDepth: f32, valid: bool, #if GSPLAT_AA aaFactor: f32, #endif } fn computeSplatCov( worldCenter: vec3f, rotation: half4, scale: half3, viewMatrix: mat4x4f, viewProj: mat4x4f, focal: f32, viewportWidth: f32, viewportHeight: f32, nearClip: f32, farClip: f32, opacity: f32, minPixelSize: f32, isOrtho: u32, alphaClip: f32, minContribution: f32, #ifdef GSPLAT_FISHEYE fisheye_k: f32, fisheye_inv_k: f32, fisheye_projMat00: f32, fisheye_projMat11: f32, #endif ) -> SplatCov2D { var result: SplatCov2D; result.valid = false; let viewCenter = (viewMatrix * vec4f(worldCenter, 1.0)).xyz; #ifdef GSPLAT_FISHEYE let fv = viewCenter; let r_xy = length(fv.xy); let neg_z = -fv.z; let theta = atan2(r_xy, neg_z); let maxTheta = min(fisheye_k * 1.5707963, 3.13); if (theta > maxTheta - 0.01 || dot(fv, fv) < 0.0001) { return result; } let tk = theta * fisheye_inv_k; let sin_tk = sin(tk); let cos_tk = cos(tk); let g_theta = fisheye_k * sin_tk / cos_tk; let fisheye_s = select(select(0.0, 1.0 / neg_z, neg_z > 0.0), g_theta / r_xy, r_xy > 1e-4); let fndc = vec2f(fisheye_projMat00 * fisheye_s * fv.x, fisheye_projMat11 * fisheye_s * fv.y); let screen = vec2f( (fndc.x * 0.5 + 0.5) * viewportWidth, (fndc.y * 0.5 + 0.5) * viewportHeight ); #else if (viewCenter.z > 0.0) { return result; } let clip = viewProj * vec4f(worldCenter, 1.0); let ndc = clip.xy / clip.w; let screen = vec2f( (ndc.x * 0.5 + 0.5) * viewportWidth, (ndc.y * 0.5 + 0.5) * viewportHeight ); #endif let rot: half3x3 = quatToMat3(rotation); let s: vec3f = vec3f(scale); let M: mat3x3f = transpose(mat3x3f( s.x * vec3f(rot[0]), s.y * vec3f(rot[1]), s.z * vec3f(rot[2]) )); let w0 = vec3f(viewMatrix[0].x, viewMatrix[1].x, viewMatrix[2].x); let w1 = vec3f(viewMatrix[0].y, viewMatrix[1].y, viewMatrix[2].y); let w2 = vec3f(viewMatrix[0].z, viewMatrix[1].z, viewMatrix[2].z); #ifdef GSPLAT_FISHEYE let fisheyeFocal = viewportWidth * fisheye_projMat00; let g_prime = 1.0 / (cos_tk * cos_tk); let d2 = dot(fv, fv); let r_sq = max(r_xy * r_xy, 1e-8); let K_coeff = select(0.0, (g_prime * neg_z / d2 - fisheye_s) / r_sq, r_xy > 1e-4); let Jxx = fisheyeFocal * (fisheye_s + K_coeff * fv.x * fv.x); let Jxy = fisheyeFocal * K_coeff * fv.x * fv.y; let Jyy = fisheyeFocal * (fisheye_s + K_coeff * fv.y * fv.y); let Jzx = fisheyeFocal * g_prime * fv.x / d2; let Jzy = fisheyeFocal * g_prime * fv.y / d2; let tt0 = Jxx * w0 + Jxy * w1 + Jzx * w2; let tt1 = Jxy * w0 + Jyy * w1 + Jzy * w2; #else let ortho = isOrtho == 1u; let v = select(viewCenter.xyz, vec3f(0.0, 0.0, 1.0), ortho); let vz = select(min(v.z, -0.001), v.z, ortho); let J1 = focal / vz; let J2 = -J1 / vz * v.xy; let tt0 = J1 * w0 + J2.x * w2; let tt1 = J1 * w1 + J2.y * w2; #endif let b0 = M * tt0; let b1 = M * tt1; let aRaw = dot(b0, b0); let b = dot(b0, b1); let cRaw = dot(b1, b1); let a = aRaw + 0.3; let c = cRaw + 0.3; let det = a * c - b * b; if (det <= 0.0) { return result; } #if GSPLAT_AA let detOrig = aRaw * cRaw - b * b; result.aaFactor = sqrt(max(detOrig / det, 0.0)); #endif let totalContribution = opacity * 6.283185 * sqrt(det); if (totalContribution < minContribution) { return result; } let radiusFactor = computeRadiusFactor(half(opacity), alphaClip); let vmin = min(1024.0, min(viewportWidth, viewportHeight)); let maxRadius = vmin; let radiusXUncapped = sqrt(2.0 * a); let radiusYUncapped = sqrt(2.0 * c); let radiusX = min(radiusXUncapped, maxRadius); let radiusY = min(radiusYUncapped, maxRadius); if (max(radiusX, radiusY) < minPixelSize) { return result; } if (screen.x + radiusX < 0.0 || screen.x - radiusX > viewportWidth || screen.y + radiusY < 0.0 || screen.y - radiusY > viewportHeight) { return result; } let capScale = max(1.0, max(radiusXUncapped, radiusYUncapped) / maxRadius); let invCapScale2 = 1.0 / (capScale * capScale); result.screen = screen; let scaledCov = vec3f(a, b, c) * invCapScale2; result.a = scaledCov.x; result.b = scaledCov.y; result.c = scaledCov.z; #ifdef GSPLAT_FISHEYE result.viewDepth = sqrt(d2); #else result.viewDepth = -viewCenter.z; #endif result.valid = true; return result; } `; export { computeGsplatCommonSource };