Click here to Skip to main content
15,881,804 members
Articles / Programming Languages / XML

Design interactive 3D Worlds with i3DML

Rate me:
Please Sign up or sign in to vote.
5.00/5 (20 votes)
24 Mar 2015CPOL7 min read 44.1K   815   18   16
This article introduces i3DML project and demonstrates how XML and JavaScript can help you build interactive 3D Worlds.

A simple Earth model - Created using i3DML

Introduction

In order to simplify the design process of 3D applications, I have developed a new XML-based markup language, just like HTML, specially developed for designing 3D scenes instead of 2D web pages. In this article, I'll introduce the i3DML Project and demonstrate how XML and JavaScript can help you to build interactive 3D Worlds with lesser coding!

The idea is creating a 3D scene by declaring the 3D objects beside their behaviours in a plain XML-based text file. This enables us to transfer a large amount of 3D primitives and meshes in smaller files and therefore it allows us to transfer them over a network. It also allows developers to build 3D Applications without any advanced technical knowledge about 3D Computer Graphics.

In this article, we'll review the basics and the execution process of an i3DML Application and then, we'll implement a simple i3DML Application using some of its basic features. Notice that you should have a little knowledge of basic Computer Graphics for reading this article.

*REQUIRMENTS FOR RUNNING THE BROWSER APPLICATION*

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

Using the code

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

i3DML relations

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

XML
<World xmlns="http://www.i3dml.org/i3DML2014">
	<World.Script>
		log("Hello World!");
	</World.Script>
	<!-- Elements -->
</World>

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

Like all XML documents, every i3DML document has a root element. The root element of every i3DML document is a Container Element. In i3DML, a Container Element is an element which will not be rendered on the screen and it'll be used just for containing (Like its name) other elements. <World> tag is the most abstract Container Element in i3DML, which is the root element of every i3DML Application and it contains all the elements that we want to use in our application. You can set the most general rendering options in the <World> tag and you should declare your application's general scripts and elements inside the <World> tag. As you can see in the above code, you should put your application scripts inside the <World.Script> tag. We'll use JavaScript Language for scripting our application.

In the next section, we'll implement a simple project with i3DML using the simplest elements that i3DML has provided to us.

Simulate the Solar System with i3DML!

Let's build a more advanced World with i3DML! Now we want to simulate the solar system in i3DML, this is a simple project that you can do with i3DML. We should define a number of Spheres as our planets in the <World> tag and simulate their rotations and their spinning over the sun with lines of codes in the <World.Script> tag. (Notice that we are not going to build an advanced solar system simulator and the distances among planets and their sizes may be not so accurate!)

Step 1 - A big space!

It's clear that we must draw our planets in a space with a large number of stars. But we can't create a unique Sphere for every single star in the space! We can use the Sky-map technique in these situations. In this method you virtually picture all of your visual elements on a textured spherical area! So the mountains, clouds, the sun, stars and the moon aren't really existed, they are just pictures. This technique provides you high level of details beside the good performance. So we should define a very big spherical-area in our World, which is textured with a spherical sky-map texture. In this case, a starred texture.

XML
<World xmlns="http://www.i3dml.org/i3DML2014">
	<World.Script>
		<!-- Planets Spinning -->
	</World.Script>
	
	<Sphere Density="50" Name="SkymapSphere"
	Size="100000" Lighting="false" TextureSource=".\Stars.png"/>
	
</World>

