These are the slides of my talk about HexGL at the Adobe User Group meetup in the Netherlands.
More info: http://bkcore.com/blog/general/adobe-user-group-nl-talk-video-hexgl.html
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
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);
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;