Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Design interactive 3D Worlds with X3DML

0.00/5 (No votes)
30 Jul 2013 2  
This article introduces X3DML project and demonstrates how XML and JavaScript can help you build interactive 3D Worlds over the web.

A simple Earth model - Created using X3DML

Introduction

Recently I've done research about 3D web design and I felt that the XML technology maybe useful in this topic. So I've developed a new XML-based markup language, just like HTML, for designing 3D scenes instead of 2D web pages. In this article, I'll introduce X3DML Project and demonstrate how XML and JavaScript can help us to build interactive 3D Worlds!

The idea is creating a 3D scene by declaring the objects with their interactions to the user in a plain XML-based text file with less of coding. This enables us to transfer a large amount of primitives and meshes in smaller files and therefore it allows us to transfer it over the web. It also allows developers to build 3D applications without any technical knowledge about advanced 3D Computer Graphics. Before the beginning, I suggest you to have a look at X3DML Basic Concepts page and checkout the basics of the XML and JavaScript technologies.

In this article, we'll review the execution process of an X3DML application and after all, we'll implement a simple X3DML application with some of its basic features. Notice that you should have a little knowledge of basic Computer Graphics for reading this article.

*Requirements for running the browser application*

  • MS Windows 7+
  • .NET Framework 4.0+
  • Xna 4.0 Runtime Components

Using the code

Let's take a look at the execution process of an X3DML application. An X3DML application is a simple XML document which will be kept in a file with the format of .x3dml. The file can be hosted in a local storage or it can be over the web. The client requests the X3DML file to the server and downloads the hosted file (The hosted file can be created dynamically!). In the next step, X3DML Parser does the document parsing for us. After the parsing, X3DML Engine will run the application and apply the relations between application elements, codes and resources. It also interacts with Graphics Device and renders the generated primitives on the screen. You can see the execution process of an X3DML application in the following figure. (We used Direct3D as our graphics API for rendering primitives)

X3DML relations

X3DML Browser includes X3DML Parser and X3DML Engine together which creates a flexible environment for surfing in the X3DML files. As I said, X3DML is an XML-based language, which means you must design your World with a set of tags and attributes. There are several types of tags and attributes in X3DML. Following code block is the simplest X3DML application, you can run it through the X3DML Editor (It's attached in the package)

<?xml version="1.0"?>

<World xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Script>
        log("Hello World!");
    </Script>
    <Resources>
        <!-- Resources -->
    </Resources>
    <Childs>
        <!-- Elements -->
    </Childs>
</World>

The code above doesn't have any elements to draw, so you should see an empty black window and the "Hello World" text in the log window.

Like all XML files, every X3DML file will start with the XML declaration line. After the XML declaration, the root element of every X3DML file is a Container element. In X3DML, a Container element is an element which will not be rendered on the screen and it'll be used just for keeping other elements. <World> is the most abstract Container Element in X3DML, which is the root element of every X3DML application and it contains all the elements that we use in our app. You can define the most general rendering options in the <World> tag and you must declare your app scripts, resources, and elements in the <World> tag. As you see in the code above you should put your application scripts in the <Script> tag. We'll use JavaScript for scripting our application. You can also define your asynchronous scripts in <AsyncScript> tag which runs asynchronously with the rendering process. Before using multimedia resources (Like images, models and external Container Elements) in your X3DML application you should define their name and their location in <Resources> tag. And, at the last you should define you drawable application elements in <Childs> tag. <Childs> tag is a common tag that will be used inside the every Container Element.

In the next section, we'll implement a simple Solar System simulator with X3DML; but before beginning, take a look at the X3DML Editor Configuration page to see how to run an X3DML document through the X3DML Editor.

Simulate the Solar System with X3DML!

Let's build a more advanced World with X3DML! Imagine that we want to simulate the Solar System in X3DML, this is a simple project that you can do with X3DML. In general, we should define a number of spheres as our planets in the <Childs> tag and simulate their rotations and their spinning over the sun with lines of code in a <Script> tag. (Notice that we are not going to build an advanced solar system simulator and the planets distances and sizes may not so accurate!)

Step 1 - A big space!

It's obvious that we must draw our planets in a space with a large number of stars, the skymaps do this for us. We should define a very big spherical-area (in X3DML, an area is a mesh that the camera surfs in it) in our World, which is textured with a spherical stars skymap texture. This is a simple technique that you can use in X3DML for simulating your virtual space. So, first we'll add a spherical-area in our World and its skymap texture Resource.

<?xml version="1.0"?>

<World xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Script>
        <!-- Planets Spinnings -->
    </Script>
    <Resources>
        <Resource Name="Skymap" Type="Texture"
        Url="http://x3dml.org/Content/Images/Upload/Stars.png" />
    </Resources>
    <Childs>
        <Sphere Density="50" Name="SkymapSphere" 
           IsArea="true" IsTextured="true"
        Size="100000" Lighting="false" 
          TextureResourceName="Skymap"/>
    </Childs>
</World>

The information of every Resource will kept in a <Resource> tag. You should define your Resources type, location and a name to have access to them in your application with their names.

In the code above we defined a texture Resource which contains the skymap's texture data with the name of Skymap and used its name in the TextureResourceName attribute of our sphere element for texturing it. (Notice that this article doesn't cover the description of all the tags and attributes that can be used in X3DML. A complete list of tags is available in X3DML Markup Guide)