In the above code we defined a Sphere in our <World> tag as our space and also we set its TextureSource attribute to our sky-map texture's URL. Because the light sources shouldn't affect on the sphere which visualizes our space, we set its Lighting attribute to false. (Notice that this article doesn't cover the description of all the tags and attributes that can be used in i3DML. A complete list of different i3DML elements may be available in The page of the project on GitHub)

Picture of the code above result:

Step 1 Result - The Space

Step 2 - The Sun

Like the previous step you should define the sun sphere with its texture source 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 is not able to affect on it

XML
<World xmlns="http://www.i3dml.org/i3DML2014"
	 CameraPosition="0,0,-2000" CameraRotation="0,0,0">
	<World.Script>
		<!-- Planets Spinning -->
	</World.Script>
	
	<PointLight Position="0"/> <!-- We also defined a point light source in the center of our sun sphere. -->
	
	<Sphere Density="50" Name="SkymapSphere" IsArea="true"
	 Size="100000" Lighting="false" TextureSource=".\Stars.png"/>
	 
	<Sphere Position="0,0,0" Density="50" Name="SunSphere" Lighting="false"
	 Ambient="0.8" Size="1000" TextureSource=".\Sun.jpg"/>
	 
</World>

Step 2 Result -  The Sun

Done! The sun is ready and it'll shine on the planets that we'll add in the next sections!

Step 3 - Planets

The drawing of the planets is a little different, because some of the planets are the combinations of multiple meshes, such as Saturn and Uranus planets that have a ring around 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. Places are 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 position and rotation of each mesh depends to the position and rotation of your Place. In this case, you should put the sphere and ring of each planet in a separate Place.

Step 3 Result - Planets

XML
<World xmlns="http://www.i3dml.org/i3DML2014"
	CameraPosition="0,0,-2000" CameraRotation="0,0,0" >
	<World.Script>
		<!-- Planets Spinning -->
	</World.Script>
	
	<PointLight Position="0"/>
	
	<Sphere Density="50" Name="SkymapSphere" IsArea="true"  
	 Size="100000" Lighting="false" TextureSource=".\Stars.jpg"/>
	 
	<Sphere Position="0,0,0" Density="50" Name="SunSphere" Lighting="false"
	 Ambient="0.8"   Size="1800" TextureSource=".\Sun.jpg"/>
	 
	 <!-- Each place contains all of the meshes of its planet -->
	<Place Name="Mercury" Position="1200,0,0">
		<Sphere Density="50" Size="100"
		 TextureSource=".\Mercury.jpg"/>
	</Place>
	
	<Place Name="Venus" Position="1400,0,0">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Venus.jpg"/>
	</Place>
	
	<Place Name="Earth" Position="1600,0,0">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Earth.jpg"/>
	</Place>
	
	<Place Name="Mars" Position="1800,0,0">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Mars.jpg"/>
	</Place>
	
	<Place Name="Saturn" Position="2000,0,0">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Saturn.jpg"/>
	</Place>
	
	<Place Name="Jupiter" Position="2200,0,0">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Jupiter.jpg"/>
	</Place>
	
	<Place Name="Uranus" Position="2400,0,0">		 
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Uranus.jpg"/>
	</Place>
	
	<Place Name="Neptune" Position="2600,0,0">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Neptune.jpg"/>
	</Place>
	
</World>

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

As we have used Places to hold the meshes of our planets, we can simply add a ring mesh to the Place of our planet!

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

For the Saturn Planet:

XML
<Place Name="Saturn" Position="2200,0,0" Rotation="-20,45,0">
	 
		<Sphere Density="50" Size="100"  
		TextureSource=".\Saturn.jpg"/>
		<Torus TubeDensity="2" Density="50"  
		TextureSource=".\SaturnRing.jpg" Size="225,0,225,30"/>
	 
</Place>

And Uranus:

XML
<Place Name="Uranus" Position="2400,0,0" Rotation="-80,45,0">
	 
		<Sphere Density="50" Size="100"  
		 TextureSource=".\Uranus.jpg"/>
		<Torus TubeDensity="2" Density="50"  
		 TextureSource=".\UranusRing.jpg" Size="225,0,225,30"/>
	 
</Place>

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 implement the animations. In an i3DML Application, general scripts should be stored in the Script attribute of the World tag. While writing the scripts you should have an access to the elements inside your World tag. There is a function named getElementByName() embedded in the <Script> tag which returns the element which you want to be accessible by its name. You can set a name for an element by setting its Name attribute.

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

JavaScript
<World.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");
</World.Script>

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

JavaScript
<World.Script>
	// Getting the planets...
	var arr=[mercury,venus,earth,mars,saturn,jupiter,uranus,neptune];
	var rotarr=[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];
</World.Script>

The <World> tag has an event attribute named OnUpdate which holds 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 invoke it in the OnUpdate attribute. Just like this:

XML
<World xmlns="http://www.i3dml.org/i3DML2014">
 CameraPosition="0,0,-2000" CameraRotation="0,0,0" OnUpdate="Update();">

And in the code:

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

With a little math operations:

JavaScript
<World.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
		}
	}
</World.Script>

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

Step 5 Result - Planets movements

Final code:

