SlideShare a Scribd company logo
The making of HexGL
• Thibaut Despoulain (@bkcore – bkcore.com)

• 22 year-old student in Computer Engineering

• University of Technology of Belfort-Montbéliard (France)

• Web dev and 3D enthousiast

• The guy behind the HexGL project
HTML5 game dev with three.js - HexGL
• Fast-paced, futuristic racing game

• Inspired by the F-Zero and Wipeout series

• HTML5, JavaScript, WebGL (via Three.js)

• Less than 2 months

• Just me.
HTML5 game dev with three.js - HexGL
HTML5 game dev with three.js - HexGL
HTML5 game dev with three.js - HexGL
HTML5 game dev with three.js - HexGL
• JavaScript API

• OpenGL ES 2.0

• Chrome, FireFox, (Opera, Safari)

• <Canvas> (HTML5)
HTML5 game dev with three.js - HexGL
• Rendering engine
• Maintained by Ricardo Cabello (MrDoob) and Altered Qualia
• R50/stable

• + : Active community, stable, updated frequently

• - : Documentation
HTML5 game dev with three.js - HexGL
HTML5 game dev with three.js - HexGL
HTML5 game dev with three.js - HexGL
• First « real » game

• 2 months to learn and code

• Little to no modeling and texturing skills

• Physics? Controls? Gameplay?
• Last time I could have 2 months free

• Visibility to get an internship

• Huge learning opportunity

• Explore Three.js for good
HTML5 game dev with three.js - HexGL
• Third-party physics engine (rejected)
   – Slow learning curve

   – Not really meant for racing games
• Ray casting (rejected)
   – Heavy perfomance-wise

   – Needs Octree-like structure

   – > too much time to learn and implement
• Home-made 2D approximation
  – Little to no learning curve

  – Easy to implement with 2D maps

  – Pretty fast

  – > But with some limitations
HTML5 game dev with three.js - HexGL
HTML5 game dev with three.js - HexGL
• Home-made 2D approximation
  – No track overlap

  – Limited track twist and gradient

  – Accuracy depends on map resolution

  – > Enough for what I had in mind
HTML5 game dev with three.js - HexGL
• No pixel getter on JS Image object/tag

• Canvas2D to the rescue
Load data                   Draw it on a             Get canvas


                            Drawing




                                                     Getting
Loading




          texture with JS             Canvas using             pixels using
          Image object                2D context               getImageData()
• ImageData (BKcore package)
  – Github.com/Bkcore/bkcore-js

var a = new bkcore.ImageData(path, callback);
//…
a.getPixel(x, y);
a.getPixelBilinear(xf, yf);
// -> {r, g, b, a};
Game loop:
  Convert world position to pixel indexes
  Get current pixel intensity (red)
  If pixel is not white:
      Collision
      Test pixels relatively (front, left, right)
:end
Front


Left            Right




Track             Void
Front


         Front
                                               Current
                                    Gradient
Left                Right    Left



                                                Right
       Height map                     Tilt
HTML5 game dev with three.js - HexGL
HTML5 game dev with three.js - HexGL
HTML5 game dev with three.js - HexGL
Model
  .OBJ               Python               Three.js
Materials           converter           JSON model
 .MTL

 $ python convert_obj_three.py -i mesh.obj -o mesh.js
var scene = new THREE.Scene();
var loader = new THREE.JSONLoader();

var createMesh = function(geometry)
{
   var mesh = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial());
   mesh.position.set(0, 0, 0);
   mesh.scale.set(3, 3, 3);
   scene.add(mesh);
};

loader.load("mesh.js", createMesh);
HTML5 game dev with three.js - HexGL
var renderer = new THREE.WebGLRenderer({
  antialias: false,
  clearColor: 0x000000
});


renderer.autoClear = false;
renderer.sortObjects = false;
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
renderer.gammaInput = true;

renderer.gammaOutput = true;



renderer.shadowMapEnabled = true;

renderer.shadowMapSoft = true;
HTML5 game dev with three.js - HexGL
• Blinn-phong
   – Diffuse + Specular + Normal + Environment maps

• THREE.ShaderLib.normal
   – > Per vertex point lights

• Custom shader with per-pixel point lights for the road
   – > Booster light
