WebGL is an OpenGL API created by the Khronos Group where it is possible to create some 3D apps inside a browser.
OpenGL
has been created in 1992 to do some 2D and 3D maths.OpenGL Embedded Systems
is a specification created for mobile console and web.- The
Khronos group
is a consortium of big companies such as Apple, Google, Nvidia, Intel, ... that are working to create free stuff
BabylonJS is a JavaScript library that allows to develop scenes inside a canvas tag with WebGL. It has been created by David Catuhe and David Rousset (Microsoft's developers) in 2013.
This is an object that will contain all the others. It is not a visible. [In cinéma: It is the place where all the actors will play and the action will happen. It stops to what the camera is seeing, even if the camera can go everywhere].
The scene contains the elements, and the graphic engine's job is to render them inside an image (handling the visible stuff in the screen). It will transform maths into a visible image. It is not a physic engine - this one gonna calculate the trajectories and gravity.
This is all about checking what to look for!
There is scene that contains a camera looking at a specific place with a graphic engine ready to receive the first calculations to do. Yet if we add an object, everything would be in the dark. Lights are there to enlight objects and create shadows.
They are the first visible elements. They are composed by several points to represents polygones and then faces. Every object in screen is a mesh.
A shader is an element associated to a mesh that will say to the graphic engine to react according to several parameters (réfraction et réflexion de la lumière, couleur, matériaux). It will create shadows, colors, lights on objects, ...
With everything above, it remains to ask the scene to render what has been created and to show it in the browser's tab. It's a requirement to do this several times to show some images per second - most of the time 60 FPS.
// Once DOM ready, here we go
document.addEventListener('DOMContentLoaded', function () {
new Game('renderCanvas')
}, false)
Heart = function (canvasId) {
var canvas = document.getElementById(canvasId)
// Will create a graphic engine based on Babylon and related to the canvas tag
var engine = new BABYLON.Engine(canvas, true)
// For the loop of the class
var _this = this
// Initialization of the scene with function associated to the Game object
this.scene = this._initScene(engine)
// Init a player and the map
var _player = new Player(_this, canvas)
var _map = new Map(_this)
// Generate the frames. Everything defined over there will be render as soon as possible
engine.runRenderLoop(function () {
_this.scene.render()
})
// Re-calculation while resizing
window.addEventListener('resize', function () {
if (engine) {
// Native function
engine.resize()
}
}, false)
}
Game.prototype = {
// Initialization prototype of the scene
_initScene: function (engine) {
// Everything will be contain inside the scene
var scene = new BABYLON.Scene(engine)
// Define the background color of the app (it should not be visible in the future)
scene.clearColor = new BABYLON.Color3(0, 0, 0)
return scene
}
}
Player = function (game, canvas) {
// The scene of the game
this.scene = game.scene
// Initialization of the camera
this._initCamera(this.scene, canvas)
}
Player.prototype = {
_initCamera: function (scene, canvas) {
// Creation of the camera
this.camera = new BABYLON.FreeCamera('camera', new BABYLON.Vector3(0, 5, -10), scene)
// Set the camera to look at the zero point of the scene
this.camera.setTarget(BABYLON.Vector3.Zero())
// Attach the control of the camera to the canvas
this.camera.attachControl(canvas, true)
}
}
Map = function (game) {
this.game = game
var scene = game.scene
// Creation of the main light
var light = new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0, 1, 0), scene)
// Sphere
var sphere = BABYLON.Mesh.CreateSphere('sphere1', 16, 2, scene)
sphere.position.y = 1
// Ground (so the sphere is somewhere)
var ground = BABYLON.Mesh.CreateGround('ground1', 6, 6, 2, scene)
}
Grounds, Squares, Sphere, Cylindre, .. these objects have commun properties:
name
(string): id of the objectsize
: size of the objectscene
: scene that will contain the objectupdatable
(boolean): is the mesh will change (size, properties) laterorientation
: way that the faces will be displayedsubdivision
: level of details of the object (the bigger, the more detailled it will be - number of points)
There are 3 types of updates with the Vector3:
position
: move the meshrotation
: rotate based on a rad anglescaling
: multiply the size
When a mesh has been created at 0, 0, 0, and that the ground is at 0, the center of the object will be in the middle of the other one. All the thing is to move it up of half of its side.
Then, BabylonJS applies a standard white material to the objects. A material is like every other object but without physic. There are 3 types of application:
Ambiant
: general light (ambiante) of the objectSpecular
: shiny aspect of the objectEmissive
: light generated by the object itself
With this, there are 2 types of application:
Reflexion
Refraction
var ground = BABYLON.Mesh.CreateGround(name, width, depth, subdivision, scene)
Example:
// Init the material
var materialGround = new BABYLON.StandardMaterial('groundTexture', scene)
materialGround.diffuseTexture = new BABYLON.Texture('assets/images/brick.jpg', scene)
materialGround.diffuseTexture.uScale = 4.0
materialGround.diffuseTexture.vScale = 4.0
// 20x20 ground
var ground = BABYLON.Mesh.CreateGround('ground1', 20, 20, 2, scene)
// Axis X: *2
// Axis Z: *3
// Axis Y: nothing, it is a ground!
ground.scaling = new BABYLON.Vector3(2, 10, 3)
// Another way
ground.scaling.z = 2
// Material
ground.material = materialGround
// Simple
var box = BABYLON.Mesh.CreateBox(name, size, scene)
// Advanced
var box = BABYLON.Mesh.CreateBox(name, size, scene, updatable, orientation)
Example:
// Init the material
var materialWall = new BABYLON.StandardMaterial('groundTexture', scene)
materialWall.diffuseTexture = new BABYLON.Texture('assets/images/wood.jpg', scene)
// First cube as model
var mainBox = BABYLON.Mesh.CreateBox('box1', 3, scene)
mainBox.material = materialWall
// 3 clones
var mainBox2 = mainBox.clone('box2')
var mainBox3 = mainBox.clone('box3')
var mainBox4 = mainBox.clone('box4')
// Multiply the size of the object per K on the Y Axis
mainBox.scaling.y = 1
mainBox2.scaling.y = 2
mainBox3.scaling.y = 3
mainBox4.scaling.y = 4
// Move the objects on the 3 axis
// Move it up from half of the height and handle the scaling height by what we did before
mainBox.position = new BABYLON.Vector3(5, ((3 / 2) * mainBox.scaling.y), 5)
mainBox2.position = new BABYLON.Vector3(5, ((3 / 2) * mainBox2.scaling.y), -5)
mainBox3.position = new BABYLON.Vector3(-5, ((3 / 2) * mainBox3.scaling.y), -5)
mainBox4.position = new BABYLON.Vector3(-5, ((3 / 2) * mainBox4.scaling.y), 5)
// 45deg in radian (no need for the other thanks to clone)
mainBox.rotation.y = (Math.PI * 45) / 180
// Simple
var sphere = BABYLON.Mesh.CreateSphere(name, segments, size, scene)
// Advanced
var sphere = BABYLON.Mesh.CreateSphere(name, segments, size, scene, updatable, orientation)
segments
: quality of the object
// Simple
var cylinder = BABYLON.Mesh.CreateCylinder(name, height, diamTop, diamBottom, tesselation, subdivision, scene)
// Advanced
var cylinder = BABYLON.Mesh.CreateCylinder(name, height, diamTop, diamBottom, tesselation, subdivision, scene, updatable, orientation)
diamTop
: width of the top colomndiamBottom
: width of the bottom colomntesselation
: quality of the object
Example:
var cylinder = BABYLON.Mesh.CreateCylinder('cyl1', 20, 5, 5, 20, 4, scene)
cylinder.material = materialWall
Like for the objects, there are 3 types of updates with the Vector3:
position
: moverotation
: rotatescaling
: multiply the size (no effect at all)
As an important note, only 3 lights can touch a mesh. Yet there is a way to avoid this issue.
A light will always has 2 value to set:
diffuse
: define the oclor of the light (default: 1, 1, 1)specular
: define the intensity of the shine (the more it is white, the more it is shiny; the more it is black, the more it is mat) (default: 1, 1, 1)intensity
: it is also possible to decrease the intensity of the lights with this parameter
For nice effects, it is pretty cool to use the range
function.
Its lighting is very close to the sky's one, with soft shadows. It is represented with an infinite plan and it's enlightened in one single direction.
The parameters are:
- light name
- position from where it will enlight
- the current scene
var light = new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0, 20, 0), scene)
light.diffuse = new BABYLON.Color3(1, 1, 1)
light.specular = new BABYLON.Color3(1, 1, 1)
This one is close to the previous one but the second parameter here is the light direction:
- light name
- direction of the light
- the current scene
var light1 = new BABYLON.DirectionalLight('Dir1', new BABYLON.Vector3(0, -1, 0), scene)
light1.diffuse = new BABYLON.Color3(1, 1, 1)
light1.specular = new BABYLON.Color3(1, 1, 1)
This light can't diffuse shadows, but its particularity is to diffuse in all the directions. It's useful for mood lights:
The parameters are:
- light name
- position of the light
- the current scene
var light1 = new BABYLON.PointLight('Omni1', new BABYLON.Vector3(1, 10, 1), scene)
light1.diffuse = new BABYLON.Color3(1, 1, 1)
light1.specular = new BABYLON.Color3(1, 1, 1)
Finally, this one is working like a physical spot: it's a cone of light. Use cases are mainly for moving lights inside a scene.
The parameters are:
- light name
- position of the light
- direction of the light
- open angle of the cone of light
- the exponent of diminishing light with distance (the more it is high, the more the light decrease quickly with the distance)
- the current scene
var light1 = new BABYLON.SpotLight('Spot1', new BABYLON.Vector3(0, 30, -10), new BABYLON.Vector3(0, -1, 0), 0.8, 2, scene)
light1.diffuse = new BABYLON.Color3(1, 1, 1)
light1.specular = new BABYLON.Color3(1, 1, 1)
There are 2 basics camera on BabylonJS, but several ones have been created for specific use cases (anaglyphe, Occulus, follow a target, ..).
This one allows you to have right at the beginning mouse and keyboard controls. Pretty close than what it is used for FPS.
The parameters are:
- an id
- a camera position
- a scene
There are also two important parameters to define:
setTarget
: is about where the camera should look at the scene creation (BABYLON.Vector3.Zero()
can be used to look at the center 0 of the scene)attachControl
: render the camera enable with the keyboard an the mouse
var camera = new BABYLON.FreeCamera('camera', new BABYLON.Vector3(0, 5, -10), scene)
camera.setTarget(BABYLON.Vector3.Zero())
camera.attachControl(canvas, true)
This one is specific to turn around a defined point and to be always centered on it.
The parameters are:
- an id
- an alpha value (horizontal in rad)
- a beta value (vertical in rad)
- a ray (radius)
- the pivot position
- the scene
var camera = new BABYLON.ArcRotateCamera('ArcRotateCamera', 1, 0.8, 10, new BABYLON.Vector3(0, 0, 0), scene)
camera.attachControl(canvas, true)