Picture of the code above result:

Step 1 Result - The Space

Step 2 - The Sun

Like the previous step you should define the sun texture resource and sphere in your World but the important thing is we want to use the sun as a light source, so like the previous code we should set the Lighting attribute to false so that our light source doesn't affect on it, and we should increase the ambient power of our Sun sphere to make it shiny! (Change the following code attributes to see the changes)

<?xml version="1.0"?>

<World xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     CameraPosition="0,0,-2000" CameraRotation="0,0,0">
    <Script>
        <!-- Planets Spinnings -->
    </Script>
    <Resources>
        <Resource Name="Skymap" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Stars.png"/>
         
        <Resource Name="Sun" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Sun.jpg"/>
    </Resources>
    <Lights>
        <Light Position="0" Power="1"/>
    </Lights>
    <Childs>
        <Sphere Density="50" Name="SkymapSphere" 
            IsArea="true" IsTextured="true"
            Size="100000" Lighting="false" 
            TextureResourceName="Skymap"/>
         
        <Sphere Position="0,0,0" Density="50" 
              Name="SunSphere" Lighting="false"
              Ambient="0.8" IsTextured="true" 
              Size="1000" TextureResourceName="Sun"/>
    </Childs>
</World>

Step 2 Result -  The Sun

Done! The sun is ready and it'll be shines on the planets that we'll add in the next section!

Step 3 - Planets

Drawing planets is a little different, because some planets are combinations of multiple meshes, such as the Saturn and Uranus planets that have a ring along the sphere, so if you change the position or rotation of one of these meshes you should apply the changes to other meshes according to the first change. The Place is the solution of this problem. As I said in previous section Places are container elements, so you can put your meshes together in a Place to create your desired model which the pose of each mesh depends to the pose of your Place. In the planets sample, you put each planet's sphere and ring in a separate Place.

Step 3 Result - Planets

<?xml version="1.0"?>

<World xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    CameraPosition="0,0,-2000" CameraRotation="0,0,0" >
    <Script>
        <!-- Planets Spinnings -->
    </Script>
    <Resources>
        <Resource Name="SkymapTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Stars.png"/>
         
        <Resource Name="SunTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Sun.jpg"/>
         
         
        <Resource Name="MercuryTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Mercury.jpg"/>
         
        <Resource Name="VenusTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Venus.jpg"/>
         
        <Resource Name="EarthTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Earth.jpg"/>
         
        <Resource Name="MarsTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Mars.jpg"/>
         
        <Resource Name="SaturnTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Saturn.jpg"/>
         
        <Resource Name="JupiterTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Jupiter.jpg"/>
         
        <Resource Name="UranusTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Uranus.jpg"/>
         
        <Resource Name="NeptuneTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Neptune.jpg"/>
         
        <Resource Name="PlutoTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Pluto.jpg"/>
    </Resources>
    <Lights>
        <Light Position="0" Power="1"/>
    </Lights>
    <Childs>
        <Sphere Density="50" Name="SkymapSphere" 
            IsArea="true" IsTextured="true"
            Size="100000" Lighting="false" 
            TextureResourceName="SkymapTexture"/>
         
        <Sphere Position="0,0,0" Density="50" 
             Name="SunSphere" Lighting="false"
             Ambient="0.8" IsTextured="true" Size="1800" 
             TextureResourceName="SunTexture"/>
         
        <!-- Each place contains all of the meshes of its planet -->
        <Place Name="Mercury" Position="1200,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="MercuryTexture"/>
            </Childs>
        </Place>
        
        <Place Name="Venus" Position="1400,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="VenusTexture"/>
            </Childs>
        </Place>
        
        <Place Name="Earth" Position="1600,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="EarthTexture"/>
            </Childs>
        </Place>
        
        <Place Name="Mars" Position="1800,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="MarsTexture"/>
            </Childs>
        </Place>
        
        <Place Name="Saturn" Position="2000,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="SaturnTexture"/>
            </Childs>
        </Place>
        
        <Place Name="Jupiter" Position="2200,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="JupiterTexture"/>
            </Childs>
        </Place>
        
        <Place Name="Uranus" Position="2400,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="UranusTexture"/>
            </Childs>
        </Place>
        
        <Place Name="Neptune" Position="2600,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="NeptuneTexture"/>
            </Childs>
        </Place>
        
        <Place Name="Pluto" Position="2800,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="PlutoTexture"/>
            </Childs>
        </Place>
    </Childs>
