Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/scene/gsplat-unified/gsplat-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,6 @@ class GSplatManager {
const textureSize = worldState.textureSize;
if (textureSize !== this.workBuffer.textureSize) {
this.workBuffer.resize(textureSize);
this.renderer.setMaxNumSplats(textureSize * textureSize);
}

// Bounds and transforms textures are needed for frustum culling.
Expand Down
40 changes: 6 additions & 34 deletions src/scene/gsplat-unified/gsplat-renderer.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { SEMANTIC_POSITION, SEMANTIC_ATTR13, CULLFACE_NONE, PIXELFORMAT_RGBA16U } from '../../platform/graphics/constants.js';
import { SEMANTIC_POSITION, CULLFACE_NONE, PIXELFORMAT_RGBA16U } from '../../platform/graphics/constants.js';
import {
BLEND_NONE, BLEND_PREMULTIPLIED, BLEND_ADDITIVE, GSPLAT_FORWARD, GSPLAT_SHADOW,
SHADOWCAMERA_NAME
} from '../constants.js';
import { ShaderMaterial } from '../materials/shader-material.js';
import { GSplatResourceBase } from '../gsplat/gsplat-resource-base.js';
import { MeshInstance } from '../mesh-instance.js';
import { math } from '../../core/math/math.js';

/**
* @import { VertexBuffer } from '../../platform/graphics/vertex-buffer.js'
* @import { StorageBuffer } from '../../platform/graphics/storage-buffer.js'
* @import { Layer } from '../layer.js'
* @import { GraphNode } from '../graph-node.js'
Expand All @@ -29,12 +27,6 @@ class GSplatRenderer {
/** @type {MeshInstance} */
meshInstance;

/** @type {VertexBuffer|null} */
instanceIndices = null;

/** @type {number} */
instanceIndicesCount = 0;

/** @type {Layer} */
layer;

Expand Down Expand Up @@ -84,11 +76,12 @@ class GSplatRenderer {
vertexWGSL: '#include "gsplatVS"',
fragmentWGSL: '#include "gsplatPS"',
attributes: {
vertex_position: SEMANTIC_POSITION,
vertex_id_attrib: SEMANTIC_ATTR13
vertex_position: SEMANTIC_POSITION
}
});

this._material.setDefine('{GSPLAT_INSTANCE_SIZE}', GSplatResourceBase.instanceSize);

this.configureMaterial();

// Capture internal define names to protect them from being cleared
Expand All @@ -97,6 +90,7 @@ class GSplatRenderer {
});

// Also protect defines that may be added dynamically
this._internalDefines.add('{GSPLAT_INSTANCE_SIZE}');
this._internalDefines.add('GSPLAT_UNIFIED_ID');
this._internalDefines.add('PICK_CUSTOM_ID');
this._internalDefines.add('GSPLAT_INDIRECT_DRAW');
Expand Down Expand Up @@ -420,34 +414,12 @@ class GSplatRenderer {
}
}

setMaxNumSplats(numSplats) {

// round up to the nearest multiple of instanceSize (same as createInstanceIndices does internally)
const roundedNumSplats = math.roundUp(numSplats, GSplatResourceBase.instanceSize);

if (this.instanceIndicesCount < roundedNumSplats) {
this.instanceIndicesCount = roundedNumSplats;

// destroy old instance indices
this.instanceIndices?.destroy();

// create new instance indices
this.instanceIndices = GSplatResourceBase.createInstanceIndices(this.device, numSplats);
this.meshInstance.setInstancing(this.instanceIndices, true);

// update texture size uniform
this._material.setParameter('splatTextureSize', this.workBuffer.textureSize);
}
}

