fix: keep world splat loading responsive
This commit is contained in:
parent
58b4fc49b9
commit
14009f869e
@ -157,7 +157,7 @@ function lerpSparkRevealProfile(
|
||||
}
|
||||
|
||||
const SPLAT_REVEAL_DURATION_MS = 2600;
|
||||
const SPLAT_PARTICLE_SAMPLE_LIMIT = 5200;
|
||||
const SPLAT_PARTICLE_SAMPLE_LIMIT = 1800;
|
||||
|
||||
const KEY_TO_MOVEMENT: Partial<Record<string, MovementCommand>> = {
|
||||
KeyW: "forward",
|
||||
@ -217,10 +217,12 @@ function buildSplatParticleCloudData(
|
||||
splatMesh: SparkSplatMesh,
|
||||
sampleLimit = SPLAT_PARTICLE_SAMPLE_LIMIT
|
||||
): SplatParticleCloudData | null {
|
||||
const totalSplats = Math.max(0, splatMesh.packedSplats?.numSplats || 0);
|
||||
const packedSplats = splatMesh.packedSplats;
|
||||
const totalSplats = Math.max(0, packedSplats?.numSplats || 0);
|
||||
if (!totalSplats) return null;
|
||||
|
||||
const sampleStep = Math.max(1, Math.floor(totalSplats / sampleLimit));
|
||||
const targetCount = Math.min(sampleLimit, totalSplats);
|
||||
const sampleStep = Math.max(totalSplats / targetCount, 1);
|
||||
const points: Array<{
|
||||
center: THREE.Vector3;
|
||||
color: THREE.Color;
|
||||
@ -228,17 +230,17 @@ function buildSplatParticleCloudData(
|
||||
}> = [];
|
||||
const warmWhite = new THREE.Color("#fff1dc");
|
||||
|
||||
splatMesh.forEachSplat((index, center, _scales, _quaternion, opacity, color) => {
|
||||
if (points.length >= sampleLimit) return;
|
||||
if (index % sampleStep !== 0) return;
|
||||
if (opacity < 0.035) return;
|
||||
for (let sampleIndex = 0; sampleIndex < targetCount; sampleIndex += 1) {
|
||||
const index = Math.min(Math.floor(sampleIndex * sampleStep), totalSplats - 1);
|
||||
const { center, opacity, color } = packedSplats.getSplat(index);
|
||||
if (opacity < 0.035) continue;
|
||||
|
||||
points.push({
|
||||
center: center.clone(),
|
||||
color: color.clone(),
|
||||
center,
|
||||
color,
|
||||
opacity,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!points.length) return null;
|
||||
|
||||
@ -758,12 +760,13 @@ function WorldSplatScene({
|
||||
applySparkRevealProfile(sparkRenderer, splatMesh, SPLAT_LOADING_PROFILE);
|
||||
|
||||
let cancelled = false;
|
||||
let idleCallbackId: number | null = null;
|
||||
let timeoutId: ReturnType<typeof globalThis.setTimeout> | null = null;
|
||||
splatMesh.initialized
|
||||
.then(() => {
|
||||
if (cancelled) return;
|
||||
window.requestAnimationFrame(() => {
|
||||
if (cancelled || hasAppliedInitialViewRef.current) return;
|
||||
setParticleCloudData(buildSplatParticleCloudData(splatMesh));
|
||||
positionCameraInsideWorld({
|
||||
camera,
|
||||
controls: orbitControlsRef.current,
|
||||
@ -772,6 +775,19 @@ function WorldSplatScene({
|
||||
});
|
||||
hasAppliedInitialViewRef.current = true;
|
||||
onLoadStateChange?.("ready");
|
||||
|
||||
const buildParticleCloud = () => {
|
||||
if (cancelled) return;
|
||||
setParticleCloudData(buildSplatParticleCloudData(splatMesh));
|
||||
};
|
||||
|
||||
if ("requestIdleCallback" in window) {
|
||||
idleCallbackId = window.requestIdleCallback(buildParticleCloud, {
|
||||
timeout: 900,
|
||||
});
|
||||
} else {
|
||||
timeoutId = globalThis.setTimeout(buildParticleCloud, 120);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
@ -779,6 +795,12 @@ function WorldSplatScene({
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
if (idleCallbackId !== null && "cancelIdleCallback" in window) {
|
||||
window.cancelIdleCallback(idleCallbackId);
|
||||
}
|
||||
if (timeoutId !== null) {
|
||||
globalThis.clearTimeout(timeoutId);
|
||||
}
|
||||
splatMesh.dispose();
|
||||
};
|
||||
}, [camera, groundPlaneOffset, onLoadStateChange, sparkRenderer, splatMesh]);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user