Show TOC

Step 3: 3D Viewer Using the Viewport ControlLocate this document in the navigation structure

In this step, you will be creating a 3D Viewer application using the sap.ui.vk.Viewport control.

Caution

The controls in the sap.ui.vk library are currently flagged as experimental. For more information, see Compatibility Rules.

In previous steps, we utilized the sap.ui.vk.Viewer composite control to create a Viewer application capable of loading a 2D or 3D resource. Now, we will create a Viewer application with a pre-loaded resource without using the composite sap.ui.vk.Viewer control. Instead, we will use the following controls and library in sap.ui.vk, which are what you'll need at a minimum to display a 3D model in your application.
  • Viewport control
  • ContentResource control
  • GraphicsCore library

We will build on this sample application in later steps of the 3D Viewer tutorial by introducing the other non-composite sap.ui.vk controls to create more complex Viewer applications.

Preview
Figure 1: Viewer application that consists solely of a Viewport
Coding

You can view and download all files in the Explored app in the Demo Kit under 3D Viewer - Step 3 - Standalone Viewport .

index.html

Update the index.html file to reference the standaloneViewport namespace, which will be the namespace we'll use for the sample application in this step.

#!html<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
        <script id="sap-ui-bootstrap"
            src="../../../../../../../../../resources/sap-ui-core.js"
            data-sap-ui-libs="sap.ui.vk"
            data-sap-ui-theme="sap_bluecrystal"
            data-sap-ui-bindingSyntax="complex"
            data-sap-ui-resourceroots='{
                "standaloneViewport": "./"
            }'>
        </script>
        <script>
        sap.ui.getCore().attachInit(function(){
            new sap.m.Shell({
                app: new sap.ui.core.ComponentContainer({
                    name : "standaloneViewport"
                })
            }).placeAt("content");
        });
        </script>
    </head>
    <body id="content" class="sapUiBody">
    </body>
</html>

Component.js

Update the Component.js file to reference the namespace specified for this application.

#!jssap.ui.define([
        "sap/ui/core/UIComponent"
], function (UIComponent) {
        "use strict";
        return UIComponent.extend("standaloneViewport.Component", {
        metadata: {
            manifest: "json"
        },
        init: function () {
            // call the init function of the parent
            UIComponent.prototype.init.apply(this, arguments);
        }
    });
});

i18n.properties

Because we are not creating any fields that a user can interact with, we only have one line of code which specifies what the label for the page title is.

#!properties# Page Descriptor
pageTitle=Standalone Viewport

manifest.json

Update the manifest.json file so that it references the correct files.

#!js{
    "_version": "1.1.0",
    "sap.app": {
        "_version": "1.1.0",
        "id": "standaloneViewport",
        "type": "application",
        "i18n": "i18n/i18n.properties",
        "title": "{{appTitle}}",
        "description": "{{appDescription}}",
        "applicationVersion": {
            "version": "1.0.0"
        },
    },
    "sap.ui": {
        "_version": "1.1.0",
        "technology": "UI5",
        "deviceTypes": {
            "desktop": true,
            "tablet": true,
            "phone": true
        },
        "supportedThemes": [
        "sap_bluecrystal"
        ]
    },
    "sap.ui5": {
        "_version": "1.1.0",
        "rootView": "standaloneViewport.view.App",
        "dependencies": {
            "minUI5Version": "1.30",
            "libs": {
                "sap.m": {}
            }
        },
        "models": {
            "i18n": {
                "type": "sap.ui.model.resource.ResourceModel",
                "settings": {
                    "bundleName": "standaloneViewport.i18n.i18n"
                }
            }
        }
    }
}

App.view.xml

Because the Viewport is the only item that we need to display on the application screen, we only need to have the <vk:Viewport> element added to this file. In the element's attributes, we specify the Viewport's width and height on the screen, and also give it an arbitrary identifier value.

#!xml<mvc:View
        controllerName="standaloneViewport.controller.App"
        xmlns="sap.m"
        xmlns:mvc="sap.ui.core.mvc"
        xmlns:vk="sap.ui.vk"
        xmlns:l="sap.ui.layout"
        xmlns:f="sap.ui.layout.form"
        xmlns:u="sap.ui.unified"
        displayBlock="true">
    <App id="standaloneViewport">
        <Page
            title="{i18n>pageTitle}">
            <vk:Viewport
                    id="viewport"
                    width="100%"
                    height="50%"/>
        </Page>
    </App>