createMeshInstance() {

const mesh = GSplatResourceBase.createMesh(this.device);
const textureSize = this.workBuffer.textureSize;
const instanceIndices = GSplatResourceBase.createInstanceIndices(this.device, textureSize * textureSize);
const meshInstance = new MeshInstance(mesh, this._material);
meshInstance.node = this.node;
meshInstance.setInstancing(instanceIndices, true);
meshInstance.setInstancing(true, true);

// only start rendering the splat after we've received the splat order data
meshInstance.instancingCount = 0;
Expand Down
9 changes: 4 additions & 5 deletions src/scene/gsplat/gsplat-instance.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Debug } from '../../core/debug.js';
import { Mat4 } from '../../core/math/mat4.js';
import { Vec3 } from '../../core/math/vec3.js';
import { BUFFERUSAGE_COPY_DST, CULLFACE_NONE, SEMANTIC_ATTR13, SEMANTIC_POSITION, PIXELFORMAT_R32U } from '../../platform/graphics/constants.js';
import { BUFFERUSAGE_COPY_DST, CULLFACE_NONE, SEMANTIC_POSITION, PIXELFORMAT_R32U } from '../../platform/graphics/constants.js';
import { StorageBuffer } from '../../platform/graphics/storage-buffer.js';
import { MeshInstance } from '../mesh-instance.js';
import { GSplatResolveSH } from './gsplat-resolve-sh.js';
Expand All @@ -16,7 +16,6 @@ import { BLEND_NONE, BLEND_PREMULTIPLIED } from '../constants.js';
* @import { GraphNode } from '../graph-node.js'
* @import { Mesh } from '../mesh.js'
* @import { Texture } from '../../platform/graphics/texture.js'
* @import { VertexBuffer } from '../../platform/graphics/vertex-buffer.js'
*/

const mat = new Mat4();
Expand Down Expand Up @@ -97,8 +96,7 @@ class GSplatInstance {
vertexWGSL: '#include "gsplatVS"',
fragmentWGSL: '#include "gsplatPS"',
attributes: {
vertex_position: SEMANTIC_POSITION,
vertex_id_attrib: SEMANTIC_ATTR13
vertex_position: SEMANTIC_POSITION
}
});

