Babylon.js: Using multi-materials

In the previous article, we talked about lights and how they influence the aspect of an object. Today we will talk about a more complex concept: the multi-materials.

We saw in another article that objects use materials in order to define (in conjunction with lights) how they look like.

A multi-material is used to apply different materials to different parts of the same object as you can see in this screen capture (from www.babylonjs.com):

To be able to define a multi-materials you first have to define some standard materials:

    var material0 = new BABYLON.StandardMaterial("mat0", scene);
    material0.diffuseColor = new BABYLON.Color3(1, 0, 0);
    material0.bumpTexture = new BABYLON.Texture("normalMap.jpg", scene);
var material1 = new BABYLON.StandardMaterial("mat1", scene); material1.diffuseColor = new BABYLON.Color3(0, 0, 1);
var material2 = new BABYLON.StandardMaterial("mat2", scene); material2.emissiveColor = new BABYLON.Color3(0.4, 0, 0.4);

Then you can create a multi-material in order to gather them all:

var multimat = new BABYLON.MultiMaterial("multi", scene);
multimat.subMaterials.push(material0);
multimat.subMaterials.push(material1);
multimat.subMaterials.push(material2);

You are now able to affect the multi-material to your mesh:

var sphere = BABYLON.Mesh.CreateSphere("Sphere0", 16, 3, scene);
sphere.material = multimat;

But if you do that, you will see that the sphere will only use the first submaterial (the red bumped one). This is because by default a mesh is is designed to use only one material.

You can specify which part of the mesh uses a specific material by using the subMeshes property. By default, every mesh comes with only one submesh that cover the entire mesh.

To define multiple submeshes, you just have to use this code:

sphere.subMeshes = [];
var verticesCount = sphere.getTotalVertices();

sphere.subMeshes.push(new BABYLON.SubMesh(0, 0, verticesCount, 0, 900, sphere));
sphere.subMeshes.push(new BABYLON.SubMesh(1, 0, verticesCount, 900, 900, sphere));
sphere.subMeshes.push(new BABYLON.SubMesh(2, 0, verticesCount, 1800, 2088, sphere));

In this case, we will have 3 parts:

  • One starting from index 0 to index 900
  • One starting from index 900 to index 1800
  • One starting from index 1800 to index 3880

A submesh is defined with:

  • The index of the material to use (this index is used to find the correct material Inside the subMaterials collection of a multi-material)
  • The index of the first vertex and the count of vertices used (To optimize things for collisions for instance)
  • Index of the first indice to use and indices count
  • The parent mesh

So with the code below, we can use the first material on the top part of the sphere, the second material on the middle part and the last material on the bottom part of the sphere.

What’s next ?

If you want to go more deeply into babylon.js, here are some useful links:

Babylon.js: Using lights in your babylon.js game

In the previous article, we discovered how to use materials to define the aspect of your meshes. Now we are ready to talk about lights.

Lights are used to produce the diffuse and specular color received by each pixel. This color is then used by materials to determine the final color of every pixel.

Babylon.js allows you to create and register as many lights as you want but beware because the StandardMaterial can handle only 4 simultaneous lights (the first four enabled lights of the lights list)

During this article, I will show you how to use every kind of lights supported by babylon.js.

Activating/Deactivating lights

Every light can be deactivated by setting its isEnabled property to false.

But you can also control the global intensity of the light with the intensity property.

The point light

A point light is a light defined by an unique point. The light is emitted in every direction from this point.

You can control the color of the light with the diffuse and specular properties:

var light0 = new BABYLON.PointLight("Omni0", new BABYLON.Vector3(1, 10, 1), scene);
light0.diffuse = new BABYLON.Color3(1, 0, 0);
light0.specular = new BABYLON.Color3(1, 1, 1);


Red diffuse point light with white specular

The directional light

A directional light is defined by a direction (what a surprise!). The light is emitted from everywhere to a specific direction and has an infinite range.

Like a point light, you can control the color of the light with the diffuse and specular properties:

var light0 = new BABYLON.DirectionalLight("Dir0", new BABYLON.Vector3(0, -1, 0), scene);
light0.diffuse = new BABYLON.Color3(1, 0, 0);
light0.specular = new BABYLON.Color3(1, 1, 1);


Red diffuse directional light with white specular

The spot light

A spot light is defined by a position, a direction, an angle and an exponent. These values define a cone of light starting from the position toward the direction. The angle defines the size of the spotlight beam and the exponent defines the speed of the decay of the light with distance:

var light0 = new BABYLON.SpotLight("Spot0", new BABYLON.Vector3(0, 30, -10), new BABYLON.Vector3(0, -1, 0), 0.8, 2, scene);
light0.diffuse = new BABYLON.Color3(1, 0, 0);
light0.specular = new BABYLON.Color3(1, 1, 1);




A red diffuse spotlight with white specular and a 0.8 radians wide cone. The exponent value is 2.

The hemispheric light

Hemispheric light represents a simple and easy way to simulate realistic ambient light. An hemispheric light is defined by a direction to the sky and by 3 colors: one for the diffuse (the sky color), one for the ground (the color when the pixel is not towards the sky) and one for the specular.

var light0 = new BABYLON.HemisphericLight("Hemi0", new BABYLON.Vector3(0, 1, 0), scene);
light0.diffuse = new BABYLON.Color3(1, 1, 1);
light0.specular = new BABYLON.Color3(1, 1, 1);
light0.groundColor = new BABYLON.Color3(0, 0, 0);


White/black hemispheric light

What’s next ?

If you want to go more deeply into babylon.js, here are some useful links:

Babylon.js: Unleash the StandardMaterial for your babylon.js game

After discovering how to load a scene in the previous chapter, I would like to share with you some informations about the StandardMaterial object of Babylon.js.

You want to discuss about this article: reach me on Twitter: @deltakosh

The StandardMaterial object is in charge of defining how an object is rendered and how it looks like.

Let’s start with a small html page:

<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
    <title>Using babylon.js - How to load a scene</title>
    <script src="hand.js"></script>
    <script src="babylon.js"></script>
    <style>
        html, body {
            width: 100%;
            height: 100%;
            padding: ;
            margin: ;
            overflow: hidden;
        }

        #renderCanvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <canvas id="renderCanvas"></canvas>
</body>
</html>

You can then add a small script to create a Babylon.js scene:

<script>
    if (BABYLON.Engine.isSupported()) {
        var canvas = document.getElementById("renderCanvas");
        var engine = new BABYLON.Engine(canvas, true);
        var scene = new BABYLON.Scene(engine);
        var sphere = BABYLON.Mesh.CreateSphere("sphere", 16, 1, scene);
        var light = new BABYLON.PointLight("light01", new BABYLON.Vector3(0, 3, -2), scene);
        var camera = new BABYLON.FreeCamera("camera01", new BABYLON.Vector3(0, 3, -2), scene);

        camera.setTarget(new BABYLON.Vector3(0, 0, 0));
        camera.attachControl(canvas);

        // Render
        engine.runRenderLoop(function() {
            scene.render();
        });
    }
</script>

This simple script creates a scene composed of a light, a camera and a sphere:

To be able to configure the aspect of our sphere, we need a material:

// Material
var material = new BABYLON.StandardMaterial("material01", scene);

sphere.material = material;

You can notice that you will have the same result with or without a material because an object without a material is rendered using a default material.

