# display-3d-model

## Overview

The `display-3d-model` UI component embeds and displays 3D models (in `.fbx` format) for a user to interact with.&#x20;

{% hint style="info" %}
**Version compatibility**

`display-3d-model` was introduced in version **4.84.0** of the JourneyApps Runtime.
{% endhint %}

{% hint style="info" %}
`display-3d-model` is currently only available for customers on the [Enterprise](https://journeyapps.com/pricing/) plan.
{% endhint %}

{% hint style="warning" %}
**Current Limitations**

* `display-3d-model` currently only supports `.fbx` files and these files need to be zipped when [bound](#bind) to the component. E.g. `my-animation.fbx.zip`
* 3D models with textures are not currently supported.
* It is not possible to toggle hidden layers, groups, or elements.
  {% endhint %}

### Basic Example

![](https://2865107717-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F9TCHLR67eLHBOjPvHhud%2Fuploads%2FXUvnKtXik35boHQ7p13Q%2Fdisplay-3d-model-example.png?alt=media\&token=da76e8df-cdc7-464a-933b-fd27ed986abe)

{% code title="main.view\.xml" %}

```xml
<!-- The attachment needs to be a zipped FBX file, e.g. my-animation.fbx.zip -->
<var name="scene" type="attachment" media="any" />

<display-3d-model bind="scene" scale="0.1" />
```

{% endcode %}

{% code title="main.js" %}

```javascript
function init() {
    var animation = DB.animation.first();
    view.scene = animation.scene;
}
```

{% endcode %}

For more examples, see our guides:

{% content-ref url="display-3d-model/display-3d-model-guides" %}
[display-3d-model-guides](https://docs.journeyapps.com/reference/build/ui-components/all-ui-components/display-3d-model/display-3d-model-guides)
{% endcontent-ref %}

### Interact with the 3D model

Once a model is loaded in `display-3d-model`, a user can interact with it by using their mouse or by using controls that programmatically manipulate the 3D model.

#### Interact with the mouse

* **Rotate the scene:** Users can drag their mouse around in the 3D model. The scene will rotate around the current center of the viewer.
* **Pan / translate the scene**: While holding the shift key, users can drag their mouse around. Dragging left and right will pan the scene horizontally, while dragging up and down will pan the scene vertically.

#### Interact programmatically

Developers can set up controls (e.g. a `button-group` containing multiple buttons linked to JS/TS functions) that allow users to manipulate various attributes of the 3D model. Configurable attributes and component methods are described further below in this document.&#x20;

Examples of controls that a user might need include:

* Increasing or decreasing the [`scale`](#scale) of the model (also see the example below)
* Enabling or disabling the [`wireframe`](#wireframe)
* [Starting](#animationstart) or [stopping](#animationstop) animations (also see the example below)
* Playing animations [from a specific point](#setplayhead)
* Setting the [camera position](#setcamera) of the scene

**Example: Programmatic controls**

{% code title="main.view\.xml" %}

```xml
<var name="scene" type="attachment" media="any" />
<var name="scale" type="number" />

<display-3d-model id="example" bind="scene" scale="scale" />
<button-group mode="row">
    <!-- Controls to allow users to increase or decrease the scale -->
    <button label="-" on-press="$:scaleDown()"/>
    <button label="+" on-press="$:scaleUp()"/> 
    <!-- Controls to allow users to start/stop animation -->
    <button label="Start Animation" on-press="$:startAnimation()"/>
    <button label="Stop Animation" on-press="$:stopAnimation()"/> 
</button-group>
```

{% endcode %}

```javascript
function init() {
    var animation = DB.animation.first();
    view.scene = animation.scene;
    view.scale = 0.1; // Set the default scale
}

function scaleUp(){
    view.scale *= 10; // Increase scale by 10
}

function scaleDown(){
    view.scale /= 10; // Decrease scale by 10
}

function startAnimation(){
    component.display3dModel({id: "example"}).animationStart(); 
}

function stopAnimation(){
    component.display3dModel({id: "example"}).animationStop(); 
}
```

### Attribute and methods overview by function

The table below summarizes the available attributes and component methods for `display-3D-model` grouped according to their primary or most common function. Each of the listed attributes is described later in this document.

| Function          | Attributes                                                                                                                                                                                                                                                                                                                                                                                                          |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Geometry          | <ul><li><a href="#offset-x"><code>offset-x</code></a></li><li><a href="#offset-y"><code>offset-y</code></a></li><li><a href="#offset-z"><code>offset-z</code></a></li><li><a href="#scale"><code>scale</code></a></li><li><a href="#computecenteroffset"><code>computeCenterOffset()</code></a></li><li><a href="#computescalefactor"><code>computeScaleFactor()</code></a></li></ul>                               |
| Animation         | <ul><li><a href="#autoplay"><code>autoplay</code></a></li><li><a href="#loop"><code>loop</code></a></li><li><a href="#animationstart"><code>animationStart()</code></a></li><li><a href="#animationstop"><code>animationStop()</code></a></li><li><a href="#getplayhead"><code>getPlayhead()</code></a></li><li><a href="#setplayhead"><code>setPlayhead()</code></a></li></ul>                                     |
| Camera            | <ul><li><a href="#getcamera"><code>getCamera()</code></a></li><li><a href="#setcamera"><code>setCamera()</code></a></li></ul>                                                                                                                                                                                                                                                                                       |
| Styling & Display | <ul><li><a href="#background-color"><code>background-color</code></a></li><li><a href="#border-color"><code>border-color</code></a></li><li><a href="#floor"><code>floor</code></a></li><li><a href="#fog"><code>fog</code></a></li><li><a href="#height"><code>height</code></a></li><li><a href="#loader-color"><code>loader-color</code></a></li></ul>                                                           |
| Troubleshooting   | <ul><li><a href="#bounding-box"><code>bounding-box</code></a></li><li><a href="#debug-normals"><code>debug-normals</code></a></li><li><a href="#double-sided-materials"><code>double-sided-materials</code></a></li><li><a href="#material-vertex-groups"><code>material-vertex-groups</code></a></li><li><a href="#stats"><code>stats</code></a></li><li><a href="#wireframe"><code>wireframe</code></a></li></ul> |

### Developer Notes

* **Performance consideration**: In general, the larger the file the worse the performance will be, especially on a mobile device (such as a RealWear HMT). File size will be directly proportional to the number of polygons and the number and characteristics of the materials included in the model (even if those materials are not actually used)&#x20;
  * As a rule of thumb, aim for a file size of under 5 MB. Practically this may mean unnecessary high fidelity elements should be removed from their original models to reduce the polygon count, and by extension the file size.
  * Unused (and non visible) materials should be removed from models before they are exported to FBX to limit the file size.
* **Materials**: The use of materials is generally supported however, trial and error in terms of which materials work well is recommended.

## Standard Attributes

### `bind`

{% content-ref url="../xml-fields/bind" %}
[bind](https://docs.journeyapps.com/reference/build/ui-components/xml-fields/bind)
{% endcontent-ref %}

### `scale`

**Optional**

**Type**: `Number`

**Default**: 1.0

Specify the scale of the model.

## Advanced Attributes

### `autoplay`

**Optional**

**Type**: `boolean`

**Default**: `true`

Specify whether the model animation should automatically start playing when the model is loaded.

### `background-color`

**Optional**

**Type**: `string` (#hex value)

**Default**: `#a0a0a0`

Specify the background color of the component.&#x20;

### `border-color`

**Optional**

**Type**: `string` - can be a named color or #HEX value

**Default**: `#546e7a` (Light theme); `#90a4ae` (Dark theme)

Specify the border color of the component.&#x20;

### `bounding-box`

**Optional**

**Type**: `boolean`

**Default**: `false`

Enable or disable the bounding box of the model.&#x20;

### `debug-normals`

**Optional**

**Type**: `boolean`

**Default**: `false`

Enable or disable the ability to debug model [normals](https://en.wikipedia.org/wiki/Normal_\(geometry\)).&#x20;

### `double-sided-materials`

**Optional**

**Type**: `boolean`

**Default**: `true`

Enable or disable double-sided materials.

### `floor`

**Optional**

**Type**: `boolean`

**Default**: `true`

Enable or disable the floor of the model.

### `fog`

**Optional**

**Type**: `boolean`

**Default**: `true`

Enable or disable a background fog effect.

### `height`

**Optional**

**Type**: `Number`

**Default**: 700 px

Specify the height of the component in pixel.

### `loader-color`

**Optional**

**Type**: `string` (#hex value)

**Default**: `#546e7a` (Light theme); `#90a4ae` (Dark theme)

Specify the color of the loader animation that displays when the component loads a model.&#x20;

### `loop`

**Optional**

**Type**: `boolean`

**Default**: `true`

Specify whether the model animation should play in a loop.

### `id`

{% content-ref url="../xml-fields/id" %}
[id](https://docs.journeyapps.com/reference/build/ui-components/xml-fields/id)
{% endcontent-ref %}

### `material-vertex-groups`

**Optional**

**Type**: `boolean`

**Default**: `true`

Enable or disable the material vertex groups.

### `offset-x`

**Optional**

**Type**: `Number`

**Default**: 0

Specify the offset of the x-axis.

### `offset-y`

**Optional**

**Type**: `Number`

**Default**: 0

Specify the offset of the y-axis.

### `offset-z`

**Optional**

**Type**: `Number`

**Default**: 0

Specify the offset of the z-axis.

### `on-pick-mesh`

**Optional**

**Default**: unset

**Triggered when**: A user clicks on the model

**Event parameter**: `$meshes`

**Return value**: An array of objects

`on-pick-mesh` is an event that calls a JS/TS [`$:function`](https://docs.journeyapps.com/reference/app-features/calling-js-functions-from-xml) or [navigation](https://docs.journeyapps.com/reference/get-started/journeyapps-fundamentals/view-navigation). See more details:

{% content-ref url="../js-ts-events" %}
[js-ts-events](https://docs.journeyapps.com/reference/build/ui-components/js-ts-events)
{% endcontent-ref %}

{% code title="main.view\.xml" %}

```xml
<var name="scene" type="attachment" media="any" />
​
<display-3d-model bind="scene" scale="0.1" on-pick-mesh="$:onPick($meshes)" />
```

{% endcode %}

{% code title="main.js" %}

```javascript
function onPick(meshArray) {
    for (var i = 0; i < meshArray.length; i++){
        console.log(meshArray[i]);
        // Example:
        // Object{name: "Plane"}
    }  
}
```

{% endcode %}

### `placeholder`

{% content-ref url="../xml-fields/placeholder" %}
[placeholder](https://docs.journeyapps.com/reference/build/ui-components/xml-fields/placeholder)
{% endcontent-ref %}

### `show-if` and `hide-if`

{% content-ref url="../xml-fields/show-if" %}
[show-if](https://docs.journeyapps.com/reference/build/ui-components/xml-fields/show-if)
{% endcontent-ref %}

{% content-ref url="../xml-fields/hide-if" %}
[hide-if](https://docs.journeyapps.com/reference/build/ui-components/xml-fields/hide-if)
{% endcontent-ref %}

### `stats`

**Optional**

**Type**: `boolean`

**Default**: `false`

Enable or disable debug info about the model such as the frames rendered per second. These are displayed in the top-left corner of the component if available.

### `wireframe`

**Optional**

**Type**: `boolean`

**Default**: `false`

Enable or disable the wireframe of the model.

## Component Methods

The following component methods are available when an [`id`](https://docs.journeyapps.com/reference/build/ui-components/xml-fields/id) is assigned to the component and `component.display3dModel({id:'my-id'})` is called from JS/TS:

### `animationStart`

This method starts the animation of a model.

### `animationStop`

This method stops the animation of a model.

### `computeCenterOffset`

**Returns**: `Array`, e.g. `[0,408.6,0]`

Generates an array with offsets for each axis (x,y,z) that centers the model on-screen.&#x20;

{% hint style="info" %}
**Note**: Some 3D models are not centered in 3D coordinate space (0,0,0) and when coupled with the [`offset-x`](#offset-x), [`offset-y`](#offset-y) and [`offset-z`](#offset-z) attributes, these can provide centering capability.
{% endhint %}

**Example**:

{% code title="main.view\.xml" %}

```xml
<var name="scene" type="attachment" media="any" />
<var name="offsetx" type="number" />
<var name="offsety" type="number" />
<var name="offsetz" type="number" />
​
<display-3d-model id="example" bind="scene" offset-x="offsetx" offset-y="offsety" offset-z="offsetz" />
<button label="Center" on-press="$:computeOffsets()" />
```

{% endcode %}

{% code title="main.js" %}

```javascript
function computeOffsets() {
    var offsets = component.display3dModel({id: "example"}).computeCenterOffset();
    view.offsetx = offsets[0];
    view.offsety = offsets[1];
    view.offsetz = offsets[2];
}
```

{% endcode %}

### `computeScaleFactor`

**Parameter**: `Number` that represents the scale

Generates a [scale](#scale) value that when used, will scale the model to an acceptable size in the current 3D viewport that will show the entire mesh.&#x20;

{% hint style="info" %}
**Note**: This is useful because not all 3D models use the same scale factor.
{% endhint %}

**Example**:

{% code title="main.view\.xml" %}

```xml
<var name="scene" type="attachment" media="any" />

<display-3d-model id="example" bind="scene" scale="scale" />
<button label="Fit" on-press="$:computeScale()" />
```

{% endcode %}

{% code title="main.js" %}

```javascript
function computeScale() {
    var scaleFactor = 550;
    view.scale = component.display3dModel({id: "example"}).computeScaleFactor(scaleFactor);
}
```

{% endcode %}

### `getCamera`

**Returns**: The current camera position as an `Object`, e.g. `{position: [100.00000000000001, 200, 299.99999999999994], rotation: [-0.1505711418828577, 0.1583076573177903, 0.024434332593631213, 0.9755357401230101]}`

Gets the camera position represented as a [quaternion](https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation).

### `setCamera`

**Parameter**: The specified camera position as an `Object`, e.g. `{position: [100.00000000000001, 200, 299.99999999999994], rotation: [-0.1505711418828577, 0.1583076573177903, 0.024434332593631213, 0.9755357401230101]}`

Sets the camera position as a [quaternion](https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation). This will animate the camera to the new position.

{% hint style="info" %}
**Tip**: This method is also useful when creating 3D step-based workflows (because the camera animates to a specified position).
{% endhint %}

### `getPlayhead`

**Returns:** The playback position in milliseconds.

Gets the playback position.

### `setPlayhead`

**Parameter**: The playback position in milliseconds.

Sets the playback position.&#x20;

### `scrollIntoView`

Programmatically scroll until the `display-3d-model` component is visible in the view.
