Autodesk Forge 3D Viewer修改元素颜色时'enumNodeFragments'未定义报错
Root Cause of the Error
The error means that instanceTree (from viewer.model.getData().instanceTree) is undefined when your code tries to access it. This usually happens because:
- You're trying to access model geometry data before the model has fully loaded
- Your event listener is incorrectly scoped inside a loop, causing closure issues and duplicate event bindings
- Missing definitions for helper functions/variables like
addMaterialandoverlayName
Step-by-Step Solution
Here's how to fix your code and make it work reliably:
Move Event Listener Out of the Loop & Handle Loading State
Don't bind theGEOMETRY_LOADED_EVENTinside your object ID loop—this creates duplicate listeners and causes scoping bugs. Instead, check if the model is already loaded first, or bind the listener once and clean it up after use.Fix Closure Scoping
Using a traditionalforloop withvarleads to all event callbacks referencing the lastdbidvalue. Switch toforEach(orletin aforloop) to preserve the correct ID for each iteration.Define Missing Helpers
Your code referencesaddMaterialandoverlayNamewhich aren't defined—add these to avoid additional errors.
Corrected Full Code
// Define a persistent overlay name for your colored elements const overlayName = 'CustomColorOverlay'; // Helper function to create a THREE.js material from a color value function addMaterial(color) { return new THREE.MeshPhongMaterial({ color: new THREE.Color(color), side: THREE.DoubleSide, // Ensure color shows on both sides of geometry transparent: false, opacity: 1.0 }); } // Extend Viewer3D with the fixed setColorMaterial method Autodesk.Viewing.Viewer3D.prototype.setColorMaterial = function(objectIds, color) { const viewer = this; const customMaterial = addMaterial(color); // Function to process object IDs once model is ready function applyColorToObjects() { const instanceTree = viewer.model.getData().instanceTree; if (!instanceTree) return; // Exit if model data still isn't ready objectIds.forEach(dbid => { // Iterate over all fragments for the given object ID instanceTree.enumNodeFragments(dbid, (fragId) => { const renderProxy = viewer.impl.getRenderProxy(viewer.model, fragId); // Create a new mesh with the custom material const meshProxy = new THREE.Mesh(renderProxy.geometry, customMaterial); meshProxy.matrix.copy(renderProxy.matrixWorld); meshProxy.matrixWorldNeedsUpdate = true; meshProxy.matrixAutoUpdate = false; meshProxy.frustumCulled = false; // Add the colored mesh to the viewer overlay viewer.impl.addOverlay(overlayName, meshProxy); viewer.impl.invalidate(true); // Trigger viewer refresh }, false); }); } // Check if model is already loaded and ready if (viewer.model && viewer.model.getData().instanceTree) { applyColorToObjects(); } else { // Wait for geometry to load, then process and clean up the listener const onGeometryLoaded = () => { applyColorToObjects(); viewer.removeEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, onGeometryLoaded); }; viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, onGeometryLoaded); } };
Additional Tips
- Call at the Right Time: To avoid timing issues entirely, call this method after the viewer fires the
Autodesk.Viewing.OBJECT_TREE_CREATED_EVENTorAutodesk.Viewing.GEOMETRY_LOADED_EVENTfor your model. - Clean Up Overlays: If you need to reset colors later, use
viewer.impl.removeOverlay(overlayName, meshProxy)orviewer.impl.clearOverlay(overlayName)to remove your custom overlays.
内容的提问来源于stack exchange,提问作者Adryan Chiko