XML
<World xmlns="http://www.i3dml.org/i3DML2014"
	CameraPosition="0,1000,-4000" CameraRotation="15,0,0" OnUpdate="Update();" >
	<World.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 arr=[mercury,venus,earth,mars,saturn,jupiter,uranus,neptune];
		var rotarr=[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];
		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
			}
		}
	</World.Script>
	
	<PointLight Position="0"/>
	
	<Sphere Density="50" Name="SkymapSphere" IsArea="true"  
	 Size="100000" Lighting="false" TextureSource=".\Stars.jpg"/>
	 
	<Sphere Position="0,0,0" Density="50" Name="SunSphere" Lighting="false"
	    Size="1800" TextureSource=".\Sun.jpg"/>
	 
	 <!-- Each place contains all of the meshes of its planet -->
	<Place Name="Mercury" Position="1200,0,0">
		<Sphere Density="50" Size="100"
		 TextureSource=".\Mercury.jpg"/>
	</Place>
	
	<Place Name="Venus" Position="1400,0,0">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Venus.jpg"/>
	</Place>
	
	<Place Name="Earth" Position="1600,0,0">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Earth.jpg"/>
	</Place>
	
	<Place Name="Mars" Position="1800,0,0">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Mars.jpg"/>
	</Place>
	
	<Place Name="Saturn" Position="2000,0,0" Rotation="-15,45,10">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Saturn.jpg"/>
			 <Torus TubeDensity="2" Density="50"
		 	TextureSource=".\SaturnRing.jpg" Size="225,0,225,30"/>
	</Place>
	
	<Place Name="Jupiter" Position="2200,0,0">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Jupiter.jpg"/>
	</Place>
	
	<Place Name="Uranus" Position="2400,0,0" Rotation="-85,-45,15">		 
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Uranus.jpg"/>
			 <Torus TubeDensity="2" Density="50"
		 	TextureSource=".\UranusRing.jpg" Size="225,0,225,30"/>
	</Place>
	
	<Place Name="Neptune" Position="2600,0,0">
			<Sphere Density="50" Size="100"  
			 TextureSource=".\Neptune.jpg"/>
	</Place>
	
</World>

Points of Interest

Designing in i3DML isn't limited to this article and you can implement much more stuff with i3DML!

Checkout the project on GitHub!

i3DML's official website

History

Project name has been changed to i3DML.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Iran (Islamic Republic of) Iran (Islamic Republic of)
I guess I'm an upper-intermediate programmer, having the experience of creating stuff in several fields including Web Applications, Distributed Computing, Computer Graphics and Machine Learning.

Comments and Discussions

 
GeneralFeedback Pin
Member 1260436626-Jun-16 2:35
professionalMember 1260436626-Jun-16 2:35 
AnswerNice Work Pin
Amir Mohammad Nasrollahi12-Aug-15 11:47
Amir Mohammad Nasrollahi12-Aug-15 11:47 
GeneralRe: Nice Work Pin
Keyvan M. Kambakhsh13-Aug-15 1:52
professionalKeyvan M. Kambakhsh13-Aug-15 1:52 
QuestionAwesome Dude, Simply Awesome! Pin
Your Display Name Here24-Mar-15 14:36
Your Display Name Here24-Mar-15 14:36 
AnswerRe: Awesome Dude, Simply Awesome! Pin
Keyvan M. Kambakhsh24-Mar-15 15:05
professionalKeyvan M. Kambakhsh24-Mar-15 15:05 
Thanks for your feedback my friend, it's my pleasure!
QuestionX3D Pin
Dave Bacher7-Aug-13 7:45
Dave Bacher7-Aug-13 7:45 
AnswerRe: X3D Pin
Keyvan M. Kambakhsh11-Aug-13 7:28
professionalKeyvan M. Kambakhsh11-Aug-13 7:28 
SuggestionNicely Done Pin
Meshack Musundi4-Aug-13 22:19
professionalMeshack Musundi4-Aug-13 22:19 
GeneralRe: Nicely Done Pin
Keyvan M. Kambakhsh4-Aug-13 23:44
professionalKeyvan M. Kambakhsh4-Aug-13 23:44 
GeneralRe: Nicely Done Pin
Meshack Musundi4-Aug-13 23:58
professionalMeshack Musundi4-Aug-13 23:58 
GeneralRe: Nicely Done Pin
Keyvan M. Kambakhsh5-Aug-13 0:06
professionalKeyvan M. Kambakhsh5-Aug-13 0:06 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun31-Jul-13 0:03
Humayun Kabir Mamun31-Jul-13 0:03 
GeneralMy vote of 5 Pin
Kerry Jackson30-Jul-13 15:00
Kerry Jackson30-Jul-13 15:00 
SuggestionMy vote of 5 Pin
Bassam Abdul-Baki30-Jul-13 6:57
professionalBassam Abdul-Baki30-Jul-13 6:57 
GeneralRe: My vote of 5 Pin
Keyvan M. Kambakhsh30-Jul-13 8:04
professionalKeyvan M. Kambakhsh30-Jul-13 8:04 
GeneralMy vote of 5 Pin
George H. Slaterpryce III30-Jul-13 6:06
George H. Slaterpryce III30-Jul-13 6:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.