How-To: Set View Behavior Prior to Model Load

As a developer, I’d like to learn how-to load a model with specific view behaviors already set without seeing a noticeable transition when the model is loading .

Introduction

User experience can suffer if we first load a model with the default settings, then change those view settings to our desired effect after the model is loaded. As a user, I want to be able to set the view settings (i.e. projection mode, visibility, camera orientation, etc) before I see the model loaded into the scene.

Instructions

In order to modify the scene before the model loads, you have a few options. Items like projection, visibility, orientation, etc fall into the View class. In this case, we want to be sure that Communicator has initialized the View object and before we start trying to make calls to it. To do this, we will leverage the built-in callbacks in Communicator.

For this case, we want to look for a callback that indicates that View related operations can now be performed. What we are looking for in this case is the sceneReady callback.

Likewise, if you needed to modify the Model class on initialization, we would need to wait for the Model object to be initialized and ready for use by the viewer. We would use modelStructureReady in that case.

You may notice that your model is still appearing in a different style for a split second. If so, and noticeable, a simple way to prevent this is to delay model load until after the WebViewer instantiation. When you instantiate a viewer, pass empty to the model configuration property. This will initialized a WebViewer object and load a blank Communicator canvas. However, all the usual setup steps are occurring, but without a model streaming in. This allows you more time to set up your initial settings as described above.

If you chose to delay model load, once your settings are step, you can use a variant of loadSubtreeFrom*** API to load your model at the end of your callback logic that is setting up the scene. The specific API will depend on the Stream Cache format you are trying to load. For example, SC workflows would use loadSubtreeFromModel , SCS files would use loadSubtreeFromScsFile, and so on. For a complete list of these load APIs, see the Model class here.

If you have additional operations that you want to perform but the model is already loaded, you can leverage hiding nodes on initial load, then setting options, then unhiding the model. This gives the effect that model is not yet loaded (when in fact it is - just hidden) and gives you time to set your settings as well.

Once your callback functions are executed, you should have a scene set up to your liking with a model showcasing those settings.

Example:

Defer model load, and use the sceneReady callback to set up an Isometric View with Perspective Projection. We also want to make sure the camera is fit to the loaded model, so we will hide the model once it has loaded, fit the nodes, then reshow the model.

hwv.setCallbacks({
    // Fired when view-related operations are ready to be called
    sceneReady: async () => {
        // Set View Orientation 
        await hwv.view.setViewOrientation(Communicator.ViewOrientation.Iso);
        // Set projection
        hwv.view.setProjectionMode(Communicator.Projection.Perspective);
        // Here we are calling model class method, which could technically result in an error if our
        // modelStructureReady callback hasn't fired. It is good to check that callback has fired before loading.
        await hwv.model.loadSubtreeFromScsFile(hwv.model.getAbsoluteRootNode(), "converted_models/standard/scs_models/microengine.scs");
        // Once the model is loaded, immedaitely hide the model
        await hwv.model.setNodesVisibility([hwv.model.getAbsoluteRootNode()], false);
        // Fit the model to our scene, if needed
        await hwv.view.fitNodes([hwv.model.getAbsoluteRootNode()]);
        // Reveal model
        hwv.model.setNodesVisibility([hwv.model.getAbsoluteRootNode()], true);
    }
});