WebGL Beginner's Guide
Diego Cantor
Brandon Jones
Chapter No. 4
"Camera"
In this package, you will find:
A Biography of the authors of the book
A preview chapter from the book, Chapter NO.4 "Camera"
A synopsis of the book’s content
Information on where to buy this book
Brandon Jones has been developing WebGL demos since the technology first began
appearing in browsers in early 2010. He finds that it's the perfect combination of two
aspects of programming that he loves, allowing him to combine eight years of web
development experience and a life-long passion for real-time graphics.
Brandon currently works with cutting-edge HTML5 development at Motorola Mobility.
I'd like to thank my wife, Emily, and my dog, Cooper, for being very
patient with me while writing this book, and Zach for convincing me that
I should do it in the first place. For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book
WebGL Beginner's Guide
WebGL is a new web technology that brings hardware-accelerated 3D graphics to the
browser without requiring the user to install additional soft ware. As WebGL is based on
OpenGL and brings in a new concept of 3D graphics programming to web development,
it may seem unfamiliar to even experienced web developers.
Packed with many examples, this book shows how WebGL can be easy to learn despite
its unfriendly appearance. Each chapter addresses one of the important aspects of 3D
graphics programming and presents different alternatives for its implementation. The
topics are always associated with exercises that will allow the reader to put the concepts
to the test in an immediate manner.
WebGL Beginner's Guide presents a clear road map to learning WebGL. Each chapter
starts with a summary of the learning goals for the chapter, followed by a detailed
description of each topic. The book offers example-rich, up-to-date introductions to a
wide range of essential WebGL topics, including drawing, color, texture, transformations,
framebuffers, light, surfaces, geometry, and more. Each chapter is packed with useful and
practical examples that demonstrate the implementation of these topics in a WebGL
scene. With each chapter, you will "level up" your 3D graphics programming skills. This
using matrix stacks and JavaScript timers. Each technique is exemplified through a
practical demo.
Chapter 6, Colors, Depth Testing, and Alpha Blending, goes in depth about the use of
colors in ESSL shaders. This chapter shows how to define and operate with more than
one light source in a WebGL scene. It also explains the concepts of Depth Testing and
Alpha Blending, and it shows how these features can be used to create translucent
objects. The chapter contains several practical exercises that put into practice
these concepts.
Chapter 7, Textures, shows how to create, manage, and map textures in a WebGL scene.
The concepts of texture coordinates and texture mapping are presented here. This chapter
discusses different mapping techniques that are presented through practical examples.
The chapter also shows how to use multiple textures and cube maps.
Chapter 8, Picking, describes a simple implementation of picking which is the technical
term that describes the selection and interaction of the user with objects in the scene. The
method described in this chapter calculates mouse-click coordinates and determines if the
user is clicking on any of the objects being rendered in the canvas. The architecture of
the solution is presented with several callback hooks that can be used to implement
logic-specific application. A couple of examples of picking are given.
Chapter 9, Putting It All Together, ties in the concepts discussed throughout the book.
In this chapter the architecture of the demos is reviewed and the virtual car showroom
application outlined in Chapter 1, Getting Started with WebGL, is revisited and
expanded. Using the virtual car showroom as the case study, this chapter shows
how to import Blender models into WebGL scenes and how to create ESSL shaders
that support the materials used in Blender.
Chapter 10, Advanced Techniques, shows a sample of some advanced techniques such as
post-processing effects, point sprites, normal mapping, and ray tracing. Each technique is
provided with a practical example. After reading this WebGL Beginner's Guide you will
be able to take on more advanced techniques on your own.
Camera
[ 106 ]
WebGL does not have cameras
This statement should be shocking! How is it that there are no cameras in a 3D computer
graphics technology? Well, let me rephrase this in a more amicable way. WebGL does not
have a camera object that you can manipulate. However, we can assume that what we see
rendered in the canvas is what our camera captures. In this chapter, we are going to solve
the problem of how to represent a camera in WebGL. The short answer is we need
4x4 matrices.
Every me that we move our camera around, we will need to update the objects according
to the new camera posi on. To do this, we need to systema cally process each vertex
applying a transforma on that produces the new viewing posi on. Similarly, we need to
make sure that the object normals and light direc ons are s ll consistent a er the camera
has moved. In summary, we need to analyze two diff erent types of transforma ons: vertex
(points) and normal (vectors).
Vertex transformations
Objects in a WebGL scene go through diff erent transforma ons before we can see them on
our screen. Each transforma on is encoded by a 4x4 matrix, as we will see later. How do we
mul ply ver ces that have three components (x,y,z) by a 4x4 matrix? The short answer is
that we need to augment the cardinality of our tuples by one dimension. Each vertex then
will have a fourth component called the homogenous coordinate. Let's see what they are
and why they are useful.
Homogeneous coordinates
Homogeneous coordinates are a key component of any computer graphics program.
Thanks to them, it is possible to represent affi ne transforma ons (rota on, scaling,
shear, and transla on) and projec ve transforma ons as 4x4 matrices.
In Homogeneous coordinates, ver ces have four components: x, y, z, and w. The fi rst three
components are the vertex coordinates in Euclidian Space . The fourth is the perspec ve
component. The 4-tuple (x,y,z,w) take us to a new space: The Projec ve Space .
Homogeneous coordinates make possible to solve a system of linear equa ons where each
//Transformedvertexposition
vec4vertex=uMVMatrix*vec4(aVertexPosition,1.0);
//Transformednormalposition
vNormal=vec3(uNMatrix*vec4(aVertexNormal,0.0));
//VectorEye
vEyeVec=-vec3(vertex.xyz);
//Finalvertexposition
gl_Position=uPMatrix*uMVMatrix*vec4(aVertexPosition,1.0);
}
Please no ce that for the aVertexPosition a ribute, which contains a vertex of our
geometry, we create a 4-tuple from the 3-tuple that we receive. We do this with the ESSL
construct vec4(). ESSL knows that aVertexPosition is a vec3 and therefore we only
need the fourth component to create a
vec4.For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book
Camera
[ 108 ]
To pass from Homogeneous coordinates to Euclidean coordinates, we divide by w
To pass from Euclidean coordinates to Homogeneous coordinates, we add w =1
Homogeneous coordinates with
w = 0 represent a point at infi nity
There is one more thing you should know about Homogeneous coordinates—while ver ces
have a Homogeneous coordinate w = 1, vectors have a Homogeneous coordinate w = 0.
This is the reason why, in the Phong vertex shader, the line that processes the normals
looks like this:
vNormal = vec3(uNMatrix * vec4(aVertexNormal, 0.0));
For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book
Camera
[ 110 ]
Projection transform
The next opera on is called the projec on transform. This opera on determines how much
of the view space will be rendered and how it will be mapped onto the computer screen.
This region is known as the frustum and it is defi ned by six planes (near, far, top, bo om,
right, and le planes), as shown in the following diagram:
These six planes are encoded in the Perspec ve matrix . Any ver ces lying outside of the
frustum a er applying the transforma on are clipped out and discarded from further
processing. Therefore, the frustum defi nes, and the projec on matrix that encodes the
frustum produces, clipping coordinates.
The shape and extent of the frustum determines the type of projec on from the 3D viewing
space to the 2D screen. If the far and near planes have the same dimensions, then the
frustum will determine an orthographic projec on. Otherwise, it will be a perspec ve
projec on, as shown in the following diagram:For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book
Chapter 4
[ 111 ]
Up to this point, we are s ll working with Homogeneous coordinates, so the clipping
coordinates have four components: x, y, z, and w. The clipping is done by comparing the x, y,
and z components against the Homogeneous coordinate w. If any of them is more than, +w,
or less than, –w , then that vertex lies outside the frustum and is discarded.
Finally, NDCs are mapped to viewport coordinates . This step maps these coordinates to the
available space in your screen. In WebGL, this space is provided by the HTML5 canvas, as
shown in the following fi gure:
Unlike the previous cases, the viewport transform is not generated by a matrix
transforma on. In this case, we use the WebGL
viewport func on . We will learn more
about this func on later in the chapter. Now it is me to see what happens to normals.For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book
Chapter 4
[ 113 ]
Normal transformations
Whenever ver ces are transformed, normal vectors should also be transformed, so they
point in the right direc on. We could think of using the Model-View matrix that transforms
ver ces to do this, but there is a problem: The Model-View matrix will not always keep the
perpendicularity of normals.
This problem occurs if there is a unidirec onal (one axis) scaling transforma on or a
shearing transforma on in the Model-View matrix. In our example, we have a triangle
that has undergone a scaling transforma on on the y-axis. As you can see, the normal
N' is not normal anymore a er this kind of transforma on. How do we solve this?
Calculating the Normal matrix
If you are not interested in fi nding out how we calculate the Normal matrix and just want the
answer, please feel free to jump to the end of this sec on. Otherwise, s ck around to see
some linear algebra in ac on!
Let's start from the mathema cal defi ni on of perpendicularity. Two vectors are
perpendicular if their dot product is zero. In our example:
N.S = 0
T
MS = 0
Grouping the inner terms:
N
T
(K
T
M)S = 0
Now remember that N.S =0 so N
T
S = 0 (again, a dot product can be wri en as a vector
mul plica on). This means that in the previous equa on, (K
T
M ) needs to be the iden ty
matrix I, so the original condi on of N and S being perpendicular holds:
K
T
M = I
Applying a bit of algebra:
K
T
MM
-1
= IM
-1
= M
-1
mul ply by the inverse of M on both
sides
K
Chapter 4
[ 115 ]
K is obtained by transposing the inverse of the Model-View matrix
(M in this example).
We need to use K to mul ply the normal vectors so they keep being perpendicular
to surface when these are transformed.
WebGL implementation
Now let's take a look at how we can implement vertex and normal transforma ons in
WebGL. The following diagram shows the theory that we have learned so far and it
shows the rela onships between the steps in the theory and the implementa on
in WebGL.
In WebGL, the fi ve transforma ons that we apply to object coordinates to obtain viewport
coordinates are grouped in three matrices and one WebGL method:
1. The Model-View matrix that groups the model and view transform in one single
matrix. When we mul ply our ver ces by this matrix, we end up in view coordinates.
2. The Normal matrix is obtained by inver ng and transposing the Model-View matrix.
This matrix is applied to normal vectors for ligh ng purposes.
3. The Perspec ve matrix groups the projec on transforma on and the perspec ve
division, and as a result, we end up in normalized device coordinates (NDC).
Finally, we use the opera on
gl.viewport to map NDCs to viewport coordinates:
gl.viewport(minX, minY, width, height);
The viewport coordinates have their origin in the lower-le corner of the
HTML5 canvas.For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book
Camera
(this is a 3-element array [x,y,z]).
glMatrix also provides func ons to perform other linear algebra opera ons. It also
operates on vectors and matrices of rank 3. To get the full list, visit
/>toji/gl-matrix
Mapping JavaScript matrices to ESSL uniforms
As the Model-View and Perspec ve matrices do not change during a single rendering step,
they are passed as uniforms to the shading program. For example, if we were applying
a transla on to an object in our scene, we would have to paint the whole object in the
new coordinates given by the transla on. Pain ng the whole object in the new posi on
is achieved in exactly one rendering step.
However, before the rendering step is invoked (by calling
drawArrays or drawElements,
as we saw in Chapter 2, Rendering Geometry), we need to make sure that the shaders have
an updated version of our matrices. We have seen how to do that for other uniforms such
as light and color proper es. The method map JavaScript matrices to uniforms is similar to
the following:For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book
Chapter 4
[ 117 ]
First, we get a JavaScript reference to the uniform with:
var reference= getUniformLocation(Object program, String uniformName)
Then, we use the reference to pass the matrix to the shader with:
gl.uniformMatrix4fv(WebGLUniformLocation reference, bool transpose,
float[] matrix);
matrix is the JavaScript matrix variable.
As it is the case for other uniforms, ESSL supports 2, 3, and 4-dimensional matrices:
For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book
Camera
[ 118 ]
//Transformed normal vector
vNormal = uNMatrix * aVertexNormal;
//Vector Eye
vEyeVec = -vec3(vertex.xyz);
//Final vertex position
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition,
1.0);
}
In ESSL, the mul plica on of matrices is straigh orward, that is, you do not need to mul ply
element by element, but as ESSL knows that you are working with matrices, it performs the
mul plica on for you.
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
The last line of this shader assigns a value to the predefi ned gl_Position variable. This
will contain the clipping coordinates for the vertex that is currently being processed by the
shader. We should remember here that the shaders work in parallel: each vertex is processed
by an instance of the vertex shader.
To obtain the clipping coordinates for a given vertex, we need to mul ply fi rst by the Model-
View matrix and then by the Projec on matrix. To achieve this, we need to mul ply to the
le (because matrix mul plica on is not commuta ve).
Also, no ce that we have had to augment the
aVertexPosition a ribute by including
the Homogeneous coordinate. This is because we have always defi ned our geometry in
nega ve direc on of the z-axis. As shown in the following diagram, the z-axis is coming out
of the screen (which means that you are looking at the nega ve z-axis).
From the center of the screen to the right, you will have the posi ve x-axis and from the
center of the screen up, you will have the posi ve y-axis. This is the ini al confi gura on
and it is the reference for affi ne transforma ons.
In this confi gura on, the Model-View matrix is the iden ty matrix of rank four.
The fi rst three rows of the Model-View matrix contain informa on about rota ons
and transla ons that are aff ec ng the world.For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book
Camera
[ 120 ]
Rotation matrix
The intersec on of the fi rst three rows with the fi rst three columns defi nes the 3x3 Rota on
matrix. This matrix contains informa on about rota ons around the standard axis. In the
ini al confi gura on, this corresponds to:
[m
1
,m
2
,m
3
] = [1, 0, 0] = x-axis
[m
5
,m
6
all the informa on that we need to operate a camera (mainly rota ons and transla ons) can
be extracted from the Model-View matrix itself!
The Camera matrix
Let's say, for a moment, that we do have a camera in WebGL. A camera should be able to
rotate and translate to explore this 3D world. For example, think of a fi rst person shooter
game where you have to walk through levels killing zombies. As we saw in the previous
sec on, a 4x4 matrix can encode rota ons and transla ons. Therefore, our hypothe cal
camera could also be represented by one such matrix.
Assume that our camera is located at the origin of the world and that it is oriented in a way
that it is looking towards the nega ve z-axis direc on. This is a good star ng point—we
already know what transforma on represents such a confi gura on in WebGL (iden ty matrix
of rank 4).For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book
Chapter 4
[ 121 ]
For the sake of analysis, let's break the problem down into two sub-problems: camera
transla on and camera rota on. We will have a prac cal demo on each one.
Camera translation
Let's move the camera to [0 ,0, 4] in world coordinates. This means 4 units from the origin on
the posi ve z-axis.
Remember that we do not know at this point of a matrix to move the camera, we only know
how to move the world (with the Model-View matrix). If we applied:
mat4.translate(mvMatrix, [0,0,4]);
In such a case, the world would be translated 4 units on the posi ve z-axis and as the camera
posi on has not been changed (as we do not know a matrix to do this), it would be located
at [0,0,-4], which is exactly the opposite of what we wanted in the fi rst place!
coordinates, do we need to increase or decrease the z-axis slider? Go ahead
and try your answer.For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book
Chapter 4
[ 123 ]
6. Now switch to camera coordinates by clicking on the Camera bu on. What is the
transla on component of this matrix? What do you need to do if you want to move
the camera closer to the cone? What does the fi nal transla on look like? What can
you conclude?
7. Go ahead and try to move the camera on the x-axis and the y-axis. Check what the
correspondent transforma ons would be on the Model-View matrix.
What just happened?
We saw that the camera transla on is the inverse of the Model-View matrix transla on.
We also learned where to fi nd transla on informa on in a transforma on matrix.
Camera rotation
Similarly, if we want to rotate the camera, say, 45 degrees to the right, this would be
equivalent to rota ng the world 45 degrees to the le . Using glMatrix to achieve this,
we write the following:
mat4.rotate(mvMatrix,45 * Math.PI/180, [0,1,0]);
Let's see this behavior in ac on!
Similar to the previous sec on where we explored transla ons, in the following me for
ac on, we are going to play with rota ons in both world and camera spaces.For More Information:
www.packtpub.com/webgl-javascript-beginners-guide/book