HTML5 game dev with three.js - HexGL
var boosterSprite = new THREE.Sprite(
{
  map: spriteTexture,
  blending: THREE.AdditiveBlending,
  useScreenCoordinates: false,
  color: 0xffffff
});

boosterSprite.mergeWith3D = false;
boosterMesh.add(boosterSprite);
HTML5 game dev with three.js - HexGL
var material = new THREE.ParticleBasicMaterial({
  color: 0xffffff,
  map: THREE.ImageUtils.loadTexture(“tex.png”),
  size: 4,
  blending: THREE.AdditiveBlending,
  depthTest: false,
  transparent: true,
  vertexColors: true,
  sizeAttenuation: true
});
var pool = [];
var geometry = new THREE.Geometry();
geometry.dynamic = true;

for(var i = 0; i < 1000; ++i)
{
   var p = new bkcore.Particle();
   pool.push(p);
   geometry.vertices.push(p.position);
   geometry.colors.push(p.color);
}
bkcore.Particle = function()
{
  this.position = new THREE.Vector3();
  this.velocity = new THREE.Vector3();
  this.force = new THREE.Vector3();
  this.color = new THREE.Color(0x000000);
  this.basecolor = new THREE.Color(0x000000);
  this.life = 0.0;
  this.available = true;
}
var system = new THREE.ParticleSystem(
   geometry,
   material
);
system.sort = false;

system.position.set(x, y, z);
system.rotation.set(a, b, c);

scene.add(system);
// Particle physics
var p = pool[i];
p.position.addSelf(p.velocity);
//…
geometry.verticesNeedUpdate = true;
geometry.colorsNeedUpdate = true;
• Particles (BKcore package)
   – Github.com/BKcore/Three-extensions
var clouds = new bkcore.Particles({
  opacity: 0.8,
  tint: 0xffffff, color: 0x666666, color2: 0xa4f1ff,
  texture: THREE.ImageUtils.loadTexture(“cloud.png”),
  blending: THREE.NormalBlending,
  size: 6, life: 60,      max: 500,
  spawn: new THREE.Vector3(3, 3, 0),
  spawnRadius: new THREE.Vector3(1, 1, 2),
  velocity: new THREE.Vector3(0, 0, 4),
  randomness: new THREE.Vector3(5, 5, 1)
});
scene.add(clouds);

// Game loop
clouds.emit(10);
clouds.update(dt);
HTML5 game dev with three.js - HexGL
• Built-in support for off-screen passes

• Already has some pre-made post effects
   – Bloom

   – FXAA

• Easy to use and Extend

• Custom shaders
var renderTargetParameters = {
   minFilter: THREE.LinearFilter,
   magFilter: THREE.LinearFilter,
   format: THREE.RGBFormat,
   stencilBuffer: false
};
var renderTarget = new THREE.WebGLRenderTarget(
   width, height,
   renderTargetParameters
);
var composer = new THREE.EffectComposer(
   renderer,
   renderTarget
);

composer.addPass( … );

composer.render();
• Generic passes
   –   RenderPass
   –   ShaderPass
   –   SavePass
   –   MaskPass

• Pre-made passes
   – BloomPass
   – FilmPass
   – Etc.
var renderModel = new THREE.RenderPass(
   scene,
   camera
);

renderModel.clear = false;

composer.addPass(renderModel);
var effectBloom = new THREE.BloomPass(
   0.8, // Strengh
   25, // Kernel size
   4, // Sigma
   256 // Resolution
);

composer.addPass(effectBloom);
HTML5 game dev with three.js - HexGL
var hexvignette: {
    uniforms: {
          tDiffuse: { type: "t", value: 0, texture: null },
          tHex: { type: "t", value: 1, texture: null},
          size: { type: "f", value: 512.0},
          color: { type: "c", value: new THREE.Color(0x458ab1) }
    },
    fragmentShader: [
          "uniform float size;",
          "uniform vec3 color;",
          "uniform sampler2D tDiffuse;",
          "uniform sampler2D tHex;",

          "varying vec2 vUv;",

          "void main() { ... }"

     ].join("n")
};
var effectHex = new THREE.ShaderPass(hexvignette);

effectHex.uniforms['size'].value = 512.0;
effectHex.uniforms['tHex'].texture = hexTexture;

composer.addPass(effectHex);