Adding some colors

The StandardMaterial supports a lot of colors combination. We will see here how things works.

Diffuse color

The diffuse color defines the basic color of an object. This color depends of the lights which means that if there is no light, there is no diffuse color or in another way, the final color is equal to the diffuse color multiplied by the light intensity for every pixel.

The final color depends on the diffuse color of the light and the diffuse color of the material (material.diffuseColor and light.diffuseColor):

material.diffuseColor = new BABYLON.Color3(1, 0, 0);


Diffuse color

Specular color

The specular color is the color of the highlight produced by a light on a surface (this is the white spot on the previous picture). It depends on the specular color of the light and the specular color of the material (material.specularColor and light.specularColor). The size of the highlight dépends on material.specularPower.

Here is an example with specular only (no diffuse):

material.diffuseColor = new BABYLON.Color3(0, 0, 0); // No diffuse color

material.specularColor = new BABYLON.Color3(1, 0, 0);
material.specularPower = 32;


Specular color


Ambient color


The ambient color is the color of the object relatively to the ambient color of the scene. The ambient color of a scene is a color available everywhere (no occlusion, no direction, no position).


To use it, just use the following code:

material.diffuseColor = new BABYLON.Color3(0, 0, 0); // No diffuse color

material.specularColor = new BABYLON.Color3(0, 0, 0); // No specular color


scene.ambientColor = new BABYLON.Color3(1, 1, 1);
material.ambientColor = new BABYLON.Color3(1, 0, 0);


Ambient color

Emissive color

Finally the emissive color is the inner color of the object (the color of the object without any light source):

material.diffuseColor = new BABYLON.Color3(0, 0, 0); // No diffuse color

material.specularColor = new BABYLON.Color3(0, 0, 0); // No specular color
material.specularPower = 32;

scene.ambientColor = new BABYLON.Color3(1, 1, 1);
material.ambientColor = new BABYLON.Color3(0, 0, 0); // No ambient color

material.emissiveColor = new BABYLON.Color3(0, 1, 0);


Emissive color

All together

So when you bring all these colors together, the result is the following:

material.diffuseColor = new BABYLON.Color3(0, 1, 0);

material.specularColor = new BABYLON.Color3(1, 1, 1);
material.specularPower = 32;

scene.ambientColor = new BABYLON.Color3(1, 1, 1);
material.ambientColor = new BABYLON.Color3(0, 0, 1);  

material.emissiveColor = new BABYLON.Color3(1, 0, 0);

Using textures

The StandardMaterial object can also use textures instead of solid colors.

Diffuse texture

To define the diffuse color using a texture, you just have to use the following code:

// Material
var material = new BABYLON.StandardMaterial("material01", scene);

sphere.material = material;

material.diffuseTexture = new BABYLON.Texture("Tree.png", scene);

The “Tree.png” texture is the following (please this is a picture with an alpha channel);

And the resulting render is the following:


Diffuse texture

You can configure the Texture object to take into account the alpha channel to activate alpha testing (discarding of pixels with alpha < 0.5):

material.diffuseTexture = new BABYLON.Texture("Tree.png", scene);
material.diffuseTexture.hasAlpha = true;


Diffuse texture with alpha testing

Specular texture

In a same way, you can also define a specular texture to control how the highlight looks like:

material.diffuseColor = new BABYLON.Color3(1, 1, 1);
material.specularPower = 32;
material.specularTexture = new BABYLON.Texture("Tree.png", scene);


Specular texture

Ambient texture

The main goal of the ambient texture is to provide a support for lightmaps (textures that contains baked shadows). Mainly the value of the ambient texture is multiplied by the diffuse value to produce the final result:

material.diffuseColor = new BABYLON.Color3(1, 0, 0);
material.ambientTexture = new BABYLON.Texture("Tree.png", scene);


Ambient texture with red diffuse

Emissive texture

The emissive texture can define the color of the object without any light:

material.emissiveTexture = new BABYLON.Texture("Tree.png", scene);


Emissive texture with diffuse color

Reflection texture

The StandardMaterial object supports 4 kinds of reflection:

  • Spherical
  • Cubic
  • Planar
  • Projection

To use a reflection texture, you can use a standard Texture or a CubeTexture:

var material = new BABYLON.StandardMaterial("material01", scene);
material.emissiveColor = new BABYLON.Color3(0.2, 0.2, 0.2);
material.reflectionTexture = new BABYLON.Texture("Tree.png", scene);
material.reflectionTexture.coordinatesMode = BABYLON.Texture.SPHERICAL_MODE;
sphere0.material = material;

material = new BABYLON.StandardMaterial("material02", scene);
material.emissiveColor = new BABYLON.Color3(0.2, 0.2, 0.2);
material.reflectionTexture = new BABYLON.Texture("Tree.png", scene);
material.reflectionTexture.coordinatesMode = BABYLON.Texture.CUBIC_MODE;
sphere1.material = material;

material = new BABYLON.StandardMaterial("material03", scene);
material.emissiveColor = new BABYLON.Color3(0.2, 0.2, 0.2);
material.reflectionTexture = new BABYLON.Texture("Tree.png", scene);
material.reflectionTexture.coordinatesMode = BABYLON.Texture.PLANAR_MODE;
sphere2.material = material;

material = new BABYLON.StandardMaterial("material04", scene);
material.emissiveColor = new BABYLON.Color3(0.2, 0.2, 0.2);
material.reflectionTexture = new BABYLON.Texture("Tree.png", scene);
material.reflectionTexture.coordinatesMode = BABYLON.Texture.PROJECTION_MODE;
sphere3.material = material;

material = new BABYLON.StandardMaterial("material05", scene);
material.emissiveColor = new BABYLON.Color3(0.2, 0.2, 0.2);
material.reflectionTexture = new BABYLON.CubeTexture("refcube3", scene);
sphere4.material = material;

The CubeTexture must be fed with 6 files representing each size of the cube (with a specific naming):



For IE11 preview users, you can click on this picture, to open a new tab with the demo:


All kind of reflection textures


Bump texture


The bump texture simulates bumps and dents using a map called a normal map.


A normal map

var material = new BABYLON.StandardMaterial("kosh", scene);
material.bumpTexture = new BABYLON.Texture("normalMap.jpg", scene);


The bump texture pertubates the normal to produce a result like this:


Bumped object


Opacity texture


The opacity texture allows the object to define his transparency (alpha blending) on a per-pixel basis:

// Material
var material = new BABYLON.StandardMaterial("material01", scene);
material.emissiveColor = new BABYLON.Color3(1, 0, 0);
material.opacityTexture = new BABYLON.Texture("Degrade.png", scene);
sphere0.material = material;


Alpha blended object


Other properties


The StandardMaterial also supports the following properties to control its behavior:



  • backFaceCulling: Enable or disable back faces removal (mostly used with alpha testing or blending)


  • alpha: The global alpha of the object


  • wireframe: display the object as a wireframe


 


Wireframe object


What’s next ?


If you want to go more deeply into babylon.js, here are some useful links:

Babylon.js: How to load a .babylon file produced with Blender

In a previous post, I described Babylon.js, a brand new 3D engine for WebGL and JavaScript. Among others features, Babylon.js is capable of loading a JSON file through the .babylon file format.

During this post, I will show you how to use Babylon.js API to load a scene created with Blender.

