Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Threedee Tales From Urban Bohemia
Search
Vicent Martí
July 07, 2013
Programming
3
810
Threedee Tales From Urban Bohemia
An introduction to 3D graphics on the web using WebGL.
Vicent Martí
July 07, 2013
Tweet
Share
More Decks by Vicent Martí
See All by Vicent Martí
Unicorns Die With Bullets Made of Glitter
tanoku
6
540
My Mom told me that Git doesn't scale
tanoku
28
1.9k
Intergalactic Javascript Robots from Outer Space
tanoku
271
27k
Ruby is Unlike a Banana
tanoku
97
11k
Oh, you're so random
tanoku
14
2.5k
A talk about libgit2
tanoku
11
1.6k
Other Decks in Programming
See All in Programming
型付きアクターモデルがもたらす分散シミュレーションの未来
piyo7
0
780
WindowInsetsだってテストしたい
ryunen344
1
160
KotlinConf 2025 現地で感じたServer-Side Kotlin
n_takehata
1
210
Elixir で IoT 開発、 Nerves なら簡単にできる!?
pojiro
1
130
Development of an App for Intuitive AI Learning - Blockly Summit 2025
teba_eleven
0
110
Datadog RUM 本番導入までの道
shinter61
1
280
Perlで痩せる
yuukis
1
680
複数アプリケーションを育てていくための共通化戦略
irof
10
3.9k
Create a website using Spatial Web
akkeylab
0
280
Select API from Kotlin Coroutine
jmatsu
1
150
Bytecode Manipulation 으로 생산성 높이기
bigstark
1
330
A comprehensive view of refactoring
marabesi
0
470
Featured
See All Featured
Rails Girls Zürich Keynote
gr2m
94
14k
RailsConf 2023
tenderlove
30
1.1k
Designing for Performance
lara
609
69k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
29
1.8k
The Language of Interfaces
destraynor
158
25k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
181
53k
Making the Leap to Tech Lead
cromwellryan
134
9.3k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
357
30k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Building Flexible Design Systems
yeseniaperezcruz
328
39k
Transcript
None
3D is hard
We’re building a videogame
We’re building a videogame
None
None
None
(You are being a smartass)
None
WHAT?
WebGL is A JavaScript API to render graphics accessing directly
the GPU
WebGL is not An API for 3D graphics
WebGL is not An OpenGL Wrapper
angle angle OpenGL ES 2.0 to DirectX 9 translation
angle angle OpenGL ES 2.0 to DirectX 9 translation
WHERE?
None
DIV
CANVAS DIV
WebGL context CANVAS “webgl” .getContext(“webgl”) WebGL context the
WebGL context WebGL context(s) a b a.getContext(“webg b.getContext(“webg
WHEN?
DRAW DRAW DRAW DRAW DRAW DRAW DRAW DRAW Not when
you want to
When the browser tells you to.
When the browser tells you to. requestAnimationFrame
BRO WHAT ABOUT DOUBLE BUFFERING
None
Tearing
Buffer A Buffer B
Buffer A Buffer B
Buffer A Buffer B
JavaScript doesn’t execute while the DOM is being rendered!
JavaScript doesn’t execute while the DOM is being rendered!
HOW?
Introducing... Jimmy the Vertex
I’m not looking forward to this...
(x, y, z)
+x +y +z RIGHT HAND REPRESENT
None
None
None
Local Space
World Space
Camera Space
Camera Space
Screen Space
xx xy xz Yx Yy Yz Zx Zy Zz {
} World Space Local Space Model Matrix
xx xy xz Yx Yy Yz Zx Zy Zz {
} Camera Space World Space View Matrix
xx xy xz Yx Yy Yz Zx Zy Zz {
} Screen Space Camera Space Projection Matrix
We could do the matrix operations in JavaScript
We could do the matrix operations in JavaScript BUT WE
DON’T
SHADER is a program that runs on the GPU. SHADER
a
(THAT WAS EASY)
N N It begins with an...
OT JAVASCRIPT N N It begins with an...
GLSL GLSL OpenGL Shader Language
precision highp float; varying vec2 t; varying vec2 pos; uniform
float time; uniform vec2 mouse; uniform int mouseLeft; uniform sampler2D tex0; void main() { float v1 = (sin(t.s+time) + 1.0) / 2.0; float v2 = (cos(t.t+time) + 1.0) / 2.0; float d = distance(mouse, pos); vec2 tt = vec2(t.s+sin(time/10.0), t.t+cos(time/10.0)); vec4 c1 = texture2D(tex0, tt) * 1.1; float avg = (c1.r+c1.g+c1.b)/3.0; float r = c1.r+v1*pow(avg,4.0) - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); float g = c1.g+v2*pow(avg,4.0) - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); float b = c1.g - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); gl_FragColor = vec4(r, g, b, 1.0); }
precision highp float; varying vec2 t; varying vec2 pos; uniform
float time; uniform vec2 mouse; uniform int mouseLeft; uniform sampler2D tex0; void main() { float v1 = (sin(t.s+time) + 1.0) / 2.0; float v2 = (cos(t.t+time) + 1.0) / 2.0; float d = distance(mouse, pos); vec2 tt = vec2(t.s+sin(time/10.0), t.t+cos(time/10.0)); vec4 c1 = texture2D(tex0, tt) * 1.1; float avg = (c1.r+c1.g+c1.b)/3.0; float r = c1.r+v1*pow(avg,4.0) - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); float g = c1.g+v2*pow(avg,4.0) - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); float b = c1.g - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); gl_FragColor = vec4(r, g, b, 1.0); } WELL THIS KINDA LOOKS LIKE JAVASCRIPT WELL THIS KINDA LOOKS LIKE JAVASCRIPT
precision highp float; varying vec2 t; varying vec2 pos; uniform
float time; uniform vec2 mouse; uniform int mouseLeft; uniform sampler2D tex0; void main() { float v1 = (sin(t.s+time) + 1.0) / 2.0; float v2 = (cos(t.t+time) + 1.0) / 2.0; float d = distance(mouse, pos); vec2 tt = vec2(t.s+sin(time/10.0), t.t+cos(time/10.0)); vec4 c1 = texture2D(tex0, tt) * 1.1; float avg = (c1.r+c1.g+c1.b)/3.0; float r = c1.r+v1*pow(avg,4.0) - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); float g = c1.g+v2*pow(avg,4.0) - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); float b = c1.g - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); gl_FragColor = vec4(r, g, b, 1.0); }
precision highp float; varying vec2 t; varying vec2 pos; uniform
float time; uniform vec2 mouse; uniform int mouseLeft; uniform sampler2D tex0; void main() { float v1 = (sin(t.s+time) + 1.0) / 2.0; float v2 = (cos(t.t+time) + 1.0) / 2.0; float d = distance(mouse, pos); vec2 tt = vec2(t.s+sin(time/10.0), t.t+cos(time/10.0)); vec4 c1 = texture2D(tex0, tt) * 1.1; float avg = (c1.r+c1.g+c1.b)/3.0; float r = c1.r+v1*pow(avg,4.0) - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); float g = c1.g+v2*pow(avg,4.0) - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); float b = c1.g - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); gl_FragColor = vec4(r, g, b, 1.0); } “
precision highp float; varying vec2 t; varying vec2 pos; uniform
float time; uniform vec2 mouse; uniform int mouseLeft; uniform sampler2D tex0; void main() { float v1 = (sin(t.s+time) + 1.0) / 2.0; float v2 = (cos(t.t+time) + 1.0) / 2.0; float d = distance(mouse, pos); vec2 tt = vec2(t.s+sin(time/10.0), t.t+cos(time/10.0)); vec4 c1 = texture2D(tex0, tt) * 1.1; float avg = (c1.r+c1.g+c1.b)/3.0; float r = c1.r+v1*pow(avg,4.0) - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); float g = c1.g+v2*pow(avg,4.0) - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); float b = c1.g - pow(d,pow(avg,2.0) +float(mouseLeft)*avg); gl_FragColor = vec4(r, g, b, 1.0); } <script id="fragment-shader" type="x-shader/x-fragment"> </script>
document.getElementById document.getElementById
GLSL GLSL GLSL compile compile compile link
xx xy xz Yx Yy Yz Zx Zy Zz {
} xx xy xz Yx Yy Yz Zx Zy Zz { } Perspective Matrix Model View Matrix
attribute vec3 aVertexPosition; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; void
main(void) { gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); }
attribute vec3 aVertexPosition; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; void
main(void) { gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); } Output
attribute vec3 aVertexPosition; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; void
main(void) { gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); } Output Uniforms
attribute vec3 aVertexPosition; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; void
main(void) { gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); } Output Uniforms Attribute
None
None
xx xy xz Yx Yy Yz Zx Zy Zz {
} xx xy xz Yx Yy Yz Zx Zy Zz { } Passing Uniforms var ptr = gl.getUniformLocation(shaderProgram, "uPMatrix") gl.uniformMatrix4fv( ptr, false, new Float32Array(vertexes));
None
-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0,
1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, Here come the vertices
-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0,
1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, Here come the vertices
-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0,
1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, Here come the vertices
-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0,
1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, Here come the vertices
-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0,
1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, Here come the vertices
cubeVertices = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertices); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER,
cubeVertices); gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); 0,1,0 1,0,0 0,1,1 1,0,1 1,1,1 Passing Vertices
cubeVertices = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertices); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER,
cubeVertices); gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); 0,1,0 1,0,0 0,1,1 1,0,1 1,1,1 Passing Vertices
xx xy xz Yx Yy Yz Zx Zy Zz {
} xx xy xz Yx Yy Yz Zx Zy Zz { } Uniforms gl_Position 0,1,0 1,0,0 0,1,1 1,0,1 1,1,1 [aVertexPosition] drawArrays*
xx xy xz Yx Yy Yz Zx Zy Zz {
} xx xy xz Yx Yy Yz Zx Zy Zz { } Uniforms gl_Position 0,1,0 1,0,0 0,1,1 1,0,1 1,1,1 [aVertexPosition] drawArrays*
xx xy xz Yx Yy Yz Zx Zy Zz {
} xx xy xz Yx Yy Yz Zx Zy Zz { } Uniforms gl_Position 0,1,0 1,0,0 0,1,1 1,0,1 1,1,1 [aVertexPosition] drawArrays*
xx xy xz Yx Yy Yz Zx Zy Zz {
} xx xy xz Yx Yy Yz Zx Zy Zz { } Uniforms gl_Position 0,1,0 1,0,0 0,1,1 1,0,1 1,1,1 [aVertexPosition] drawArrays*
xx xy xz Yx Yy Yz Zx Zy Zz {
} xx xy xz Yx Yy Yz Zx Zy Zz { } Uniforms gl_Position 0,1,0 1,0,0 0,1,1 1,0,1 1,1,1 [aVertexPosition] drawArrays*
Rasterization
None
None
Fragments
Fragment Shader varying lowp vec4 vColor; void main(void) { gl_FragColor
= vColor; }
Fragment Shader varying lowp vec4 vColor; void main(void) { gl_FragColor
= vColor; } Output
Fragment Shader varying lowp vec4 vColor; void main(void) { gl_FragColor
= vColor; } Output Variant
Variants Vertex Shader Fragment Shader
None
None
Color
Color Texture
Color Texture Lighting
Color Texture Lighting Specularity
Color Texture Lighting Specularity Normal Mapping
Color Texture Lighting Specularity Normal Mapping ...
Clear Canvas Load Perspective M atrixes Load O bject M
atrixes Render O bject
None
Three.js https://github.com/mrdoob/three.js A.K.A. use
3D is hard
3D is hard hard to understand
3D is hard hard to understand hard to learn
Hard to get right
But we need to try
None
twitter.com/vmg github.com/vmg
With demos from: http://wagerfield.github.io/flat-surface-shader/ http://lab.aerotwist.com/webgl/surface/ http://www.mrdoob.com/lab/javascript/beachballs/ http://plumegraph.org/