</mvc:View>

App.controller.js

The logic in this App.controller.js file can be summarized as follows:
  1. Create a Content Resource that stores a pre-specified model
  2. Initiate a scene in our application in the following order:
    1. Create a Graphics Core instance
    2. Create a Viewport that is bound to the Graphics Core instance
    3. Load the Content Resource to the Graphics Core for rendering on the Viewport
#!jssap.ui.define([
    "sap/ui/core/mvc/Controller",
    "sap/ui/model/json/JSONModel",
    "sap/ui/vk/ContentResource",
], function (Controller, JSONModel, ContentResource) {
    "use strict";

    var contentResource = new sap.ui.vk.ContentResource({
        source: "/models/boxTestModel.vds",
        sourceType: "vds",
        id: "abc123"
    });

    return Controller.extend("standaloneViewport.controller.App",{
        onInit: function() {

            var mainScene;

            jQuery.sap.require("sap.ui.vk.GraphicsCore");
            var graphicsCore = new sap.ui.vk.GraphicsCore({},{
                antialias: true,
                alpha: true,
                premultipliedAlpha: false
            });

            var view = this.getView();
            var viewport = view.byId("viewport");
            
            viewport.setGraphicsCore(graphicsCore);
            graphicsCore.loadContentResourcesAsync([contentResource], function(sourcesFailedToLoad){
                if (sourcesFailedToLoad){
                    jQuery.sap.log.error("Some of content resources cannot be loaded.");
                } else {
                    var scene = graphicsCore.buildSceneTree([contentResource]);
                    if (scene){
                        mainScene = scene;
                        viewport.setScene(mainScene);
                    } else {
                        jQuery.sap.log.error("Failed to load viewport");
                    }
                }
            });
        }
    });
});

We'll now break the code down to look at each part in more detail.

Create a New Content Resource
Create a contentResource object that specifies the resource to load. In this case, we're pre-loading the boxTestModel.vds model into the application. This occurs before the scene in our Viewer application is initiated.
#!jssap.ui.define([
    "sap/ui/core/mvc/Controller",
    "sap/ui/model/json/JSONModel",
    "sap/ui/vk/ContentResource",
], function (Controller, JSONModel, ContentResource) {
    "use strict";

    var contentResource = new sap.ui.vk.ContentResource({
        source: "/models/boxTestModel.vds",
        sourceType: "vds",
        id: "abc123"
Create a New Graphics Core Instance
Create a new Graphics Core instance. We're only specifying one input parameter, which is for the WebGL context attributes. We then get the current viewport, and attach it to the Graphics Core instance so the model we've loaded can be rendered.
#!jsreturn Controller.extend("standaloneViewport.controller.App",{
    onInit: function() {
 
    var mainScene;
        jQuery.sap.require("sap.ui.vk.GraphicsCore");
        var graphicsCore = new sap.ui.vk.GraphicsCore({},{
            antialias: true,
            alpha: true,
            premultipliedAlpha: false
        });

        var view = this.getView();
        var viewport = view.byId("viewport");
         
        viewport.setGraphicsCore(graphicsCore);
Load the Content Resource for Rendering
Now that we've associated the viewport with the Graphics Core, we can load our model to be displayed on the Viewport. In the following code block, we have specified some checks to make sure that the model loads correctly. If no resource is loaded, or if there is an error loading the resource, we throw the following error on the screen "Some of content resources cannot be loaded". Otherwise, we build a scene with the loaded resource, and then display this scene on the viewport. If the scene itself does not load into the Viewport, we throw an error saying the scene could not be built "Failed to build the scene."
#!jsgraphicsCore.loadContentResourcesAsync([contentResource], function(sourcesFailedToLoad){
    if (sourcesFailedToLoad){
        jQuery.sap.log.error("Some of content resources cannot be loaded.");
    } else {
        var scene = graphicsCore.buildSceneTree([contentResource]);
            if (scene){
                mainScene = scene;
                viewport.setScene(mainScene);
            } else {
                jQuery.sap.log.error("Failed to load viewport");
            }
    }
});
}
});
API Reference