One important thing to remember with Blender is to use the Blender Render if you want to export your scene to Babylon.js

Creating a scene and exporting a .babylon file with Blender

In my previous post, I already described how to install the .babylon exporter in Blender, but for the sake of comprehension, I copy/paste the process here:

First of all, please download the exporter script right here: https://github.com/BabylonJS/Babylon.js/tree/master/Exporters/Blender

To install it in Blender, please follow this small guide:

  • Unzip the file to your Blender’s plugins folder (Should be C:Program FilesBlender FoundationBlender2.67scriptsaddons for Blender 2.67 x64).
  • Launch Blender and go to File/User Préférences/Addon and select Import-Export category. You will be able to activate Babylon.js exporter.

  • Create your scene
  • Go to File/Export and select Babylon.js format. Choose a filename and you are done !

Once the exporter is installed, you can unleash your artist side and create the most beautiful scene your imagination can produce. In my case, it will be fairly simple:

  • A camera
  • A point light
  • A plane for the ground
  • A sphere

Just to be something a bit less austere, I will add some colors for the ground and the sphere:

I will also add a texture for the sphere. This texture will be used for the diffuse channel of the material:

Please pay attention to:

  • Use Alpha checkbox to indicate to Babylon.js to use alpha values from the texture
  • Color checkbox to indicate that this texture must be use for diffuse color

Once you are satisfied (You can obviously create a more complex scene), just go to File/Export/Babylon.js to create your .babylon file.

Using the Babylon.js Sandbox

There is a great and easy way to test your scene: the Babylon.js Sandbox. With a single drag’n’drop into a web page, you will be able to test your scene without any more setup:

https://blogs.msdn.com/b/davrous/archive/2013/12/17/designers-test-amp-create-your-webgl-3d-worlds-inside-the-babylon-js-sandbox-amp-editor.aspx

Loading your .babylon inside your page/app

First of all, you should create a simple html web page:

<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
    <title>Using babylon.js - How to load a scene</title>
    <script src="babylon.js"></script>
    <style>
        html, body {
            width: 100%;
            height: 100%;
            padding: ;
            margin: ;
            overflow: hidden;
        }

        #renderCanvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <canvas id="renderCanvas"></canvas>
 </body>
</html>

This page is pretty simple because all you need is just a canvas and a reference to babylon.js.

Then you will have to use BABYLON.SceneLoader object to load your scene. To do so, just add this script block right after the canvas:

<script>
    if (BABYLON.Engine.isSupported()) {
        var canvas = document.getElementById("renderCanvas");
        var engine = new BABYLON.Engine(canvas, true);

        BABYLON.SceneLoader.Load("", "scene.babylon", engine, function (newScene) {
            // Wait for textures and shaders to be ready
            newScene.executeWhenReady(function () {
                // Attach camera to canvas inputs
                newScene.activeCamera.attachControl(canvas);

                // Once the scene is loaded, just register a render loop to render it
                engine.runRenderLoop(function() {
                    newScene.render();
                });
            });
        }, function (progress) {
            // To do: give progress feedback to user
        });
    }
</script>

the Load function takes the following parameters:

  • scene folder (can be empty to use the same folder as your page)
  • scene file name
  • a reference to the engine
  • a callback to give you the loaded scene (in my case, I use this callback to attach the camera to the canvas and to launch my render loop)
  • a callback for progress report

Once the scene is loaded, just wait for the textures and shaders to be ready, connect the camera to the canvas and let’s go!

Fairly simple, isn’t it?

Please note that the textures and the .babylon file must be side by side

Another function is also available to interact with .babylon files: BABYLON.SceneLoader.importMesh:

BABYLON.SceneLoader.ImportMesh("spaceship", "Scenes/SpaceDek/", "SpaceDek.babylon", scene, function (newMeshes, particleSystems) {
});

This function is intended to import meshes (with their materials and particle systems) from a scene to another. It takes the following parameters:

  • object name (if you omit this parameter, all the objects are imported)
  • scene folder (can be empty to use the same folder as your page)
  • scene file name
  • a reference to the target scene
  • a callback to give you the list of imported meshes and particle systems

Adding MIME types to your web server

You will need to authorize .babylon MIME type on your web server (and furthermore you will also need to authorize .babylonmeshdata MIME type if you want to use incremental loading)

For IIS, you will need to update your web.config with this section:

Babylon.js: a complete JavaScript framework for building 3D games with HTML 5 and WebGL


/ Updated on 4/10/14 to reflect API changes /


I am a real fan of 3D development. Since I was 16, I spent all my spare time creating 3d engines with various technologies (DirectX, OpenGL, Silverlight 5, pure software, etc.).

My happiness was complete when I discovered that Internet Explorer 11 has native support for WebGL. So I decided to write once again a new 3D engine but this time using WebGL and my beloved JavaScript.

If you are a 3D beginner, I suggest you to read this excellent series of blogs written by my friend David Rousset: https://blogs.msdn.com/b/davrous/archive/2013/06/13/tutorial-series-learning-how-to-write-a-3d-soft-engine-from-scratch-in-c-typescript-or-javascript.aspx

Thus babylon.js was born and you can find some samples right here: https://www.babylonjs.com.

You can also find all the sources on Babylon.js Github repository: https://github.com/BabylonJS/Babylon.js


espilitflat2009wcafeHeartTheCarviper



All the scenes were created by one of the most talented 3D artist I know: Michel Rousseau who by the magic of the life is also my colleague at Microsoft and has a really cool blog for designers: https://blogs.msdn.com/b/designmichel/

The engine is currently at early stage but I plan to add a lot of cool new features quickly.

The current version supports the following features (I always loved this kind of very long and very technical list):

  • Complete scene graph with lights, cameras, materials, sprites, layers and meshes
  • Complete collisions/responses system
  • Highly configurable material with support with
    • Diffuse
    • Specular
    • Emissive
    • Opacity / Alpha
    • Reflection
    • Ambient
    • Bump
    • Up to 4 simultaneous lights
  • Four kind of lights:
    • Point
    • Directional
    • Spot
    • Hemispheric
  • Three kind of cameras:
    • Free camera (FPS like)
    • Touch compatible camera
    • Arc rotate camera
  • Textures:
    • 2D
    • Render target
    • Mirrors
    • Dynamic
    • Video Textures
  • Alpha blending
  • Alpha testing
  • Billboarding / sprites
  • Scene picking
  • Frustum clipping
  • Sub-meshes clipping
  • Antialiasing
  • Particles system
  • Animations engine
  • Fog
  • Babylon file format is a JSON file that can be produced from:
    • .OBJ
    • .FBX
    • .MXB
    • Blender

 

Obviously I will not cover ALL the features during this article. Indeed this one is just the first one of a long series that will focused on every feature of babylon.js.

You want to discuss about this article: reach me on Twitter: @deltakosh

Agenda

  1. Getting started with babylon.js
  2. Materials
  3. Lights, cameras and meshes
  4. Collisions
  5. Particle Systems
  6. Spites and layers
  7. Animations
  8. Advanced textures
  9. Importing scene from 3D assets
    1. And much more to come…
    2. Next chapters

Getting started with babylon.js

The only thing you really need to unleash the power of babylon.js is a small js file (less than 200 KB uncompressed). You can find the latest version at the root of the Github repo: https://github.com/BabylonJS/Babylon.js

