UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

211 lines (208 loc) 9.35 kB
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 };