100 000 et un object WebGL / three.js 

 sli.do/1618

Prince of Persia - 1989

La cité idéale - 1465

Starfox - 1993

Metal Gear Solid - 1998

Uncharted 4 - 2016

@AnasAmeziane

anas@ozzo.io

Fondateur de ozzo.io

Anas AMEZIANE

Trading automatique et évolutif sur les marchés de cryptomonnaie

Architecture

WebGL 

Browsers

 WebGL est une API de pixellisation, pas une API 3D

The graphics pipeline

Vertex processing

Les "vertex" sont transformés à des positions sur l’écran

Primitive processing 

Puis organisés et assemblés en primitives

Primitive processing 

les primitives sont pixelisées en fragments

Fragment processing

les fragment sont transformés à des pixels colorés

Fragment processing

Les fragments sont mélangés dans le buffer d'image à leur emplacements de pixels 

pipeline

Shader

Les shaders sont un ensemble d'instructions exécutées en une seule fois pour chaque pixel de l'écran.

CPU

GPU

<script id="vertex-shader" type="notjs">
 
  attribute vec4 a_position;
 
  void main() {
    gl_Position = a_position;
  }
 
</script>
 
<script id="fragment-shader" type="notjs">
 
  precision mediump float;
 
  void main() {
    gl_FragColor = vec4(1, 0, 0.5, 1);
  }

</script>

GLSL

( openGL Shading Language)

webglfundamentals.org

thebookofshaders.com

WebGL libraries

Threejs 

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Basic Three.js App</title>
    <style>
      html, body { margin: 0; padding: 0; overflow: hidden; }
    </style>
  </head>
  <body>
    <script src="js/three.min.js"></script>
    <script>
      // Javascript will go here.
    </script>
  </body>
</html>
var scene = new THREE.Scene();
var aspect = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera( 75, aspect, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshNormalMaterial();
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;

var render = function () {
  requestAnimationFrame( render );
  cube.rotation.x += 0.1;
  cube.rotation.y += 0.1;
  renderer.render( scene, camera );
};

render();

Scene

Camera

var camera = new THREE.PerspectiveCamera( 
  40, //fov
  canvasWidth / canvasHeight, //aspect
  0.1, //near 
  1000 //far
);

Perspective Camera

var viewSize = 900;
var aspectRatio = canvasWidth/canvasHeight;

var camera = new THREE.OrthographicCamera( 
  -aspectRatio * viewSize / 2, //left
   aspectRatio * viewSize / 2, //right
   viewSize / 2, //top
  -viewSize / 2, //bottom
  -1000, //near
   1000 //far
);
  

Orthographic Camera

Diablo, Civilization and SimCity

Orthographic Camera

<script src="path/to/OrbitControls.js"></script>

controls = new THREE.OrbitControls( camera );

function render() {
  requestAnimationFrame( render );
  controls.update();
  renderer.render( scene, camera );
}

Camera controls

https://threejs.org/examples/js/controls/OrbitControls.js

Mesh

Geometry + Material

Geometry

BoxBufferGeometry, BoxGeometry, ,CircleBufferGeometry, CircleGeometry, ConeBufferGeometry, ConeGeometry, CylinderBufferGeometry, CylinderGeometry, DodecahedronBufferGeometry, DodecahedronGeometry, EdgesGeometry, ExtrudeBufferGeometry, ExtrudeGeometry, IcosahedronBufferGeometry, IcosahedronGeometry, LatheBufferGeometry, LatheGeometry, OctahedronBufferGeometry, OctahedronGeometry, ParametricBufferGeometry, ParametricGeometry, PlaneBufferGeometry, PlaneGeometry, PolyhedronBufferGeometry, PolyhedronGeometry, RingBufferGeometry, RingGeometry, ShapeBufferGeometry, ShapeGeometry, SphereBufferGeometry, SphereGeometry, TetrahedronBufferGeometry, TetrahedronGeometry, TextBufferGeometry, TextGeometry, TorusBufferGeometry, TorusGeometry, TorusKnotBufferGeometry, TorusKnotGeometry, TubeBufferGeometry, TubeGeometry, WireframeGeometry

 

Cube

var geometry = new THREE.BoxGeometry( 
    1, //width
    1, //height
    1  //depth
);

var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );

Sphere

var geometry = new THREE.SphereGeometry( 
    5,  //radius
    32, //widthSegments
    32  //heightSegments
);

var material = new THREE.MeshBasicMaterial( {color: 0xffff00} );
var sphere = new THREE.Mesh( geometry, material );
scene.add( sphere );

BufferGeometry

 var geometry = new THREE.BufferGeometry();
 var vertices = new Float32Array( [
  -1.0, -1.0,  1.0,
   1.0, -1.0,  1.0,
   1.0,  1.0,  1.0,
  -1.0,  1.0,  1.0
 ]);

geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
var material = new THREE.PointsMaterial( { color: 0xff0000 } );
var mesh = new THREE.Points( geometry, material );

Material

MeshNormalMaterial

MeshNormalMaterial( parameters : Object )

MeshStandardMaterial

MeshStandardMaterial( parameters : Object )

MeshPhongMaterial

MeshPhongMaterial( parameters : Object )

PointsMaterial

let ozzoBotPointsMaterial = new THREE.PointsMaterial({
    size: 8,
    vertexColors: THREE.VertexColors,
    map: new THREE.TextureLoader().load(CircleSprite),
});

Texture

+

=

http://planetpixelemporium.com/mars.html

Texture map

var PLANET_RADIUS = 1;
let planetMesh = new THREE.Mesh(
  new THREE.SphereBufferGeometry(PLANET_RADIUS, 32, 32), 
  new THREE.MeshPhongMaterial({
    map: new THREE.TextureLoader().load('images/mars_4k_color.jpg')
  })
);

Texture bump

var PLANET_RADIUS = 1;
var planetMesh = new THREE.Mesh(
  new THREE.SphereBufferGeometry(PLANET_RADIUS, 32, 32), 
  new THREE.MeshPhongMaterial({
    map: new THREE.TextureLoader().load('images/mars_4k_color.jpg'),
    bumpMap: new THREE.TextureLoader().load('images/mars_4k_bump.jpg'),
    bumpScale: 0.05
  })
);

Light & shadows

var light = new THREE.DirectionalLight( 0xdddddd, 0.8 );
light.position.set(5, 0, 5);
scene.add(light);

DirectionalLight

scene.add(new THREE.AmbientLight( 0x444444, 0.8));

AmbientLight

renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

light.castShadow = true; 

planetMesh.receiveShadow = true;
planetMesh.castShadow = true;  
moonMesh.castShadow = true;
moonMesh.receiveShadow = true;

Shadow

var D_THETA = 0.005;
var theta = 0;

function animate() {
  requestAnimationFrame( animate );
  
  //rotate animation
  planetMesh.rotation.y += (0.5*(Math.PI / 180)) % 360;
  moonMesh.rotation.y   += (0.5*(Math.PI / 180)) % 360;

  //orbit animation
  theta += D_THETA;
  moonMesh.position.x = (PLANET_RADIUS + MOON_RADIUS + MOON_DISTANCE) * Math.cos(theta);
  moonMesh.position.z = (PLANET_RADIUS + MOON_RADIUS + MOON_DISTANCE) * Math.sin(theta);

  controls.update();
  renderer.render( scene, camera );
}

Animation

Made with Slides.com