Documentation

3D Models

This example shows how to augment a target image with 3D content. It starts by displaying a 3D model on a target and advances by adding displayed animations, interactivity and demonstrates the snap-to-screen functionality. The last example shows how 3D content can be placed at a certain geographic location.

If you are not yet familiar with how to create a vision based augmented reality scene (based on image recognition and tracking), please have a look at the previous example Client Recognition.

3D content within Wikitude can only be loaded from Wikitude 3D Format files (.wt3). This is a compressed binary format for describing 3D content which is optimized for fast loading and handling of 3D content on a mobile device. You still can use 3D models from your favorite 3D modeling tools (Autodesk® Maya® or Blender) but you'll need to convert them into the wt3 file format. The Wikitude 3D Encoder desktop application (Windows and Mac) encodes your 3D source file. The Encoder can handle Autodesk® FBX® files (.fbx)for encoding to .wt3 .

For more details on how to convert your 3D content please see the Wikitude 3D Encoder section. In this example the .wt3 file has already been prepared and saved to assets/car.wt3.

3D content is rendered on top of 2D objects. This limitation exists because of some SDK internal restrictions and might change in an upcoming release.

This sample consists of four parts

  1. 3D Model on Target Image
  2. Appearing Animation
  3. Interactivity
  4. Snap to Screen
  5. Animation of Model Parts
  6. 3D Model at GeoLocation

Rendering of car model in Wikitude 3D Encoder

The following fictional print advertisement is used as target image, which will be augmented with a 3D model of the car advertised in the print ad.

Print ad used as image target

3D Model on Target (1/6)

First of all create an AR.Model and pass the URL to the actual .wt3 file of the model. Additional options allow for scaling, rotating and positioning the model in the scene.

this.modelCar = new AR.Model("assets/car.wt3", {
    onLoaded: this.loadingStep,
    scale: {
        x: 0.045,
        y: 0.045,
        z: 0.045
    },
    translate: {
        x: 0.0,
        y: 0.05,
        z: 0.0
    },
    rotate: {
        z: -25
    }
});
view source code on GitHub

In this example a function is attached to the onLoaded trigger to receive a notification once the 3D model is fully loaded. Depending on the size of the model and where it is stored (locally or remotely) it might take some time to completely load and it is recommended to inform the user about the loading time.

Similar to 2D content the 3D model is added to the drawables.cam property of an AR.ImageTrackable.

var trackable = new AR.ImageTrackable(this.tracker, "*", {
    drawables: {
        cam: [this.modelCar]
    }
});
view source code on GitHub

This is everything that is needed to allow the 3D model appear on an image target. To adjust scaling and position of the model pass the scale and translate properties as options to the AR.Model.

To view the sample you can use the image in on this page

Appearing Animation (2/6)

As a next step, an appearing animation is added which scales up the 3D model once the target is inside the field of vision. Creating an animation on a single property of an object is done using an AR.PropertyAnimation. Since the car model needs to be scaled up on all three axis, three animations are needed. These animations are grouped together utilizing an AR.AnimationGroup that allows them to play them in parallel.

var sx = new AR.PropertyAnimation(model, "scale.x", 0, scale, 1500, {
    type: AR.CONST.EASING_CURVE_TYPE.EASE_OUT_QUAD
});
var sy = new AR.PropertyAnimation(model, "scale.y", 0, scale, 1500, {
    type: AR.CONST.EASING_CURVE_TYPE.EASE_OUT_QUAD
});
var sz = new AR.PropertyAnimation(model, "scale.z", 0, scale, 1500, {
    type: AR.CONST.EASING_CURVE_TYPE.EASE_OUT_QUAD
});

return new AR.AnimationGroup(AR.CONST.ANIMATION_GROUP_TYPE.PARALLEL, [sx, sy, sz]);
view source code on GitHub

Each AR.PropertyAnimation targets one of the three axis and scales the model from 0 to the value passed in the scale variable. An EASE_OUT_QUAD easing curve is used to create a more dynamic effect of the animation.

To get a notification once the image target is inside the field of vision the onEnterFieldOfVision trigger of the AR.ImageTrackable is used. In the example the function appear() is attached.

appear: function appearFn() {
    World.trackableVisible = true;
    if (World.loaded) {
        World.appearingAnimation.start();
    }
},
view source code on GitHub

Within the appear function the previously created AR.AnimationGroup is started by calling its start() function which plays the animation once.

Interactivity (3/6)

To add more functionality, a rotating animation is added to the 3D model. It is started and paused by clicking on the button or on the 3D model.

Additionally to the 3D model an image that will act as a button is added to the image target. This can be accomplished by loading an AR.ImageResource and creating a drawable from it.

var imgRotate = new AR.ImageResource("assets/rotateButton.png");
var buttonRotate = new AR.ImageDrawable(imgRotate, 0.2, {
    translate: {
        x: 0.35,
        y: 0.45
    },
    onClick: this.toggleAnimateModel
});
view source code on GitHub

To add the AR.ImageDrawable to the image target together with the 3D model both drawables are supplied to the AR.ImageTrackable.

var trackable = new AR.ImageTrackable(this.tracker, "*", {
    drawables: {
        cam: [this.modelCar, buttonRotate]
    },
    onEnterFieldOfVision: this.appear
});
view source code on GitHub

The rotation animation for the 3D model is created by defining an AR.PropertyAnimation for the rotate.z property.

// Rotation Animation
this.rotationAnimation = new AR.PropertyAnimation(this.modelCar, "rotate.z", -25, 335, 10000);
view source code on GitHub

