Skip to content

Using Assets and Models

Christian Schlinkmann edited this page Oct 26, 2015 · 11 revisions

Note: Assets are currently a work in progress. If you find any problems please don't hesitate to file an Issue and be aware that some implementation details may change in the future.

Introduction

For this tutorial we'll be looking at the new Asset and Model format introduced in XML3D 4.7. Concretely we'll cover:

  • The motivation behind the Asset format
  • The Asset format itself
  • Instantiating an Asset with a Model tag
  • Overwriting parts of the Asset from inside your scene

To convert your own models to the XML3D Asset format give this Blender exporter a try.

Why use Assets?

One of the difficulties in creating complex interactive 3D application is the rapidly growing amount of objects in the scene. In most cases, however, the application modifies a small subset of all scene objects only. The other parts remain static or just change due to data dependencies (typically modeled with Xflow).

For example, consider a firetruck which consists of multiple meshes, materials and animations. You might want to have multiple firetrucks in your scene, but each instance should have individual animations (e.g. the angle of the wheels).

XML3D Assets allow factoring logically distinct features into independent modules, or to put it simply: just put all parts of the firetruck into one asset. In contrast to other approaches, the firetruck asset remains configurable from outside. As you will see later, it's still possible to override parameters of the asset and thus to modify e.g. the appearance, the geometry meshes, and animations of each instance.

Using external assets helps keeping the HTML document concise by only exposing those elements to the DOM that are actually required by the application. Since the memory footprint of DOM elements is still relatively high, one can additionally benefit from using assets.

For this reason Assets were introduced to XML3D. By converting our complex object to the Asset format we can introduce an instance of it into our scene with a single <model> element.

Lets start by taking a quick look at the Asset format itself.

The Asset format

Resources: ciccio_asset.zip

The above zip archive above contains the data, textures and Asset file needed to create an instance of the Ciccio robot from the FIcontent initiative in our scene.

Lets take a closer look at the Asset file ciccio.xml:

<xml3d xmlns="http://www.xml3d.org/2009/xml3d" >
    <material id="glassShader" model="urn:xml3d:material:phong">
        <float3 name="emissiveColor">0.5 0.5 0.5</float3>
        <float3 name="diffuseColor">0.1936 0.636474 0.8</float3>
        <float3 name="specularColor">0.5 0.5 0.5</float3>
        <float name="shininess">0.15625</float>
        <float name="ambientIntensity">0.0</float>
        <float name="opacity">0.85</float>
    </material>

    <material id="armorShader" model="urn:xml3d:material:phong">
        <float3 name="emissiveColor">0.5 0.5 0.5</float3>
        <float name="ambientIntensity">0.1</float>
        <texture name="diffuseTexture">
            <img src="textures/Ciccio_Armor_D.png"/>
        </texture>
        <texture name="emissiveTexture">
            <img src="textures/Ciccio_Armor_EM.png"/>
        </texture>
        <texture name="normalTexture">
            <img src="textures/Ciccio_Armor_NM.png"/>
        </texture>
        <float3 name="specularColor">0.5 0.5 0.5</float3>
        <float name="shininess">0.05625</float>
        <float name="opacity">0.99</float>
    </material>

    <asset id="ciccio" >

        <!-- shared data -->
        <assetdata name="base">
            <data src="data/ciccio-mesh.xml#shared" />
            <data src="data/ciccio-anims.xml#animation" />
        </assetdata>

        <!-- meshes -->
        <assetmesh name="armor" material="#armorShader" includes="base" >
            <data src="data/ciccio-mesh.xml#index1" />
        </assetmesh>
        <assetmesh name="glass" material="#glassShader" includes="base" >
            <data src="data/ciccio-mesh.xml#index2" />
        </assetmesh>
    </asset>
</xml3d>

The material definitions should be familiar to us (although here we use a slightly more complicated Phong material with three textures). The interesting bit begins at the <asset> tag, which defines an object that can be referenced from inside our scene with a <model> tag through its id.

Inside the <asset> element we have an <assetdata> block, which functions much like a normal <data> element. You'll notice that instead of being given an id, these elements are given a name instead. Unlike an id, which must be unique per document, the name attribute is always relative to its parent <asset> element.

Finally we have two <assetmesh> elements which define the two meshes that make up this Asset. Again, each is given a name. Each mesh references its material through the material attribute. We also use the includes attribute to reference the <assetdata> element "base", which includes all the mesh data that is shared by both meshes. This is semantically equivalent to:

<assetmesh name="armor" material="#armorShader">
    <data src="data/ciccio-mesh.xml#shared" />
    <data src="data/ciccio-anims.xml#animation" />
    <data src="data/ciccio-mesh.xml#index1" />
</assetmesh>

Sharing data is more efficient and requires less resources, so it's a good idea to do it whenever possible.

Of course each <assetmesh> element can also have or reference it's own transformation through the transform attribute.

Note: <assetdata> and <assetmesh> elements may not be nested. <asset> elements, however, can be nested.

Instantiating an Asset with a Model tag

Now that the hard work is done, adding an instance of the Ciccio robot to a scene is quite easy:

<xml3d>
    <transform id="ciccio_transform" scale="0.5 0.5 0.5"></transform>

    <!-- Our viewpoint from where we see the 3D content -->
    <transform id="cameraTransform" translation="0 0 40"></transform>
    <view transform="#cameraTransform"></view>

    <!-- Some light source in our scene -->
    <light id="light1" model="urn:xml3d:light:directional">
        <float3 name="intensity">1 1 1</float3>
    </light>

    <model src="ciccio.xml#ciccio" transform="#ciccio_transform"></model>
</xml3d>

As you can see, we now have a single <model> tag referencing the <asset> element in ciccio.xml. XML3D handles all the rest for us.

Instantiating our asset

Overriding parts of an Asset

Lets liven our Ciccio up a bit with some brighter colors. To do this we're going to override material colors from inside our scene. Lets start by making the emissive parts of his armor (the light grey, glowing bits) a nice shade of blue to match his glass dome:

<model src="ciccio.xml#ciccio" transform="#ciccio_transform">
    <assetmesh name="armor">
        <float3 name="emissiveColor">0.1936 0.636474 0.8</float3>
    </assetmesh>
</model>

Coloring our asset

This is where our name attributes come in handy. By creating an <assetmesh> element inside our <model> we are telling XML3D that we'd like to selectively replace certain data for this particular mesh. In this case we're replacing the emissiveColor of the mesh's material, but we could also replace, for example, certain mesh data if we wanted to.

Any overrides we make are local to the mesh, so even if this material were shared with many different meshes only this one would appear blue. This ability to selectively override data is one of the main strengths of the Xflow data system that XML3D uses.

Just for fun lets also change the color of his glass dome to red:

<model src="ciccio.xml#ciccio" transform="#ciccio_transform">
    <assetmesh name="armor">
        <float3 name="emissiveColor">0.2 0.6 0.8</float3>
    </assetmesh>
    <assetmesh name="glass">
        <float3 name="diffuseColor">1.0 0.2 0.2</float3>
    </assetmesh>
</model>

Coloring our asset further

We learned earlier that <asset> elements may be nested. In this case, to override something inside one of the nested assets we would need to re-create the hierarchy of <asset> elements inside our <model> tag, complete with their id attributes, all the way down to the <assetdata> or <assetmesh> block that we want to override.

Note: Currently, adding or removing an override for any part of an <asset> will cause the entire asset to be re-created internally. However changing the value of an existing override (ie. changing the color inside one of the "diffuseColor" elements above) has no performance penalty. Bottom line: Assets were designed to be static in structure. If you need more flexibility it may be better to split your asset up into smaller pieces or to use the standard <mesh> and <data> system, which handles structure changes much more efficiently.

That's it for this time. Our final scene now looks like this:

 <xml3d>
    <transform id="ciccio_transform" scale="0.5 0.5 0.5"></transform>
		
    <!-- Our viewpoint from where we see the 3D content -->
    <transform id="cameraTransform" translation="0 0 40"></transform>
    <view transform="#cameraTransform"></view>

    <!-- Some light source in our scene -->
    <light id="light1" model="urn:xml3d:light:directional">
        <float3 name="intensity">1 1 1</float3>
    </light>
	
    <model src="ciccio.xml#ciccio" transform="#ciccio_transform">
        <assetmesh name="armor">
            <float3 name="emissiveColor">0.2 0.6 0.8</float3>
        </assetmesh>
        <assetmesh name="glass">
            <float3 name="diffuseColor">1.0 0.2 0.2</float3>
        </assetmesh>
    </model>
</xml3d>
Clone this wiki locally