A taste of awesomeness: Testing the Dell Venue 8 tablet

Windows 8.1 introduced the support for new range of resolutions and form factors. Among others, the 8’’ form factor is definitely a must have for me.

That is why I bought a Dell Venue 8 tablet. And I can say I am not disappointed at all!

The beast

One of is obvious quality is its price: 299$ for the 32Gb version.

At this price, you will get:

  • 32 bits version of Windows 8.1
  • 2Gb of RAM
  • MicroSD reader
  • Wifi 802.11n
  • Two webcams (5MP and 1.2MP)
  • Micro-AB USB2.0 (for trickle charging and data transfer)
  • Headphone and microphone combojack
  • Miracast support for Wireless display

The dimensions are the following;

  • Thickness: 0.35” (9mm)
  • Width: 5.12” (130mm)
  • Length: 8.50” (216mm)
  • Weight: 395g

A Intel® Atom™ processor Z3740 (1.3GHz Quad-Core) is running a fully functional Windows 8.1 accompanied by a version of Microsoft Office Home and Students 2013.

The thing is that in the palm of your hand you can get all the raw power of Windows 8.1 with both the Windows Store apps and the desktop apps (for instance VLC or Visual Studio).

This tablet is also able to accept stylus (you have to buy it separately)

Some tests

Performances

From the performance side, I must admit I was amazed by the power of the GPU of the Z3740. For instance here is a scene grabbed from www.babylonjs.com:

You can see that babylon.js is running at an incredible frame rate of almost 30! Everything is smooth and perfectly fluid.

This is the very first time I saw a tablet running 3D graphics at that speed (Please note that babylon.js is running inside Internet Explorer 11 using WebGL).

Windows 8.1 seems to be happy with this processor and runs like a charm. You can easily switch between apps without any lags or glitches.

Battery

With an intensive use of 3D, apps and videos, the battery was able to last more than 7 hours which is great.

What can be improved?

For me the main issue is the lack of a true USB port. There is a mini USB but you need to buy a special cable to be able to connect your devices.

The resolution of 1200×800 could be a bit low and perhaps a full HD version would have been better but thanks to WIndows 8.1 the screen is well used and filled:

Conclusion

This is (by far) my favorite tablet right now. I love the form factor and the overall performance. This is the first time I have the feeling that I get a really powerful PC inside the palm of my hand.

What a cool feature!! Controling the Windows 8.1 lock screen slide show

Windows 8.1 introduced a really cool feature for users and developers: the control of the lock screen slide show.

Starting with Windows 8, we were already able to define the lock screen background image but now we can do more: we can transform the lock screen into a cool slide show:




I really love this feature and I can spend hours watching beautiful pictures (always from Magic the Gathering) sliding on my screens.


You will see that enabling this feature from your own application is pretty simple!

The LockScreen class

The LockScreen class was introduced with WinRT and Windows 8. Initially, It allowed you to control the lock screen background image with this simple piece of code:

var lockScreen = Windows.System.UserProfile.LockScreen;
lockScreen.setImageFileAsync(file);

Really simple, isn’t it ?

Controling the slide show

Starting with Windows 8.1, the LockScreen is now able to control the slide show feature. It can be activated from the PC Settings screen:

As you can see, your application can provide the content displayed by the lock screen. To do so the following code is used:

Windows.System.UserProfile.LockScreen.requestSetImageFeedAsync(
   new Windows.Foundation.Uri("https://urzagatherer.azure-mobile.net/api/wallpapers")).then(function (result)
    if (result === Windows.System.UserProfile.SetImageFeedResult.success) {
        …
    } else {
        …
    }
});

To control the slide show, Windows 8.1 will use a remote RSS feed provided to requestSetImageFeedAsync function.

Here is an example of the awaited structure of the RSS feed:

<?xml version="1.0" ?>
<rss version="2.0">
<channel>
    <title>UrzaGatherer's Wallpapers</title>
    <link>https://urzagatherer.azure-mobile.net/api/wallpapers</link>
    <description>List of wallpapers published on Magic the Gathering official site</description>
    <pubDate>Wed, 13 Nov 2013 13:48:57 GMT</pubDate>
    <lastBuildDate>Wed, 13 Nov 2013 13:48:57 GMT</lastBuildDate>
    <item>
        <title>Wallpaper Thassa God ofthe Sea 1920x1080</title>
        <link>https://media.wizards.com/images/magic/daily/wallpapers/Wallpaper_Thassa_God_ofthe_Sea_1920x1080.jpg</link>
        <description>Wallpaper Thassa God ofthe Sea 1920x1080</description>
        <enclosure url="https://media.wizards.com/images/magic/daily/wallpapers/Wallpaper_Thassa_God_ofthe_Sea_1920x1080.jpg" type="image/jpg" />
        <pubDate>Sun, 10 Nov 2013 22:00:05 GMT</pubDate>
    </item>
    <item>
        <title>Wallpaper Nylea God ofthe Hunt 1920x1080</title>
        <link>https://media.wizards.com/images/magic/daily/wallpapers/Wallpaper_Nylea_God_ofthe_Hunt_1920x1080.jpg</link>
        <description>Wallpaper Nylea God ofthe Hunt 1920x1080</description>
        <enclosure url="https://media.wizards.com/images/magic/daily/wallpapers/Wallpaper_Nylea_God_ofthe_Hunt_1920x1080.jpg" type="image/jpg" />
        <pubDate>Sun, 10 Nov 2013 22:00:05 GMT</pubDate>
    </item>
    <item>
        <title>Wallpaper Nykthos Shrine to Nyx 1920x1080</title>
        <link>https://media.wizards.com/images/magic/daily/wallpapers/Wallpaper_Nykthos_Shrine_to_Nyx_1920x1080.jpg</link>
        <description>Wallpaper Nykthos Shrine to Nyx 1920x1080</description>
        <enclosure url="https://media.wizards.com/images/magic/daily/wallpapers/Wallpaper_Nykthos_Shrine_to_Nyx_1920x1080.jpg" type="image/jpg" />
        <pubDate>Sun, 10 Nov 2013 22:00:05 GMT</pubDate>
    </item>
</channel>
</rss>

Do not hesitate to add this feature to your application. It is simple to use and integrate and provide a very differentiating value.

How to use specific WinRT API from Desktop apps: capturing a photo using your webcam into a WPF app

Windows Runtime (WinRT) APIs are a platform-homogeneous application architecture on the Windows 8 operating system. These APIs are used to develop Windows Store applications.

However, some APIs can also be called from the desktop. The MSDN documentation is really useful to determine which are compatible. For instance, here is the requirements of the MediaCapture class of WinRT:

As you can see, this API can be called by a desktop application.

A friend of mine, Christophe Nasarre (who is Premier Field Engineer at Microsoft France) wrote a great tool to get the list of all supported WinRT APIs for desktop applications:

Creating a WPF app that can access WinRT APIs

First of all, let’s start with a simple WPF 4.5 application. The main page will look like this:

<Window x:Class="WPF_WinRT.MainWindow"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Image x:Name="displayImage"/>
    </Grid>
</Window>

Nothing special. Just an Image control to display the photo.

To add support for WinRT, you will have to unload the project from Visual Studio 2013 and add the following lines into the project file:

  <PropertyGroup>
    <TargetPlatformVersion>8.0</TargetPlatformVersion>
  </PropertyGroup>

These lines allow you to reference Windows core APIs for WinRT (once you have reloaded your project):

Using MediaCapture API

The MediaCapture class is a wonderful tool to access microphone and camera. Here is a standard (and simple) code used to get a photo from a webcam:

var devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
if (devices.Count == 0)
{
    MessageBox.Show("Unable to connect to a video capture device", "Error", MessageBoxButton.OK);
    return;
}

var mediaCapture = new MediaCapture();
mediaCapture.Failed += (s, errorEventArgs) => MessageBox.Show("Unable to start capture:" + 
errorEventArgs.Message,
"Error", MessageBoxButton.OK); await mediaCapture.InitializeAsync(); var jpgProperties = ImageEncodingProperties.CreateJpeg(); jpgProperties.Width = (uint)displayImage.ActualWidth; jpgProperties.Height = (uint)displayImage.ActualHeight; using (var randomAccessStream = new InMemoryRandomAccessStream()) { await mediaCapture.CapturePhotoToStreamAsync(jpgProperties, randomAccessStream); }

If you try to compile it, you will get some errors.

The first one is related to System.Runtime:

The type ‘System.Collections.Generic.IEnumerable`1’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’.

To solve this issue (mainly related to missing types), you just have to add a reference to this assembly (System.Runtime.dll):

The second error is the related to the await keyword. Actually, in order to await an IAsyncAction (the result type of FindAllAsync method for instance), you have to provide a GetAwaiter method:

‘await’ requires that the type ‘Windows.Foundation.IAsyncOperation<Windows.Devices.Enumeration.DeviceInformationCollection>’ have a suitable GetAwaiter method. Are you missing a using directive for ‘System’?

To fix this issue, you have to reference the following assembly (System.Runtime.WindowsRuntime.dll):

Finally a last error remains:

Property, indexer, or event ‘Windows.Media.Capture.MediaCapture.Failed’ is not supported by the language; try directly calling accessor methods ‘Windows.Media.Capture.MediaCapture.add_Failed(Windows.Media.Capture.MediaCaptureFailedEventHandler)’ or ‘Windows.Media.Capture.MediaCapture.remove_Failed(System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken)’

To add the missing interop features, just add the following assembly (System.Runtime.InteropServices.WindowsRuntime):

Once you have added these three references you are done! Nothing more is required.

However, you must note that event though some WinRT APIs are available for the Desktop, this is NOT the case for XAML controls (such as CaptureElement for instance).

Converting IRandomAccessStream to System.IO.Stream

The last point here is about the IRandonAccessStream (implemented by the InMemoryRandomAccessStream class). If we want to work with WPF, we have to convert it to System.IO.Stream.

Obviously, there is a simple way to do that: You just have to reference System.IO.WindowsRuntimeStreamExtensions class. Using this class, you will be able to use handy extensions methods such as AsStream:

using (var randomAccessStream = new InMemoryRandomAccessStream())
{
    await mediaCapture.CapturePhotoToStreamAsync(jpgProperties, randomAccessStream);

    randomAccessStream.Seek(0);
    using (var ioStream = randomAccessStream.AsStream())
    {
        var bitmapImage = new BitmapImage();
        bitmapImage.BeginInit();
        bitmapImage.StreamSource = ioStream;
        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
        bitmapImage.EndInit();

        displayImage.Source = bitmapImage;
    }
}

And that’s it! You can now use the power of some WinRT APIs from your desktop app!

[Video] Another WinRT/Desktop application

Christophe Nasarre also created an excellent video which talk about the same topic. This is a really good and educational resource:

https://blogs.msdn.com/b/mspfe/archive/2013/09/24/winrt-for-desktop-apps.aspx

[Babylon.js]–The Train demo

To celebrate the launch of Windows 8.1 and Internet Explorer 11, we decided to create a new demo scene for Babylon.js.

This demo was intended to show off the raw power of WebGL on modern browsers like Internet Explorer 11. I asked one of my friend (Romuald Rouhier) to allow us to use a 3D scene that he created with 3dsMax.

As you can see here, the scene is really beautiful. The challenge was to enable it to run in realtime under WebGL.

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

Some statistics

The scene itself is a big bunch of more than 900 000 active vertices (the mirror used for the water almost multiply the volume of vertices by 2). It uses more than 28 differents shaders and weight 70 MB.

In order to evaluate the performance of the scene, we did two benchmarks: One on my personal PC (a fat and powerful Intel Core-I7 PC with a Nvidia GeForce 680) and one on my laptop (a Lenovo X1 Carbon with an Intel Core-I7 and an Intel onboard graphics card (HD4000).

We run two tests each time. One on the main rotating camera and one on a less wide camera (Walk camera). The rotating camera has this point of view:

This camera requires huge power because every single object is visible!

The other camera is a bit less complex to render:

The results for these benchmarks are the following:

 

As you can see, even in a middle range hardware (my laptop) the power of WebGL allows us to deliver 30 frames per second on Internet Explorer 11.

Under the hood

To be able to render such a scene, we had to add new features to Babylon.js.

First of all this is the first time that we are able to dynamically change cameras using this new interface:

Then to add more life to the scene, we added support for animated cameras. For instance, the camera called CAM_ROT is rotating around the full scene.

In a same way, if you switch to _CAM_TRAIN_ camera or CAM_TRAIIN_AVANT camera, we will also discover a new feature: cameras can be related to mesh. This allows a camera to be linked (as a child) to an object (for instance the train right here):

About raw performances, in order to streamline the rendering, we spent a lot of time creating caches for almost every WebGL functions. These caches allow us to remove redundant states changes which are really expensive for the WebGL state machine.

Using the F12 developer bar of Internet Explorer 11, we were able to optimize the engine so that Javascript code is not a bottleneck. The integrated profiler (see below) tells us that almost all the time is spent INSIDE the graphics card code:

The drawElements functions is a WebGL function used to render triangles. We can see on the previous screenshot that Babylon.js (starting at the second line) is not a problem.

Do not hesitate to use the comments to share the performance you achieved on your own computer (Do not forget to indicate which version you use for OS, browser and hardware). We are eager to hear about your own experience!

Going further

You want to do the same and unleash the power of WebGL? Here are some interesting links:

Understanding DeviceOrientation events by creating a small 3D game with babylon.js

Internet Explorer 11 adds support for some new cool DOM events: the DeviceOrientation events. These events provide information about the physical orientation and motion of the current hardware.

The W3C has published a specification for these events: https://www.w3.org/TR/orientation-event/

During this article I will show you how to use these events within a small 3D game featuring an “Amiga” ball.

The final result will look like this:




Wanna try it? Just go there (you can use device orientation or the cursors keys).

DeviceOrientation events and babylon.js

Before looking in detail at the DeviceOrientation specification, you can have a look at this video showing the usage of device orientation within a babylon.js scene. And as you can see it ROCKS!



How DeviceOrientation events work ?

There are two types of data exposed by the DeviceOrientation events:

  • Orientation (deviceorientation): This value defines the orientation of the physical device in relation to a coordinate system centered on Earth. It is expressed in degree. Three coordinates are provided:
    • alpha: rotation around z axis
    • beta: rotation around x axis
    • gamma: rotation around y axis

The axis are defined using a right handed convention:

To understand these values, let’s start with the device in your hands:

The alpha orientation changes when you move the device around the z axis:

The beta orientation changes when you move the device around the x axis:

Finally, the gamma orientation changes when you move the device around the y axis:

  • Motion (devicemotion): This value defined the acceleration along each axis (x, y, z). The values are expressed in m/s² and can include (or not) the effect of the gravity). This event can also provide the rate of rotation (in deg/s) around each axis.

For more in-depth information, please have a look to the MSDN documentation.

The orientation is retrieved using the “deviceorientation” event fired on the window object:

window.addEventListener("deviceorientation", moveBall);
function moveBall(evt) {
    if (evt.alpha < 5 || evt.alpha > 355) {
        ball.position.z += 0.1;

    }
}

The motion is retrieved using the “devicemotion” event fired on the window object:

window.addEventListener("devicemotion", detectShake);
function detectShake(evt) {
    var accl = evt.acceleration;
    if (accl.x > 1.5 || accl.y > 1.5 || accl.z > 1.5) {
        // Tilt 🙂
        onLose();
    }
}

The first obvious usage of these events is to control a game. You can also use them for gesture recognition or for detecting the orientation of the user to use accordingly with a map.

Creating the ball game

The game that we will create is a simple ball game where you must control a ball and make it move to specific points in order to gain points:

The particle system in the upper right corner defines the place where you must move the ball. Once the ball is near the good place, you will earn a point.

Every time you earn a point, the ball speed will be increased and the playground will rotate to increase difficulty.

So first of all, you need to create a simple html file with a reference to babylon.js (incredible!!):

<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
    <title>Device orientation - ball game</title>
    <link href="index.css" rel="stylesheet" />
    <script src="babylon.js"></script>
</head>
<body>
    <canvas id="renderCanvas"></canvas>   
    <div id="score">Score: 0</div>
    <div id="speed">Speed: 1</div>
    <div id="gameOver" class="hidden">
        <div id="gameOverText">Game Over</div>
    </div>
    <script src="index.js"></script>
</body>
</html>

Then inside index.js, we can create the 3D environment required by our game. The first thing to do is to create the engine and the scene;

var canvas = document.getElementById("renderCanvas");
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;

if (BABYLON.Engine.isSupported()) {

    var engine = new BABYLON.Engine(canvas, true);
    var scene = new BABYLON.Scene(engine);
    var light = new BABYLON.DirectionalLight("light", new BABYLON.Vector3(2, -10, 5), scene);
    var camera = new BABYLON.ArcRotateCamera("camera", 3 * Math.PI / 2.0, Math.PI / 4.0, 20.0, new BABYLON.Vector3(0, 0, 0), scene);

    scene.activeCamera = camera;

You will also need a render loop to ensure frames are drawn to the canvas:

engine.runRenderLoop(function () {
    scene.render();

    if (!started) {
        return;
    }

});

For now, the screen is a bit empty:

Then we can create the starfield to get a cool background. It will be created as a particle system:

// Starfield
var starfield = new BABYLON.ParticleSystem("particles", 4000, scene);
starfield.particleTexture = new BABYLON.Texture("star.png", scene);
starfield.minAngularSpeed = -4.5;
starfield.maxAngularSpeed = 4.5;
starfield.minSize = 0.5;
starfield.maxSize = 1.0;
starfield.minLifeTime = 0.5;
starfield.maxLifeTime = 2.0;
starfield.minEmitPower = 0.5;
starfield.maxEmitPower = 1.0;
starfield.emitRate = 600;
starfield.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE;
starfield.minEmitBox = new BABYLON.Vector3(-25, 0, -25);
starfield.maxEmitBox = new BABYLON.Vector3(25, 0, 25);
starfield.direction1 = new BABYLON.Vector3(0, 1, 0);
starfield.direction2 = new BABYLON.Vector3(0, 1, 0);
starfield.color1 = new BABYLON.Color4(0, 0, 0, 1);
starfield.color2 = new BABYLON.Color4(1, 1, 1, 1);
starfield.gravity = new BABYLON.Vector3(0, 5, 0);
starfield.emitter = new BABYLON.Vector3(0, -2, 0);
starfield.start();

For more information on particle system, you can go here.

Now it starts to have a good looking:

Then we have to create the ball (a simple sphere), add a material and prepare a small animation (used when the ball grabs a point):

// Ball
var ball = BABYLON.Mesh.CreateSphere("ball", 16, 1.0, scene, false);
var ballMaterial = new BABYLON.StandardMaterial("ballMaterial", scene);
ballMaterial.diffuseColor = new BABYLON.Color3(1, 0, 0);
ballMaterial.diffuseTexture = new BABYLON.Texture("amiga.jpg", scene);
ballMaterial.diffuseTexture.uScale = 3;
ballMaterial.diffuseTexture.vScale = 4;
ball.material = ballMaterial;
ball.position = new BABYLON.Vector3(0, 0.5, 0);
ball.renderingGroupId = 1;
ball.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(0, 0, 0);
var animationScale = new BABYLON.Animation("scale", "scaling", 30, BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
animationScale.setKeys([{ frame: 0, value: new BABYLON.Vector3(1, 1, 1) }, { frame: 20, value: new BABYLON.Vector3(2.0, 2.0, 2.0) },
                        { frame: 40, value: new BABYLON.Vector3(1, 1, 1) }]);
ball.animations.push(animationScale);

Please note the usage of ball.renderingGroupId = 1 that will allow the ball (and the playground to be on a different layer than the starfield in order to avoid having stars that are going through the playground).

For more information on how to create simple objects with babylon.js, you can go there.

For more information on materials, you can go here.

For more information on animations, you can go here.

The ball is the center of the universe:

The playground will be a simple plane textured with a wood picture:

// Playground
var ground = BABYLON.Mesh.CreateGround("ground", 20, 20, 1, scene, false);
var groundMaterial = new BABYLON.StandardMaterial("groundMaterial", scene);
groundMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
groundMaterial.diffuseTexture = new BABYLON.Texture("wood.png", scene);
groundMaterial.diffuseTexture.uScale = 2;
groundMaterial.diffuseTexture.vScale = 2;
ground.material = groundMaterial;
ground.receiveShadows = true;
ground.renderingGroupId = 1;

The game is almost ready:

To add a more realistic effect, let’s add some shadows:

// Shadows
var shadowCaster = new BABYLON.ShadowGenerator(1024, light);
light.position = new BABYLON.Vector3(-4, 14, -12.5);
shadowCaster.useVarianceShadowMap = true;
shadowCaster.getShadowMap().renderList.push(ball);

You can have more information about shadows here.

And it looks great:

The final thing to add is the target (ie. place where to go to gain one point). We will also use a particle system here:

// Target
var target = new BABYLON.ParticleSystem("particles", 4000, scene);
target.particleTexture = new BABYLON.Texture("star.png", scene);
target.minAngularSpeed = -4.5;
target.maxAngularSpeed = 4.5;
target.minSize = 0.5;
target.maxSize = 3.0;
target.minLifeTime = 0.5;
target.maxLifeTime = 2.0;
target.minEmitPower = 0.5;
target.maxEmitPower = 1.0;
target.emitRate = 200;
target.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE;
target.minEmitBox = new BABYLON.Vector3(-1, 0, -1);
target.maxEmitBox = new BABYLON.Vector3(1, 0, 1);
target.direction1 = new BABYLON.Vector3(0, 1, 0);
target.direction2 = new BABYLON.Vector3(0, 1, 0);
target.color1 = new BABYLON.Color4(1, 1, 0, 1);
target.color2 = new BABYLON.Color4(1, 1, 1, 1);
target.gravity = new BABYLON.Vector3(0, 5, 0);
target.emitter = new BABYLON.Vector3(8, 0, 8);
target.renderingGroupId = 1;
target.start();

Our game is ready to be played:

Adding DeviceOrientation events to our game

Using the DeviceOrientation events is pretty straightforward. The ball will be controlled using the device rotation. To do so, you need some variables to store the current and previous rotations values:

var orientationGamma = 0;
var orientationBeta = 0;
var initialOrientationGamma = 0;
var initialOrientationBeta = 0;

Using these variables, here is the code to detect rotations changes:

// Orientation
window.addEventListener("deviceorientation", moveBall);
function moveBall(evt) {
    if (!started) {
        return;
    }
    if (!initialOrientationGamma) {
        initialOrientationGamma = evt.gamma;
        initialOrientationBeta = evt.beta;
    }

    orientationGamma = evt.gamma;
    orientationBeta = evt.beta;
}

window.addEventListener("devicemotion", detectShake);
function detectShake(evt) {
    var accl = evt.acceleration;
    if (accl.x > 1.5 || accl.y > 1.5 || accl.z > 1.5) {
        // Tilt 🙂
        onLose();
    }
}

You can note that gamma and beta values are used here. The devicemotion is used to simulate a “tilt” when you shake too quickly the device.

For the sake of simplicity, I will not include code for onLose (and onWin) functions but you can find them in the game source code available below.

You then have to update the renderLoop to use these values:

engine.runRenderLoop(function () {
    scene.render();


    // Compute direction
    if (orientationGamma) {
        var z = (initialOrientationBeta - orientationBeta) * 0.05;
        var x = (initialOrientationGamma - orientationGamma) * -0.05;
        direction.addInPlace(new BABYLON.Vector3(0, 0, z * speed * scale));
        direction.addInPlace(new BABYLON.Vector3(x * speed * scale, 0, 0));
    }

    // Moving and rotating ball
    ball.position.addInPlace(direction);
    var rotationToApply = BABYLON.Quaternion.RotationYawPitchRoll(0, direction.z * 1.5, -direction.x * 1.5);
    ball.rotationQuaternion = rotationToApply.multiply(ball.rotationQuaternion);

    direction.scaleInPlace(0.95);

    // Collisions
    checkCollisions();
});

Gamma rotation controls the direction to x and beta to z. The ball is then moved accordingly and rotated a bit in the right direction to simulate a rolling.

The checkCollisions function just checks if the ball is still inside the playground and if the target is not reached (to call the onWin function then):

// Collisions
var checkCollisions = function() {
    // Target met
    if (BABYLON.Vector3.Distance(ball.position, target.emitter) < 1.2) {
        onWin();
        return;
    }

    var point = ball.position.clone();
    point.y -= 0.5;
    if (!ground.intersectsPoint(point)) {
        onLose();
    }
};

And that’s it. You now have a modern, beautiful and “device orientation controlled” game!

The complete game

The complete game also supports cursors keys. You can find the code here. Feel free to use it as a base for your own applications!

Going further

If you want to go further, here are some pointers:

How to Improve ergonomy of your JavaScript/HTML5/CSS3 Windows 8.1 apps with the new navigation bar control

Windows 8.1 added a cool new control to WinJS: the navigation bar. This controls can be really helpful when it comes to organize the navigation inside your application. It allows you to create chapters and sub-chapters and then it helps the user to get access to all parts of your application.

For instance, here is the navigation bar of Urzagatherer:

Implementing the navigation bar

This bar is created using the following HTML code:

<div id="navBar" data-win-control="WinJS.UI.NavBar">
        <div id="navMenu" data-win-control="WinJS.UI.NavBarContainer">
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'homeLink', icon: 'home' }" 
                                                           data-win-res="{winControl: {label:'Home'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'toolsGroup', icon: 'repair', splitButton: 'true' }" 
                                                           data-win-res="{winControl: {label:'Tools'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'optionsGroup', icon: 'settings', splitButton: 'true' }" 
                                                           data-win-res="{winControl: {label:'Options'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'statisticsLink', icon: 'paste' }" 
                                                           data-win-res="{winControl: {label:'Statistics'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'searchLink', icon: 'find' }" 
                                                           data-win-res="{winControl: {label:'AdvancedSearch'}}"></div>
        </div>
        <div id="searchZone">
            <div id="searchButton" class="win-searchbox-button searchglyph"></div>
            <div id="searchBox" class="SearchBox" data-win-control="WinJS.UI.SearchBox"></div>
        </div>
    </div>

A navigation bar (WinJS.UI.Navbar) contains some WinJS.UI.NavBarContainer which in turn contains WinJS.UI.NavBarCommand.

The navigation bar can also contain basic controls such as the search box here in my example.

The NavBarCommand can use “splitButton = true” to specify it will contain a sub-level. For instance, here is the declaration for the flyout that will be used as su-level for the Tools button:

<div id="toolsGroupFlyout" data-win-control="WinJS.UI.Flyout" data-win-options="{ placement: 'bottom' }">
        <div id="toolsGroupNavBarContainer" data-win-control="WinJS.UI.NavBarContainer">
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'listsLink', icon: 'list' }" 
                                                           data-win-res="{winControl: {label:'Lists'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'decksLink', icon: 'calendarweek' }" 
                                                           data-win-res="{winControl: {label:'Decks'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'lifeCountersLink', icon: 'trim' }" 
                                                           data-win-res="{winControl: {label:'LifeCounters'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'myCardsLink', icon: 'paste' }" 
                                                           data-win-res="{winControl: {label:'AllExceptMissing'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'newsLink', icon: 'globe' }" 
                                                           data-win-res="{winControl: {label:'News'}}"></div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{ id:'slideshowLink', icon: 'slideshow' }" 
                                                           data-win-res="{winControl: {label:'slideshow'}}"></div>
        </div>
    </div>

You will need to add some JavaScript code in order to connect everything.

First of all, here is the code for the non-splitted buttons:

document.querySelector('#navBar').addEventListener('invoked', function (ev) {
    var navbarCommand = ev.detail.navbarCommand;

    switch (navbarCommand.id) {
        case "homeLink":
            while (nav.canGoBack) {
                nav.back();
            }
            break;
        case "statisticsLink":
            nav.navigate("/pages/collectionStatistics/collectionStatistics.html", {});
            break;
        case "searchLink":
            nav.navigate("/pages/advancedsearch/advancedsearch.html", {});
            break;
    }
});

Using the navbarCommand.id, you can determine which button was pushed and then react accordingly.

To work with the sub-menus, you have to connect to the splittoggle event of the NavBarContainer.

Using this event, you will handle the opening and the closing of the flyout used as sub-menu:

navMenu.addEventListener('splittoggle', function (ev) {
    var flyout;
    // Choose the right flyout 
    if (ev.detail.index == 2) {
        flyout = document.getElementById("optionsGroupFlyout").winControl;
    } else {
        flyout = document.getElementById("toolsGroupFlyout").winControl;
    }

    var navbarCommand = ev.detail.navbarCommand;
    if (ev.detail.opened) {
        flyout.show(navbarCommand.element);
        var subNavBarContainer = flyout.element.querySelector('.win-navbarcontainer');
        if (subNavBarContainer) {
            // Switching the navbarcontainer from display none to display block requires 
            // forceLayout in case there was a pending measure.
            subNavBarContainer.winControl.forceLayout();
            // Reset back to the first item:
            subNavBarContainer.currentIndex = 0;
        }
        flyout.addEventListener('beforehide', go);
    } else {
        flyout.removeEventListener('beforehide', go);
        flyout.hide();
    }

    function go() {
        flyout.removeEventListener('beforehide', go);
        navbarCommand.splitOpened = false;
    }
});

Eventually, you have to handle the click for items inside the sub-menu with a regular invoked event:

document.querySelector('#optionsGroupNavBarContainer').addEventListener('invoked', function (ev) {
                        var navbarCommand = ev.detail.navbarCommand;

                        switch (navbarCommand.id) {
                            case "slideShowButton":
                                setSlideShow();
                                break;
                            case "dataButton":
                                document.getElementById("databaseDiv").winControl.show();
                                break;
                            case "settingsButton":
                                document.getElementById("settingsDiv").winControl.show();
                                break;
                            case 'whatsnewButton':
                                document.getElementById("hintsDiv").winControl.show();
                                break;
                            case 'aboutButton':
                                document.getElementById("aboutDiv").winControl.show();
                                break;
                            case 'donateButton2':

                                donate();
                                break;
                        }
                    });

So to summarize you have to:

  • Declare a WinJS.UI.NavBar
  • Declare a WinJS.UI.NavBarContainer
  • Add some WinJS.UI.NavBarCommand to the container
  • Declare flyouts for sub-menus
  • Add code when button’s code is invoked
  • Handle the display of sub-menus using splittoggle event

Helping users discover your UI (and for instance the navigation bar)

Windows 8 modern apps have revolutionized the way windows communicates with users. All the chrome was removed to leave all the screen available for application’s content. However, this can lead your users to have some problems finding your navigation bar because they must be aware of the ways they can use to make it appears:

  • Right click with the mouse
  • Using the top or bottom edge gesture

That is why, based on feedbacks I got from my own users, I suggest you to add a small hint link this (the red drawings are not part of the image):

This small button is just here to indicate to users that more options are available. When the user clicks on this button, the following code can be executed to display the navigation bar:

// Hint
document.getElementById("navBarHint").onclick = function () {
    document.querySelector('#navBar').winControl.show();
};

This tips was also used by some Bing apps such as “Mail” (see the bottom bar)

I hope you will like the navigation bar and used it to improve your apps for Windows 8.1!

Reducing the pressure on the garbage collector by using the F12 developer bar of Internet Explorer 11

As you may know, I’m working on a 3D engine for WebGL (Babylon.js) during my spare time. A 3D engine is a place where matrices, vectors and quaternions live. And there may be tons of them!

Please note that everything done here applies to Internet Explorer 11 and Windows 8.1 apps developed with HTML5/JavaScript.

Removing non required instantiations

For instance, let’s have a look at this scene:

Using the F12 developer bar, you can launch a profiler to analyze what is going on from the point of view of the performance. The profiler has a Start/Stop button to capture a period of time and then give you this screen:

The drawElements function is the function that *EFFECTIVELY* renders the objects. We’re then not surprised to get it first. The second one (multiply) is about multiplying two matrices. This function is used a lot. Indeed, for each object, you have to compute the matrix required to draw it, the matrix to compute the position of every texture, etc…

multiply is used more than 12000 times during a period of 2 seconds!

Here is the code for this function:

BABYLON.Matrix.prototype.multiply = function (other) {
    var result = new BABYLON.Matrix();

    result.m[0] = this.m[0] * other.m[0] + this.m[1] * other.m[4] + this.m[2] * other.m[8] + this.m[3] * other.m[12];
    result.m[1] = this.m[0] * other.m[1] + this.m[1] * other.m[5] + this.m[2] * other.m[9] + this.m[3] * other.m[13];
    result.m[2] = this.m[0] * other.m[2] + this.m[1] * other.m[6] + this.m[2] * other.m[10] + this.m[3] * other.m[14];
    result.m[3] = this.m[0] * other.m[3] + this.m[1] * other.m[7] + this.m[2] * other.m[11] + this.m[3] * other.m[15];

    result.m[4] = this.m[4] * other.m[0] + this.m[5] * other.m[4] + this.m[6] * other.m[8] + this.m[7] * other.m[12];
    result.m[5] = this.m[4] * other.m[1] + this.m[5] * other.m[5] + this.m[6] * other.m[9] + this.m[7] * other.m[13];
    result.m[6] = this.m[4] * other.m[2] + this.m[5] * other.m[6] + this.m[6] * other.m[10] + this.m[7] * other.m[14];
    result.m[7] = this.m[4] * other.m[3] + this.m[5] * other.m[7] + this.m[6] * other.m[11] + this.m[7] * other.m[15];

    result.m[8] = this.m[8] * other.m[0] + this.m[9] * other.m[4] + this.m[10] * other.m[8] + this.m[11] * other.m[12];
    result.m[9] = this.m[8] * other.m[1] + this.m[9] * other.m[5] + this.m[10] * other.m[9] + this.m[11] * other.m[13];
    result.m[10] = this.m[8] * other.m[2] + this.m[9] * other.m[6] + this.m[10] * other.m[10] + this.m[11] * other.m[14];
    result.m[11] = this.m[8] * other.m[3] + this.m[9] * other.m[7] + this.m[10] * other.m[11] + this.m[11] * other.m[15];

    result.m[12] = this.m[12] * other.m[0] + this.m[13] * other.m[4] + this.m[14] * other.m[8] + this.m[15] * other.m[12];
    result.m[13] = this.m[12] * other.m[1] + this.m[13] * other.m[5] + this.m[14] * other.m[9] + this.m[15] * other.m[13];
    result.m[14] = this.m[12] * other.m[2] + this.m[13] * other.m[6] + this.m[14] * other.m[10] + this.m[15] * other.m[14];
    result.m[15] = this.m[12] * other.m[3] + this.m[13] * other.m[7] + this.m[14] * other.m[11] + this.m[15] * other.m[15];

    return result;
};

It is a bit brutal but there is nothing complex.

Things are going crazy when you use the F12 developer bar to track the responsiveness of your page:

As you can see the garbage collector (orange bars) is called very often! And this is not a good thing because it can lead to visual glitches due to interruption in your frames’ rendering.

On the same screen, you can also have more details:

This capture shows an important thing: The garbage collector runs on a background thread (12516) which is really good to free time for the render thread (you can see that the garbage collector runs simultaneously with the animation frame callback (babylon.js uses requestAnimationFrame to render each frame).

Even if the garbage collector of IE11 runs on a background thread, we have to reduce the memory pressure. This is because our code can run on a low end hardware where threads are not available or because not all browsers have a background garbage collector.

So as much as you can, do not rely on instantiation (the new BABYLON.Matrix() here). You should prefer reusing objects instead of creating new ones. The updated multiply function can be then:

BABYLON.Matrix.prototype.multiplyToRef = function (other, result) {
    result[0] = this.m[0] * other.m[0] + this.m[1] * other.m[4] + this.m[2] * other.m[8] + this.m[3] * other.m[12];
    result[1] = this.m[0] * other.m[1] + this.m[1] * other.m[5] + this.m[2] * other.m[9] + this.m[3] * other.m[13];
    result[2] = this.m[0] * other.m[2] + this.m[1] * other.m[6] + this.m[2] * other.m[10] + this.m[3] * other.m[14];
    result[3] = this.m[0] * other.m[3] + this.m[1] * other.m[7] + this.m[2] * other.m[11] + this.m[3] * other.m[15];

    result[4] = this.m[4] * other.m[0] + this.m[5] * other.m[4] + this.m[6] * other.m[8] + this.m[7] * other.m[12];
    result[5] = this.m[4] * other.m[1] + this.m[5] * other.m[5] + this.m[6] * other.m[9] + this.m[7] * other.m[13];
    result[6] = this.m[4] * other.m[2] + this.m[5] * other.m[6] + this.m[6] * other.m[10] + this.m[7] * other.m[14];
    result[7] = this.m[4] * other.m[3] + this.m[5] * other.m[7] + this.m[6] * other.m[11] + this.m[7] * other.m[15];

    result[8] = this.m[8] * other.m[0] + this.m[9] * other.m[4] + this.m[10] * other.m[8] + this.m[11] * other.m[12];
    result[9] = this.m[8] * other.m[1] + this.m[9] * other.m[5] + this.m[10] * other.m[9] + this.m[11] * other.m[13];
    result[10] = this.m[8] * other.m[2] + this.m[9] * other.m[6] + this.m[10] * other.m[10] + this.m[11] * other.m[14];
    result[11] = this.m[8] * other.m[3] + this.m[9] * other.m[7] + this.m[10] * other.m[11] + this.m[11] * other.m[15];

    result[12] = this.m[12] * other.m[0] + this.m[13] * other.m[4] + this.m[14] * other.m[8] + this.m[15] * other.m[12];
    result[13] = this.m[12] * other.m[1] + this.m[13] * other.m[5] + this.m[14] * other.m[9] + this.m[15] * other.m[13];
    result[14] = this.m[12] * other.m[2] + this.m[13] * other.m[6] + this.m[14] * other.m[10] + this.m[15] * other.m[14];
    result[15] = this.m[12] * other.m[3] + this.m[13] * other.m[7] + this.m[14] * other.m[11] + this.m[15] * other.m[15];
};

Almost the same thing without the instantiation! But removing 6000 instantiations per second can be a great optimization!

The point here is that you have to create a storage matrix for each operation (the matrix is created once inside the constructor and reuse each time the multiply operation needs to be used).

After doing the same thing for every function working with matrices, vectors, colors and quaternions, the responsiveness graph of babylon.js is far better:

Great isn’t it? Obviously the garbage collector will be called but in a less frequent way.

GC Friendly array object

I also found another solution to remove the memory pressure. Indeed, during a frame’s render, I have to use a lot of arrays to determine active objects, active shaders, active particles, etc…

So basically at the beginning of every frame, I was using this code:

this._activeMeshes = [];

But obviously even if the code is simple, it has a big impact on memory. That’s why I decided to create a new kind of array that is able to reuse the initially allocated space:

// Garbage collector friendly array
BABYLON.Tools.GCFriendlytArray = function (capacity) {
    this.data = new Array(capacity);
    this.length = 0;
};

BABYLON.Tools.GCFriendlytArray.prototype.push = function (value) {
    if (this.length >= this.data.length) {
        this.data.length *= 2;
    }
    this.data[this.length++] = value;
};

BABYLON.Tools.GCFriendlytArray.prototype.reset = function () {
    this.length = 0;
};

BABYLON.Tools.GCFriendlytArray.prototype.indexOf = function (value) {
    var position = this.data.indexOf(value);

    if (position >= this.length) {
        return -1;
    }

    return position;
};

With this small piece of code, you can have an array that can be reset in order to reuse its memory. You can create it with an estimated size and just call reset() to, well, reset it.

Using our new array is like using a standard array, you have a length property and a push function. The only difference is when you want to access data because you have to use myArray.data:

for (subIndex = 0; subIndex < activeMeshes.length; subIndex++) {
    activeMeshes.data[subIndex].render();
}

Some additional notes

Please note that the optimizations described here are useful in my case because I was looking for performances and I did not care about memory consumptions. Indeed, I had to use a lot of memory to create the required cached objects.

For instance, the GC friendly arrays have to reserve a lot of memory that will not necessary be used. The tradeoff between memory and performance must be taken seriously.

Going further

Please find here some great links about the F12 developer bar of IE delivered during Build 2013:

Windows 8 &#038; 8.1: Improve the visibility of your app by inviting users to rate it

The rule is the same for all applications stores. The more good ratings you have, the more visible your app will be.

And there are some simple things you can do to increase the number of good ratings you can get:

  • Create a good app. There is no magical way to transform a crap app into a wonderful and super useful app.
  • Invite your user to rate the app: Users are not always accustomed to the rating system. Your app must help them discover the feature and obviously it should encourage them to give a good rating.

To create a good app, you can find a lot of information on the Microsoft Dev Center.

For inviting users to rate your app, many strategies can be applied and I will talk about two of them in this article. I used both of them for my app Urzagatherer and I’m pretty satisfied by the result:

I will use JavaScript for the code samples. Obviously the same thing can be done with .NET as I only use WinRT code.

Strategy 1 – At the very first launch

The first solution I used to invite users to rate my application was to display a screen with a button to rate the application at the first launch of the app.

To do so, you just have to compare the current version of the application with a locally saved variable:

var currentVersion = version.major + "." + version.minor + "." + version.build + "." + version.revision;
var hintsVersion = Windows.Storage.ApplicationData.current.localSettings.values["hintsVersion"];

if (!hintsVersion || hintsVersion != currentVersion) {
    // Display the invitation

    Windows.Storage.ApplicationData.current.localSettings.values["hintsVersion"] = currentVersion;
}

Simple, isn’t it? You just have to save the current version to the local settings so that you will not bother the user twice. In my case, I also add a “what’s new” list to the invitation screen:

Strategy 2 – When you are sure that the user likes your app

Another solution can be to check that the users REALLY appreciate your app before talking about rating. To do so, we can again use a locally saved variable and increment it every time the user launches the app. When the count is equal to a specific value you can display the invitation:

var currentVersion = version.major + "." + version.minor + "." + version.build + "." + version.revision;
var hintsVersion = Windows.Storage.ApplicationData.current.localSettings.values["hintsVersion"];

if (!hintsVersion || hintsVersion != currentVersion) {
    Windows.Storage.ApplicationData.current.localSettings.values["hintsVersion"] = currentVersion;
    Windows.Storage.ApplicationData.current.localSettings.values["hintsCount"] = 1;
} else {
    var count = Windows.Storage.ApplicationData.current.localSettings.values["hintsCount"];
    count++;
    Windows.Storage.ApplicationData.current.localSettings.values["hintsCount"] = count;

    if (count == 5) {
        // Display the invitation
    }
}

Displaying the invitation

For displaying the invitation in a non intrusive way, I decided to use a SettingsFlyout (or a _Popup_ in XAML):

<div id="hintsDiv" data-win-control="WinJS.UI.SettingsFlyout" data-win-options="{width:'wide'}">
     <div class="win-header accent-back">
         <button type="button" onclick="WinJS.UI.SettingsFlyout.show()" class="win-backbutton">
         </button>
         <div class="win-label" data-win-res="{innerText: 'WhatsNewTitle'}"></div>
     </div>
     <div class="win-content" id="whatsnew">
         <div class="whatsnewBlock hintBlock accent-back" id="feature00"></div>
         <div class="newsBlock" id="feature00Text" data-win-res="{innerHTML: 'feature00'}"></div>
         <div class="whatsnewBlock hintBlock accent-back" id="feature01"></div>
         <div class="newsBlock" id="feature01Text" data-win-res="{innerHTML: 'feature01'}"></div>
         <div class="whatsnewBlock hintBlock accent-back" id="feature02"></div>
         <div class="newsBlock" id="feature02Text" data-win-res="{innerHTML: 'feature02'}"></div>
         <div class="whatsnewBlock hintBlock accent-back" id="feature03"></div>
         <div class="newsBlock" id="feature03Text" data-win-res="{innerHTML: 'feature03'}"></div>
         <div class="whatsnewBlock hintBlock accent-back" id="feature04"></div>
         <div class="newsBlock" id="feature04Text" data-win-res="{innerHTML: 'feature04'}"></div>
         <div class="whatsnewBlock hintBlock accent-back" id="feature05"></div>
         <div class="newsBlock" id="feature05Text" data-win-res="{innerHTML: 'feature05'}"></div>
         <div class="whatsnewBlock hintBlock accent-back" id="feature06"></div>
         <div class="newsBlock" id="feature06Text" data-win-res="{innerHTML: 'feature06'}"></div>
         <hr id="hintsSeparator" />
         <button id="rateButton" class="externalButton" data-win-res="{innerText: 'rateApp'}"></button>
         <button id="facebookButton" class="externalButton" data-win-res="{innerText: 'facebook'}"></button>
         <button id="donateButton" class="externalButton" data-win-res="{innerText: 'donate'}"></button>
     </div>
 </div>

To display it, just use this code:

document.getElementById("hintsDiv").winControl.show();

Invoking the rating screen

Finally when the user clicks on the rate button, you have to call this WinRT functions to navigate to the Windows’s rating screen:

Windows.System.Launcher.launchUriAsync(
          new Windows.Foundation.Uri("ms-windows-store:REVIEW?PFN=15798DavidCatuhe.UrzaGatherer_x8akzp4bebrnj")
);

To find the good Uri for your app, you must open the package.appxmanifest file in your project and go to the Packaging tab:

The Package family name value is the key for your Uri.

Other things

There are tons of others thing to do to be able to gather a lot of ratings but these two solutions are a good start. Do not also forget to check the comments of your users and to update accordingly your app.

Creating a 3D chart for your Windows 8.1 app using babylon.js

Windows 8.1 added the support of WebGL for Internet Explorer and JavaScript applications. This is a huge evolution because we are now able to unleash the raw power of the GPU even with HTML5 and JavaScript!

This power can be tricky to master and that’s why I created babylon.js. And using it, the wonderful world of accelerated 3D will welcome you.

Today, I would like to show you how to use babylon.js inside your app in order to improve user experience:



Preparing the project

For instance, I always wanted to create an app to have my blog’s statistics at a glance.

If you want to get the final application, you can download the complete project here (127KB)

To do so, let’s start with a empty Windows 8.1 JavaScript app.

The first thing is to reference babylon.js (and hand.js for supporting touch events):

The default.html page should be changed to add a canvas and to reference babylon.js and hand.js:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Chart3D</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.2.0.Preview/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.2.0.Preview/js/base.js"></script>
    <script src="//Microsoft.WinJS.2.0.Preview/js/ui.js"></script>

    <!-- Chart3D references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="js/hand.minified-1.1.1.js"></script>
    <script src="js/babylon.js"></script>
    <script src="/js/default.js"></script>
</head>
<body>
    <canvas id="renderCanvas"></canvas>
</body>
</html>

Connecting babylon.js

As you may have seen in my previous posts, babylon.js needs to connect with the canvas through the BABYLON.Engine object. We can do that right after the completion of the processAll function:

args.setPromise(WinJS.UI.processAll().then(function() {
                var canvas = document.getElementById("renderCanvas");
                var engine = new BABYLON.Engine(canvas, true);

Then we have to create some entities required to generate a complete scene:

var scene = new BABYLON.Scene(engine);
var light = new BABYLON.DirectionalLight("dir01", new BABYLON.Vector3(0, -0.5, 1.0), scene);
var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 10, BABYLON.Vector3.Zero(), scene);
camera.setPosition(new BABYLON.Vector3(20, 70, -100));
light.position = new BABYLON.Vector3(0, 25, -50);

The scene, a light and a camera to define the user’s point of view. Nothing special here.

Finally we have to connect the camera with the canvas (to allow the user to control the camera) and launch the render loop:

// Render
camera.attachControl(canvas);

engine.runRenderLoop(function () {
    scene.render();
});

// Resize
window.addEventListener("resize", function () {
    engine.resize();
});

Creating the ground and the background

If we launch our app right now, it will be a little bit empty. Indeed there is nothing to display.

Let’s add the ground and the background to create something like this:

The ground will be generated with BABYLON.Mesh.CreateGround (!!) and the background with BABYLON.Mesh.CreatePlane:

var playgroundSize = 100;
// Background
var background = BABYLON.Mesh.CreatePlane("background", playgroundSize, scene, false);
background.material = new BABYLON.StandardMaterial("background", scene);
background.scaling.y = 0.5;
background.position.z = playgroundSize / 2 - 0.5;
background.position.y = playgroundSize / 4;

var backgroundTexture = new BABYLON.DynamicTexture("dynamic texture", 512, scene, true);
background.material.diffuseTexture = backgroundTexture;
background.material.specularColor = new BABYLON.Color3(0, 0, 0);
background.material.backFaceCulling = false;

backgroundTexture.drawText("Eternalcoding", null, 80, "bold 70px Segoe UI", "white", "#555555");
backgroundTexture.drawText("- browsers statistics -", null, 250, "35px Segoe UI", "white", null);

// Ground    
var ground = BABYLON.Mesh.CreateGround("ground", playgroundSize, playgroundSize, 1, scene, false);
var groundMaterial = new BABYLON.StandardMaterial("ground", scene);
groundMaterial.diffuseColor = new BABYLON.Color3(0.5, 0.5, 0.5);
groundMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
ground.material = groundMaterial;

ground.position.y = -0.1;

The main point to note here is the usage of a BABYLON.DynamicTexture: This object allows you to draw in a texture with a canvas. There are also some handy functions like drawText to simplify complex tasks. Instead of using drawText you could have written the following code (just for the sake of comprehension):

 BABYLON.DynamicTexture.prototype.drawText = function (text, x, y, font, color, clearColor, invertY) {
     var size = this.getSize();
     if (clearColor) {
         this._context.fillStyle = clearColor;
         this._context.fillRect(0, 0, size.width, size.height);
     }

     this._context.font = font;
     if (x === null) {
         var textSize = this._context.measureText(text);
         x = (size.width - textSize.width) / 2;
     }

     this._context.fillStyle = color;
     this._context.fillText(text, x, y);

     this.update(invertY);
 };

As you can see this is a regular 2D canvas code.

Adding the series’ data

Now it is time to add some data to display. For not complicating things up, we will consider static data but obviously you are free to use dynamic data:

var browsers_Series = [
    { label: "IE", value: 32, color: new BABYLON.Color3(0, 0, 1) },
    { label: "Chrome", value: 28, color: new BABYLON.Color3(1, 0, 0) },
    { label: "Firefox", value: 16, color: new BABYLON.Color3(1, 0, 1) },
    { label: "Opera", value: 14, color: new BABYLON.Color3(1, 1, 0) },
    { label: "Safari", value: 10, color: new BABYLON.Color3(0, 1, 1) }
];

Every entry is composed of a label, a value (which is a percentage) and a color.

To display them, we have to add a new function in our code:

var createSeries = function (series) {
    var margin = 2;
    var offset = playgroundSize / (series.length) - margin;
    var x = -playgroundSize / 2 + offset / 2;

    for (var index = 0; index < series.length; index++) {
        var data = series[index];

        var bar = BABYLON.Mesh.CreateBox(data.label, 1.0, scene, false);
        bar.scaling = new BABYLON.Vector3(offset / 2.0, data.value * scale, offset / 2.0);
        bar.position.x = x;
        bar.position.y = data.value * scale / 2.0;

        // Material
        bar.material = new BABYLON.StandardMaterial(data.label + "mat", scene);
        bar.material.diffuseColor = data.color;
        bar.material.emissiveColor = data.color.scale(0.3);
        bar.material.specularColor = new BABYLON.Color3(0, 0, 0);

        // Going next
        x += offset + margin;
    }
};

For each entry, we create a box associated with a colored material. The box is then scaled depending on the entry’s value. The result is the following screen:

Shadows

The previous screen may look a bit flat. We can improve things up by adding dynamic shadows.

Real-time shadows are complex to produce (you need to create a shadow map and then use it in your shaders). But with babylon.js, you just have to create a BABYLON.ShadowGenerator and define which objects cast shadows and which objects receive shadows:

// Shadows
var shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
ground.receiveShadows = true;
background.receiveShadows = true;

To cast shadows, boxes must be added to the shadowGenerator object:

shadowGenerator.getShadowMap().renderList.push(bar);

The result is more beautiful, isn’t it?

Adding the legend

There is an issue with our chart: no one can say the value and the associated label of each box. That is why we need to add a legend.

Every box will be associated with a small plane with a dynamic texture filled with the label and the value of the current entry:

To do so, we have to update our createSeries function in order to generate a legend for each entry:

// Legend
var barLegend = BABYLON.Mesh.CreateGround(data.label + "Legend", playgroundSize / 2, offset * 2, 1, scene, false);
barLegend.position.x = x;
barLegend.position.z = -playgroundSize / 4;
barLegend.rotation.y = Math.PI / 2;

barLegend.material = new BABYLON.StandardMaterial(data.label + "LegendMat", scene);
var barLegendTexture = new BABYLON.DynamicTexture("dynamic texture", 512, scene, true);
barLegendTexture.hasAlpha = true;
barLegend.material.diffuseTexture = barLegendTexture;
barLegend.material.emissiveColor = new BABYLON.Color3(0.4, 0.4, 0.4);

var size = barLegendTexture.getSize();
barLegendTexture.drawText(data.label + " (" + data.value + "%)", 80, size.height / 2 + 30, 
                                       "bold 50px Segoe UI", "white", "transparent", false);

Sprinkling a bit of animations

Finally for the “waoouh” effect, I suggest we can animate the boxes: They will start with a 0 height and they will grow up to their effective value:

var bar = BABYLON.Mesh.CreateBox(data.label, 1.0, scene, false);
bar.scaling = new BABYLON.Vector3(offset / 2.0, 0, offset / 2.0);
bar.position.x = x;
bar.position.y = 0;

// Animate a bit
var animation = new BABYLON.Animation("anim", "scaling", 30, BABYLON.Animation.ANIMATIONTYPE_VECTOR3);
animation.setKeys([
    { frame: 0, value: new BABYLON.Vector3(offset / 2.0, 0, offset / 2.0) },
    { frame: 100, value: new BABYLON.Vector3(offset / 2.0, data.value * scale, offset / 2.0) }]);
bar.animations.push(animation);

animation = new BABYLON.Animation("anim2", "position.y", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT);
animation.setKeys([
    { frame: 0, value: 0 },
    { frame: 100, value: (data.value * scale) / 2 }]);
bar.animations.push(animation);
scene.beginAnimation(bar, 0, 100, false, 2.0);

You can note that we create two animations: one for the scaling and one for the position (the pivot of each box is in the middle of the mesh). The scene.beginAnimation is then used to launch to animation.

Nothing complex here but a cool effect for the user.

Conclusion

If you want to go further, you can consider embedding this code in a control and work with dynamic data to achieve a really mind-lowing way to display data.

Going further with babylon.js

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

Babylon.js: Creating a convincing world for your game with custom shaders, height maps and skyboxes

After talking about multi-materials in the previous post, I would like to share with you a more advanced sample. This sample will allow me to introduce you some really powerful features of Babylon.js:

  • Height maps
  • Skyboxes
  • Custom shaders

The result will look like that (using IE11 preview in this case):




Click here if you want a live demonstration (If your browser supports WebGL of course)

This world is composed of a sky, a ground and a reflective/refractive water. So let’s discuss about each of them.

Preparing the web page

First of all we need a simple HTML 5 page with a full page canvas:

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

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

The page just needs to reference babylon.js (you can find the latest version here) and hand.js for the touch support (latest version here).

Then you can create a script block right after the canvas element with the following code:

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

        var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 10, BABYLON.Vector3.Zero(), scene);
        var sun = new BABYLON.PointLight("Omni0", new BABYLON.Vector3(60, 100, 10), scene);

        camera.setPosition(new BABYLON.Vector3(-40, 40, 0));

        var beforeRenderFunction = function () {
            // Camera
            if (camera.beta < 0.1)
                camera.beta = 0.1;
            else if (camera.beta > (Math.PI / 2) * 0.9)
                camera.beta = (Math.PI / 2) * 0.9;

            if (camera.radius > 50)
                camera.radius = 50;

            if (camera.radius < 5)
                camera.radius = 5;
        };

        camera.attachControl(canvas);

        scene.registerBeforeRender(beforeRenderFunction);

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

This code creates the engine, the main scene and add a camera and a light (the sun) to it.

The camera is an ArcRotateCamera so you can use your mouse/touch/keyboard to rotate around a central pivot. We just want to limit the amplitude of the camera with beforeRenderFunction function (because we don’t want to go under the ground or beyond the sky). This function is attached to the scene with registerBeforeRender so it will be called before every frame to guarantee our constraints.

Adding a skybox

A skybox is a box with a special material used to simulate the sky:




The material uses a special reflection texture. To create a skybox with Babylon.js you just have to use this code (because skyboxes are already supported by the StandardMaterial):

// Skybox
var skybox = BABYLON.Mesh.CreateBox("skyBox", 1000.0, scene);
var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
skyboxMaterial.backFaceCulling = false;
skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("skybox/skybox", scene);
skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
skybox.material = skyboxMaterial;

A skybox is just a box with a StandardMaterial. The key point is the CubeTexture used for the reflection channel. A cube texture is composed of 6 textures (one for each face of a cube). Babylon.js will choose the right one depending on the position of the viewer to simulate a continuous sky:


When you want to create a CubeTexture, you have to specify a file scheme based on the following; nx, ny, nz stand for negative (x, y, z) and px, py, pz stand for positive (x, y, z).

Adding the ground and the island

The ground is a simple plane textured with a repetitive bitmap:

To create it, the code is really simple:

var extraGround = BABYLON.Mesh.CreateGround("extraGround", 1000, 1000, 1, scene, false);
var extraGroundMaterial = new BABYLON.StandardMaterial("extraGround", scene);
extraGroundMaterial.diffuseTexture = new BABYLON.Texture("ground.jpg", scene);
extraGroundMaterial.diffuseTexture.uScale = 60;
extraGroundMaterial.diffuseTexture.vScale = 60;
extraGround.position.y = -2.05;
extraGround.material = extraGroundMaterial;

The diffuse texture is scaled by a ratio of 60 in order to repeat it along the ground.

The island also uses a plane but deforms it through an height map.

The height map is a simple map used to define the altitude of every vertex of the plane:

To use it, you have to create a plane with more subdivisions. The plane is then updated using the height map:

var ground = BABYLON.Mesh.CreateGroundFromHeightMap("ground", "heightMap.png", 100, 100, 100, 0, 10, scene, false);
var groundMaterial = new BABYLON.StandardMaterial("ground", scene);
groundMaterial.diffuseTexture = new BABYLON.Texture("ground.jpg", scene);
groundMaterial.diffuseTexture.uScale = 6;
groundMaterial.diffuseTexture.vScale = 6;
groundMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
ground.position.y = -2.0;
ground.material = groundMaterial;

The definition of the CreateGroundFromHeightMap is the following:

function (name, url, width, height, subdivisions, minHeight, maxHeight, scene, updatable)

As you can see the fifth parameter allows you to increase the complexity of your mesh in order to improve the visual quality of it:

The water

The water itself is just a simple plane created with the following code:

var water = BABYLON.Mesh.CreateGround("water", 1000, 1000, 1, scene, false);

The true water lies within the material used to display it. And this time we will not use the good old StandardMaterial.

Indeed, to create a convincing water surface, we need to take in account complex phenomena like refraction and reflection that the StandardMaterial is not intended to handle. To reproduce them, we will use a very powerful feature of Babylon.js: the render target textures. This kind of textures allows you to render a scene into a texture in order to use it later in your own shaders.

Creating an empty custom material

So we need to create our first custom material! To do so, we first need to add a new JavaScript file to our site. This file named waterMaterial.js will contains the following empty anonymous function:

(function() {
})();

Do not forget to reference it in your HTML page:

<script src="Water/waterMaterial.js"></script>

Starting from our empty anonymous function, let’s add a new object called WaterMaterial:

(function() {
    WaterMaterial = function (name, scene, light) {
        this.name = name;
        this.id = name;
        this.light = light;

        this._scene = scene;
        scene.materials.push(this);
    };

    WaterMaterial.prototype = Object.create(BABYLON.Material.prototype);

    // Properties   
    WaterMaterial.prototype.needAlphaBlending = function () {
        return false;
    };

    WaterMaterial.prototype.needAlphaTesting = function () {
        return false;
    };

    // Methods  
    WaterMaterial.prototype.isReady = function (mesh) {
        return true;
    };

    WaterMaterial.prototype.bind = function (world, mesh) {
    };

    WaterMaterial.prototype.dispose = function () {
        this.baseDispose();
    };
})();

This is the minimal code to provide for a custom material:

  1. A constructor to register the material to the scene and get important information (in my case I need the current light to simulate the sun)
  2. Our material MUST retrieve and use the BABYLON.Material prototype
  3. needAlphaBlending: The material must indicate to Babylon.js if it requires alpha blending (in our case we are not based on alpha blending but on render target textures)
  4. needAlphatesting: The material must indicate to Babylon.js if it requires alpha testing (same thing here, we do not need alpha testing)
  5. isReady: Babylon.js will call this function to know if the material is ready to be used
  6. bind: Babylon.js will call this function to activate the shader before rendering objects that use it
  7. dispose: This function allows you to release resources you may have created for your material

The vertex and fragment shaders

The next thing we need to prepare are the shaders themselves. Shaders define the code executed by the GPU to process the vertices sent by the meshes and the pixels produced by these vertices.

For more information about how a GPU works internally and how to create a 3D engine I suggest you to read the excellent series on how to create a 3D soft engine from scratch written by 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

The goal of this blog is not to talk about shaders and GLSL but we need them, so here is the vertex shader that we will use for our material:


#ifdef GL_ES
precision mediump float;
#endif

 


// Attributes
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;

// Uniforms
uniform vec2 waveData;
uniform mat4 windMatrix;
uniform mat4 world;
uniform mat4 worldViewProjection;

// Normal
varying vec3 vPositionW;
varying vec3 vNormalW;
varying vec4 vUV;
varying vec2 vBumpUV;

void main(void) {
    vec4 outPosition = worldViewProjection * vec4(position, 1.0);
    gl_Position = outPosition;

    vPositionW = vec3(world * vec4(position, 1.0));
    vNormalW = normalize(vec3(world * vec4(normal, 0.0)));

    vUV = outPosition;

    vec2 bumpTexCoord = vec2(windMatrix * vec4(uv, 0.0, 1.0));
    vBumpUV = bumpTexCoord / waveData.x;
}

And here is the fragment shader

#ifdef GL_ES
precision mediump float;
#endif

uniform vec3 vEyePosition;
uniform vec4 vLevels;
uniform vec3 waterColor;
uniform vec2 waveData;

// Lights
varying vec3 vPositionW;
varying vec3 vNormalW;
uniform vec3 vLightPosition;

// Refs
varying vec2 vBumpUV;
varying vec4 vUV;
uniform sampler2D refractionSampler;
uniform sampler2D reflectionSampler;
uniform sampler2D bumpSampler;

void main(void) {
    vec3 viewDirectionW = normalize(vEyePosition - vPositionW);

    // Light
    vec3 lightVectorW = normalize(vLightPosition - vPositionW);

    // Wave
    vec3 bumpNormal = 2.0 * texture2D(bumpSampler, vBumpUV).rgb - 1.0;
    vec2 perturbation = waveData.y * bumpNormal.rg;

    // diffuse
    float ndl = max(0., dot(vNormalW, lightVectorW));

    // Specular
    vec3 angleW = normalize(viewDirectionW + lightVectorW);
    float specComp = dot(normalize(vNormalW), angleW);
    specComp = pow(specComp, 256.);

    // Refraction
    vec2 texCoords;
    texCoords.x = vUV.x / vUV.w / 2.0 + 0.5;
    texCoords.y = vUV.y / vUV.w / 2.0 + 0.5;

    vec3 refractionColor = texture2D(refractionSampler, texCoords + perturbation).rgb;

    // Reflection
    vec3 reflectionColor = texture2D(reflectionSampler, texCoords + perturbation).rgb;

    // Fresnel
    float fresnelTerm = dot(viewDirectionW, vNormalW);
    fresnelTerm = clamp((1.0 - fresnelTerm) * vLevels.y, 0., 1.);

    // Water color

    vec3 finalColor = (waterColor * ndl) * vLevels.x + (1.0 - vLevels.x) * (reflectionColor * fresnelTerm * vLevels.z + 
                                                       (1.0 - fresnelTerm) * refractionColor * vLevels.w) + specComp;


    gl_FragColor = vec4(finalColor, 1.);
}

These shaders use many external variables to achieve the rendering. External variables (defined with the uniform keyword) are used to communicate between your code and the GPU. The GPU will execute the shaders code using the values provided to the external variables by your code:

  • waveData: Defines height and amplitude of waves
  • windMatrix: Defines the direction of the water
  • world: World matrix (Matrix of the current mesh)
  • worldViewProjection: Combined transformation matrix (world x view x projection)
  • vEyePosition: Camera’s position
  • vLightPosition: Sun’s position
  • vLevels: Blending levels of reflection and refraction
  • waterColor: Water’s color
  • refractionSampler: Variable used to read the refraction texture
  • reflectionSampler: Variable used to read the reflection texture
  • bumpSampler: Variable used to read the bump texture (which is used to generate the waves) 

To sum things up, we can decompose the shaders’ work through the following pipeline:

  1. The mesh is transformed by the vertex shader to generate the triangle used to find the pixels that require to be painted:

  1. Diffuse color is computed first (based on the sun position and on the water’s color)

  1. Specular is then added (based on camera’s position):

  1. The refraction texture is then used to simulate the transparency of the water:

  1. The bump texture is then used to add perturbations:

  1. The reflection texture is finally used to add the reflected objects (island and sky):

  1. The cherry on the cake is added by using a Fresnel computation in order to prioritize reflection or refraction depending on the view angle of the camera:



As you can see we start for an almost full reflection to finish to full with a full refraction when we are perpendicular with the ground.

Linking shaders to the material

Now we have created our shaders, we need to link them with the material. We also need to prepare data for the external variables used by the shaders. To do so, let’s update the constructor:

WaterMaterial = function (name, scene, light) {
    this.name = name;
    this.id = name;
    this.light = light;

    this._scene = scene;
    scene.materials.push(this);

    this.bumpTexture = new BABYLON.Texture("Water/bump.png", scene);
    this.bumpTexture.uScale = 2;
    this.bumpTexture.vScale = 2;
    this.bumpTexture.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE;
    this.bumpTexture.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE;

    this.reflectionTexture = new BABYLON.MirrorTexture("reflection", 512, scene, true);
    this.refractionTexture = new BABYLON.RenderTargetTexture("refraction", 512, scene, true); 
    this.reflectionTexture.mirrorPlane = new BABYLON.Plane(0, -1, 0, 0);

    this.refractionTexture.onBeforeRender = function() {
        BABYLON.clipPlane = new BABYLON.Plane(0, 1, 0, 0);
    };

    this.refractionTexture.onAfterRender = function() {
        BABYLON.clipPlane = null;
    };

    this.waterColor = new BABYLON.Color3(0.0, 0.3, 0.1);
    this.waterColorLevel = 0.2;
    this.fresnelLevel = 1.0;
    this.reflectionLevel = 0.6;
    this.refractionLevel = 0.8;

    this.waveLength = 0.1;
    this.waveHeight = 0.15;

    this.waterDirection = new BABYLON.Vector2(0, 1.0);

    this._time = 0;
};

The bump texture is a standard texture:

The reflection texture is created from a BABYLON.MirrorTexture which is able to simulate a mirror (exactly what we need!).

The refraction texture is based on a BABYLON.RenderTargetTexture. This kind of texture can receive the rendering of a scene and can then be used as standard texture resource for a shader. With the onBeforeRender and onAfterRender functions you can configure and restore back the scene for your rendering (In this case, I’ve just activated a clipping plane to limit the refraction to the objects over the water).

Then we need to add a new function to the WaterMaterial in order to register these two special textures:

WaterMaterial.prototype.getRenderTargetTextures = function () {
    var results = [];

    results.push(this.reflectionTexture);
    results.push(this.refractionTexture);

    return results;
};

This function is mandatory for us, because we need to have our textures prepared before using our shaders.

The link with the shaders itself is done with the isReady function:

WaterMaterial.prototype.isReady = function (mesh) {
    var engine = this._scene.getEngine();

    if (this.bumpTexture && !this.bumpTexture.isReady) {
        return false;
    }

    this._effect = engine.createEffect("Water/water",
        ["position", "normal", "uv"],
        ["worldViewProjection", "world", "view", "vLightPosition", "vEyePosition", "waterColor", "vLevels", "waveData", "windMatrix"],
        ["reflectionSampler", "refractionSampler", "bumpSampler"],
        "");

    if (!this._effect.isReady()) {
        return false;
    }

    return true;
};

The engine object has a function called createEffect that you can use to compile/link your shaders into a simple object. This function has the following parameters:

  • An array of attributes describing the topology of your vertices
  • An array of uniforms (the external variables) defined by the shaders
  • An array of samplers (the objects used to read textures)
  • An optional define string

The createEffect has an internal cache in order to compile/link your shaders only once (the subsequent calls return directly the cached effect).

Once the effect is created we can use it to transfer values to the shaders within the bind function:

WaterMaterial.prototype.bind = function (world, mesh) {
    this._time += 0.0001 * this._scene.getAnimationRatio();

    this._effect.setMatrix("world", world);
    this._effect.setMatrix("worldViewProjection", world.multiply(this._scene.getTransformMatrix()));
    this._effect.setVector3("vEyePosition", this._scene.activeCamera.position);
    this._effect.setVector3("vLightPosition", this.light.position);
    this._effect.setColor3("waterColor", this.waterColor);
    this._effect.setFloat4("vLevels", this.waterColorLevel, this.fresnelLevel, this.reflectionLevel, this.refractionLevel);
    this._effect.setFloat2("waveData", this.waveLength, this.waveHeight);

    // Textures        
    this._effect.setMatrix("windMatrix", this.bumpTexture._computeTextureMatrix().multiply(
                               BABYLON.Matrix.Translation(this.waterDirection.x * this._time, this.waterDirection.y * this._time, 0)));
    this._effect.setTexture("bumpSampler", this.bumpTexture);
    this._effect.setTexture("reflectionSampler", this.reflectionTexture);
    this._effect.setTexture("refractionSampler", this.refractionTexture);
};

Please note that I use the animated __time_ variable to generate the windMatrix variable in order to simulate waves movement.

Finally do not forget to clean things up when leaving.

WaterMaterial.prototype.dispose = function () {
    if (this.bumpTexture) {
        this.bumpTexture.dispose();
    }

    if (this.groundTexture) {
        this.groundTexture.dispose();
    }

    if (this.snowTexture) {
        this.snowTexture.dispose();
    }
    this.baseDispose();
};

Using our material

Now we have a specific material to simulate the water, we can go back to our HTML page. We have to attach the WaterMaterial to the water object and specify which meshes are used by the reflection and the refraction textures:

// Water
BABYLON.Engine.ShadersRepository = "";
var water = BABYLON.Mesh.CreateGround("water", 1000, 1000, 1, scene, false);
var waterMaterial = new WaterMaterial("water", scene, sun);
waterMaterial.refractionTexture.renderList.push(extraGround);
waterMaterial.refractionTexture.renderList.push(ground);

waterMaterial.reflectionTexture.renderList.push(ground);
waterMaterial.reflectionTexture.renderList.push(skybox);

water.material = waterMaterial;

One important thing to note here: The BABYLON.Engine.ShadersRepository is used to specify the path to shaders’ folder. For this demo I did not use one so we have to set it to empty string.

You are now ready to see your wonderful world with its so cute moving water.

Going further

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