-
Notifications
You must be signed in to change notification settings - Fork 25
Using Assets and Models
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.
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
One of the difficulties in using the HTML DOM to describe a 3D scene is the sheer number of DOM elements required for large models with many individual meshes. Not only does this impact the memory footprint of the tab, but it makes editing the HTML file a pain.
Even when storing the mesh data in an external file (as we did with our teapot in The Basics of XML3D) we still need to create a <mesh> element for each part of the object. For a simple teapot this is easy, a single <mesh> is all we need, but consider a more complex object. A car may consist of many hundreds of individual meshes each with their own material, but we'd like to be able to treat it as a single model in our scene.
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.
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" >
<shader id="glassShader" script="urn:xml3d:shader: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="transparency">0.154467</float>
</shader>
<shader id="armorShader" script="urn:xml3d:shader: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="transparency">0.01</float>
</shader>
<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" shader="#armorShader" includes="base" >
<data src="data/ciccio-mesh.xml#index1" />
</assetmesh>
<assetmesh name="glass" shader="#glassShader" includes="base" >
<data src="data/ciccio-mesh.xml#index2" />
</assetmesh>
</asset>
</xml3d>The shader definitions should be familiar to us (although here we use a slightly more complicated Phong shader 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 shader through the shader 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" shader="#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.
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 -->
<view position="0 0 40"></view>
<!-- Some light source in our scene -->
<lightshader id="light1" script="urn:xml3d:lightshader:directional">
<float3 name="intensity">1 1 1</float3>
</lightshader>
<light shader="#light1"></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.
Lets liven our Ciccio up a bit with some brighter colors. To do this we're going to overwrite 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>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>One last note, 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.
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 -->
<view position="0 0 40" ></view>
<!-- Some light source in our scene -->
<lightshader id="light1" script="urn:xml3d:lightshader:directional" >
<float3 name="intensity" >1 1 1</float3>
</lightshader>
<light shader="#light1" ></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>

