•WebGL 1.0
• Typescript
•Math (a lot of Math)
• Passion 😄
How was it made
Demo: https://goo.gl/Q7Ggih
- MDN web docs
WebGL (Web Graphics Library) is a JavaScript API for rendering interactive 3D and 2D graphics within any compatible web browser without the use of plug-ins. WebGL does so by introducing an API that closely conforms to OpenGL ES 2.0 that can be used in HTML5 <canvas> elements.
WebGL
Demo: https://goo.gl/Q7Ggih
HTML:
<body> <canvas id="webgl-canvas"></canvas> </body>
engine.ts:
let canvas = <HTMLCanvasElement>document.getElementById('webgl-canvas'); let gl = <WebGLRenderingContext>canvas.getContext("webgl"); if (gl == null) { throw "No WebGL support"; }
WebGL - initial setup
Demo: https://goo.gl/Q7Ggih
• WebGL is a state machine
• WebGL can draw primitive shapes (lines, points, triangles) based on supplied data
• WebGL can color every single pixel of a drawn primitive shape
• To draw and color things WebGL uses Shaders
WebGL - facts
Demo: https://goo.gl/Q7Ggih
WebGL - mesh representation in fileGeometryObject $geometry1 {
Mesh (primitive = "triangles") {
VertexArray (attrib = "position") {
float[3] // 3623 {
{-2.2362539768218994, 5.515564441680908, 12.59365177154541}, {-2.12605881690979, 4.948864459991455, 11.504551887512207}, {-2.521761178970337, 3.9739651679992676, 13.54375171661377}, {4.045838832855225, -4.078834056854248, 2.3464717864990234}, {4.3393378257751465, -4.510035991668701, 22.21135139465332}, {2.264341115951538, -4.585536479949951, 6.199451446533203}, {1.5406397581100464, -5.000636577606201, 10.583052635192871}, {0.363237202167511, -5.689136028289795, 21.08005142211914},
{0.363237202167511, -5.689136028289795, 21.08005142211914}, {4.3393378257751465, -4.510035991668701, 22.21135139465332}, {4.157639980316162, -4.222136974334717, 22.212251663208008}, {6.5994391441345215, -3.316436290740967, 23.439550399780273}, {6.417638301849365, -3.0286364555358887, 23.4405517578125}, {6.5994391441345215, -3.316436290740967, 23.439550399780273}, {8.894240379333496, -1.9856371879577637, 22.21755027770996}, {6.417638301849365, -3.0286364555358887, 23.4405517578125},
{8.712542533874512, -1.6977343559265137, 22.218551635742188}, {11.588839530944824, 0.532265305519104, 21.095550537109375}, {11.588839530944824, 0.532265305519104, 21.095550537109375}, {8.894240379333496, -1.9856371879577637, 22.21755027770996}, {10.65034008026123, 0.04806584119796753, 10.595551490783691}, {10.253241539001465, -0.15873652696609497, 6.450220108032227}, {8.600741386413574, -1.5544352531433105, 2.352720260620117}, {6.5994391441345215, -3.316436290740967, 23.439550399780273},
{6.50433874130249, -3.0976366996765137, -0.0046596527099609375}, {1.970239520072937, 4.9177632331848145, 0.44479942321777344}, {1.2974413633346558, 3.160862445831299, 0.4396800994873047}, {2.3366410732269287, 5.037765979766846, 1.3988895416259766}, {1.374841570854187, 3.062065601348877, -0.12100028991699219}, {1.5675410032272339, 1.5510642528533936, 0.44030189514160156}, {2.02243971824646, 4.753563404083252, -0.11606025695800781}, {2.02243971824646, 4.753563404083252, -0.11606025695800781},
{1.970239520072937, 4.9177632331848145, 0.44479942321777344}, {3.96343731880188, 4.822266101837158, -0.11646080017089844}, {3.9862377643585205, 4.989162921905518, 0.44439125061035156}, {2.3366410732269287, 5.037765979766846, 1.3988895416259766}, {4.052037715911865, 5.091564655303955, 1.406270980834961}, {2.416738271713257, 4.575165271759033, 4.059070587158203}, {3.5210397243499756, 4.6211628913879395, 4.16963005065918}, {2.045438528060913, 5.279263019561768, 9.835280418395996},
{2.416738271713257, 4.575165271759033, 4.059070587158203}, {1.6227396726608276, 2.6208655834198, 5.369930267333984}, {2.045438528060913, 5.279263019561768, 9.835280418395996}, {1.6047381162643433, 1.876763105392456, 1.8999900817871094}, {1.8072413206100464, 0.2383657991886139, 1.5104618072509766}, {1.2648409605026245, 2.5120627880096436, 2.0103302001953125}, {1.2648409605026245, 2.5120627880096436, 2.0103302001953125}, {1.7093409299850464, 2.7398648262023926, 3.6971702575683594},
{1.7093409299850464, 2.7398648262023926, 3.6971702575683594}, {2.7904412746429443, 1.585564374923706, 4.851861953735352}, {1.6227396726608276, 2.6208655834198, 5.369930267333984}, {2.567739248275757, 1.8070647716522217, 6.24104118347168}, {2.7904412746429443, 1.585564374923706, 4.851861953735352}, {3.75003981590271, 1.9715659618377686, 6.206731796264648}, {3.6324403285980225, 1.6986663341522217, 4.916341781616211}, {2.7904412746429443, 1.585564374923706, 4.851861953735352}, …
Demo: https://goo.gl/Q7Ggih
• WebGL uses small programs called Shaders to draw geometry and colors onto the screen
• These programs are written in GLSL (GL Shading Language)
• The most used types of Shaders are: Vertex Shader and Fragment Shader
• Two Shaders are linked in a Shader Program
Shaders
Demo: https://goo.gl/Q7Ggih
• Attributes and Buffers
• Uniforms
• Textures
• Varyings
Passing data to shaders
Demo: https://goo.gl/Q7Ggih
• Buffers are arrays of binary data uploaded to the GPU
• Usually they contain things like: positions, normals, texture coordinates, etc.
• But they can have anything that can be useful in Vertex Shader
Attributes and buffers
Demo: https://goo.gl/Q7Ggih
• There can be many buffers
• Buffer must be set (bind) as the current to be able use its content (e.g. draw objects)
• Buffer binding is a costly operation !Optimize!
• We need to tell WebGL how the data is positioned in the buffer
Attributes and buffers
Demo: https://goo.gl/Q7Ggih
// Create an empty buffer let vertexBuffer = gl.createBuffer();
// Pass down the vertices data gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
Buffers - example
Demo: https://goo.gl/Q7Ggih
// Get location of a_position variable placed in the shader program let positionAttributeLocation = gl.getAttribLocation(program, "a_position");
// Bind the position buffer. gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER) var size = 2; // 2 components per iteration var type = gl.FLOAT; // the data is 32bit floats var normalize = false; // don't normalize the data var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position var offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer(positionAttributeLocation, size, type, normalize, stride, offset);
Attributes
Demo: https://goo.gl/Q7Ggih
• Allow to pass data to the shader program
• Passed data is not stored in any buffer (e.g. this could be a ordinary property like position in the game’s code)
• They can be understood as global variables set before execution of shader program
Uniforms
Demo: https://goo.gl/Q7Ggih
let someFloatLocation = gl.getUniformLocation(program, "u_some_float_location"); gl.uniform1f(someFloatLocation, 1.0);
Uniforms - example
Demo: https://goo.gl/Q7Ggih
• To draw images in WebGL we need to use textures
• Texture coordinates must be provided (0.0 to 1.0)
• To be able to use Texture it must be set as current and made active
• Single reference to a Texture is called texture unit
• There is a limitation of number of texture units active at the same time
Textures
Demo: https://goo.gl/Q7Ggih
let image = new Image(); image.src = "some_url.png" image.onload = () => {
var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texImage2D(gl.TEXTURE_2D, // type of data
0, // level of details gl.RGBA, // internal color components in the texture gl.RGBA, // color components in the texture gl.UNSIGNED_BYTE, // data type image); // the image
textures.push(texture);
}
Textures - creation example
Demo: https://goo.gl/Q7Ggih
var u_image0Location = gl.getUniformLocation(program, "u_image0"); var u_image1Location = gl.getUniformLocation(program, "u_image1"); // set which texture units to render with. gl.uniform1i(u_image0Location, 0); // texture unit 0 gl.uniform1i(u_image1Location, 1); // texture unit 1
gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures[0]); gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D, textures[1]);
Textures - usage example
Demo: https://goo.gl/Q7Ggih
• Varying variables are used to pass data from Vertex Shader to Fragment Shader
• Data from buffers cannot be passed directly to Fragment Shader
• The most common case is extracting texture coordinates in Vertex Shader and passing it to Fragment Shader
Varyings
Demo: https://goo.gl/Q7Ggih
attribute vec2 a_position; attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main() { gl_Position = vec4(a_position, 0, 1);
// pass the texCoord to the fragment shader // The GPU will interpolate this value between points. v_texCoord = a_texCoord; }
Vertex Shader - example
Demo: https://goo.gl/Q7Ggih
uniform sampler2D u_image0; uniform sampler2D u_image1;
// the texCoords passed in from the vertex shader. varying vec2 v_texCoord;
void main() { vec4 color0 = texture2D(u_image0, v_texCoord); vec4 color1 = texture2D(u_image1, v_texCoord); gl_FragColor = color0 * color1; }
Fragment shader - example
Demo: https://goo.gl/Q7Ggih
gl.drawArrays(gl.TRIANGLES, 0, 6);
Final step - making draw call
⚠ Very costly operation ⚠
Demo: https://goo.gl/Q7Ggih
Engine
Master renderer
RayCaster
Scene navigation controller
Game architecture
Sprite render 3D renderer
[Scene controllers]
Scene
Sprites 3D objects
Get current scene from Scene Navigation Controller
Draw call is requested
Get All 3D objects added to scene
Pass the 3d objects to Master
renderer
Master renderer sets the 3d shader and renders the models using object 3d
renderer
Get All 2D objects (Sprites) added to
scene
Master renderer sets the 2d shader and renders the
Sprites using Sprite renderer
Clear the screen and repeat
Rendering
Demo: https://goo.gl/Q7Ggih
Rendering - Shared geometry
SharedGeometry (static instance)
Knight vertices + texture coords
Create vertices + texture coords
Grass vertices + texture coords
Register
Model
Model
Model
models = Map<string, Model>
Demo: https://goo.gl/Q7Ggih
Rendering - Shared texture
SharedTexture (static instance)
Knight texture image data
Create texture image data
Grass texture image data
Register
textures = Map<string, Texture>
Demo: https://goo.gl/Q7Ggih
Rendering - Object3D
Knight
SharedGeometry (static instance) SharedTexture (static instance)
Get texture with key “knight”Get Model with key “knight”
Demo: https://goo.gl/Q7Ggih
Process input Update game Render
• Too fast or too slow
• Better experience for high-end devices
• Non-deterministic
Fluid time step
Demo: https://goo.gl/Q7Ggih
Process input Update game Render
• Deterministic
• Framerate drops
• Requires tuning for high-end and low-end devices
Fixed time step
Demo: https://goo.gl/Q7Ggih