UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

165 lines (162 loc) 5.24 kB
import { Vec2 } from '../../core/math/vec2.js'; import { BoundingBox } from '../../core/shape/bounding-box.js'; import { TYPE_UINT32, SEMANTIC_ATTR13, BUFFER_STATIC, ADDRESS_CLAMP_TO_EDGE, FILTER_NEAREST, SEMANTIC_POSITION } from '../../platform/graphics/constants.js'; import { Texture } from '../../platform/graphics/texture.js'; import { VertexFormat } from '../../platform/graphics/vertex-format.js'; import { VertexBuffer } from '../../platform/graphics/vertex-buffer.js'; import { Mesh } from '../mesh.js'; import { ShaderMaterial } from '../materials/shader-material.js'; import { QuadRender } from '../graphics/quad-render.js'; import { ShaderUtils } from '../shader-lib/shader-utils.js'; import glslGsplatCopyToWorkBufferPS from '../shader-lib/glsl/chunks/gsplat/frag/gsplatCopyToWorkbuffer.js'; import wgslGsplatCopyToWorkBufferPS from '../shader-lib/wgsl/chunks/gsplat/frag/gsplatCopyToWorkbuffer.js'; let id = 0; const tempMap = new Map(); class WorkBufferRenderInfo { constructor(device, key, material){ this.device = device; this.material = material; const clonedDefines = new Map(material.defines); const shader = ShaderUtils.createShader(this.device, { uniqueName: `SplatCopyToWorkBuffer:${key}`, attributes: { vertex_position: SEMANTIC_POSITION }, vertexDefines: clonedDefines, fragmentDefines: clonedDefines, vertexChunk: 'fullscreenQuadVS', fragmentGLSL: glslGsplatCopyToWorkBufferPS, fragmentWGSL: wgslGsplatCopyToWorkBufferPS }); this.quadRender = new QuadRender(shader); } destroy() { this.material?.destroy(); this.quadRender?.destroy(); } } class GSplatResourceBase { constructor(device, gsplatData){ this.id = id++; this.workBufferRenderInfos = new Map(); this.device = device; this.gsplatData = gsplatData; this.centers = gsplatData.getCenters(); this.aabb = new BoundingBox(); gsplatData.calcAabb(this.aabb); this.mesh = GSplatResourceBase.createMesh(device); this.instanceIndices = GSplatResourceBase.createInstanceIndices(device, gsplatData.numSplats); this.mesh.incRefCount(); this.mesh.aabb.copy(this.aabb); } destroy() { this.mesh?.destroy(); this.instanceIndices?.destroy(); this.workBufferRenderInfos.forEach((info)=>info.destroy()); this.workBufferRenderInfos.clear(); } getWorkBufferRenderInfo(useIntervals) { this.configureMaterialDefines(tempMap); if (useIntervals) tempMap.set('GSPLAT_LOD', ''); const key = Array.from(tempMap.entries()).map(([k, v])=>`${k}=${v}`).join(';'); let info = this.workBufferRenderInfos.get(key); if (!info) { const material = new ShaderMaterial(); this.configureMaterial(material); tempMap.forEach((v, k)=>material.setDefine(k, v)); info = new WorkBufferRenderInfo(this.device, key, material); this.workBufferRenderInfos.set(key, info); } tempMap.clear(); return info; } static createMesh(device) { const splatInstanceSize = GSplatResourceBase.instanceSize; const meshPositions = new Float32Array(12 * splatInstanceSize); const meshIndices = new Uint32Array(6 * splatInstanceSize); for(let i = 0; i < splatInstanceSize; ++i){ meshPositions.set([ -1, -1, i, 1, -1, i, 1, 1, i, -1, 1, i ], i * 12); const b = i * 4; meshIndices.set([ 0 + b, 1 + b, 2 + b, 0 + b, 2 + b, 3 + b ], i * 6); } const mesh = new Mesh(device); mesh.setPositions(meshPositions, 3); mesh.setIndices(meshIndices); mesh.update(); return mesh; } static createInstanceIndices(device, splatCount) { const splatInstanceSize = GSplatResourceBase.instanceSize; const numSplats = Math.ceil(splatCount / splatInstanceSize) * splatInstanceSize; const numSplatInstances = numSplats / splatInstanceSize; const indexData = new Uint32Array(numSplatInstances); for(let i = 0; i < numSplatInstances; ++i){ indexData[i] = i * splatInstanceSize; } const vertexFormat = new VertexFormat(device, [ { semantic: SEMANTIC_ATTR13, components: 1, type: TYPE_UINT32, asInt: true } ]); const instanceIndices = new VertexBuffer(device, vertexFormat, numSplatInstances, { usage: BUFFER_STATIC, data: indexData.buffer }); return instanceIndices; } static get instanceSize() { return 128; } get numSplats() { return this.gsplatData.numSplats; } configureMaterial(material) {} configureMaterialDefines(defines) {} evalTextureSize(count) { return Vec2.ZERO; } createTexture(name, format, size, data) { 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, ...data ? { levels: [ data ] } : {} }); } instantiate() {} } export { GSplatResourceBase };