You will also need to include hand.js to your page if you want to seamlessly support touch events: https://handjs.codeplex.com

Once you grabbed this file, you just have to import it in your HTML file and create a canvas (this is where babylon.js will render the scenes)

<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
    <title>Using babylon.js - Test page</title>
    <script src="babylon.js"></script>
    <style>
        html, body {
            width: 100%;
            height: 100%;
            padding: ;
            margin: ;
            overflow: hidden;
        }
        #renderCanvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <canvas id="renderCanvas"></canvas>
</body>
</html>

Babylon.js is built around a main object: the engine. This object will let you create a scene where you will be able to add meshes (the 3D objects), lights, cameras and materials:

<script>
    var canvas = document.getElementById("renderCanvas");
    var engine = new BABYLON.Engine(canvas, true);
</script>

You may want to test if WebGL is supported on the current browser by using the following code:

<script>
    if (BABYLON.Engine.isSupported()) {
        var canvas = document.getElementById("renderCanvas");
        var engine = new BABYLON.Engine(canvas, true);
    }
</script>

The engine is the hub between babylon.js and WebGL. It is in charge of sending orders to WebGL and creating internal WebGL related objects.

Once the engine is created, you are able to create the scene:

var scene = new BABYLON.Scene(engine);

The scene can be seen as a container for all entities that works together to create a 3D image. With the scene you can create a light, a camera and a mesh (in this case a sphere):

var camera = new BABYLON.FreeCamera("Camera", new BABYLON.Vector3(0, 0, -10), scene);
var light0 = new BABYLON.PointLight("Omni0", new BABYLON.Vector3(0, 100, 100), scene);
var sphere = BABYLON.Mesh.CreateSphere("Sphere", 16, 3, scene);

Babylon.js supports different kind of cameras, lights and meshes. I will get back to them in this article.

You may have noticed the usage of BABYLON.Vector3 to define a 3D position. Indeed, babylon.js comes with a complete math Library that can handle vectors, matrix, colors, rays and quaternions.

Please note that babylon.js use a left handed coordinate system:

 

The last thing you need to do is to register a render loop:

// Render loop
var renderLoop = function () {
    // Start new frame
    engine.beginFrame();

    scene.render();

    // Present
    engine.endFrame();

    // Register new frame
    BABYLON.Tools.QueueNewFrame(renderLoop);
};

BABYLON.Tools.QueueNewFrame(renderLoop);

Using QueueNewFrame (which is just a call to requestAnimationFrame when supported or setTimeout else), you will ask the browser to call your renderLoop as soon as possible. The renderLoop itself is based upon 4 parts:

  • engine.beginFrame: This is a required call to determine the start of a new frame
  • scene.render: Asks the scene to render all entities it owns
  • engine.endFrame: Closes the current frame and present it to the canvas
  • QueueNewFrame: Registers a new frame for rendering

To simplify the code you can also use this construct:

// Render loop
var renderLoop = function () {
    scene.render();
};

// Launch render loop
engine.runRenderLoop(renderLoop);

If you want to add a bit more of real-time, you can add function for scene.beforeRender and use it to animate the sphere:

var alpha = 0;
sphere.scaling.x = 0.5;
sphere.scaling.z = 1.5;
scene.beforeRender = function() {
    sphere.rotation.x = alpha;
    sphere.rotation.y = alpha;

    alpha += 0.01;
};

The result is the following (if your browser does not support WebGL, you will see a wonderful white on white rectangle):



Materials


Our sphere is a bit sad with its simple gray color. This is time for us to talk about materials. A material for babylon.js is an object that defines how a mesh looks like.


Babylon.js has an object called StandardMaterial which supports the following properties:


  • diffuseColor and diffuseTexture: Define the base color of the mesh

  • ambientColor and ambientTexture: Define the ambient color of the mesh (can be used for light maps for instance)

  • specularColor and specularTexture: Define the specular color of the mesh

  • emissiveColor and emissiveTexture: Define the color emitted by the mesh (the color the object has without light)

  • opacityTexture: Define the transparency of the mesh

  • reflectionTexture: Define the reflection color received by the mesh (can be a texture or a dynamic mirror)

  • bumpTexture: Define the bump level of the mesh on a per-pixel basis. You must provide a normal map picture here.

  • alpha: Define the global transparency of the mesh


color properties define an unique color where texture properties use a bitmap to define colors


So let’s add some color to our sphere:

// Material
var material = new BABYLON.StandardMaterial("default", scene);
material.diffuseTexture = new BABYLON.Texture("kosh.jpg", scene);
material.emissiveColor = new BABYLON.Color3(0.3, 0.3, 0.3);
sphere.material = material;

And the result (once again, with WebGL, it should be white…):


The StandardMaterial is very versatile and there are tons of available combinations. For instance let’s change the texture used by the diffuseTexture with a texture that contains alpha values:

var material = new BABYLON.StandardMaterial("default", scene);
material.diffuseTexture = new BABYLON.Texture("tree.png", scene);
material.diffuseTexture.hasAlpha = true;
material.emissiveColor = new BABYLON.Color3(0.3, 0.3, 0.3);
material.backFaceCulling = false;
sphere.material = material;

And the result:


Please note that in this case, we have to indicate that the texture contains useful alpha values (hasAlpha = true). We also need to deactivate the back face culling system (which remove the faces that are not toward us) to see back faces.

To learn more about materials: https://blogs.msdn.com/b/eternalcoding/archive/2013/07/01/babylon-js-unleash-the-standardmaterial-for-your-babylon-js-game.aspx

You may also be interested by multi-materials: https://blogs.msdn.com/b/eternalcoding/archive/2013/07/10/babylon-js-using-multi-materials.aspx

Lights, cameras and meshes

Lights

Babylon.js lets you create 4 kind of lights:

  • pointLight (like the sun for instance) which emits light in every direction from a specific position
  • directionalLight which emits light from the infinite towards a specific direction
  • spotLight which emits light from a position to a direction Inside a cone
  • hemisphericLight which is a special ambient light based on a direction to determine if the light color comes from the ground or from the sky

Creating them is easy:

var point = new BABYLON.PointLight("point", new BABYLON.Vector3(20, 100, 2), scene);
var directional = new BABYLON.DirectionalLight("directional", new BABYLON.Vector3(1, 1, 0), scene);
var spot = new BABYLON.SpotLight("spot", new BABYLON.Vector3(20, 100, 2), new BABYLON.Vector3(1, 1, 0), 0.8, 1, scene);
var hemi = new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1, 0), scene);

You can create as much lights as you want but beware: the StandardMaterial can only take in account up to 4 lights simultaneously.

Lights have three main properties:

  • diffuse: Diffuse color
  • specular: Specular color
  • position / direction

Spot lights also have:

  • angle: Cone angle
  • exponent: Attenuation exponent (1 for linear, 2 for pow2, etc…)

Hemispheric lights have:

  • groundColor: color of the “ground” part of the light (sky color is defined by diffuse property)

To learn more about lights: https://blogs.msdn.com/b/eternalcoding/archive/2013/07/08/babylon-js-using-lights-in-your-babylon-js-game.aspx

Cameras

Babylon.js supports 3 kind of cameras:

  • freeCamera is a FPS like camera where you control the camera with the cursors keys and the mouse
  • touchCamera is a camera controlled with touch events (it requires hand.js to work)
  • arcRotateCamera is a camera that rotates around a given pivot. It can be controlled with the mouse or touch events (and it also requires hand.js to work)

