Skip to content

The Basics of XML3D

Christian Schlinkmann edited this page Mar 31, 2016 · 25 revisions

Introduction

This is a tutorial that leads you through the basics of XML3D. What we will cover:

  • 3D geometry
  • Viewports
  • Transform Hierarchy
  • Surface appearance
  • Light sources

Requirements of this tutorial:

  • Basic understanding of HTML, CSS and JavaScript

Using XML3D locally

XML3D, like all WebGL based frameworks, will not work properly when served from a filesystem! If you want to develop XML3D websites locally on your machine you should do it through a local HTTP server like Wamp, Apache or a simple Node.js web server.

First steps

XML3D is an extension to HTML. Just as you write HTML for text and images like so:

<p>
   This is some generic paragraph <span>with a twist</span>
   <img src="yayColors.png" alt="and an image" />
</p>

You can write XML3D for 3D content:

<p>Following this paragraphs we will break the second dimension!</p>
<xml3d>
   <mesh src="yayVertices.xml"></mesh>
</xml3d>
<p>... did you see it?</p>

About XML3D inside of HTML:

  1. All 3D content is declared inside an <xml3d> element, which defines the canvas through which the 3D scene is displayed.
  2. The <xml3d> element is displayed as an inline-block element like <canvas> and can be styled exactly the same way.

Displaying our first mesh

We have already established that all our 3D content is placed inside an <xml3d> element, so let's start with that:

<html>
<head>
  <script type="text/javascript" src="http://www.xml3d.org/xml3d/script/xml3d.js"></script>
  <title>My very first XML3D teapot</title>
</head>
<body>
    <xml3d>
      <!-- Incoming 3D! -->
    </xml3d>
</body>
</html>

To add some 3D geometry to our scene, we use the <mesh> element. Just as with <img>, the <mesh> element links an external file containing the 3D geometry data. Here is one of these files for the good ol' teapot: teapot.json

Including the mesh is now fairly simple:

<xml3d>
  <mesh src="resource/teapot.json"></mesh>
</xml3d>

An this is what we get:

step1

...That's not a teapot. There is just a red square on the upper half of the screen!

Here is where 3D gets a bit complicated: The teapot is there, it's just that its scale and position relative to your viewpoint are rather badly chosen.

Why is that?

  • the XML3D viewpoint by default is set at the origin of 3D space (x=y=z=0), looking at direction (0,0, -1), so in negative z direction.
  • most meshes tend to be places around the origin as well

So consequently: our viewpoint is right next to the surface to the mesh.

Let's change the viewpoint to get some distance to the object. XML3D provides the <view> element to define the viewpoint of the scene:

<xml3d>
  <view style="transform: translate3d(0, 0, 100px)"></view>
  <mesh src="resource/teapot.json"></mesh>
</xml3d>

Since our viewpoint looks into the direction (0,0,-1), we move along the z coordinate to get some distance, thus the new position (0,0,100).

Now we get this:

step2

Now we start to recognize our teapot, but it's still a bit high up, not quite inside the center. We could simply move the viewpoint up a bit again, however, thanks to relativity there is a second option: Let's move the mesh instead.

In order to move the mesh we can either add a transformation to it directly or put it inside a <group> element with a transformation. The group element can enclose multiple <mesh> and other <group> elements and transform all of it's content.

To declare the transformation we can simply use CSS 3D Transformations as we did above :

<xml3d>
  <view style="transform: translate3d(0, 0, 100px)"></view>
  <mesh src="resource/teapot.json" style="transform: translate3d(0px, -20px, 0px)"></mesh>
</xml3d>

Or alternatively, with a <group> element:

<xml3d>
  <view style="transform: translate3d(0, 0, 100px)"></view>
  <group style="transform: translate3d(0px, -20px, 0px)">
     <mesh src="resource/teapot.json"></mesh>
  </group>
</xml3d>

The declared transformation moves the teapot downwards, placing it nicely centered in the viewport:

step3

Shading the teapot

You might have noticed that our teapot is actually just a red silhouette. We should expect more from 3D graphics, so let's change the shading of our 3D object. XML3D provides the <material> element to define materials. However, as you will see, we define <material> not quite like other XML3D nodes. Here an example material:

<material id="orange" model="urn:xml3d:material:matte">
</material>

We specify a document id for our <material> (just as we do with other HTML elements) and a shading model which defines the behaviour or type of the material. "urn:xml3d:material:matte" is a predefined behavior that simply fills the element with the specified color.

But wait, how do we specify the color for our new "orange" matte material, anyway?

We don't use any more attributes to further configure our <material>. Instead, we place generic ValueElements such as <float3> inside of <material>:

<material id="orange" model="urn:xml3d:material:matte">
  <float3 name="diffuseColor" >1 0.5 0</float3>
</material>

We added a ValueElement of type float3 (reads: 3 floating point numbers) with name diffuseColor and values 1, 0.5, and 0. The <material> will evaluate the input provided by it's child ValueElements to shade as requested. Each float value is used as a color component of an RGB color. The names of these elements are important as they must match up with what the material shader requires as input.