//…
effectHex.renderToScreen = true;
HTML5 game dev with three.js - HexGL
HTML5 game dev with three.js - HexGL
HTML5 game dev with three.js - HexGL

More Related Content

PPTX
WebGL and three.js - Web 3D Graphics
PDF
WebGL and three.js
PDF
From Hello World to the Interactive Web with Three.js: Workshop at FutureJS 2014
PPTX
Introduction to three.js
PDF
PDF
Creating Applications with WebGL and Three.js
PPTX
[JS EXPERIENCE 2018] Jogos em JavaScript com WebGL - Juliana Negreiros, Codem...
ODP
Introduction to threejs
WebGL and three.js - Web 3D Graphics
WebGL and three.js
From Hello World to the Interactive Web with Three.js: Workshop at FutureJS 2014
Introduction to three.js
Creating Applications with WebGL and Three.js
[JS EXPERIENCE 2018] Jogos em JavaScript com WebGL - Juliana Negreiros, Codem...
Introduction to threejs

What's hot (20)

PDF
Introduction to three.js & Leap Motion
PDF
ENEI16 - WebGL with Three.js
PDF
Three.js basics
PDF
Портируем существующее Web-приложение в виртуальную реальность / Денис Радин ...
PDF
3D Web Programming [Thanh Loc Vo , CTO Epsilon Mobile ]
PPTX
Bs webgl소모임004
PDF
CUDA Raytracing을 이용한 Voxel오브젝트 가시성 테스트
PDF
HTML5 Canvas - Let's Draw!
PPT
HTML5 Canvas
KEY
Cocos2dを使ったゲーム作成の事例
PDF
3D everywhere
PDF
How to Hack a Road Trip with a Webcam, a GSP and Some Fun with Node
PDF
Html5 canvas
PPTX
The State of JavaScript
PDF
Having fun with graphs, a short introduction to D3.js
PPTX
Making Games in JavaScript
PDF
Begin three.js.key
PDF
A Novice's Guide to WebGL
PPTX
HTML 5 Canvas & SVG
PPTX
nunuStudio Geometrix 2017
Introduction to three.js & Leap Motion
ENEI16 - WebGL with Three.js
Three.js basics
Портируем существующее Web-приложение в виртуальную реальность / Денис Радин ...
3D Web Programming [Thanh Loc Vo , CTO Epsilon Mobile ]
Bs webgl소모임004
CUDA Raytracing을 이용한 Voxel오브젝트 가시성 테스트
HTML5 Canvas - Let's Draw!
HTML5 Canvas
Cocos2dを使ったゲーム作成の事例
3D everywhere
How to Hack a Road Trip with a Webcam, a GSP and Some Fun with Node
Html5 canvas
The State of JavaScript
Having fun with graphs, a short introduction to D3.js
Making Games in JavaScript
Begin three.js.key
A Novice's Guide to WebGL
HTML 5 Canvas & SVG
nunuStudio Geometrix 2017
Ad

Similar to HTML5 game dev with three.js - HexGL (20)

PPTX
PDF
Gems of GameplayKit. UA Mobile 2017.
PPTX
Learning Predictive Modeling with TSA and Kaggle
PDF
Real life XNA
PDF
Exploring Canvas
PDF
Intro to HTML5 Canvas
PDF
The Ring programming language version 1.5.3 book - Part 48 of 184
PDF
The Ring programming language version 1.5.3 book - Part 58 of 184
KEY
Pointer Events in Canvas
PDF
Need an detailed analysis of what this code-model is doing- Thanks #St.pdf
PDF
Deep dive into deeplearn.js
KEY
Stupid Canvas Tricks
PDF
Html5 game programming overview
PDF
The Ring programming language version 1.3 book - Part 38 of 88
PDF
Bindings: the zen of montage
PDF
Presentation: Plotting Systems in R
PDF
Can someone please explain what the code below is doing and comment on.pdf
PDF
A More Flash Like Web?
DOC
COMPUTER GRAPHICS LAB MANUAL
PPTX
How to make a video game
Gems of GameplayKit. UA Mobile 2017.
Learning Predictive Modeling with TSA and Kaggle
Real life XNA
Exploring Canvas
Intro to HTML5 Canvas
The Ring programming language version 1.5.3 book - Part 48 of 184
The Ring programming language version 1.5.3 book - Part 58 of 184
Pointer Events in Canvas
Need an detailed analysis of what this code-model is doing- Thanks #St.pdf
Deep dive into deeplearn.js
Stupid Canvas Tricks
Html5 game programming overview
The Ring programming language version 1.3 book - Part 38 of 88
Bindings: the zen of montage
Presentation: Plotting Systems in R
Can someone please explain what the code below is doing and comment on.pdf
A More Flash Like Web?
COMPUTER GRAPHICS LAB MANUAL
How to make a video game
Ad