</World>

Step 4 - Build the Rings! (Saturn and Uranus)

As we used Places to keep our planets meshes, we can simply add a ring mesh to our planet Place and build the rings of Saturn and Uranus!

In X3DML you can build a ring by setting the TubeDensity of <Torus> tag to "2".

For the Saturn Planet:

<Place Name="Saturn" Position="2200,0,0" Rotation="-20,45,0">
    <Childs>
        <Sphere Density="50" Size="100" IsTextured="true"
        TextureResourceName="SaturnTexture"/>
        <Torus TubeDensity="2" Density="50" IsTextured="true"
        TextureResourceName="SaturnRingTexture" Size="225,0,225" TubeSize="30,0"/>
    </Childs>
</Place>

And Uranus:

<Place Name="Uranus" Position="2400,0,0" Rotation="-80,45,0">
    <Childs>
        <Sphere Density="50" Size="100" IsTextured="true"
         TextureResourceName="UranusTexture"/>
        <Torus TubeDensity="2" Density="50" IsTextured="true"
         TextureResourceName="UranusRingTexture" Size="225,0,225" TubeSize="30,0"/>
    </Childs>
</Place>

Don't forget to add the required resources!

Result:

Step 4 Result - Rings of Saturn and Uranus

Step 5 - Make it move!

Everything is ready! We just need to add some scripts to rotate the planets. In X3DML, the scripts will be placed in <Script> tag. While writing the scripts you should have an access to the elements in your World Childs tag. There is a function named getElementByName() embedded in both of the <Script> and <AsyncScript> tags which returns the element that you want to make changes on it by its name. As you see before, you can set name for elements that you want have access to them in the code.

So first we'll get our elements in the code:

<Script>
    var sun=getElementByName("SunSphere");
    var mercury=getElementByName("Mercury");
    var venus=getElementByName("Venus");
    var earth=getElementByName("Earth");
    var mars=getElementByName("Mars");
    var saturn=getElementByName("Saturn");
    var jupiter=getElementByName("Jupiter");
    var uranus=getElementByName("Uranus");
    var neptune=getElementByName("Neptune");
    var pluto=getElementByName("Pluto");
</Script>

Now we want to declare some arrays that provide the required information for each planet movement. We declare an array named arr that represents the planet elements and another array named rotarr that represents the Y-Axis rotation of the planet whole the sun and an array named rotspeedarr that keeps the spinning speed of each planet.

<Script>
    // Getting the planets...
    var arr=[mercury,venus,earth,mars,saturn,jupiter,uranus,neptune,pluto];
    var rotarr=[0,0,0,0,0,0,0,0,0];
    var rotspeedarr=[1.1,2.3,3.2,1.3,1.7,2.1,3.2,-0.9,1.5];
</Script>

The <World> tag has an event attribute named OnUpdate which keeps a javascript statement and executes it in every frame update. We should do the rotation changes in the frame updates, so we could declare a function named Update that does the spinning effects and call it in the OnUpdate attribute. Just like this:

<World xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 CameraPosition="0,0,-2000" CameraRotation="0,0,0" OnUpdate="Update()">

And in the code:

<Script>
    // Initializations
    function Update()
    {
        // This function will be called in every frame update.
    }
</Script>

With a little math operations:

<Script>
    // Initializations
    function Update()
    {
        sun.Rotation.Y+=0.05; // Rotate the sun
        for(var i=0;i<arr.length;i++)
        {
            rotarr[i]+=rotspeedarr[i]/400; // Change the planet rotation over the sun
            arr[i].Rotation.Y+=0.1; // Rotate the planet
            var rad=Math.sqrt(Math.pow(arr[i].Position.X,2)
                +Math.pow(arr[i].Position.Z,2)); // Calculating radius (Distance from sun)
            arr[i].Position.X=Math.cos(rotarr[i])*rad; // Rotating over the sun
            arr[i].Position.Z=Math.sin(rotarr[i])*rad; // Rotating over the sun
        }
    }
</Script>

Congratulations! You have implemented a simple Solar System simulator with X3DML!

Step 5 Result - Planets movements

Final code:

<?xml version="1.0"?>