You can create as much cameras as you want but only one camera can be active at a time

var camera = new BABYLON.ArcRotateCamera("Camera1", 0, 0.8, 10, BABYLON.Vector3.Zero(), scene);
var camera2 = new BABYLON.FreeCamera("Camera2", new BABYLON.Vector3(0, 0, -10), scene);
var camera3 = new BABYLON.TouchCamera("Camera3", new BABYLON.Vector3(0, 0, -10), scene);

scene.activeCamera = camera;

All the cameras can automatically handle inputs for you by calling attachControl function on the canvas. And you can revoke the control by using detachControl function:

camera.attachControl(canvas);

Meshes

Creation

Meshes are the only entities that you can effectively see. They have tons of properties and can be created from basic shapes or from a list of vertices and faces.

Basic shapes are:

  • Cube
  • Sphere
  • Plane
var box = BABYLON.Mesh.CreateBox("Box", 0.8, scene);
var sphere = BABYLON.Mesh.CreateSphere("Sphere", 16, 3, scene);
var plane = BABYLON.Mesh.CreatePlane("plane", 3, scene);

You can also create a mesh from a list of vertices and faces:

var plane = new BABYLON.Mesh(name, scene);

 var indices = [];
 var positions = [];
 var normals = [];
 var uvs = [];

 // Vertices
 var halfSize = size / 2.0;
 positions.push(-halfSize, -halfSize, 0);
 normals.push(0, 0, -1.0);
 uvs.push(0.0, 0.0);

 positions.push(halfSize, -halfSize, 0);
 normals.push(0, 0, -1.0);
 uvs.push(1.0, 0.0);

 positions.push(halfSize, halfSize, 0);
 normals.push(0, 0, -1.0);
 uvs.push(1.0, 1.0);

 positions.push(-halfSize, halfSize, 0);
 normals.push(0, 0, -1.0);
 uvs.push(0.0, 1.0);

 // Indices
 indices.push(0);
 indices.push(1);
 indices.push(2);

 indices.push(0);
 indices.push(2);
 indices.push(3);

 plane.setVerticesData(positions, BABYLON.VertexBuffer.PositionKind);
 plane.setVerticesData(normals, BABYLON.VertexBuffer.NormalKind);
 plane.setVerticesData(uvs, BABYLON.VertexBuffer.UVKind);
 plane.setIndices(indices);

 return plane;

You have to create a blank new mesh and call setVerticesData and setIndices.

To define where the mesh is, you can use the position/rotation/scaling properties:

plane.position = new BABYLON.Vector3(0, 7, 0);
plane.rotation.z = 0.1;
plane.scaling.x = 2;

Meshes hierarchy

You can create meshes hierarchies by setting the parent property of a mesh. By doing this you create a link between two meshes. This link implies that all parent transformations (position/rotation/scaling) will be combined with the child’s transformations.

For instance, with the following code:

var box = BABYLON.Mesh.CreateBox("Box", 1.0, scene);
box.position = new BABYLON.Vector3(0, 2, 2);
box.parent = sphere;

You will get the following result (based obviously on the previous scene we created, where I removed the scaling of the sphere for clarity):


Activation and visibility

You can control the visibility and the activation of meshes according to following rules:

  • StandardMaterial can control the opacity of an object with
    • alpha property to control alpha blending (transparency) per mesh
    • alpha channel of the diffuseTexture: this will cause babylon.js to activate alpha testing which means it will discard all pixel with alpha value < 0.5
    • opacityTexture to define alpha blending per pixel (and not for the whole mesh like alpha property)
  • visibility property to control the transparency per mesh directly (without using a material)
  • isVisible property to activate the rendering of the mesh. The mesh is kept into the scene for others operations (collisions, picking, etc.). This property is not transmitted to children
  • setEnabled function to deactivate completely a mesh and all its descendants.

Collisions

One of the great feature of babylon.js is certainly its complete and really simple to use collisions system. By settings a small set of options, you will be able to reproduce a first person shooter.

There are three levels of options to set. First of all you have to activate the collisions globally on the scene and define the gravity:

 scene.collisionsEnabled = true;
 scene.gravity = new BABYLON.Vector3(0, -9, 0);

Then you have to configure the camera you want to use for collisions:

camera.checkCollisions = true;
camera.applyGravity = true;
camera.ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);

The collisions engine considers the camera like an ellipsoid (a kind of capsule). In this case the camera is like a big ellipsoid measuring 1mx2mx1m (the ellipsoid property defines the radius of the ellipsoid).

You can also create a flying camera by not applying gravity.

Finally you have to define which meshes can collide:

plane.checkCollisions = true;
sphere.checkCollisions = true;

The result is the following (use the cursors keys to move and the mouse to change your point of view by clicking and moving it. Beware not to fall off of the ground): https://www.babylonjs.com/tutorials/simple5.html

Babylon.js can even handle stairs as you can see in the “Espilit demo” on the main site.

Particle systems

Particle systems are a cool toy when you play with 3D. They can easily add stunning effects on your scene (explosions, impacts, magic effects, etc.).

Creating a particle system is simple as follow:

var particleSystem = new BABYLON.ParticleSystem("particles", 4000, scene);

You have to define the maximum capacity of a particle system to allow babylon.js to create associated WebGL objects. So in this case, there will be no more than 4000 active particles simultaneously.

Particle systems are highly configurable with the help of the following set of properties:

  • particleTexture: Defines the texture associated with every particle
  • minAngularSpeed / maxAngularSpeed: The range of the angular rotation speeds of every particle
  • minSize / maxSize: The range of sizes of every particle
  • minLifeTime / maxLifeTime: The range of lifetimes for every particle
  • minEmitPower / maxEmitPower:: The range of emission powers (emission speed) of every particle
  • minEmitBox / maxEmitBox:: The box from where every particle starts (can be a point if min == max)
  • direction1 / direction2: The range of directions for every particle
  • color1 / color2: The range of colors for every particle
  • colorDead: The color of a dead particle (Babylon.js will interpolate particle’s color to this color)
  • deadAlpha: The alpha of a dead particle (in a same way, babylon.js will interpolate particle’s alpha to finish with this specific alpha)
  • textureMask: A mask used to filter which part of the texture is used for every particle
  • blendMode: Alpha blending mode (_BLENDMODE_ONEONE_ to add current color and particle color or _BLENDMODE_STANDARD_ to blend current color and particle color using particle’s alpha)
  • emitter: A Vector3 to define the position of the particle system. You can also used a mesh here and in this case the particle system will use the mesh position
  • emitRate: How many particles are launched on every frame.
  • manualEmitCount: Specifying a value greater or equal to zero here will disable emitRate. You are then responsible for feeding this value to control the particles count emitted.
  • updateSpeed: The global speed of the system
  • gravity: Graviy applied to particles
  • targetStopDuration: Stops the particle system after a specific duration
  • disposeOnStop: Disposes the particle system on stop (Very useful if you want to create a one shot particle system with a specific targetStopDuration)

Every range values are used to generate a controlled random value for every particle.

You can control a particle system by calling start / stop functions.

That’s a lot of properties, isn’t it ? The best way to understand them is to try all of them on a test scene and play with properties. For instance, the following code:

