feat: add model hierarchy panel
This commit is contained in:
@@ -18,6 +18,16 @@ export interface ModelStats {
|
||||
triangles: number
|
||||
}
|
||||
|
||||
export interface ModelHierarchyNode {
|
||||
children: ModelHierarchyNode[]
|
||||
id: string
|
||||
name: string
|
||||
position: [number, number, number]
|
||||
rotation: [number, number, number]
|
||||
type: string
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
interface OpacityMapEntry {
|
||||
target: string
|
||||
url: string
|
||||
@@ -207,6 +217,30 @@ function getModelStats(scene: Object3D, assetUrls: Record<string, string>): Mode
|
||||
}
|
||||
}
|
||||
|
||||
function roundTransformValue(value: number) {
|
||||
return Number(value.toFixed(4))
|
||||
}
|
||||
|
||||
function getObjectHierarchy(object: Object3D): ModelHierarchyNode {
|
||||
return {
|
||||
children: object.children.map(getObjectHierarchy),
|
||||
id: object.uuid,
|
||||
name: object.name || object.type,
|
||||
position: [
|
||||
roundTransformValue(object.position.x),
|
||||
roundTransformValue(object.position.y),
|
||||
roundTransformValue(object.position.z),
|
||||
],
|
||||
rotation: [
|
||||
roundTransformValue(object.rotation.x),
|
||||
roundTransformValue(object.rotation.y),
|
||||
roundTransformValue(object.rotation.z),
|
||||
],
|
||||
type: object.type,
|
||||
visible: object.visible,
|
||||
}
|
||||
}
|
||||
|
||||
function pickOpacityMap(
|
||||
mesh: Mesh,
|
||||
material: Material,
|
||||
@@ -234,10 +268,12 @@ function Model({
|
||||
url,
|
||||
assetUrls,
|
||||
onStatsReady,
|
||||
onHierarchyReady,
|
||||
}: {
|
||||
url: string
|
||||
assetUrls: Record<string, string>
|
||||
onStatsReady: (stats: ModelStats) => void
|
||||
onHierarchyReady: (hierarchy: ModelHierarchyNode) => void
|
||||
}) {
|
||||
const { scene } = useLoader(GLTFLoader, url, (loader) => {
|
||||
loader.manager.setURLModifier((requestedUrl) => resolveAssetUrl(requestedUrl, assetUrls))
|
||||
@@ -247,7 +283,8 @@ function Model({
|
||||
|
||||
useEffect(() => {
|
||||
onStatsReady(getModelStats(scene, assetUrls))
|
||||
}, [assetUrls, onStatsReady, scene])
|
||||
onHierarchyReady(getObjectHierarchy(scene))
|
||||
}, [assetUrls, onHierarchyReady, onStatsReady, scene])
|
||||
|
||||
useEffect(() => {
|
||||
if (opacityMapEntries.length === 0) return
|
||||
@@ -270,16 +307,23 @@ export default function SceneViewer({
|
||||
url,
|
||||
assetUrls,
|
||||
onStatsReady,
|
||||
onHierarchyReady,
|
||||
}: {
|
||||
url: string
|
||||
assetUrls: Record<string, string>
|
||||
onStatsReady: (stats: ModelStats) => void
|
||||
onHierarchyReady: (hierarchy: ModelHierarchyNode) => void
|
||||
}) {
|
||||
return (
|
||||
<Canvas dpr={[1, 2]} camera={{ fov: 50 }}>
|
||||
<Suspense fallback={null}>
|
||||
<Stage environment="city" intensity={0.6} adjustCamera={1.2}>
|
||||
<Model url={url} assetUrls={assetUrls} onStatsReady={onStatsReady} />
|
||||
<Model
|
||||
url={url}
|
||||
assetUrls={assetUrls}
|
||||
onStatsReady={onStatsReady}
|
||||
onHierarchyReady={onHierarchyReady}
|
||||
/>
|
||||
</Stage>
|
||||
</Suspense>
|
||||
<OrbitControls makeDefault autoRotate autoRotateSpeed={0.5} />
|
||||
|
||||
Reference in New Issue
Block a user