Amusons nous avec Angular, BabylonJs et la réalité virtuelle (partie 1)

Bonjour,

Cela fait une éternité que je n'ai pas écrit d'article, donc pour cette reprise, on va s'amuser un peu.

Pour Noël, le petit papa m'a apporté une caméra 360 de la marque Ricoh, la Theta V.

Cette caméra permet de prendre des photos 360° et même des films en HD. Le logiciel fournit avec est, comment dire, pas vraiment au top. J'ai donc décidé de créer une appli qui me permettra de visualiser ces photos 360 et surtout, de les visualiser via mon casque de Mixed reality.

Comme je suis à fond pour le boulot sur Angular, j'ai décidé de créer cette appli sous Angular et d'utiliser l'excellent moteur 3D BabylonJs.

La première étape, et donc l'objet de ce premier article est de mettre en place la solution côté client.

Angular Cli

Nous supposerons ici que vous maitrisez AngularCli. Cet utilitaire vous permet de créer très rapidement la structure de votre application Angular. Un petit :

ng n ab

Et hop, le projet est créer et l'on peu le charger dans Visual Studio Code.

Notre projet comportera dans un premier temps une page d'accueil (home) puis une page viewer :

ng g c home
ng g c viewer

N'oublions pas dans notre page app.component.html le router et le paramétrage du router dans le module app.module.ts :

Enfin, dans notre page home, un lien vers le viewer :

Le plus simple est en place, il ne nous reste plus qu'à intégrer maintenant BabylonJs.

BabylonJs

L'intégration de BabylonJs se fait tout naturellement via npm. Dans notre fichier package.json, ajoutons donc la référence à ce moteur 3D :

Le principe de babylonJs est d'effectuer le rendu 3D de votre scène dans un canvas Html5. Donc dans notre component viewer, nous allons ajouter juste un tag canvas :

<canvas id="renderCanvas" touch-action="none"></canvas>

N'oublions pas au niveau du style du canvas de lui demander d'occuper l'entièreté de l'écran :

#renderCanvas {
width: 100%;
height: 100%;
touch-action: none;
}

Tout est en place pour créer la logique de notre jeu 3D. Pour cela, nous ajoutons une classe typescript simple appelée Game. Elle gèrera le moteur 3D (Engine), la scène (Scene), les caméras (camera), lumières (light) et objets 3D (meshes).

Comme dans tout moteur 3D, il y a une première phase de création de la scène puis une boucle de rendu (méthode createScene). Voici le code complet commenté de la classe Game :

import {
Engine, Scene, Light,
Vector3, HemisphericLight, MeshBuilder,
ArcRotateCamera, StandardMaterial, Texture,
Color3
} from 'babylonjs';

export class Game {
private canvas: HTMLCanvasElement;
private engine: Engine;
private scene: Scene;
private camera: ArcRotateCamera;
private light: Light;
constructor(canvasElement: string) {
this.canvas = <HTMLCanvasElement>document.getElementById(canvasElement);
// on attache le moteur de rendu avec le canvas
this.engine = new Engine(this.canvas, true);
// au cas ou il y ai un redimensionnement de la fenêtre du navigateur
window.addEventListener('resize', () => {
this.engine.resize();
});
}

createScene(): void {
// création de la scène associée au moteur de rendu (engine)
this.scene = new Scene(this.engine);

// création de la caméra
this.camera = new ArcRotateCamera('Camera', -Math.PI / 2, Math.PI / 2, 5, BABYLON.Vector3.Zero(), this.scene);
this.camera.position = new Vector3(0, 0, 0);
this.camera.attachControl(this.canvas, false);

// création de la lumière
this.light = new HemisphericLight('skyLight', new Vector3(1, 1, 0), this.scene);

// ajout d'une sphère dans la scène
const sphere = MeshBuilder.CreateSphere('sphere', { segments: 16, diameter: 1 }, this.scene);
sphere.position.y = 1;

// ajout d'un 'skybox' pour l'environnement
const skybox = BABYLON.MeshBuilder.CreateBox('skyBox', { size: 1000.0 }, this.scene);
const skyboxMaterial = new StandardMaterial('skyBox', this.scene);
skyboxMaterial.backFaceCulling = false;

// création de la texture de l'environnement
const fixedTexture = new Texture('/assets/StJean.JPG', this.scene);
skyboxMaterial.reflectionTexture = fixedTexture; // videoTexture;
skyboxMaterial.reflectionTexture.coordinatesMode = Texture.FIXED_EQUIRECTANGULAR_MODE;
skyboxMaterial.diffuseColor = new Color3(0, 0, 0);
skyboxMaterial.specularColor = new Color3(0, 0, 0);
skybox.material = skyboxMaterial;

}

run(): void {
// boucle du rendu
this.engine.runRenderLoop(() => {
this.scene.render();
});
}
}

C'est très simple. Pour infoi, l'image StJean.JPG est une photo prise avec le Theta V du port de Saint Jean de Luz (prise le 31 Décembre 2017, oui il faisait beau ;-))

Il ne nous reste plus qu'à instancier la classe Game dans notre compnent viewer pour visualiser notre photo 360 :

import { Component, OnInit } from '@angular/core';
import { Game } from '../logic/game';

@Component({
selector: 'app-viewer',
templateUrl: './viewer.component.html'
})
export class ViewerComponent implements OnInit {

constructor() { }

ngOnInit() {
// Create our game class using the render canvas element
const game = new Game('renderCanvas');

// Create the scene
game.createScene();

// start animation
game.run();
}
}

3 lignes de code et voila le résultat :

En plus, l'appli marche mieux que l'appli officielle de Ricoh ;-)

Vous pouvez télécharger le projet ici.

Suite de l'article ici.

blog comments powered by Disqus