Active viewer model for miltimodel mode - autodesk-forge

Then several models are loaded in viewer, only one of them is "active". I mean that Object tree is shown for this model and select(),isolate() etc methods are related to it. I try to use following method to set "active" model:
function setActiveModel(model) {
var instanceTree = model.getData().instanceTree;
viewer.modelstructure.setModel(instanceTree);
}
But object tree doesn't change.
Questions are:
That is correct way to change viewer "active" model?
How can I get current "active" model in viewer?

Here is a patched version that supports multi-model switching. It is a drop-in replacement, simply include the file after the viewer3D.js script:
MultiModelStructurePanel.js
Multi-models will be supported soon in a future version of the API.

Related

Query properties using the forge-viewer library without rendering model

I'm using the forge-viewer library to display models. I'm wondering if it is possible to at the same time query properties from another model, without rendering the other model or altering the state of the original viewer instance?
Preferably by obtaining a new instance of Autodesk.Viewing.Model, in order to use methods like model.getProperties(...).
Loading with the original viewer instance causes the other model to display in the browser
const document: Autodesk.Viewing.Document = await myLoadDocumentFunction("urn:another-model-urn");
const defaultModel = document.getRoot().getDefaultGeometry();
const model = await viewer.loadDocumentNode(document, defaultModel);
As the documentation states, the options input variable for loadDocumentNode() is passed on to loadModel() so you can check the documentation of that function to see what options are available.
One of them is loadAsHidden which seems to do exactly what you need:
FYI: it should also be possible to create another Viewer instance, make it invisible (e.g. placing it off the screen) and load extra models there: Multiple instances of Autodesk Forge Viewer

Forge Viewer 7.71 throws errors when removing and recreating custom meshes in ModelViewer

I have an application that adds many custom meshes to the Forge Viewer using the ModelBuilder extension. This application has worked for quite a while but ran into issues with version 7.71 of the viewer.
When graphics are updated in my application, I remove all existing meshes and then recreate them based on new data. With version 7.71 of the viewer, when I recreate the meshes I get many instances the following error in the dev tools console:
Uncaught TypeError: Cannot read properties of undefined (reading 'material')
at FragmentList.getMaterial (FragmentList.js:760:1)
at FragmentList.getMaterialId (FragmentList.js:754:1)
at RenderBatch.js:222:1
at Int32Array.sort (<anonymous>)
at RenderBatch.sortByMaterial (RenderBatch.js:220:1)
at RenderModel.applyVisibility (RenderModel.js:388:1)
at RenderModel.nextBatch (RenderModel.js:360:1)
at RenderScene.reset (RenderScene.js:387:1)
at Array.cmdBeginPhase (Viewer3DImpl.js:1125:1)
at RenderCommandSystem.executeCommandList (Viewer3DImpl.js:847:1)
After these errors, the new meshes are not created.
The release notes don't mention anything about any expected changes here. Looking for guidance from the Autodesk team.
Here is a repo that reproduces the issue:
https://github.com/bencameron/custom-mesh-refresh
I'm told it will take some time to implement the fix (ticket id LMV-6757). In the meantime you could stick with v7.70 or try these workarounds a colleague suggested:
1.) If all of the custom geometry is removed, like it is in the example app, it's probably simpler to remove the model entirely and start with a new one. Here is an (untested) snippet to do that:
// Instead of deleting all geometries individually, simply delete the model and create a new one
viewer.unloadModel(modelBuilder.model);
// drop the reference to the model builder instance, i.e. assign a new instance
modelBuilder = await sceneBuilder.addNewModel({});
// start adding the geometry again...
...
2.) If option #1 doesn't work, or if the user doesn't want to delete all geometries, they could also avoid the crash by running this snippet right after adding new geometries (i.e. every time they add a batch of geometries):
const scenes = modelBuilder.model.getIterator().getGeomScenes();
for (let i = 0; i < scenes.length; ++i) {
scenes[i].numAdded = 0;
}
I would recommend the first option over the second one if applicable.

How can I load only specifc objects in the forge viewer using SFV2?

SVF2 has different objectids/dbids than SVF1. In this SO-Answer, it was advised to use externalId instead of objectid. However, viewer.loadModel(svfUrl,{ids:[dbIds...]}) takes dbIds to load only specified objects. How can I load only specified objects using SVF2 and the https://developer.api.autodesk.com/modelderivative/v2/regions/eu/designdata/:urn /metadata/:guid/properties endpoint? Can I access the svf2 objectIds anywhere or can I use the externalIds when calling Viewer3d::loadModel?
You're right, there's a difference between the "SVF1 dbIDs" and the "SVF2 dbIDs" - the IDs in SVF2 format are "persistent", meaning that in different versions of the same design file, a single ID will reference the same design element (which was not the case in SVF1).
Unfortunately, there are parts of the platform (like the loadModel viewer method and the /modelderivative/v2/regions/eu/designdata/:urn /metadata/:guid/properties endpoint) that have not "caught up" with SVF2 yet. And before those updates are available, you would have to map "between the old and new dbIDs" manually which is itself another, non-trivial task.

Autodesk Forge Viewer - Click Events on models created through SceneBuilder

I am working on adding geometry to the viewer using the new SceneBuilder extension (using this guide). I have been able to show the geometry in the viewer and also been able to add TextGeometry to the same dbId as some of the models.
The viewer is allowing me to click and isolate the geometry, but when I use viewer.getSelection(), it returns an empty array. I even added a click event listener to the Geometry itself, but no luck there as well.
Would any one know of a way to add a listener to this newly created fragment or geometry.
Did you set dbid to the mesh appended to the scene? Otherwise the selector wouldn't be able to pick up their dbids as it would for the document(original model)'s bubble:
sceneBuilder.addNewModel({conserveMemory: false,
modelNameOverride: 'My Model Name233'})
.then(modelBuilder => {
//...
mesh = new THREE.Mesh(geom, phongMaterial);
mesh.dbId=23333;
modelBuilder.addMesh(mesh);
})
Then you would be able to call the selector on the custom model to get the current selection - since we are getting selection status from the custom model as opposed to the one loaded by Viewer (exposed via viewer.model):
modelBuilder.model.selector.getSelection() //[23333]
EDIT
Forgot to mention you may also subscribe to the AGGREGATE_SELECTION_CHANGED_EVEN since we are dealing with multiple models here:
NOP_VIEWER.addEventListener(Autodesk.Viewing.AGGREGATE_SELECTION_CHANGED_EVENT,e=>{
//...
})

Forge Viewer rendering pipeline

In the latest release of THREE.js, Mesh can implement following callback in order to hook into the rendering pipeline:
this.onBeforeRender = function (renderer, scene, camera ) {
..
}
Is there any way to achieve a similar logic in the current implementation of the viewer?
Unfortunately Engineering just confirmed the closet options we have out of the box the latest Viewer v7 is the OverlayManager - see its doc here:
viewer.overlays.addScene(name)
viewer.overlays.addMesh(mesh, name)
Which obviously isn't exactly what you are after but we will assess the possibilities of adding these hooks to our future versions.