Recently uploaded (20)

PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Encapsulation theory and applications.pdf
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Machine learning based COVID-19 study performance prediction
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Encapsulation_ Review paper, used for researhc scholars
PPTX
Big Data Technologies - Introduction.pptx
PDF
KodekX | Application Modernization Development
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Unlocking AI with Model Context Protocol (MCP)
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Approach and Philosophy of On baking technology
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Network Security Unit 5.pdf for BCA BBA.
Encapsulation theory and applications.pdf
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Machine learning based COVID-19 study performance prediction
Dropbox Q2 2025 Financial Results & Investor Presentation
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Mobile App Security Testing_ A Comprehensive Guide.pdf
sap open course for s4hana steps from ECC to s4
Encapsulation_ Review paper, used for researhc scholars
Big Data Technologies - Introduction.pptx
KodekX | Application Modernization Development
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Unlocking AI with Model Context Protocol (MCP)
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Approach and Philosophy of On baking technology
Reach Out and Touch Someone: Haptics and Empathic Computing
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Build a system with the filesystem maintained by OSTree @ COSCUP 2025

HTML5 game dev with three.js - HexGL

  • 2. • Thibaut Despoulain (@bkcore – bkcore.com) • 22 year-old student in Computer Engineering • University of Technology of Belfort-Montbéliard (France) • Web dev and 3D enthousiast • The guy behind the HexGL project
  • 4. • Fast-paced, futuristic racing game • Inspired by the F-Zero and Wipeout series • HTML5, JavaScript, WebGL (via Three.js) • Less than 2 months • Just me.
  • 9. • JavaScript API • OpenGL ES 2.0 • Chrome, FireFox, (Opera, Safari) • <Canvas> (HTML5)
  • 11. • Rendering engine • Maintained by Ricardo Cabello (MrDoob) and Altered Qualia • R50/stable • + : Active community, stable, updated frequently • - : Documentation
  • 15. • First « real » game • 2 months to learn and code • Little to no modeling and texturing skills • Physics? Controls? Gameplay?
  • 16. • Last time I could have 2 months free • Visibility to get an internship • Huge learning opportunity • Explore Three.js for good
  • 18. • Third-party physics engine (rejected) – Slow learning curve – Not really meant for racing games
  • 19. • Ray casting (rejected) – Heavy perfomance-wise – Needs Octree-like structure – > too much time to learn and implement
  • 20. • Home-made 2D approximation – Little to no learning curve – Easy to implement with 2D maps – Pretty fast – > But with some limitations
  • 23. • Home-made 2D approximation – No track overlap – Limited track twist and gradient – Accuracy depends on map resolution – > Enough for what I had in mind
  • 25. • No pixel getter on JS Image object/tag • Canvas2D to the rescue
  • 26. Load data Draw it on a Get canvas Drawing Getting Loading texture with JS Canvas using pixels using Image object 2D context getImageData()
  • 27. • ImageData (BKcore package) – Github.com/Bkcore/bkcore-js var a = new bkcore.ImageData(path, callback); //… a.getPixel(x, y); a.getPixelBilinear(xf, yf); // -> {r, g, b, a};
  • 28. Game loop: Convert world position to pixel indexes Get current pixel intensity (red) If pixel is not white: Collision Test pixels relatively (front, left, right) :end
  • 29. Front Left Right Track Void
  • 30. Front Front Current Gradient Left Right Left Right Height map Tilt
  • 34. Model .OBJ Python Three.js Materials converter JSON model .MTL $ python convert_obj_three.py -i mesh.obj -o mesh.js
  • 35. var scene = new THREE.Scene(); var loader = new THREE.JSONLoader(); var createMesh = function(geometry) { var mesh = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial()); mesh.position.set(0, 0, 0); mesh.scale.set(3, 3, 3); scene.add(mesh); }; loader.load("mesh.js", createMesh);
  • 37. var renderer = new THREE.WebGLRenderer({ antialias: false, clearColor: 0x000000 }); renderer.autoClear = false; renderer.sortObjects = false; renderer.setSize(width, height); document.body.appendChild(renderer.domElement);
  • 38. renderer.gammaInput = true; renderer.gammaOutput = true; renderer.shadowMapEnabled = true; renderer.shadowMapSoft = true;
  • 40. • Blinn-phong – Diffuse + Specular + Normal + Environment maps • THREE.ShaderLib.normal – > Per vertex point lights • Custom shader with per-pixel point lights for the road – > Booster light
  • 42. var boosterSprite = new THREE.Sprite( { map: spriteTexture, blending: THREE.AdditiveBlending, useScreenCoordinates: false, color: 0xffffff }); boosterSprite.mergeWith3D = false; boosterMesh.add(boosterSprite);
  • 44. var material = new THREE.ParticleBasicMaterial({ color: 0xffffff, map: THREE.ImageUtils.loadTexture(“tex.png”), size: 4, blending: THREE.AdditiveBlending, depthTest: false, transparent: true, vertexColors: true, sizeAttenuation: true });
  • 45. var pool = []; var geometry = new THREE.Geometry(); geometry.dynamic = true; for(var i = 0; i < 1000; ++i) { var p = new bkcore.Particle(); pool.push(p); geometry.vertices.push(p.position); geometry.colors.push(p.color); }
  • 46. bkcore.Particle = function() { this.position = new THREE.Vector3(); this.velocity = new THREE.Vector3(); this.force = new THREE.Vector3(); this.color = new THREE.Color(0x000000); this.basecolor = new THREE.Color(0x000000); this.life = 0.0; this.available = true; }
  • 47. var system = new THREE.ParticleSystem( geometry, material ); system.sort = false; system.position.set(x, y, z); system.rotation.set(a, b, c); scene.add(system);
  • 48. // Particle physics var p = pool[i]; p.position.addSelf(p.velocity); //… geometry.verticesNeedUpdate = true; geometry.colorsNeedUpdate = true;
  • 49. • Particles (BKcore package) – Github.com/BKcore/Three-extensions
  • 50. var clouds = new bkcore.Particles({ opacity: 0.8, tint: 0xffffff, color: 0x666666, color2: 0xa4f1ff, texture: THREE.ImageUtils.loadTexture(“cloud.png”), blending: THREE.NormalBlending, size: 6, life: 60, max: 500, spawn: new THREE.Vector3(3, 3, 0), spawnRadius: new THREE.Vector3(1, 1, 2), velocity: new THREE.Vector3(0, 0, 4), randomness: new THREE.Vector3(5, 5, 1) });
  • 53. • Built-in support for off-screen passes • Already has some pre-made post effects – Bloom – FXAA • Easy to use and Extend • Custom shaders
  • 54. var renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false }; var renderTarget = new THREE.WebGLRenderTarget( width, height, renderTargetParameters );
  • 55. var composer = new THREE.EffectComposer( renderer, renderTarget ); composer.addPass( … ); composer.render();
  • 56. • Generic passes – RenderPass – ShaderPass – SavePass – MaskPass • Pre-made passes – BloomPass – FilmPass – Etc.
  • 57. var renderModel = new THREE.RenderPass( scene, camera ); renderModel.clear = false; composer.addPass(renderModel);
  • 58. var effectBloom = new THREE.BloomPass( 0.8, // Strengh 25, // Kernel size 4, // Sigma 256 // Resolution ); composer.addPass(effectBloom);
  • 60. var hexvignette: { uniforms: { tDiffuse: { type: "t", value: 0, texture: null }, tHex: { type: "t", value: 1, texture: null}, size: { type: "f", value: 512.0}, color: { type: "c", value: new THREE.Color(0x458ab1) } }, fragmentShader: [ "uniform float size;", "uniform vec3 color;", "uniform sampler2D tDiffuse;", "uniform sampler2D tHex;", "varying vec2 vUv;", "void main() { ... }" ].join("n") };
  • 61. var effectHex = new THREE.ShaderPass(hexvignette); effectHex.uniforms['size'].value = 512.0; effectHex.uniforms['tHex'].texture = hexTexture; composer.addPass(effectHex); //… effectHex.renderToScreen = true;