Feat/polish-mission1 #12
@@ -1,9 +1,29 @@
|
|||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import type { RefObject } from "react";
|
import type { RefObject } from "react";
|
||||||
import type { Object3D } from "three";
|
import { Mesh, type Object3D } from "three";
|
||||||
import { Octree } from "three-stdlib";
|
import { Octree } from "three-stdlib";
|
||||||
import type { OctreeReadyHandler } from "@/types/three/three";
|
import type { OctreeReadyHandler } from "@/types/three/three";
|
||||||
|
|
||||||
|
// [diag] temporary — count meshes/triangles captured in the octree graph node
|
||||||
|
function snapshotGraphNode(node: Object3D): {
|
||||||
|
meshCount: number;
|
||||||
|
triCount: number;
|
||||||
|
} {
|
||||||
|
let meshCount = 0;
|
||||||
|
let triCount = 0;
|
||||||
|
node.traverse((obj) => {
|
||||||
|
if (obj instanceof Mesh) {
|
||||||
|
meshCount += 1;
|
||||||
|
const geom = obj.geometry;
|
||||||
|
const idx = geom.index;
|
||||||
|
triCount += idx
|
||||||
|
? idx.count / 3
|
||||||
|
: (geom.attributes.position?.count ?? 0) / 3;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { meshCount, triCount };
|
||||||
|
}
|
||||||
|
|
||||||
export function useOctreeGraphNode(
|
export function useOctreeGraphNode(
|
||||||
graphNodeRef: RefObject<Object3D | null>,
|
graphNodeRef: RefObject<Object3D | null>,
|
||||||
onOctreeReady: OctreeReadyHandler,
|
onOctreeReady: OctreeReadyHandler,
|
||||||
@@ -28,6 +48,15 @@ export function useOctreeGraphNode(
|
|||||||
const octree = new Octree();
|
const octree = new Octree();
|
||||||
octree.fromGraphNode(graphNode);
|
octree.fromGraphNode(graphNode);
|
||||||
|
|
||||||
|
// [diag] temporary — log octree contents to detect partial builds
|
||||||
|
const snapshot = snapshotGraphNode(graphNode);
|
||||||
|
console.log("[octree:build]", {
|
||||||
|
rebuildKey,
|
||||||
|
meshCount: snapshot.meshCount,
|
||||||
|
triCount: Math.round(snapshot.triCount),
|
||||||
|
timestamp: performance.now().toFixed(0),
|
||||||
|
});
|
||||||
|
|
||||||
onOctreeReady(octree);
|
onOctreeReady(octree);
|
||||||
}, [enabled, graphNodeRef, onOctreeReady, rebuildKey]);
|
}, [enabled, graphNodeRef, onOctreeReady, rebuildKey]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -277,12 +277,22 @@ function CollisionModelInstance({
|
|||||||
// by MergedStaticMapModel and is unaffected.
|
// by MergedStaticMapModel and is unaffected.
|
||||||
if (node.name !== "lafabrik") return;
|
if (node.name !== "lafabrik") return;
|
||||||
|
|
||||||
|
// [diag] temporary — collect all door-like candidate names to debug stripping
|
||||||
|
const candidates: string[] = [];
|
||||||
const removed: THREE.Object3D[] = [];
|
const removed: THREE.Object3D[] = [];
|
||||||
sceneInstance.traverse((child) => {
|
sceneInstance.traverse((child) => {
|
||||||
|
if (/porte/i.test(child.name)) {
|
||||||
|
candidates.push(child.name);
|
||||||
|
}
|
||||||
if (child.name === "porte") {
|
if (child.name === "porte") {
|
||||||
removed.push(child);
|
removed.push(child);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
console.log("[lafabrik:porte-strip]", {
|
||||||
|
candidates,
|
||||||
|
strippedCount: removed.length,
|
||||||
|
strippedNames: removed.map((c) => c.name),
|
||||||
|
});
|
||||||
for (const child of removed) {
|
for (const child of removed) {
|
||||||
child.removeFromParent();
|
child.removeFromParent();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,6 +98,27 @@ export function Lighting(): React.JSX.Element {
|
|||||||
hasShadowMap: !!sun.current.shadow.map,
|
hasShadowMap: !!sun.current.shadow.map,
|
||||||
...counts,
|
...counts,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// [diag] temporary — track WebGL context loss/restore to correlate with shadow drops
|
||||||
|
const canvas = gl.domElement;
|
||||||
|
const handleContextLost = (event: Event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
console.log("[ctx:lost]", { timestamp: performance.now().toFixed(0) });
|
||||||
|
};
|
||||||
|
const handleContextRestored = () => {
|
||||||
|
console.log("[ctx:restored]", {
|
||||||
|
timestamp: performance.now().toFixed(0),
|
||||||
|
});
|
||||||
|
if (sun.current) {
|
||||||
|
sun.current.shadow.needsUpdate = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
canvas.addEventListener("webglcontextlost", handleContextLost);
|
||||||
|
canvas.addEventListener("webglcontextrestored", handleContextRestored);
|
||||||
|
return () => {
|
||||||
|
canvas.removeEventListener("webglcontextlost", handleContextLost);
|
||||||
|
canvas.removeEventListener("webglcontextrestored", handleContextRestored);
|
||||||
|
};
|
||||||
}, [gl, scene]);
|
}, [gl, scene]);
|
||||||
|
|
||||||
useDebugFolder("Lighting", (folder) => {
|
useDebugFolder("Lighting", (folder) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user