var particleSystem = new BABYLON.ParticleSystem("particles", 4000, scene);
particleSystem.particleTexture = new BABYLON.Texture("Flare.png", scene);
particleSystem.minAngularSpeed = -0.5;
particleSystem.maxAngularSpeed = 0.5;
particleSystem.minSize = 0.1;
particleSystem.maxSize = 0.5;
particleSystem.minLifeTime = 0.5;
particleSystem.maxLifeTime = 2.0;
particleSystem.minEmitPower = 0.5;
particleSystem.maxEmitPower = 1.0;
particleSystem.emitter = new BABYLON.Vector3(0, 0, 0);
particleSystem.emitRate = 500;
particleSystem.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE;
particleSystem.minEmitBox = new BABYLON.Vector3(0, 0, 0);
particleSystem.maxEmitBox = new BABYLON.Vector3(0, 0, 0);
particleSystem.direction1 = new BABYLON.Vector3(-1, -1, -1);
particleSystem.direction2 = new BABYLON.Vector3(1, 1, 1);
particleSystem.color1 = new BABYLON.Color4(1, 0, 0, 1);
particleSystem.color2 = new BABYLON.Color4(0, 1, 1, 1);
particleSystem.gravity = new BABYLON.Vector3(0, -5, 0);
particleSystem.disposeOnStop = true;
particleSystem.targetStopDuration = 0;
particleSystem.start();

Sprites and layers

Babylon.js is designed to extract the full power of WebGL for your apps and games. And even if you want to create a 2D game, babylon.js can help you by providing a support for sprites and 2D layers.

Please note than you can also define the billboardMode property of a mesh to align it with the camera to simulate a 2D object: plane.billboardMode = BABYLON.Mesh.BILLBOARDMODE_ALL

A sprite is defined by a texture containing all its animation states:

The current state (the current cell displayed) is defined using the cellIndex property. You can then manipulate it by code or use the playAnimation function to let babylon.js control the cellIndex property.

Sprites working on the same texture are gathered around a SpriteManager to optimize resources usage:

var spriteManager = new BABYLON.SpriteManager("MonsterA", "MonsterARun.png", 100, 64, scene);
for (var index = 0; index < 100; index++) {
    var sprite = new BABYLON.Sprite("toto", spriteManager);
    sprite.position.y = 0;
    sprite.position.z = Math.random() * 10 - 5;
    sprite.position.x = Math.random() * 10 - 5;
    sprite.invertU = (Math.random() < 0.5);

    sprite.playAnimation(0, 9, true, 100);
}

Please note the usage of invertU for inverting horizontally the texture.

 

In addition to sprites, babylon.js also supports 2D layers in order to let you add backgrounds or foregrounds:

var background0 = new BABYLON.Layer("back0", "Layer0_0.png", scene);
 var background1 = new BABYLON.Layer("back1", "Layer1_0.png", scene);
 var foreground = new BABYLON.Layer("fore0", "Layer2_0.png", scene, false);

The last boolean defines if the layer is background (or not).

 

Animations

There are two ways of animating properties in babylon.js: You can do it by yourself using JavaScript (see previous samples) or you can use the animations engine.

The animations engine is based on objects called Animation (!!). An Animation is defined by various properties and a collection of keys. Every key represents the value of the Animation at a given time. Once an Animation is created you can add it to the animations property of a given object:

// Animations
var animation = new BABYLON.Animation("anim0", "scaling.x", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, 
                                                                BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);

var keys = [];
keys.push({
    frame: 0,
    value: 1
});

keys.push({
    frame: 50,
    value: 0.2
});

keys.push({
    frame: 100,
    value: 1
});

animation.setKeys(keys);

box.animations.push(animation);

Animations can work on types:

  • float (BABYLON.Animation.ANIMATIONTYPE_FLOAT)
  • Vector3 (BABYLON.Animation.ANIMATIONTYPE_VECTOR3)
  • Quaternion (BABYLON.Animation.ANIMATIONTYPE_QUATERNION)

They can have various behaviors when they hit their upper limit:

  • Use previous values and increment it (BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE)
  • Restart from initial value (BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE)
  • Keep their final value (BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT)

So using the previous codea and this small line will launch the animation:

scene.beginAnimation(box, 0, 100, true);

 

Advanced textures

Textures can obviously be based on pictures but you have the opportunity with babylon.js to use Advanced features to generate textures at runtime.

Dynamic textures

A dynamic texture uses a canvas to generate its content.

Creating and affecting a dynamic texture is simple:

var dynamicTexture = new BABYLON.DynamicTexture("dynamic texture", 512, scene, true);
dynamicTexture.hasAlpha = true;
material.diffuseTexture = dynamicTexture;

Once the texture is created, you can updated it when you want (for instance here every time the scene is rendered) using the getContext and update functions:

var count = 0;
scene.beforeRender = function() {
    // Dynamic
    var textureContext = dynamicTexture.getContext();
    var size = dynamicTexture.getSize();
    var text = count.toString();

    textureContext.save();
    textureContext.fillStyle = "red";
    textureContext.fillRect(0, 0, size.width, size.height);

    textureContext.font = "bold 120px Calibri";
    var textSize = textureContext.measureText(text);
    textureContext.fillStyle = "white";
    textureContext.fillText(text, (size.width - textSize.width) / 2, (size.height - 120) / 2);

    textureContext.restore();

    dynamicTexture.update();
    count++;
};

 

The getContext returns a true canvas’ context so everything you can do with a canvas is available with a dynamic texture.

Video textures

You can also create textures that use video as content source:

var ecran = scene.getMeshByName("Ecran");
ecran.material.diffuseTexture = new BABYLON.VideoTexture("video", 
["Scenes/Flat2009/babylonjs.mp4", "Scenes/Flat2009/babylonjs.webm"], 256, scene, true);

The VideoTexture object accepts an array of videos (to take in account various codecs) and once a video can be loaded, it uses it as content source.

The internal video DOM object is accessible via VideoTexture.video property to allow you to control the status of the video (play/pause/stop).

For instance, I used this solution to simulate a TV in the Flat2009 demo:

Mirrors

Mirrors textures are another kind of dynamic textures. You can use them to simulate “mirrors” which mean that babylon.js will compute for you the reflection and fill the texture with the results. A Mirror texture must be set in the reflectionTexture channel of a standardMaterial:

// Mirror
var mirror = BABYLON.Mesh.createBox("Mirror", 1.0, scene);
mirror.material = new BABYLON.StandardMaterial("mirror", scene);
mirror.material.diffuseColor = new BABYLON.Color3(0.4, 0, 0);
mirror.material.reflectionTexture = new BABYLON.MirrorTexture("mirror", 512, scene, true);
mirror.material.reflectionTexture.mirrorPlane = new BABYLON.Plane(0, -1.0, 0, -2.0);
mirror.material.reflectionTexture.renderList = [box, sphere];

A mirrorTexture is created with a parameter that specify the size of the rendering buffer (512x512here). Then you have to define the reflection plane and a render list (the list of meshes to render Inside the mirror).

 

Importing scene from 3D assets

Babylon.js can load scenes from a file format called .babylon. This file format is based on JSON and contains all required data to create a complete scene.

BabylonExport

A .babylon can be created with a custom tool I developed: BabylonExport. This command line tool can generate .babylon file from various file formats:

  • .FBX
  • .OBJ
  • .MXB