The drawables are made clickable by setting their onClick triggers. Click triggers can be set in the options of the drawable when the drawable is created. Thus, when the 3D model onClick: this.toggleAnimateModel is set in the options it is then passed to the AR.Model constructor. Similar the button's onClick: this.toggleAnimateModel trigger is set in the options passed to the AR.ImageDrawable constructor. toggleAnimateModel() is therefore called when the 3D model or the button is clicked.

Inside the toggleAnimateModel() function, it is checked if the animation is running and decided if it should be started, resumed or paused.

toggleAnimateModel: function toggleAnimateModelFn() {
    if (!World.rotationAnimation.isRunning()) {
        if (!World.rotating) {
            World.rotationAnimation.start(-1);
            World.rotating = true;
        } else {
            World.rotationAnimation.resume();
        }
    } else {
        World.rotationAnimation.pause();
    }

    return false;
}
view source code on GitHub

Starting an animation with .start(-1) will loop it indefinitely.

Snap to Screen (4/6)

To finish things up, the snap to screen feature is added so that the 3D model can be explored in a more immersive way. Snap to screen will bring the drawables, attached to a AR.ImageTrackable, out of the augmented reality scene and directly onto the screen. Once snapped, the drawables will stay on the screen as long as they are not set back into the augmented reality context. Thereby users can explore content even if they don't look at the target image.

The snap position on the screen is defined through a div element. During the AR.ImageTrackable creation, the div is passed as a additional option. In this example a div with id snapContainer is used.

this.trackable = new AR.ImageTrackable(this.tracker, "*", {
    drawables: {
        ...
    },
    snapToScreen: {
        snapContainer: document.getElementById('snapContainer')
    },
    ...
});
view source code on GitHub

Snapping is then enabled through an additional button. The button is created and setup just the same way as the rotate button. The only difference is that the onClick function of the newly created button is pointing to a different function.

toggleSnapping: function toggleSnappingFn() {
    if (World.appearingAnimation.isRunning()) {
        World.appearingAnimation.stop();
    }
    World.snapped = !World.snapped;
    World.trackable.snapToScreen.enabled = World.snapped;

    if (World.snapped) {
        World.applyLayout(World.layout.snapped);
    } else {
        World.applyLayout(World.layout.normal);
    }
}
view source code on GitHub

To enable snapping, set the AR.ImageTrackable property snapToScreen.enabled accordingly (either true or false). Based on the current snapping state, the drawables are positioned and scaled differently.

In the sample the 3D model can be rotated and scaled through gestures once it is snapped to the screen. To apply the new rotation, position and scale values, the gesture callbacks onScale, onDrag and onRotation are used.

Animation of Model Parts (5/6)

A 3D model represents a set of triangle meshes which can further be subdivided in mesh parts. Each mesh or mesh part stores material properties and transformations which determines its appearance and spatial position. In case of the red Lamborghini model discussed above the wheels, doors, roof and the hood, a.s.o. represent meshes. The car's door, for example, is further subdivided into mesh parts representing the door's frame, side mirror or door handle. The grouping of meshes parts allows to animate parts of the 3D model independently. In the Lamborghini example the door with all its parts can be opened (see figure below).

Animation of a model part in the 3D Encoder

Meshes and mesh parts and can have identifiers which are passed to the onClick trigger function of the AR.Model as parameter modelPart. This allows to apply different actions when certain parts of a 3D model have been clicked/touched by the user. In the code snippet shown below the parameter modelPart is used in a switch instruction. If the modelPart reported is part of the car's left door an animation from the 3D model is created and started. Otherwise the identifier of the mesh or mesh part (parameter modelPart) is displayed in a pop-up window via the alert function.

this.model = new AR.Model("assets/car_animated.wt3", {
    ...
});

this.animationDoorL = new AR.ModelAnimation(this.model, "DoorOpenL_animation");

this.model.onClick = function( drawable, model_part ) {
switch(model_part)
{
    case 'WindFL': 
    case 'DoorL[0]':
    case 'DoorL[1]':
    case 'DoorL[2]':
    case 'DoorL[3]':                
        World.animationDoorL.start();
        break;
    ...
}
view source code on GitHub

The identifiers of the mesh parts are provided by the 3D model. They are specified by the modeling tool the 3D model was created with (e.g. 3d Studio Max, Maya, Blender, ...). A list of meshes and mesh parts for a 3D model can be obtained from by the Wikitude 3D Encoder (see figure below). If a mesh consists of single part, the identifier contains the name of the mesh, e.g., 'WindFL'. If it consists of several parts, the identifier contains the index of the part in square brackets attached to its name, e.g., DoorL[0].

Copy identifiers of model parts with the 3D Encoder

3D Model at GeoLocation (6/6)

Beside rendering 3D models on top of recognized target images, the Wikitude SDK can also render 3D models at any kind of location. In the example below we are showing how to place a 3D model at a specific relative location. The location of the 3D model is relative to the user's current position and placed about 5 meters away to the north and 2 meters above. We are using a relative location so it is easier for you to try it out on your own, however it is easy to change that to a real geo-location. (See AR.GeoLocation and AR.RelativeLocation for details)

var location = new AR.RelativeLocation(null, 5, 0, 2);

var modelEarth = new AR.Model("assets/earth.wt3", {
    onLoaded: this.worldLoaded,
    scale: {
        x: 1,
        y: 1,
        z: 1
    }
});

var obj = new AR.GeoObject(location, {
    drawables: {
       cam: [modelEarth]
    }
});
view source code on GitHub

When starting the experience you will need to point your camera a little bit to the east and little bit up and you will see a 3D model of the earth floating in front of you.