fix(editor): don't crash GLB export on a material-less renderable
Baking some projects failed with "Cannot read properties of undefined (reading 'isShaderMaterial')". GLTFExporter reads material.isShaderMaterial unconditionally, so a renderable (Mesh / Line / Points) with no material crashes the export — and a non-Mesh renderable slips past both the isMesh prune check and material conversion. Guard it in pruneNonRenderableMeshes: a material-less renderable is dropped if it's a leaf, or neutralised (empty geometry + a hidden placeholder material) if it has children so its subtree survives. Post-FX disable now lets these scenes reach the exporter, which is why it surfaced. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
460b924577
commit
f75cffed9f
@@ -156,6 +156,11 @@ function pairClones(
|
|||||||
// plain transform node instead of a primitive.
|
// plain transform node instead of a primitive.
|
||||||
const EMPTY_GEOMETRY = new THREE.BufferGeometry()
|
const EMPTY_GEOMETRY = new THREE.BufferGeometry()
|
||||||
|
|
||||||
|
// Hidden placeholder for a neutralised renderable that has no material: a valid
|
||||||
|
// material keeps GLTFExporter from crashing on `material.isShaderMaterial`, while
|
||||||
|
// EMPTY_GEOMETRY makes it emit a transform node instead of a primitive.
|
||||||
|
const PLACEHOLDER_MATERIAL = new THREE.MeshBasicMaterial({ visible: false })
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strip everything that must not bake into the model:
|
* Strip everything that must not bake into the model:
|
||||||
* - Editor overlays on non-scene layers (gizmos, selection handles, ground
|
* - Editor overlays on non-scene layers (gizmos, selection handles, ground
|
||||||
@@ -182,6 +187,25 @@ function pruneNonRenderableMeshes(root: THREE.Object3D, identityNodes: Set<THREE
|
|||||||
toRemove.push(object)
|
toRemove.push(object)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// A renderable (Mesh / Line / Points) with no material can't produce valid
|
||||||
|
// glTF and crashes GLTFExporter, which reads `material.isShaderMaterial`
|
||||||
|
// unconditionally — e.g. an imported sub-model that left a mesh material-less.
|
||||||
|
// Non-Mesh renderables also slip past the `isMesh` checks below and the
|
||||||
|
// material conversion. Neutralise it: keep the node (so children survive) but
|
||||||
|
// strip its geometry + give it the hidden placeholder, or drop it if a leaf.
|
||||||
|
const renderable = object as THREE.Mesh & { isLine?: boolean; isPoints?: boolean }
|
||||||
|
if (
|
||||||
|
(renderable.isMesh === true || renderable.isLine === true || renderable.isPoints === true) &&
|
||||||
|
renderable.material == null
|
||||||
|
) {
|
||||||
|
if (object.children.length > 0) {
|
||||||
|
renderable.geometry = EMPTY_GEOMETRY
|
||||||
|
renderable.material = PLACEHOLDER_MATERIAL
|
||||||
|
} else {
|
||||||
|
toRemove.push(object)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
const mesh = object as THREE.Mesh
|
const mesh = object as THREE.Mesh
|
||||||
if (!mesh.isMesh || isRenderableMesh(mesh)) return
|
if (!mesh.isMesh || isRenderableMesh(mesh)) return
|
||||||
if (mesh.children.length > 0) {
|
if (mesh.children.length > 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user