BabylonExport takes 2 parameters:

BabylonExport /i:”Test scenesViperViper.obj” /o:”c:ExportViper”

The tool can be found here: https://www.babylonjs.com/babylonexport.zip

Warning: The tool requires XNA 4.0 runtime: https://www.microsoft.com/en-us/download/details.aspx?id=20914

Blender

You can also produce .babylon files with Blender. To do so, please download the exporter script right here:

https://github.com/BabylonJS/Babylon.js/tree/master/Exporters/Blender

A more complete article is dedicated to this feature: https://blogs.msdn.com/b/eternalcoding/archive/2013/06/28/babylon-js-how-to-load-a-babylon-file-produced-with-blender.aspx

To install it, please follow this small guide:

  • Unzip the file to your Blender’s plugins folder (Should be C:Program FilesBlender FoundationBlender2.67scriptsaddons for Blender 2.67 x64).
  • Launch Blender and go to File/User Préférences/Addon and select Import-Export category. You will be able to activate Babylon.js exporter.

  • Create your scene
  • Go to File/Export and select Babylon.js format. Choose a filename and you are done !

You are now able to produce .babylon scene! The exporter will be able to support more and more options in the future but right now the following features are already supported:

  • Cameras
  • Lights
  • Meshes
  • Material and Multimaterials
    • Diffuse
    • Ambient
    • Opacity
    • Reflection
    • Emissive
    • Bump
  • Collisions (with custom UI Inside Blender)
  • Fog

To learn more about how to load a blender scene: https://blogs.msdn.com/b/eternalcoding/archive/2013/06/28/babylon-js-how-to-load-a-babylon-file-produced-with-blender.aspx

And much more to come…

The backlog is full of cool things among which we can note:

  • Bones
  • Morphing
  • Refraction
  • Water shader

The main goal of babylon.js is to provide you with a strong framework for simplifying 3D. Use it freely as a foundation for your games and applications.

The thing that is also really cool is that you also can use Babylon.js with your Windows 8.1 apps!

So now go to https://www.babylonjs.com and start exploring the wonderful world of 3D rendering!

Next chapters

If you want to go more deeply into babylon.js, here are some useful links:

Benchmarking a HTML5 game: HTML5 Potatoes Gaming Bench

HTML5 Potatoes logo

A few weeks ago, my friend David Rousset wrote an excellent article about “benchmarking your sprites animations to target all devices & browsers”. This article used a benchmark framework called “HTML5 Potatoes Gaming Bench” to obtain a consistent scoring for various sprites tests.

I will try to explain you how we built this framework and the decision we made to make it representative of the effective performance of the tested hardware and browser.

You will see that this framework can be used to measure any scenarios you want to benchmark for your own games.

The delta time

First of all, we have to talk about the delta time. Indeed, when you wrote games or any resources intensive applications, the principle is always the same: you must have a render loop where the display is done (sprites, effects, etc.).

The user will have a feeling of great performance when the elapsed time between two rendered frames is near the well known target of (1000 / 60)ms (about 16ms).

So targeting 60 frames per second will be the duty of any game developer: No one is prone to experience lag or slowness in the responsiveness of their game.

Actually, the delta time can be defined as the elapsed time between two passes in the render loop.

To compute this value, you just have to store the current date() when you start a new frame and subtract the previous stored date(). The result is the number of milliseconds between the two frames:

var previousDate;

var computeDeltaTime = function() {
    if (!previousDate) {
        previousDate = Date.now();
        return 0;
    }

    var currentDate = Date.now();
    var delta = currentDate - previousDate;
    previousDate = currentDate;

    return delta;
};

Calling this function just before rendering a new frame will allow us to determine the current delta time:

var renderLoop = function() {
    while (renderInProgress) {
        var deltaTime = computeDeltaTime();

        // render your frame here
    }
};

Render loop

Actually, the render loop cannot be a while(true){} function. Indeed, JavaScript is mono-threaded so looping in a function will just block entirely your browser.

So you must be called by the browser every time a frame is requested. To do so, the W3C introduced a new API called requestAnimationFrame.

This API tells the browser that you wish to perform an animation and requests that the browser schedule a repaint of the window for the next animation frame. It also takes in account the visibility of the page in order to avoid unnecessary renders.

requestAnimationFrame is far better than a simple setTimeout API because setTimeout API can provide choppy animations and increase resource consumption by rendering not required frames.

This is the PERFECT place to render your new frame. And ovbiously this is the perfect place to evalute your delta time. (It is worth noting that requestAnimationFrame gives you a parameter indicating the time at which the function is scheduled to be called).

So the new render loop looks like this:

var renderLoop = function () {
    var deltaTime = computeDeltaTime();

    // render your frame here

    // Schedule new frame
    requestAnimationFrame(renderLoop);
};

// First call
requestAnimationFrame(renderLoop);

Alas, the requestAnimationFrame API is not supported by every browser according to www.caniuse.com:

To prevent the benchmark for not working on every browser, we can use this small polyfill:

POTATOES.Tools.queueNewFrame = function (func) {
    if (window.requestAnimationFrame)
        window.requestAnimationFrame(func);
    else if (window.msRequestAnimationFrame)
        window.msRequestAnimationFrame(func);
    else if (window.webkitRequestAnimationFrame)
        window.webkitRequestAnimationFrame(func);
    else if (window.mozRequestAnimationFrame)
        window.mozRequestAnimationFrame(func);
    else if (window.oRequestAnimationFrame)
        window.oRequestAnimationFrame(func);
    else {
        window.setTimeout(func, 16);
    }
};

You can note that the setTimeout API is used as a fallback for the requestAnimationFrame API.

Measuring FPS

The benchmark need a value called FPS (standing for frames per second). Computing the FPS is an easy task when you have requestAnimationFrame and the delta time.

To do so, HTML5 Potatoes Gaming Bench uses a function called handleMetrics. This function is responsible for computing the immediate FPS and the average FPS. The first one is just the FPS based on the delta time between the current frame and the previous one. The second one is the average of FPS for a given number of previous frames:

var fpsFrame = 20; // fps window frame
var fpsCap = 60;
var previousFramesDuration = [];

var handleMetrics = function () {
    previousFramesDuration.push(Date.now());

    if (previousFramesDuration.length >= fpsFrame) {

        if (previousFramesDuration.length > fpsFrame) {
            previousFramesDuration.splice(0, 1);
        }

        var avg = 0;
        for (var id = 0; id < fpsFrame - 1; id++) {
            avg += previousFramesDuration[id + 1] - previousFramesDuration[id];
        }
        avg /= fpsFrame - 1;

        POTATOES.GamingBench.currentFPS = Math.min(fpsCap, 1000.0 / (
previousFramesDuration[fpsFrame - 1] - previousFramesDuration[fpsFrame - 2])); POTATOES.GamingBench.averageFPS = Math.min(fpsCap, 1000.0 / avg);
} POTATOES.Tools.queueNewFrame(handleMetrics); };

To be sure the results are correct, I installed the Windows Performance Toolkit in order to compare the measures.

For my tests I used these benches: https://www.html5potatoes.com/gamingbench/index.htm

Two tests are used:

  • Canvas pixels manipulations
  • Processing images with web workers

The Windows Performance Analyser gave the following results:

