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
550
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
初学者でも今すぐできる、Claude Codeの生産性を10倍上げるTips
s4yuba
16
13k
MCPを使ってイベントソーシングのAIコーディングを効率化する / Streamlining Event Sourcing AI Coding with MCP
tomohisa
0
180
レトロゲームから学ぶ通信技術の歴史
kimkim0106
0
120
チームで開発し事業を加速するための"良い"設計の考え方 @ サポーターズCoLab 2025-07-08
agatan
1
480
AI Agent 時代のソフトウェア開発を支える AWS Cloud Development Kit (CDK)
konokenj
6
930
ソフトウェア品質を数字で捉える技術。事業成長を支えるシステム品質の マネジメント
takuya542
2
16k
バイブスあるコーディングで ~PHP~ 便利ツールをつくるプラクティス
uzulla
1
220
オンコール⼊⾨〜ページャーが鳴る前に、あなたが備えられること〜 / Before The Pager Rings
yktakaha4
2
1.1k
抽象化という思考のツール - 理解と活用 - / Abstraction-as-a-Tool-for-Thinking
shin1x1
0
110
MCPで実現できる、Webサービス利用体験について
syumai
1
100
コーディングエージェント概観(2025/07)
itsuki_t88
0
120
ISUCON研修おかわり会 講義スライド
arfes0e2b3c
1
480
Featured
See All Featured
Statistics for Hackers
jakevdp
799
220k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
161
15k
Git: the NoSQL Database
bkeepers
PRO
431
65k
It's Worth the Effort
3n
185
28k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
126
53k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.4k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
138
34k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
30
2.2k
Practical Orchestrator
shlominoach
189
11k
Designing Experiences People Love
moore
142
24k
Why Our Code Smells
bkeepers
PRO
337
57k
Become a Pro
speakerdeck
PRO
29
5.4k
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/