Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion src/scene/gsplat-unified/gsplat-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ class GSplatManager {
let anyInstanceNeedsLodUpdate = false;
for (const [, inst] of this.octreeInstances) {

const isDirty = inst.update();
const isDirty = inst.update(this.scene);
this.layerPlacementsDirty ||= isDirty;

const instNeeds = inst.consumeNeedsLodUpdate();
Expand Down
34 changes: 32 additions & 2 deletions src/scene/gsplat-unified/gsplat-octree-instance.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
// import { Debug } from '../../core/debug.js';
import { Debug } from '../../core/debug.js';
import { Mat4 } from '../../core/math/mat4.js';
import { Vec2 } from '../../core/math/vec2.js';
import { Vec3 } from '../../core/math/vec3.js';
import { BoundingBox } from '../../core/shape/bounding-box.js';
import { Color } from '../../core/math/color.js';
import { GSplatPlacement } from './gsplat-placement.js';

/**
* @import { GraphNode } from '../graph-node.js'
* @import { GSplatOctree } from './gsplat-octree.js'
* @import { GSplatAssetLoaderBase } from './gsplat-asset-loader-base.js'
* @import { Scene } from '../scene.js'
*/

const _invWorldMat = new Mat4();
Expand All @@ -16,6 +19,16 @@ const _localCameraFwd = new Vec3();
const _dirToNode = new Vec3();

const _tempCompletedUrls = [];
const _tempDebugAabb = new BoundingBox();

// Color instances used by debug wireframe rendering for LOD visualization
const _lodColors = [
new Color(1, 0, 0),
new Color(0, 1, 0),
new Color(0, 0, 1),
new Color(1, 1, 0),
new Color(1, 0, 1)
];

class GSplatOctreeInstance {
/** @type {GSplatOctree} */
Expand Down Expand Up @@ -532,9 +545,10 @@ class GSplatOctreeInstance {
/**
* Updates the octree instance each frame.
*
* @param {Scene} scene - Optional scene for debug rendering.
* @returns {boolean} True if octree instance is dirty, false otherwise.
*/
update() {
update(scene) {

// handle pending loads
if (this.pending.size) {
Expand Down Expand Up @@ -585,6 +599,22 @@ class GSplatOctreeInstance {
// watch prefetched loads for completion to allow promotion
this.pollPrefetchCompletions();

// debug render world space bounds for octree nodes based on current LOD selection
Debug.call(() => {
if (scene.gsplat.debugNodeAabbs) {
const modelMat = this.placement.node.getWorldTransform();
const nodes = this.octree.nodes;
for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex++) {
const lodIndex = this.nodeLods[nodeIndex];
if (lodIndex >= 0) {
const color = _lodColors[Math.min(lodIndex, _lodColors.length - 1)];
_tempDebugAabb.setFromTransformedAabb(nodes[nodeIndex].bounds, modelMat);
scene.immediate.drawWireAlignedBox(_tempDebugAabb.getMin(), _tempDebugAabb.getMax(), color, true, scene.defaultDrawLayer);
}
}
}
});

// check if any placements need LOD update
const dirty = this.dirtyModifiedPlacements;
this.dirtyModifiedPlacements = false;
Expand Down
7 changes: 7 additions & 0 deletions src/scene/gsplat-unified/gsplat-params.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ class GSplatParams {
*/
debugAabbs = false;

/**
* Enables debug rendering of AABBs for GSplat octree nodes. Defaults to false.
*
* @type {boolean}
*/
debugNodeAabbs = false;

/**
* Internal dirty flag to trigger update of gsplat managers when some params change.
*
Expand Down