UNPKG

playcanvas

Version:

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

90 lines (88 loc) 2.64 kB
class GSplatSortBinWeights { static get NUM_BINS() { return 32; } static get WEIGHT_TIERS() { return [ { maxDistance: 0, weight: 40.0 }, { maxDistance: 2, weight: 20.0 }, { maxDistance: 5, weight: 8.0 }, { maxDistance: 10, weight: 3.0 }, { maxDistance: Infinity, weight: 1.0 } ]; } static computeCameraBin(radialSort, minDist, range) { const numBins = GSplatSortBinWeights.NUM_BINS; if (radialSort) { return numBins - 1; } const cameraOffsetFromRangeStart = -minDist; const cameraBinFloat = cameraOffsetFromRangeStart / range * numBins; return Math.max(0, Math.min(numBins - 1, Math.floor(cameraBinFloat))); } compute(cameraBin, bucketCount) { if (cameraBin === this.lastCameraBin && bucketCount === this.lastBucketCount) { return this.binWeights; } this.lastCameraBin = cameraBin; this.lastBucketCount = bucketCount; const numBins = GSplatSortBinWeights.NUM_BINS; const bitsPerBin = this.bitsPerBin; for(let i = 0; i < numBins; i++){ const distFromCamera = Math.abs(i - cameraBin); bitsPerBin[i] = this.weightByDistance[distFromCamera]; } let totalWeight = 0; for(let i = 0; i < numBins; i++){ totalWeight += bitsPerBin[i]; } let accumulated = 0; for(let i = 0; i < numBins; i++){ const divider = Math.max(1, Math.floor(bitsPerBin[i] / totalWeight * bucketCount)); this.binWeights[i * 2] = accumulated; this.binWeights[i * 2 + 1] = divider; accumulated += divider; } if (accumulated > bucketCount) { const excess = accumulated - bucketCount; const lastDividerIdx = (numBins - 1) * 2 + 1; this.binWeights[lastDividerIdx] = Math.max(1, this.binWeights[lastDividerIdx] - excess); } return this.binWeights; } constructor(){ this.binWeights = new Float32Array(GSplatSortBinWeights.NUM_BINS * 2); this.lastCameraBin = -1; this.lastBucketCount = -1; const numBins = GSplatSortBinWeights.NUM_BINS; const weightTiers = GSplatSortBinWeights.WEIGHT_TIERS; this.bitsPerBin = new Float32Array(numBins); this.weightByDistance = new Float32Array(numBins); for(let dist = 0; dist < numBins; dist++){ let weight = 1.0; for(let j = 0; j < weightTiers.length; j++){ if (dist <= weightTiers[j].maxDistance) { weight = weightTiers[j].weight; break; } } this.weightByDistance[dist] = weight; } } } export { GSplatSortBinWeights };