The <material> element is a generic DataContainer, just like several other XML3D elements. This is a very powerful concept that allows all kinds of nifty data processing, but we'll save that for a later tutorial.

For now we have our new material! All that remains is connecting it with our <mesh>. We do this using the material attribute of the <group>:

<xml3d>
  <material id="orange" model="urn:xml3d:material:matte">
    <float3 name="diffuseColor" >1 0.5 0</float3>
  </material>

  <view style="transform: translate3d(0, 0, 100px)"></view>
  <group material="#orange" style="transform: translate3d(0px,-20px, 0px)" >
    <mesh src="resource/teapot.json"></mesh>
  </group>
</xml3d>

Note the # sign before orange: This is the syntax to refer an element of the same document via document id. Note that XML3D also allows us to refer materials from external files e.g. material="materials.xml#wood". And as with the transformation we could also reference the material directly from the <mesh> element instead.

Now we've finally got our newly shaded, orange teapot:

step4

But wait... that's just a different silhouette! We wanted to get some decent shading with a 3D feel to it.

For that we need a different kind of material model: a phong material.

<xml3d>
  <material id="orange" model="urn:xml3d:material:phong">
    <float3 name="diffuseColor" >1 0.5 0</float3>
  </material>

  <view style="transform: translate3d(0, 0, 100px)"></view>
  <group material="#orange" style="transform: translate3d(0px,-20px, 0px)" >
    <mesh src="resource/teapot.json"></mesh>
  </group>
</xml3d>

So now we get...

step5

...another silhouette! (Please bear with us)

We're still missing one crucial piece: The light source. Phong shading will only look interesting with a light source placed somewhere inside the scene. We can, in fact, configure our phong material to have some ambientIntensity, that will make the defined diffuseColor visible even without any light source:

  <material id="orangePhong" model="urn:xml3d:material:phong">
    <float3 name="diffuseColor" >1 0.5 0</float3>
    <float name="ambientIntensity" >0.5</float>
  </material>

However, this will just result in a differently colored silhouette:

step6

So there is no way around it, we have to add a light source. To add a light source we use the <light> element. Much like the <material> element uses material models, the <light> element uses light models. For now, let's only consider a directional light source:

<light id="light1" model="urn:xml3d:light:directional" >
  <float3 name="intensity" >1 1 1</float3>
</light>

The <light> is similar to <material> in that it also accepts a model (here referring to a urn) and is itself a generic DataContainer. For directional light sources we can specify an intensity value with a <float3> (each float is the intensity of a channel from an RGB color).

The final scene looks like this:

<xml3d>
  <material id="orangePhong" model="urn:xml3d:material:phong">
    <float3 name="diffuseColor" >1 0.5 0</float3>
    <float name="ambientIntensity" >0.5</float>
  </material>

  <light id="light1" model="urn:xml3d:light:directional">
    <float3 name="intensity" >1 1 1</float3>
  </light>

  <view style="transform: translate3d(0, 0, 100px)"></view>
  <group material="#orangePhong" style="transform: translate3d(0px,-20px,0px)" >
    <mesh src="resource/teapot.json"></mesh>
  </group>
</xml3d>

And finally we get our nicely shaded teapot:

step7

This almost concludes our tutorial about the basics of XML3D.

As a last step, how about adding the following script to your document:

<script src="http://www.xml3d.org/xml3d/script/tools/camera.js"></script>

This will allow you to rotate and scale the camera around the teapot by clicking and dragging with the left or right mouse button over the visible 3D scene. However, this camera controller doesn't support CSS transforms yet so we'll want to change our <view> element to use a <transform> element instead:

<transform id="cameraTransform" translation="0 0 100"></transform>
<view transform="#cameraTransform"></view>

Now you can inspect your nicely shaded teapot from all angles!

Here the final document (don't forget to place the teapot.json in the same folder):

<html>
<head>
  <script type="text/javascript" src="http://www.xml3d.org/xml3d/script/xml3d.js"></script>
  <script type="text/javascript" src="http://www.xml3d.org/xml3d/script/tools/camera.js"></script>
  <title>My very first XML3D teapot</title>
</head>
<body>
    <xml3d>
      <material id="orangePhong" model="urn:xml3d:material:phong">
        <float3 name="diffuseColor" >1 0.5 0</float3>
        <float name="ambientIntensity" >0.5</float>
      </material>

      <light id="light1" model="urn:xml3d:light:directional">
        <float3 name="intensity" >1 1 1</float3>
      </light>

      <transform id="cameraTransform" translation="0 0 100"></transform>
      <view transform="#cameraTransform"></view>

      <group material="#orangePhong" style="transform: translate3d(0px,-20px,0px)" >
        <mesh src="resource/teapot.json"></mesh>
      </group>
    </xml3d>
</body>
</html>
Clone this wiki locally