We can see that the first test runs between 25 and 30 frames per second. The second one runs almost at full speed.

The good news is that the results computed by the Gaming Bench are similar:

The second test is not at more than 60fps because we use requestAnimationFrame which prevents unnecessary renders.

So we can consider that the measured values are consistent.

Using HTML5 Potatoes Gaming Bench

HTML5 Potatoes Gaming Bench is an open and free Framework that you can use freely Sourire

You can download all the code used previously here: https://www.html5potatoes.com/gamingbench/gamingbench.zip

The Gaming Bench was designed to provide an infrastructure to test whatever you want on a browser. So to add your own test on the gaming bench, you just have to create a Bench object with this code:

var tunnelBench = new POTATOES.GamingBench.Bench("Canvas pixels manipulations", "https://aka.ms/potatoes_tunnel",
    function (workbench) { // Init
        init(workbench, this.onInitCompleted);
    }, function () { // Run
        render = true;
        POTATOES.Tools.queueNewFrame(renderingLoop);
    }, function (workbench) { // End
        render = false;            
    });

POTATOES.GamingBench.registerBench(tunnelBench);

You have to provide 3 functions:

  • Init: This function is called once in order to create the DOM required by your test. It gives you the workbench parameter which is the DOM container where you can add your objects.
  • Run: This function is called to launch your test (this is where you can call the queueNewFrame function)
  • End: This function is called to stop your render and eventually clean associated ressources

The POTATOES.GamingBench.registerBench function is used to add your bench to the list of active benches.

To run the complete Gaming Bench, you have to use this code:

// Starting benchmark
POTATOES.GamingBench.start();

If you need to cancel it, just use this code:

POTATOES.GamingBench.cancel();

You can also skip the current test and go to the next one:

POTATOES.GamingBench.skipCurrent();

Finally if you want to gather results, you have to use this kind of code:

POTATOES.GamingBench.onprocessended = function () {
    // Generating the result list
    var score = 0;
    for (var index = 0; index < POTATOES.GamingBench.benches.length; index++) {
        var bench = POTATOES.GamingBench.benches[index];
        score += bench.score;

And that’s it! Feel free to take a look at the sample code to see how you can use the framework to extract all the infos you can need.

Understanding score

After running the complete Gaming Bench, you can analyse the score using a chart produced with d3.js. The score is computed by adding one point on every rendered frame. Obviously, you can modify this behavior for your own bench to take in account another metric. This is what David Rousset did for his own benches.

Here is a sample on how you can use details provided by the framework to compute a global fps:

var avgFps = 0;
for (var i = 0; i < bench.stats.length; i++) {
    avgFps += bench.stats[i].y;
}

avgFps /= bench.stats.length;

I really hope you will find this framework useful to help you create wonderful and efficient games!

Going further

Using Visual Studio’s Javascript Memory Analysis tool to find memory leaks on your Windows 8 Javascript app

Javascript is a wonderful language for developing Windows 8 apps. As a untyped, dynamic language, Javascript is really flexible but sometimes if you are not careful you may leave some memory leaks in your code.

But do not worry, Visual Studio includes a great tool called Javascript Memory Analysis in order to help you find out where the leaks are.

Using the Javascript Memory Analysis tool

This tool is available in the Debug menu of your Visual Studio:

Launching the tool will launch your app and will show this screen:

The first part of the window is dedicated to the real-time monitoring of the memory used by the application:

Right after you can find a button (Take Heap Snapshot) used to capture the instantaneous state of the memory heap (The control also indicates the size of the heap and the number of active objects):

By clicking on the heap size, a more detailed view is generated:

This view presents a sorted list of the objects by retained size, which means the objects consuming the most memory that are potentially easiest to free would be listed first.

For instance, in my app, I can see that the UrzaGatherer object retains almost 60 MB (which is normal because it handles a huge list of cards):

The view can also display:

  • a list of types sorted by occurrence count
  • a list of root objects (from the garbage collector point of view)
  • a list of DOM objects sorted by retained size
  • a list of WinRT objects sorted by retained size

All of these views can potentially help you find inconsistent memory usage.

Comparing snapshots

Each time you click on Take Heap Snapshot button, the system generates a new dump of the heap for further analysis. Furthermore, each snapshot indicates the difference of the heap size and objects count against previous snapshot.

This is the key for finding memory leaks.

For instance, in my app, I will take a first snapshot, navigate to a given page, then go back to home page and finally take a second snapshot. Doing this I will be able to see if the given page produces memory leaks.

We can see here that between the two snapshots, the heap size has grown of 6.12 MB and more than 53k objects were generated and still alive.  

By clicking on the heap size difference (+6.12 MB), you can view a detail of the heap size compared to previous snapshot:


The Dominators view indicates that new objects remain when we come back to the home page. You can use this view to identify unwanted objects.

In my case, the first line seems suspicious. By right-clicking on it, I can go to the Root view to see which function retains my objects:

We can see that the object is retained by a function called ImportFromTappedOut.

After looking for this function in my code, it turns out that this function is a global function which takes a  function as parameter:

ImportFromTappedOut = function (deckName, <u>custom</u>) {

The custom parameter is used by this function to call some specific user code. The main problem is that because the ImportFromTappedOut is a global function it will retain all the code referenced by the function affected to the custom parameter and in my case I used an anonymous function that references a lot of local DOM objects:

 Tools.ImportFromTappedOut("test", function () {
     var select = document.querySelector("#addToDeck");
     var count = document.querySelector("#addToDeckCount").value;

     listView.selection.getItems().then(function (items) {
         appBar.hide();
         appBar.sticky = false;
         listView.selection.clear();
…code continue…

And this exactly the problem described by the tool:

The solution is easy: I just have to call importFromTappedOut with a null function when I leave the page in order to allow the garbage collector to collect all retained objects (1.25 MB here).

I clearly encourage you to use this tool to detect and eradicate memory leaks. It is simple and really powerful and can help you get rid of memory problems.

More about the tool

Others articles you may find useful:

Reading PDF and XPS on your Windows 8 application using WinRT

PDF and XPS file formats are widely used across the world and you could need one day to display them inside your application.

Today I would like to share with you a simple way to do so by using an open source solution: MuPDF (a multiplatform lightweight PDF and XPS viewer).

MuPDF is already working on a WinRT solution you can grab on this GIT repo: https://git.ghostscript.com/?p=user/mvrhel/mupdf.git;a=summary

I also used the work of Libreliodev and especially their advanced port of MuPDF for WinRT.

The result is a simple but really useful Windows 8 Modern UI app that is able to display a PDF/XPS file: https://www.catuhe.com/msdn/pdfreader.zip



Read More

WinRT component: How to generate a GUID?

For your Windows 8 applications, you may need to generate a unique identifier (for instance, if you want to uniquely identify your users).

To do so, here is a small C++ WinRT component (I decided not to use C# to make the component light-weighted because it is pure native code and so you do not need to load the CLR to use it).

#pragma once
#include <Objbase.h>
using namespace Platform;

namespace UrzaBox
{
    public ref class Tools sealed
    {
    public:
        Tools();

        static Platform::String^ GetNewID()
        {
            GUID result;
            HRESULT hr = CoCreateGuid(&result);

            if (SUCCEEDED(hr))
            {
                Guid gd(result);
                return gd.ToString();
            }

            throw Exception::CreateException(hr);
        }
    };
}