Skip to main content

2 posts tagged with "showroom"

View All Tags

Tutorial - Integrate Sketchfab viewer with Elfsquad

· 6 min read
Johannes Heesterman
Lead Software Engineer @ Elfsquad

In this tutorial I will show you a basic integration of the Sketchfab viewer with Elfsquad.

1. Embed Sketchfab viewer

Let's start with creating creating a new HTML page that embeds a Sketchfab viewer. This sample code can also be found on the official Sketchfab for Developers Viewer API page.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sketchfab Viewer API example</title>

<!-- Insert the Sketchfab viewer script -->
<script type="text/javascript" src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script>

<style>
html, body{
margin:0;
padding:0;
overflow: hidden;
}
iframe {
border:none;
height:100vh;
width:100vw;
}
</style>
</head>

<body>
<!-- Insert an empty iframe with attributes -->
<iframe src="" id="api-frame" allow="autoplay; fullscreen; xr-spatial-tracking" xr-spatial-tracking execution-while-out-of-viewport execution-while-not-rendered web-share allowfullscreen mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>

<!-- Initialize the viewer -->
<script type="text/javascript">
const iframe = document.getElementById( 'api-frame' );
const uid = 'cee9dd8f490c47469d2a4e64f99e8056'; // Replace with the ID of your model.
const client = new Sketchfab( iframe );
let sketchfabApi;
client.init( uid, {
success: function onSuccess( api ){
sketchfabApi = api;
api.start();
api.addEventListener( 'viewerready', function() {

console.log( 'Viewer is ready' );

} );
},
error: function onError() {
console.log( 'Viewer error' );
}
} );
</script>
</body>
</html>

Now you should be able to open the HTML file in your browser and see your 3D model:

Screenshot 1

2. Serve through web server

In order to be able to embed the viewer as a third party visualization within Elfsquad, the newly created HTML page needs to be served through a web server. For this tutorial it is sufficient to use localhost.

From within the folder in which you created the HTML file type the following command:

python -m http.server 8000

Now if you navigate to http://localhost:8000, you should see your page being served.

3. Embed in Elfsquad

Now that we have a web server running, we can embed the viewer in Elfsquad. Within the Elfsquad EMS navigate to the step editor of the model you want to embed the viewer in.

Create a new step and select the Type "Third party visualization". In the "Third party visualization URL" field enter the URL of your HTML page. In this case, it would be http://localhost:8000.

Screenshot 2

Now hit save and you should see your 3D model being embedded in Elfsquad.

4. Listening to configuration changes

In order to be able to react to configuration changes, we need to add a listener to the viewer. This listener will be activated in the viewerReady event callback.

Update the viewerready event listener to first retrieve a node map of the model. This node map will be used to identify the parts of the model that need to be shown or hidden. Then we will call the activateConfigurationUpdateListener function that will add the listener to the page.

let nodeMap = null;
client.init( uid, {
success: function onSuccess( api ){
sketchfabApi = api;
api.start();
api.addEventListener( 'viewerready', function() {

api.getNodeMap(function(err, nodes) {
if (!err) {
nodeMap = nodes;
activateConfigurationUpdateListener();
}
});
} );
},
error: function onError() {
console.log( 'Viewer error' );
}
} );

Now we can define the activateConfigurationUpdateListener function. This function will be called when the viewer is ready and will add a listener to page that will be activated when the configuration changes. The listener will then call the updateViewer function with the new configuration as an argument.

function activateConfigurationUpdateListener() {
window.addEventListener('message', function(e){
if (e.data && e.data.name == 'elfsquad.configurationUpdated'){
updateViewer(e.data.args);
}
});
}

Now we can define the updateViewer function. This function will be called when the configuration changes and will update the viewer with the new configuration.

For this example I will recursively iterate over all the features in the configuration and based on whether the feature is enabled or not, I will either show or hide the corresponding part of the model. This is just an example and you can implement any logic you want here.

function updateViewer(configuration) {
const stack = configuration.steps.map(step => step.features).flat(1);

while(stack.length > 0) {
const current = stack.pop();
for (let f of current.features) stack.push(f);
if (!current.code) continue;

const ids = Object.values(nodeMap)
.filter(node => node.name == current.code)
.map(node => node.instanceID);

for (let id of ids) {
if (current.isSelected) {
sketchfabApi.show(id);
} else {
sketchfabApi.hide(id);
}
}
}
}

If you mapped the feature codes to the corresponding parts of the model correctly, you should now be able to see the model update when you change the configuration in Elfsquad:

Result

5. Initialize with configuration

Now you may have noticed that the model is not initialized with the configuration. This is because the updateViewer function is only called when the configuration changes. In order to initialize the model with the configuration, we need to trigger the configurationUpdated event once manually within the viewerready function when the viewer is ready.

After the activateConfigurationUpdateListener call add a postMessage call to the top window. This will trigger the configurationUpdated event in Elfsquad and the model will be initialized with the configuration.

api.addEventListener( 'viewerready', function() {
api.getNodeMap(function(err, nodes) {
if (!err) {
nodeMap = nodes;
console.log('nodeMap', nodeMap);
activateConfigurationUpdateListener();

window.top.postMessage({
name: 'elfsquad.triggerConfigurationUpdated'
}, '*');
}
});
} );

