playcanvas
Version:
PlayCanvas WebGL game engine
211 lines (208 loc) • 9.35 kB
JavaScript
import { FloatPacking } from '../../core/math/float-packing.js';
import { Quat } from '../../core/math/quat.js';
import { Vec2 } from '../../core/math/vec2.js';
import { Vec3 } from '../../core/math/vec3.js';
import { ADDRESS_CLAMP_TO_EDGE, FILTER_NEAREST, PIXELFORMAT_RGBA16F, PIXELFORMAT_RGBA32U, PIXELFORMAT_R32U } from '../../platform/graphics/constants.js';
import { Texture } from '../../platform/graphics/texture.js';
import { BoundingBox } from '../../core/shape/bounding-box.js';
import { createGSplatMaterial } from './gsplat-material.js';
var getSHData = (gsplatData, numCoeffs)=>{
var result = [];
for(var i = 0; i < numCoeffs; ++i){
result.push(gsplatData.getProp("f_rest_" + i));
}
return result;
};
class GSplat {
destroy() {
var _this_colorTexture, _this_transformATexture, _this_transformBTexture, _this_sh1to3Texture, _this_sh4to7Texture, _this_sh8to11Texture, _this_sh12to15Texture;
(_this_colorTexture = this.colorTexture) == null ? void 0 : _this_colorTexture.destroy();
(_this_transformATexture = this.transformATexture) == null ? void 0 : _this_transformATexture.destroy();
(_this_transformBTexture = this.transformBTexture) == null ? void 0 : _this_transformBTexture.destroy();
(_this_sh1to3Texture = this.sh1to3Texture) == null ? void 0 : _this_sh1to3Texture.destroy();
(_this_sh4to7Texture = this.sh4to7Texture) == null ? void 0 : _this_sh4to7Texture.destroy();
(_this_sh8to11Texture = this.sh8to11Texture) == null ? void 0 : _this_sh8to11Texture.destroy();
(_this_sh12to15Texture = this.sh12to15Texture) == null ? void 0 : _this_sh12to15Texture.destroy();
}
createMaterial(options) {
var result = createGSplatMaterial(options);
result.setParameter('splatColor', this.colorTexture);
result.setParameter('transformA', this.transformATexture);
result.setParameter('transformB', this.transformBTexture);
result.setParameter('numSplats', this.numSplatsVisible);
result.setDefine('SH_BANDS', this.shBands);
if (this.sh1to3Texture) result.setParameter('splatSH_1to3', this.sh1to3Texture);
if (this.sh4to7Texture) result.setParameter('splatSH_4to7', this.sh4to7Texture);
if (this.sh8to11Texture) result.setParameter('splatSH_8to11', this.sh8to11Texture);
if (this.sh12to15Texture) result.setParameter('splatSH_12to15', this.sh12to15Texture);
return result;
}
evalTextureSize(count) {
var width = Math.ceil(Math.sqrt(count));
var height = Math.ceil(count / width);
return new Vec2(width, height);
}
createTexture(name, format, size) {
return new Texture(this.device, {
name: name,
width: size.x,
height: size.y,
format: format,
cubemap: false,
mipmaps: false,
minFilter: FILTER_NEAREST,
magFilter: FILTER_NEAREST,
addressU: ADDRESS_CLAMP_TO_EDGE,
addressV: ADDRESS_CLAMP_TO_EDGE
});
}
updateColorData(gsplatData) {
var texture = this.colorTexture;
if (!texture) {
return;
}
var float2Half = FloatPacking.float2Half;
var data = texture.lock();
var cr = gsplatData.getProp('f_dc_0');
var cg = gsplatData.getProp('f_dc_1');
var cb = gsplatData.getProp('f_dc_2');
var ca = gsplatData.getProp('opacity');
var SH_C0 = 0.28209479177387814;
for(var i = 0; i < this.numSplats; ++i){
var r = cr[i] * SH_C0 + 0.5;
var g = cg[i] * SH_C0 + 0.5;
var b = cb[i] * SH_C0 + 0.5;
var a = 1 / (1 + Math.exp(-ca[i]));
data[i * 4 + 0] = float2Half(r);
data[i * 4 + 1] = float2Half(g);
data[i * 4 + 2] = float2Half(b);
data[i * 4 + 3] = float2Half(a);
}
texture.unlock();
}
updateTransformData(gsplatData) {
var float2Half = FloatPacking.float2Half;
if (!this.transformATexture) {
return;
}
var dataA = this.transformATexture.lock();
var dataAFloat32 = new Float32Array(dataA.buffer);
var dataB = this.transformBTexture.lock();
var p = new Vec3();
var r = new Quat();
var s = new Vec3();
var iter = gsplatData.createIter(p, r, s);
for(var i = 0; i < this.numSplats; i++){
iter.read(i);
r.normalize();
if (r.w < 0) {
r.mulScalar(-1);
}
dataAFloat32[i * 4 + 0] = p.x;
dataAFloat32[i * 4 + 1] = p.y;
dataAFloat32[i * 4 + 2] = p.z;
dataA[i * 4 + 3] = float2Half(r.x) | float2Half(r.y) << 16;
dataB[i * 4 + 0] = float2Half(s.x);
dataB[i * 4 + 1] = float2Half(s.y);
dataB[i * 4 + 2] = float2Half(s.z);
dataB[i * 4 + 3] = float2Half(r.z);
}
this.transformATexture.unlock();
this.transformBTexture.unlock();
}
updateSHData(gsplatData) {
var _this_sh4to7Texture, _this_sh8to11Texture, _this_sh12to15Texture, _this_sh4to7Texture1, _this_sh8to11Texture1, _this_sh12to15Texture1;
var sh1to3Data = this.sh1to3Texture.lock();
var sh4to7Data = (_this_sh4to7Texture = this.sh4to7Texture) == null ? void 0 : _this_sh4to7Texture.lock();
var sh8to11Data = (_this_sh8to11Texture = this.sh8to11Texture) == null ? void 0 : _this_sh8to11Texture.lock();
var sh12to15Data = (_this_sh12to15Texture = this.sh12to15Texture) == null ? void 0 : _this_sh12to15Texture.lock();
var numCoeffs = {
1: 3,
2: 8,
3: 15
}[this.shBands];
var src = getSHData(gsplatData, numCoeffs * 3);
var t11 = (1 << 11) - 1;
var t10 = (1 << 10) - 1;
var float32 = new Float32Array(1);
var uint32 = new Uint32Array(float32.buffer);
var c = new Array(numCoeffs * 3).fill(0);
for(var i = 0; i < gsplatData.numSplats; ++i){
for(var j = 0; j < numCoeffs; ++j){
c[j * 3] = src[j][i];
c[j * 3 + 1] = src[j + numCoeffs][i];
c[j * 3 + 2] = src[j + numCoeffs * 2][i];
}
var max = c[0];
for(var j1 = 1; j1 < numCoeffs * 3; ++j1){
max = Math.max(max, Math.abs(c[j1]));
}
if (max === 0) {
continue;
}
for(var j2 = 0; j2 < numCoeffs; ++j2){
c[j2 * 3 + 0] = Math.max(0, Math.min(t11, Math.floor((c[j2 * 3 + 0] / max * 0.5 + 0.5) * t11 + 0.5)));
c[j2 * 3 + 1] = Math.max(0, Math.min(t10, Math.floor((c[j2 * 3 + 1] / max * 0.5 + 0.5) * t10 + 0.5)));
c[j2 * 3 + 2] = Math.max(0, Math.min(t11, Math.floor((c[j2 * 3 + 2] / max * 0.5 + 0.5) * t11 + 0.5)));
}
float32[0] = max;
sh1to3Data[i * 4 + 0] = uint32[0];
sh1to3Data[i * 4 + 1] = c[0] << 21 | c[1] << 11 | c[2];
sh1to3Data[i * 4 + 2] = c[3] << 21 | c[4] << 11 | c[5];
sh1to3Data[i * 4 + 3] = c[6] << 21 | c[7] << 11 | c[8];
if (this.shBands > 1) {
sh4to7Data[i * 4 + 0] = c[9] << 21 | c[10] << 11 | c[11];
sh4to7Data[i * 4 + 1] = c[12] << 21 | c[13] << 11 | c[14];
sh4to7Data[i * 4 + 2] = c[15] << 21 | c[16] << 11 | c[17];
sh4to7Data[i * 4 + 3] = c[18] << 21 | c[19] << 11 | c[20];
if (this.shBands > 2) {
sh8to11Data[i * 4 + 0] = c[21] << 21 | c[22] << 11 | c[23];
sh8to11Data[i * 4 + 1] = c[24] << 21 | c[25] << 11 | c[26];
sh8to11Data[i * 4 + 2] = c[27] << 21 | c[28] << 11 | c[29];
sh8to11Data[i * 4 + 3] = c[30] << 21 | c[31] << 11 | c[32];
sh12to15Data[i * 4 + 0] = c[33] << 21 | c[34] << 11 | c[35];
sh12to15Data[i * 4 + 1] = c[36] << 21 | c[37] << 11 | c[38];
sh12to15Data[i * 4 + 2] = c[39] << 21 | c[40] << 11 | c[41];
sh12to15Data[i * 4 + 3] = c[42] << 21 | c[43] << 11 | c[44];
} else {
sh8to11Data[i] = c[21] << 21 | c[22] << 11 | c[23];
}
}
}
this.sh1to3Texture.unlock();
(_this_sh4to7Texture1 = this.sh4to7Texture) == null ? void 0 : _this_sh4to7Texture1.unlock();
(_this_sh8to11Texture1 = this.sh8to11Texture) == null ? void 0 : _this_sh8to11Texture1.unlock();
(_this_sh12to15Texture1 = this.sh12to15Texture) == null ? void 0 : _this_sh12to15Texture1.unlock();
}
constructor(device, gsplatData){
var numSplats = gsplatData.numSplats;
this.device = device;
this.numSplats = numSplats;
this.numSplatsVisible = numSplats;
this.centers = new Float32Array(gsplatData.numSplats * 3);
gsplatData.getCenters(this.centers);
this.aabb = new BoundingBox();
gsplatData.calcAabb(this.aabb);
var size = this.evalTextureSize(numSplats);
this.colorTexture = this.createTexture('splatColor', PIXELFORMAT_RGBA16F, size);
this.transformATexture = this.createTexture('transformA', PIXELFORMAT_RGBA32U, size);
this.transformBTexture = this.createTexture('transformB', PIXELFORMAT_RGBA16F, size);
this.updateColorData(gsplatData);
this.updateTransformData(gsplatData);
this.shBands = gsplatData.shBands;
if (this.shBands > 0) {
this.sh1to3Texture = this.createTexture('splatSH_1to3', PIXELFORMAT_RGBA32U, size);
if (this.shBands > 1) {
this.sh4to7Texture = this.createTexture('splatSH_4to7', PIXELFORMAT_RGBA32U, size);
if (this.shBands > 2) {
this.sh8to11Texture = this.createTexture('splatSH_8to11', PIXELFORMAT_RGBA32U, size);
this.sh12to15Texture = this.createTexture('splatSH_12to15', PIXELFORMAT_RGBA32U, size);
} else {
this.sh8to11Texture = this.createTexture('splatSH_8to11', PIXELFORMAT_R32U, size);
}
}
this.updateSHData(gsplatData);
}
}
}
export { GSplat };