playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
90 lines (88 loc) • 2.64 kB
JavaScript
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 };