6. Result

The final code should look like this:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sketchfab Viewer API example</title>

<script type="text/javascript" src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script>

<style>
html, body{
margin:0;
padding:0;
overflow: hidden;
}
iframe {
border:none;
height:100vh;
width:100vw;
}
</style>
</head>

<body>
<iframe src="" id="api-frame" allow="autoplay; fullscreen; xr-spatial-tracking" xr-spatial-tracking execution-while-out-of-viewport execution-while-not-rendered web-share allowfullscreen mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>

<script type="text/javascript">
const iframe = document.getElementById( 'api-frame' );
const uid = 'cee9dd8f490c47469d2a4e64f99e8056';
const client = new Sketchfab( iframe );
let sketchfabApi;
let nodeMap;
client.init( uid, {
success: function onSuccess( api ){
sketchfabApi = api;
api.start();
api.addEventListener( 'viewerready', function() {

api.getNodeMap(function(err, nodes) {
if (!err) {
nodeMap = nodes;
console.log('nodeMap', nodeMap);
activateConfigurationUpdateListener();

window.top.postMessage({
name: 'elfsquad.triggerConfigurationUpdated'
}, '*');
}
});
} );
},
error: function onError() {
console.log( 'Viewer error' );
}
} );


function activateConfigurationUpdateListener() {
window.addEventListener('message', function(e){
if (e.data && e.data.name == 'elfsquad.configurationUpdated'){
updateViewer(e.data.args);
}
});
}

function updateViewer(configuration) {
const stack = configuration.steps.map(step => step.features).flat(1);

while(stack.length > 0) {
const current = stack.pop();
for (let f of current.features) stack.push(f);
if (!current.code) continue;

const ids = Object.values(nodeMap)
.filter(node => node.name == current.code)
.map(node => node.instanceID);

for (let id of ids) {
if (current.isSelected) {
sketchfabApi.show(id);
} else {
sketchfabApi.hide(id);
}
}
}
}

</script>
</body>
</html>

7. Next steps

Now that you have a working integration, you can start to customize it to your needs. Here are some resources you can use to get started:

Tutorial - Custom viewer based on Verge3D

· 4 min read
Johannes Heesterman
Lead Software Engineer @ Elfsquad

Quick overview

Verge3D is a 3D viewer that can be used to bring your Blender, 3ds Max or Maya scene to life in the browser. For more information on how to use it, please refer to the Verge3D documentation.

Using the Elfsquad Verge3D blocks, you can easily create interactions between the Showroom and your 3D scene. An overview of the available blocks and other examples can be found on GitHub.

Installing the Elfsquad Verge3D blocks

Plugins can be installed by unzipping the zip file inside Verge3D's puzzles/plugins directory. The default location for the plugins should be: C:\Program Files\Verge3D_for_Blender\puzzles\plugins.

  1. Download the latest version here.
  2. Create a directory called Elfsquad inside the puzzles/plugins directory.
  3. Extract the contents of the .zip file inside the Elfsquad directory.

A list of all releases can be found here.

Setting the example scene in Verge3D

The Elfsquad Verge3D plugin provides sample scenes for the Showroom. These can be found in the Examples directory.

If you would like to use the sample scene, you can copy the contents of the Examples directory to the verge3d applications folder.

  1. Locate the applications folder of your Verge3D project. This is the folder where the Verge3D App Manager stores its data. The default location should be: %USERPROFILE%\verge3d_apps Verge3D App Manager
  2. Move the parametric_models directory from the plugin's Examples directory into the applications folder. Verge3D application folder

This should add a new entry to your Verge3D App Manager: Parametric Models. This is a modified version of the original Parameteric Models sample scene, that interacts with the Showroom, using the newly added Elfsquad Verge3D blocks.

A block has been added to listen to configuration updates and update the configuration model accordingly:

On configuration update sample

Update requirement actions have been added to the UI buttons to tell the configurator to update the configuration model:

On update sample

A JavasScript block has been added to trigger the On configuration update event when the scene is fully loaded:

On scene load sample

Available puzzle blocks

As you can see in the examples, the Elfsquad Verge3D plugin provides several puzzle blocks that can be used to interact with the configurator.

Events

On configuration update

On configuration update block

This block is called when the configuration is updated.

Actions

Get value by code

Get value by code block

This block can be used to retrieve the value of a feature by its feature code.

Get value by name

Get value by name block

This block can be used to retrieve the value of a feature by its feature name.

Update requirement by code

Update requirement by code block

This block can be used to update the requirement of a feature by its feature code.

Setting up the Showroom

Configuration model

In order to fully interact with the sample Verge3D scene, we need to setup a configuration model that has 3 features: Height, Thickness, and Corners.

The Update requirement [Feature code] Value block uses the feature code to update the requirements of the features in the Verge3D scene. For the sample scene to work, we need to create 3 features in our model with the codes: height, thickness, and corners:

Sample model

Third party visualization step

Now we can add a step to the configuration model to display our Verge3D scene, using the following settings:

Step editor

Result

With the setup done we can open the example model in the showroom and should see the following result:

Result

Changelog

  • 2024-07-01: Updated installation instructions to reflect Verge3D version 4.6.0