Expand All @@ -108,7 +106,7 @@ class GSplatInstance {

resource.ensureMesh();
this.meshInstance = new MeshInstance(/** @type {Mesh} */ (resource.mesh), this._material);
this.meshInstance.setInstancing(/** @type {VertexBuffer} */ (resource.instanceIndices), true);
this.meshInstance.setInstancing(true, true);
this.meshInstance.gsplatInstance = this;

// only start rendering the splat after we've received the splat order data
Expand Down Expand Up @@ -176,6 +174,7 @@ class GSplatInstance {
configureMaterial(material, options = {}) {
this.resource.configureMaterial(material, null, this.resource.format.getInputDeclarations());

material.setDefine('{GSPLAT_INSTANCE_SIZE}', GSplatResourceBase.instanceSize);
material.setParameter('numSplats', 0);
this.setMaterialOrderData(material);
material.setParameter('alphaClip', 0.3);
Expand Down
7 changes: 4 additions & 3 deletions src/scene/gsplat/gsplat-material.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import {
CULLFACE_NONE, SEMANTIC_ATTR13, SEMANTIC_POSITION, SHADERLANGUAGE_GLSL, SHADERLANGUAGE_WGSL
CULLFACE_NONE, SEMANTIC_POSITION, SHADERLANGUAGE_GLSL, SHADERLANGUAGE_WGSL
} from '../../platform/graphics/constants.js';

import { BLEND_NONE, BLEND_PREMULTIPLIED, DITHER_NONE } from '../constants.js';
import { ShaderMaterial } from '../materials/shader-material.js';
import { ShaderChunks } from '../shader-lib/shader-chunks.js';
import { GSplatResourceBase } from './gsplat-resource-base.js';

/**
* @import { GraphicsDevice } from '../../platform/graphics/graphics-device.js'
Expand Down Expand Up @@ -38,11 +39,11 @@ const createGSplatMaterial = (device, options = {}) => {
vertexWGSL: options.vertex ? '' : ShaderChunks.get(device, SHADERLANGUAGE_WGSL).get('gsplatVS'),
fragmentWGSL: options.vertex ? '' : ShaderChunks.get(device, SHADERLANGUAGE_WGSL).get('gsplatPS'),
attributes: {
vertex_position: SEMANTIC_POSITION,
vertex_id_attrib: SEMANTIC_ATTR13
vertex_position: SEMANTIC_POSITION
}
});

material.setDefine('{GSPLAT_INSTANCE_SIZE}', GSplatResourceBase.instanceSize);
material.setDefine(`DITHER_${ditherEnum.toUpperCase()}`, '');

material.cull = CULLFACE_NONE;
Expand Down
35 changes: 0 additions & 35 deletions src/scene/gsplat/gsplat-resource-base.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { Debug } from '../../core/debug.js';
import { BoundingBox } from '../../core/shape/bounding-box.js';
import { BUFFER_STATIC, SEMANTIC_ATTR13, TYPE_UINT32 } from '../../platform/graphics/constants.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 { WorkBufferRenderInfo } from '../gsplat-unified/gsplat-work-buffer.js';
Expand Down Expand Up @@ -61,12 +58,6 @@ class GSplatResourceBase {
*/
mesh = null;

/**
* @type {VertexBuffer|null}
* @ignore
*/
instanceIndices = null;

/**
* @type {number}
* @ignore
Expand Down Expand Up @@ -154,7 +145,6 @@ class GSplatResourceBase {
_actualDestroy() {
this.streams.destroy();
this.mesh?.destroy();
this.instanceIndices?.destroy();
this.workBufferRenderInfos.forEach(info => info.destroy());
this.workBufferRenderInfos.clear();
}
Expand Down Expand Up @@ -203,7 +193,6 @@ class GSplatResourceBase {
if (!this.mesh) {
this.mesh = GSplatResourceBase.createMesh(this.device);
this.mesh.aabb.copy(this.aabb);
this.instanceIndices = GSplatResourceBase.createInstanceIndices(this.device, this.gsplatData.numSplats);
}
this._meshRefCount++;
}
Expand All @@ -218,8 +207,6 @@ class GSplatResourceBase {
this._meshRefCount--;
if (this._meshRefCount < 1) {
this.mesh = null; // mesh instances destroy mesh when their refCount reaches zero
this.instanceIndices?.destroy();
this.instanceIndices = null;
}
}

Expand Down Expand Up @@ -323,28 +310,6 @@ class GSplatResourceBase {
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; // number of splats per instance
}
Expand Down
25 changes: 17 additions & 8 deletions src/scene/mesh-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { BoundingBox } from '../core/shape/bounding-box.js';
import { BoundingSphere } from '../core/shape/bounding-sphere.js';
import { BindGroup } from '../platform/graphics/bind-group.js';
import { UniformBuffer } from '../platform/graphics/uniform-buffer.js';
import { VertexBuffer } from '../platform/graphics/vertex-buffer.js';
import { DrawCommands } from '../platform/graphics/draw-commands.js';
import { indexFormatByteSize } from '../platform/graphics/constants.js';
import {
Expand Down Expand Up @@ -39,7 +40,6 @@ import { PickerId } from './picker-id.js';
* @import { Texture } from '../platform/graphics/texture.js'
* @import { UniformBufferFormat } from '../platform/graphics/uniform-buffer-format.js'
* @import { Vec3 } from '../core/math/vec3.js'
* @import { VertexBuffer } from '../platform/graphics/vertex-buffer.js'
* @import { CameraComponent } from '../framework/components/camera/component.js';
*/

Expand Down Expand Up @@ -1129,20 +1129,27 @@ class MeshInstance {
* Note that {@link instancingCount} is automatically set to the number of vertices of the
* vertex buffer when it is provided.
*
* @param {VertexBuffer|null} vertexBuffer - Vertex buffer to hold per-instance vertex data
* (usually world matrices). Pass null to turn off hardware instancing.
* @param {VertexBuffer|true|null} vertexBuffer - Vertex buffer to hold per-instance vertex data
* (usually world matrices). Pass `true` to enable attributeless instancing where the instance
* index is derived from `gl_InstanceID` / `instance_index` builtins rather than a vertex
* buffer attribute — the caller must set {@link instancingCount} manually. Pass null to turn
* off hardware instancing.
* @param {boolean} cull - Whether to perform frustum culling on this instance. If true, the whole
* instance will be culled by the camera frustum. This often involves setting
* {@link RenderComponent#customAabb} containing all instances. Defaults to false, which means
* the whole instance is always rendered.
*/
setInstancing(vertexBuffer, cull = false) {
if (vertexBuffer) {
this.instancingData = new InstancingData(vertexBuffer.numVertices);
this.instancingData.vertexBuffer = vertexBuffer;
if (vertexBuffer === true) {
this.instancingData = new InstancingData(0);
} else {
this.instancingData = new InstancingData(vertexBuffer.numVertices);
this.instancingData.vertexBuffer = vertexBuffer;

// mark vertex buffer as instancing data
vertexBuffer.format.instancing = true;
// mark vertex buffer as instancing data
vertexBuffer.format.instancing = true;
}

// set up culling
this.cull = cull;
Expand All @@ -1151,7 +1158,9 @@ class MeshInstance {
this.cull = true;
}

this._updateShaderDefs(vertexBuffer ? (this._shaderDefs | SHADERDEF_INSTANCING) : (this._shaderDefs & ~SHADERDEF_INSTANCING));
this._updateShaderDefs(vertexBuffer instanceof VertexBuffer ?
(this._shaderDefs | SHADERDEF_INSTANCING) :
(this._shaderDefs & ~SHADERDEF_INSTANCING));
}

/**
Expand Down
7 changes: 3 additions & 4 deletions src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplatSource.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
export default /* glsl */`
attribute vec3 vertex_position; // xy: cornerUV, z: render order offset
attribute uint vertex_id_attrib; // render order base
attribute vec3 vertex_position; // xy: cornerUV, z: render order offset within instance

uniform uint numSplats; // total number of splats
uniform highp usampler2D splatOrder; // per-splat index to source gaussian

// initialize the splat source structure and global splat
bool initSource(out SplatSource source) {
// calculate splat order
source.order = vertex_id_attrib + uint(vertex_position.z);
// calculate splat order from instance index and vertex position offset
source.order = uint(gl_InstanceID) * {GSPLAT_INSTANCE_SIZE}u + uint(vertex_position.z);

// return if out of range (since the last block of splats may be partially full)
if (source.order >= numSplats) {
Expand Down
7 changes: 3 additions & 4 deletions src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatSource.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export default /* wgsl */`
attribute vertex_position: vec3f; // xy: cornerUV, z: render order offset
attribute vertex_id_attrib: u32; // render order base
attribute vertex_position: vec3f; // xy: cornerUV, z: render order offset within instance

#ifdef GSPLAT_INDIRECT_DRAW
// When using indirect draw with compaction, numSplats is written by the
Expand All @@ -16,8 +15,8 @@ attribute vertex_id_attrib: u32; // render order base

// initialize the splat source structure
fn initSource(source: ptr<function, SplatSource>) -> bool {
// calculate splat order
source.order = vertex_id_attrib + u32(vertex_position.z);
// calculate splat order from instance index and vertex position offset
source.order = pcInstanceIndex * {GSPLAT_INSTANCE_SIZE}u + u32(vertex_position.z);

// return if out of range (since the last block of splats may be partially full)
#ifdef GSPLAT_INDIRECT_DRAW
Expand Down