<World xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 CameraPosition="0,0,-2000" CameraRotation="0,0,0" OnUpdate="Update()">
    <Script>
        var sun=getElementByName("SunSphere");
        var mercury=getElementByName("Mercury");
        var venus=getElementByName("Venus");
        var earth=getElementByName("Earth");
        var mars=getElementByName("Mars");
        var saturn=getElementByName("Saturn");
        var jupiter=getElementByName("Jupiter");
        var uranus=getElementByName("Uranus");
        var neptune=getElementByName("Neptune");
        var pluto=getElementByName("Pluto");
        var arr=[mercury,venus,earth,mars,saturn,jupiter,uranus,neptune,pluto];
        var rotarr=[0,0,0,0,0,0,0,0,0];
        var rotspeedarr=[1.1,2.3,3.2,1.3,1.7,2.1,3.2,-0.9,1.5];
        function Update()
        {
            sun.Rotation.Y+=0.05; // Rotate the sun
            for(var i=0;i<arr.length;i++)
            {
                rotarr[i]+=rotspeedarr[i]/400; // Change the rotation over the sun
                arr[i].Rotation.Y+=0.1; // Rotate the planet
                var rad=Math.sqrt(Math.pow(arr[i].Position.X,2)
                    +Math.pow(arr[i].Position.Z,2)); // Calculating radius
                arr[i].Position.X=Math.cos(rotarr[i])*rad; // Rotating over the sun
                arr[i].Position.Z=Math.sin(rotarr[i])*rad; // Rotating over the sun
            }
        }
    </Script>
    <Resources>
        <Resource Name="SkymapTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Stars.png"/>
        <Resource Name="SunTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Sun.jpg"/>
        <Resource Name="MercuryTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Mercury.jpg"/>
        <Resource Name="VenusTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Venus.jpg"/>
        <Resource Name="EarthTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Earth.jpg"/>
        <Resource Name="MarsTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Mars.jpg"/>
        <Resource Name="SaturnTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Saturn.jpg"/>
        <Resource Name="SaturnRingTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/SaturnRing.jpg"/>
        <Resource Name="JupiterTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Jupiter.jpg"/>
        <Resource Name="UranusTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Uranus.jpg"/>
        <Resource Name="UranusRingTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/UranusRing.jpg"/>
        <Resource Name="NeptuneTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Neptune.jpg"/>
        <Resource Name="PlutoTexture" Type="Texture"
         Url="http://x3dml.org/Content/Images/Upload/Planets/Pluto.jpg"/>
    </Resources>
    <Lights>
        <Light Position="0" Power="1"/>
    </Lights>
    <Childs>
        <Sphere Density="50" Name="SkymapSphere" 
            IsArea="true" IsTextured="true"
            Size="100000" Lighting="false" 
            TextureResourceName="SkymapTexture"/>
        <Sphere Position="0,0,0" Density="50" 
           Name="SunSphere" Lighting="false"
           Ambient="0.8" IsTextured="true" Size="1800" 
           TextureResourceName="SunTexture"/>
        <Place Name="Mercury" Position="1200,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="MercuryTexture"/>
            </Childs>
        </Place>
        <Place Name="Venus" Position="1400,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="VenusTexture"/>
            </Childs>
        </Place>
        <Place Name="Earth" Position="1600,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="EarthTexture"/>
            </Childs>
        </Place>
        <Place Name="Mars" Position="1800,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="MarsTexture"/>
            </Childs>
        </Place>
        <Place Name="Saturn" Position="2000,0,0" Rotation="-20,45,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="SaturnTexture"/>
                <Torus TubeDensity="2" Density="50" IsTextured="true"
                 TextureResourceName="SaturnRingTexture" 
                 Size="225,0,225" TubeSize="30,0"/>
            </Childs>
        </Place>
        <Place Name="Jupiter" Position="2200,0,0" Rotation="0,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="JupiterTexture"/>
            </Childs>
        </Place>
        <Place Name="Uranus" Position="2400,0,0" Rotation="-80,45,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="UranusTexture"/>
                <Torus TubeDensity="2" Density="50" IsTextured="true"
                 TextureResourceName="UranusRingTexture" 
                 Size="225,0,225" TubeSize="30,0"/>
            </Childs>
        </Place>
        <Place Name="Neptune" Position="2600,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="NeptuneTexture"/>
            </Childs>
        </Place>
        <Place Name="Pluto" Position="2800,0,0">
            <Childs>
                <Sphere Density="50" Size="100" IsTextured="true"
                 TextureResourceName="PlutoTexture"/>
            </Childs>
        </Place>
    </Childs>
</World>

Points of Interest

Designing in X3DML isn't limited to this article and you could do amazing stuff with X3DML! See more screenshots of different X3DML applications.

History

No changes have been made so far.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here