playcanvas
Version:
PlayCanvas WebGL game engine
171 lines (168 loc) • 7.58 kB
JavaScript
import { Vec2 } from '../../core/math/vec2.js';
import { Texture } from '../../platform/graphics/texture.js';
import { BoundingBox } from '../../core/shape/bounding-box.js';
import { FILTER_NEAREST, ADDRESS_CLAMP_TO_EDGE, PIXELFORMAT_RGBA32U, PIXELFORMAT_RGBA32F } from '../../platform/graphics/constants.js';
import { createGSplatMaterial } from './gsplat-material.js';
function _extends() {
_extends = Object.assign || function(target) {
for(var i = 1; i < arguments.length; i++){
var source = arguments[i];
for(var key in source){
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
/**
* @import { GSplatCompressedData } from './gsplat-compressed-data.js'
* @import { GraphicsDevice } from '../../platform/graphics/graphics-device.js'
* @import { Material } from '../materials/material.js'
* @import { SplatMaterialOptions } from './gsplat-material.js'
*/ // copy data with padding
var strideCopy = (target, targetStride, src, srcStride, numEntries)=>{
for(var i = 0; i < numEntries; ++i){
for(var j = 0; j < srcStride; ++j){
target[i * targetStride + j] = src[i * srcStride + j];
}
}
};
class GSplatCompressed {
destroy() {
var _this_packedTexture, _this_chunkTexture, _this_shTexture0, _this_shTexture1, _this_shTexture2;
(_this_packedTexture = this.packedTexture) == null ? undefined : _this_packedTexture.destroy();
(_this_chunkTexture = this.chunkTexture) == null ? undefined : _this_chunkTexture.destroy();
(_this_shTexture0 = this.shTexture0) == null ? undefined : _this_shTexture0.destroy();
(_this_shTexture1 = this.shTexture1) == null ? undefined : _this_shTexture1.destroy();
(_this_shTexture2 = this.shTexture2) == null ? undefined : _this_shTexture2.destroy();
}
/**
* @param {SplatMaterialOptions} options - The splat material options.
* @returns {Material} material - The material to set up for the splat rendering.
*/ createMaterial(options) {
var result = createGSplatMaterial(options);
result.setDefine('GSPLAT_COMPRESSED_DATA', true);
result.setParameter('packedTexture', this.packedTexture);
result.setParameter('chunkTexture', this.chunkTexture);
result.setParameter('numSplats', this.numSplatsVisible);
if (this.shTexture0) {
result.setDefine('SH_BANDS', 3);
result.setParameter('shTexture0', this.shTexture0);
result.setParameter('shTexture1', this.shTexture1);
result.setParameter('shTexture2', this.shTexture2);
} else {
result.setDefine('SH_BANDS', 0);
}
return result;
}
/**
* Evaluates the texture size needed to store a given number of elements.
* The function calculates a width and height that is close to a square
* that can contain 'count' elements.
*
* @param {number} count - The number of elements to store in the texture.
* @returns {Vec2} The width and height of the texture.
*/ evalTextureSize(count) {
var width = Math.ceil(Math.sqrt(count));
var height = Math.ceil(count / width);
return new Vec2(width, height);
}
/**
* Creates a new texture with the specified parameters.
*
* @param {string} name - The name of the texture to be created.
* @param {number} format - The pixel format of the texture.
* @param {Vec2} size - The width and height of the texture.
* @param {Uint8Array|Uint16Array|Uint32Array} [data] - The initial data to fill the texture with.
* @returns {Texture} The created texture instance.
*/ createTexture(name, format, size, data) {
return new Texture(this.device, _extends({
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
}, data ? {
levels: [
data
]
} : {}));
}
/**
* @param {GraphicsDevice} device - The graphics device.
* @param {GSplatCompressedData} gsplatData - The splat data.
*/ constructor(device, gsplatData){
var { chunkData, chunkSize, numChunks, numSplats, vertexData, shBands } = gsplatData;
this.device = device;
this.numSplats = numSplats;
this.numVisibleSplats = numSplats;
// initialize aabb
this.aabb = new BoundingBox();
gsplatData.calcAabb(this.aabb);
// initialize centers
this.centers = new Float32Array(numSplats * 3);
gsplatData.getCenters(this.centers);
// initialize packed data
this.packedTexture = this.createTexture('packedData', PIXELFORMAT_RGBA32U, this.evalTextureSize(numSplats), vertexData);
// initialize chunk data
var chunkTextureSize = this.evalTextureSize(numChunks);
chunkTextureSize.x *= 5;
this.chunkTexture = this.createTexture('chunkData', PIXELFORMAT_RGBA32F, chunkTextureSize);
var chunkTextureData = this.chunkTexture.lock();
strideCopy(chunkTextureData, 20, chunkData, chunkSize, numChunks);
if (chunkSize === 12) {
// if the chunks don't contain color min/max values we must update max to 1 (min is filled with 0's)
for(var i = 0; i < numChunks; ++i){
chunkTextureData[i * 20 + 15] = 1;
chunkTextureData[i * 20 + 16] = 1;
chunkTextureData[i * 20 + 17] = 1;
}
}
this.chunkTexture.unlock();
// load optional spherical harmonics data
if (shBands > 0) {
var { shData } = gsplatData;
var size = this.evalTextureSize(numSplats);
var texture0 = this.createTexture('shTexture0', PIXELFORMAT_RGBA32U, size);
var texture1 = this.createTexture('shTexture1', PIXELFORMAT_RGBA32U, size);
var texture2 = this.createTexture('shTexture2', PIXELFORMAT_RGBA32U, size);
var data0 = texture0.lock();
var data1 = texture1.lock();
var data2 = texture2.lock();
var target0 = new Uint8Array(data0.buffer);
var target1 = new Uint8Array(data1.buffer);
var target2 = new Uint8Array(data2.buffer);
var srcCoeffs = [
3,
8,
15
][shBands - 1];
for(var i1 = 0; i1 < numSplats; ++i1){
for(var j = 0; j < 15; ++j){
target0[i1 * 16 + j] = j < srcCoeffs ? shData[(i1 * 3 + 0) * srcCoeffs + j] : 127;
target1[i1 * 16 + j] = j < srcCoeffs ? shData[(i1 * 3 + 1) * srcCoeffs + j] : 127;
target2[i1 * 16 + j] = j < srcCoeffs ? shData[(i1 * 3 + 2) * srcCoeffs + j] : 127;
}
}
texture0.unlock();
texture1.unlock();
texture2.unlock();
this.shTexture0 = texture0;
this.shTexture1 = texture1;
this.shTexture2 = texture2;
} else {
this.shTexture0 = null;
this.shTexture1 = null;
this.shTexture2 = null;
}
}
}
export { GSplatCompressed };