Web GL Beginner's Guide

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 377

DownloadWeb GL Beginner's Guide
Open PDF In BrowserView PDF
WebGL Beginner's Guide

Become a master of 3D web programming in WebGL
and JavaScript

Diego Cantor
Brandon Jones

BIRMINGHAM - MUMBAI

WebGL Beginner's Guide
Copyright © 2012 Packt Publishing

All rights reserved. No part of this book may be reproduced, stored in a retrieval system,
or transmitted in any form or by any means, without the prior written permission of the
publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the
information presented. However, the information contained in this book is sold without
warranty, either express or implied. Neither the authors, nor Packt Publishing, and its dealers
and distributors will be held liable for any damages caused or alleged to be caused directly or
indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the
companies and products mentioned in this book by the appropriate use of capitals.
However, Packt Publishing cannot guarantee the accuracy of this information.

First published: June 2012

Production Reference: 1070612

Published by Packt Publishing Ltd.
Livery Place
35 Livery Street
Birmingham B3 2PB, UK.
ISBN 978-1-84969-172-7
www.packtpub.com

Cover Image by Diego Cantor (diego.cantor@gmail.com)

Credits
Authors
Diego Cantor

Copy Editor
Leonard D'Silva

Brandon Jones
Project Coordinator
Reviewers

Joel Goveya

Paul Brunt
Dan Ginsburg
Andor Salga
Giles Thomas
Acquisition Editor
Wilson D'Souza
Lead Technical Editor
Azharuddin Sheikh
Technical Editors
Manasi Poonthottam
Manali Mehta
Rati Pillai
Ankita Shashi
Manmeet Singh Vasir

Proofreader
Lesley Harrison
Indexer
Monica Ajmera Mehta
Graphics
Valentina D'silva
Manu Joseph
Production Coordinator
Melwyn D'sa
Cover Work
Melwyn D'sa

About the Authors
Diego Hernando Cantor Rivera is a Software Engineer born in 1980 in Bogota, Colombia.
Diego completed his undergraduate studies in 2002 with the development of a computer
vision system that tracked the human gaze as a mechanism to interact with computers.
Later on, in 2005, he finished his master's degree in Computer Engineering with emphasis
in Software Architecture and Medical Imaging Processing. During his master's studies, Diego
worked as an intern at the imaging processing laboratory CREATIS in Lyon, France and later
on at the Australian E-Health Research Centre in Brisbane, Australia.
Diego is currently pursuing a PhD in Biomedical Engineering at Western University
in London, Canada, where he is involved in the development augmented reality systems
for neurosurgery.
When Diego is not writing code, he enjoys singing, cooking, travelling, watching a good play,
or bodybuilding.
Diego speaks Spanish, English, and French.

Acknowledgement
I would like to thank all the people that in one way or in another have been involved with
this project:
My partner Jose, thank you for your love and infinite patience.
My family Cecy, Fredy, and Jonathan.
My mentors Dr. Terry Peters and Dr. Robert Bartha for allowing me to work on this project.
Thank you for your support and encouragement.
My friends and collegues Danielle Pace and Chris Russ. Guys your work ethic,
professionalism, and dedication are inspiring. Thank you for supporting me during
the development of this project.
Brandon Jones, my co-author for the awesome glMatrix library! This is a great contribution
to the WebGL world! Also, thank you for your contributions on chapters 7 and 10. Without
you this book would not had been a reality.
The technical reviewers who taught me a lot and gave me great feedback during the
development of this book: Dan Ginsburg, Giles Thomas, Andor Salga, and Paul Brunt.
You guys rock!
The tireless PACKT team: Joel Goveya, Wilson D'souza, Maitreya Bhakal, Meeta Rajani,
Azharuddin Sheikh, Manasi Poonthottam, Manali Mehta, Manmeet Singh Vasir, Archana
Manjrekar, Duane Moraes, and all the other people that somehow contributed to this
project at PACKT publishing.

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.

About the Reviewers
Paul Brunt has over 10 years of web development experience, initially working on
e-commerce systems. However, with a strong programming background and a good grasp
of mathematics, the emergence of HTML5 presented him with the opportunity to work
with richer media technologies with particular focus on using these web technologies in the
creation of games. He was working with JavaScript early on in the emergence of HTML5 to
create some early games and applications that made extensive use of SVG, canvas, and a
new generation of fast JavaScript engines. This work included a proof of concept platform
game demonstration called Berts Breakdown.
With a keen interest in computer art and an extensive knowledge of Blender, combined with
knowledge of real-time graphics, the introduction of WebGL was the catalyst for the creation
of GLGE. He began working on GLGE in 2009 when WebGL was still in its infancy, gearing it
heavily towards the development of online games.
Apart from GLGE he has also contributed to other WebGL frameworks and projects as well as
porting the JigLib physics library to JavaScript in 2010, demoing 3D physics within a browser
for the first time.

Dan Ginsburg is the founder of Upsample Software, LLC, a software company
offering consulting services with a specialization in 3D graphics and GPU computing.
Dan has co-authored several books including the OpenGL ES 2.0 Programming Guide
and OpenCL Programming Guide. He holds a B.Sc in Computer Science from Worcester
Polytechnic Institute and an MBA from Bentley University.

Andor Salga graduated from Seneca College with a bachelor's degree in software
development. He worked as a research assistant and technical lead in Seneca's open
source research lab (CDOT) for four years, developing WebGL libraries such as Processing.
js, C3DL, and XB PointStream. He has presented his work at SIGGRAPH, MIT, and Seneca's
open source symposium.
I'd like to thank my family and my wife Marina.

Giles Thomas has been coding happily since he first encountered an ICL DRS 20 at
the age of seven. Never short on ambition, he wrote his first programming language
at 12 and his first operating system at 14. Undaunted by their complete lack of success,
and thinking that the third time is a charm, he is currently trying to reinvent cloud
computing with a startup called PythonAnywhere. In his copious spare time, he runs
a blog at http://learningwebgl.com/

www.PacktPub.com
Support files, eBooks, discount offers, and more
You might want to visit www.PacktPub.com for support files and downloads related to
your book.
Did you know that Packt offers eBook versions of every book published, with PDF and ePub
files available? You can upgrade to the eBook version at www.PacktPub.com and as a print
book customer, you are entitled to a discount on the eBook copy. Get in touch with us at
service@packtpub.com for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a
range of free newsletters and receive exclusive discounts and offers on Packt books and eBooks.

http://PacktLib.PacktPub.com

Do you need instant solutions to your IT questions? PacktLib is Packt's online digital book
library. Here, you can access, read and search across Packt's entire library of books.

Why Subscribe?
‹‹

Fully searchable across every book published by Packt

‹‹

Copy and paste, print and bookmark content

‹‹

On demand and accessible via web browser

Free Access for Packt account holders
If you have an account with Packt at www.PacktPub.com, you can use this to access
PacktLib today and view nine entirely free books. Simply use your login credentials for
immediate access.

Table of Contents
Preface
Chapter 1: Getting Started with WebGL
System requirements
What kind of rendering does WebGL offer?
Structure of a WebGL application
Creating an HTML5 canvas
Time for action – creating an HTML5 canvas
Defining a CSS style for the border
Understanding canvas attributes
What if the canvas is not supported?
Accessing a WebGL context
Time for action – accessing the WebGL context
WebGL is a state machine
Time for action – setting up WebGL context attributes
Using the context to access the WebGL API
Loading a 3D scene
Virtual car showroom
Time for action – visualizing a finished scene
Summary

Chapter 2: Rendering Geometry
Vertices and Indices
Overview of WebGL's rendering pipeline
Vertex Buffer Objects (VBOs)
Vertex shader
Fragment shader
Framebuffer
Attributes, uniforms, and varyings

1
7
8
8
10
10
11
12
12
12
13
13
15
15
18
18
18
19
21

23
23
24
25
25
25
25
26

Table of Contents

Rendering geometry in WebGL
Defining a geometry using JavaScript arrays
Creating WebGL buffers
Operations to manipulate WebGL buffers

26
26
27
30

Associating attributes to VBOs

31

Binding a VBO
Pointing an attribute to the currently bound VBO
Enabling the attribute

Rendering

32
32
33

33

The drawArrays and drawElements functions

33

Putting everything together
Time for action – rendering a square
Rendering modes
Time for action – rendering modes
WebGL as a state machine: buffer manipulation
Time for action – enquiring on the state of buffers
Advanced geometry loading techniques: JavaScript Object Notation (JSON)
and AJAX
Introduction to JSON – JavaScript Object Notation
Defining JSON-based 3D models
JSON encoding and decoding

37
37
41
41
45
46
48
48
48
50

Time for action – JSON encoding and decoding
Asynchronous loading with AJAX
Setting up a web server
Working around the web server requirement

50
51
53
54

Time for action – loading a cone with AJAX + JSON
Summary

Chapter 3: Lights!

54
58

59

Lights, normals, and materials
Lights
Normals
Materials
Using lights, normals, and materials in the pipeline
Parallelism and the difference between attributes and uniforms

Shading methods and light reflection models
Shading/interpolation methods
Goraud interpolation
Phong interpolation

60
60
61
62
62
63

64
65
65
65

Light reflection models

66

Lambertian reflection model
Phong reflection model

66
67

ESSL—OpenGL ES Shading Language
Storage qualifier

68
69
[ ii ]

Table of Contents

Types
Vector components
Operators and functions
Vertex attributes
Uniforms
Varyings
Vertex shader
Fragment shader
Writing ESSL programs
Goraud shading with Lambertian reflections
Time for action – updating uniforms in real time
Goraud shading with Phong reflections
Time for action – Goraud shading
Phong shading
Time for action – Phong shading with Phong lighting
Back to WebGL
Creating a program
Initializing attributes and uniforms
Bridging the gap between WebGL and ESSL
Time for action – working on the wall
More on lights: positional lights
Time for action – positional lights in action
Nissan GTS example
Summary

Chapter 4: Camera

69
70
71
72
72
73
73
75
75
76
77
80
83
86
88
89
90
92
93
95
99
100
102
103

105

WebGL does not have cameras
Vertex transformations
Homogeneous coordinates
Model transform
View transform
Projection transform
Perspective division
Viewport transform
Normal transformations
Calculating the Normal matrix
WebGL implementation
JavaScript matrices
Mapping JavaScript matrices to ESSL uniforms
Working with matrices in ESSL

[ iii ]

106
106
106
108
109
110
111
112
113
113
115
116
116
117

Table of Contents

The Model-View matrix
Spatial encoding of the world

118
119

Rotation matrix
Translation vector
The mysterious fourth row

120
120
120

The Camera matrix
Camera translation
Time for action – exploring translations: world space versus camera space
Camera rotation
Time for action – exploring rotations: world space versus camera space
The Camera matrix is the inverse of the Model-View matrix
Thinking about matrix multiplications in WebGL
Basic camera types
Orbiting camera
Tracking camera
Rotating the camera around its location
Translating the camera in the line of sight
Camera model

120
121
122
123
124
127
127
128
129
129
129
129
130

Time for action – exploring the Nissan GTX
The Perspective matrix
Field of view
Perspective or orthogonal projection
Time for action – orthographic and perspective projections
Structure of the WebGL examples
WebGLApp
Supporting objects
Life-cycle functions
Configure
Load
Draw

131
135
136
136
137
142
142
143
144
144
144
144

Matrix handling functions

144

initTransforms
updateTransforms
setMatrixUniforms

144
145
146

Summary

146

Chapter 5: Action

149

Matrix stacks
Animating a 3D scene
requestAnimFrame function
JavaScript timers
Timing strategies
Animation strategy
Simulation strategy

150
151
151
152
152
153
154
[ iv ]

Table of Contents

Combined approach: animation and simulation
Web Workers: Real multithreading in JavaScript
Architectural updates
WebGLApp review
Adding support for matrix stacks
Configuring the rendering rate
Creating an animation timer
Connecting matrix stacks and JavaScript timers
Time for action – simple animation
Parametric curves
Initialization steps
Setting up the animation timer
Running the animation
Drawing each ball in its current position
Time for action – bouncing ball
Optimization strategies
Optimizing batch performance
Performing translations in the vertex shader
Interpolation
Linear interpolation
Polynomial interpolation
B-Splines
Time for action – interpolation
Summary

Chapter 6: Colors, Depth Testing, and Alpha Blending
Using colors in WebGL
Use of color in objects
Constant coloring
Per-vertex coloring
Per-fragment coloring
Time for action – coloring the cube
Use of color in lights
Using multiple lights and the scalability problem

154
156
156
156
157
157
158
158
158
160
161
162
163
163
164
166
167
168
170
170
170
172
173
175

177
178
179
179
180
181
181
185
186

How many uniforms can we use?
Simplifying the problem

186
186

Architectural updates
Adding support for light objects

187
187

Improving how we pass uniforms to the program

188

Time for action – adding a blue light to a scene
Using uniform arrays to handle multiple lights

190
196

Uniform array declaration

197
[v]

Table of Contents
JavaScript array mapping

198

Time for action – adding a white light to a scene
Time for action – directional point lights
Use of color in the scene
Transparency
Updated rendering pipeline
Depth testing
Depth function
Alpha blending
Blending function
Separate blending functions
Blend equation
Blend color
WebGL alpha blending API
Alpha blending modes
Additive blending
Subtractive blending
Multiplicative blending
Interpolative blending

198
202
206
207
207
208
210
210
211
212
213
213
214
215
216
216
216
216

Time for action – blending workbench
Creating transparent objects
Time for action – culling
Time for action – creating a transparent wall
Summary

Chapter 7: Textures

217
218
220
222
224

225

What is texture mapping?
Creating and uploading a texture
Using texture coordinates
Using textures in a shader
Time for action – texturing the cube
Texture filter modes
Time for action – trying different filter modes
NEAREST
LINEAR

226
226
228
230
231
234
237
238
238

Mipmapping

239

NEAREST_MIPMAP_NEAREST
LINEAR_MIPMAP_NEAREST
NEAREST_MIPMAP_LINEAR
LINEAR_MIPMAP_LINEAR

240
240
240
241

Generating mipmaps
Texture wrapping
Time for action – trying different wrap modes
CLAMP_TO_EDGE

241
242
243
244

[ vi ]

Table of Contents
REPEAT
MIRRORED_REPEAT

244
245

Using multiple textures
Time for action – using multitexturing
Cube maps
Time for action – trying out cube maps
Summary

246
247
250
252
255

Chapter 8: Picking

257

Picking
Setting up an offscreen framebuffer
Creating a texture to store colors
Creating a Renderbuffer to store depth information
Creating a framebuffer for offscreen rendering
Assigning one color per object in the scene
Rendering to an offscreen framebuffer
Clicking on the canvas
Reading pixels from the offscreen framebuffer
Looking for hits
Processing hits
Architectural updates
Time for action – picking
Picker architecture
Implementing unique object labels
Time for action – unique object labels
Summary

Chapter 9: Putting It All Together

257
259
259
260
260
261
262
264
266
268
269
269
271
272
274
274
285

287

Creating a WebGL application
Architectural review
Virtual Car Showroom application
Complexity of the models
Shader quality
Network delays and bandwidth consumption
Defining what the GUI will look like
Adding WebGL support
Implementing the shaders
Setting up the scene
Configuring some WebGL properties
Setting up the camera
Creating the Camera Interactor
The SceneTransforms object
[ vii ]

287
288
290
291
291
292
292
293
295
297
297
298
298
298

Table of Contents

Creating the lights
Mapping the Program attributes and uniforms
Uniform initialization
Loading the cars
Exporting the Blender models
Understanding the OBJ format
Parsing the OBJ files
Load cars into our WebGL scene
Rendering
Time for action – customizing the application
Summary

Chapter 10: Advanced Techniques

299
300
301
301
302
303
306
307
308
310
313

315

Post-processing
Creating the framebuffer
Creating the geometry
Setting up the shader
Architectural updates
Time for action – testing some post-process effects
Point sprites
Time for action – using point sprites to create a fountain of sparks
Normal mapping
Time for action – normal mapping in action
Ray tracing in fragment shaders
Time for action – examining the ray traced scene
Summary

Index

315
316
317
318
320
320
325
327
330
332
334
336
339

341

[ viii ]

Preface
WebGL is a new web technology that brings hardware-accelerated 3D graphics to the
browser without requiring the user to install additional software. 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 book will become your
trustworthy companion filled with the information required to develop cool-looking 3D web
applications with WebGL and JavaScript.

What this book covers

Chapter 1, Getting Started with WebGL, introduces the HTML5 canvas element and describes
how to obtain a WebGL context for it. After that, it discusses the basic structure of a WebGL
application. The virtual car showroom application is presented as a demo of the capabilities
of WebGL. This application also showcases the different components of a WebGL application.
Chapter 2, Rendering Geometry, presents the WebGL API to define, process, and render
objects. Also, this chapter shows how to perform asynchronous geometry loading using
AJAX and JSON.

Preface

Chapter 3, Lights!, introduces ESSL the shading language for WebGL. This chapter shows
how to implement a lighting strategy for the WebGL scene using ESSL shaders. The theory
behind shading and reflective lighting models is covered and it is put into practice through
several examples.
Chapter 4, Camera, illustrates the use of matrix algebra to create and operate cameras
in WebGL. The Perspective and Normal matrices that are used in a WebGL scene are also
described here. The chapter also shows how to pass these matrices to ESSL shaders so they
can be applied to every vertex. The chapter contains several examples that show how to set
up a camera in WebGL.
Chapter 5, Action, extends the use of matrices to perform geometrical transformations
(move, rotate, scale) on scene elements. In this chapter the concept of matrix stacks is
discussed. It is shown how to maintain isolated transformations for every object in the scene
using matrix stacks. Also, the chapter describes several animation techniques 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.

[2]

Preface

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.

What you need for this book
‹‹

You need a browser that implements WebGL. WebGL is supported by all major
browser vendors with the exception of Microsoft Internet Explorer. An updated
list of WebGL-enabled browsers can be found here:
http://www.khronos.org/webgl/wiki/Getting_a_WebGL_
Implementation

‹‹

A source code editor that recognizes and highlights JavaScript syntax.

‹‹

You may need a web server such as Apache or Lighttpd to load remote geometry
if you want to do so (as shown in Chapter 2, Rendering Geometry). This is optional.

Who this book is for

This book is written for JavaScript developers who are interested in 3D web development.
A basic understanding of the DOM object model, the JQuery library, AJAX, and JSON is ideal
but not required. No prior WebGL knowledge is expected.
A basic understanding of linear algebra operations is assumed.

Conventions

In this book, you will find several headings appearing frequently.
To give clear instructions of how to complete a procedure or task, we use:

Time for action – heading
1.

Action 1

2.

Action 2

3.

Action 3

Instructions often need some extra explanation so that they make sense, so they are
followed with:

[3]

Preface

What just happened?
This heading explains the working of tasks or instructions that you have just completed.
You will also find some other learning aids in the book, including:

Have a go hero – heading
These set practical challenges and give you ideas for experimenting with what you
have learned.
You will also find a number of styles of text that distinguish between different kinds of
information. Here are some examples of these styles, and an explanation of their meaning.
Code words in text are shown as follows: "Open the file ch1_Canvas.html using one of the
supported browsers."
A block of code is set as follows:



 WebGL Beginner's Guide - Setting up the canvas 




Your browser does not support HTML5




When we wish to draw your attention to a particular part of a code block, the relevant lines
or items are set in bold:



 WebGL Beginner's Guide - Setting up the canvas 



[4]

Preface

Your browser does not support HTML5




Any command-line input or output is written as follows:
--allow-file-access-from-files

New terms and important words are shown in bold. Words that you see on the screen, in
menus or dialog boxes for example, appear in the text like this: "Now switch to camera
coordinates by clicking on the Camera button."
Warnings or important notes appear in a box like this.

Tips and tricks appear like this.

Reader feedback

Feedback from our readers is always welcome. Let us know what you think about this
book—what you liked or may have disliked. Reader feedback is important for us to develop
titles that you really get the most out of.
To send us general feedback, simply send an e-mail to feedback@packtpub.com, and
mention the book title via the subject of your message.
If there is a book that you need and would like to see us publish, please send us a note in
the SUGGEST A TITLE form on www.packtpub.com or e-mail suggest@packtpub.com.
If there is a topic that you have expertise in and you are interested in either writing or
contributing to a book, see our author guide on www.packtpub.com/authors.

Customer support

Now that you are the proud owner of a Packt book, we have a number of things to help you
to get the most from your purchase.

[5]

Preface

Downloading the example code
You can download the example code files for all Packt books you have purchased from your
account at http://www.PacktPub.com. If you purchased this book elsewhere, you can
visit http://www.PacktPub.com/support and register to have the files e-mailed directly
to you.

Downloading the color images of this book
We also provide you a PDF file that has color images of the screenshots/diagrams used
in this book. The color images will help you better understand the changes in the output.
You can download this file from http://www.packtpub.com/sites/default/files/
downloads/1727_images.pdf

Errata
Although we have taken every care to ensure the accuracy of our content, mistakes do
happen. If you find a mistake in one of our books—maybe a mistake in the text or the
code—we would be grateful if you would report this to us. By doing so, you can save other
readers from frustration and help us improve subsequent versions of this book. If you
find any errata, please report them by visiting http://www.packtpub.com/support,
selecting your book, clicking on the errata submission form link, and entering the details
of your errata. Once your errata are verified, your submission will be accepted and the
errata will be uploaded on our website, or added to any list of existing errata, under the
Errata section of that title. Any existing errata can be viewed by selecting your title from
http://www.packtpub.com/support.

Piracy
Piracy of copyright material on the Internet is an ongoing problem across all media. At Packt,
we take the protection of our copyright and licenses very seriously. If you come across any
illegal copies of our works, in any form, on the Internet, please provide us with the location
address or website name immediately so that we can pursue a remedy.
Please contact us at copyright@packtpub.com with a link to the suspected
pirated material.
We appreciate your help in protecting our authors, and our ability to bring you
valuable content.

Questions
You can contact us at questions@packtpub.com if you are having a problem with any
aspect of the book, and we will do our best to address it.
[6]

1

Getting Started with WebGL
In 2007, Vladimir Vukicevic, an American-Serbian software engineer, began
working on an OpenGL prototype for the then upcoming HTML 
element which he called Canvas 3D. In March, 2011, his work would lead
Kronos Group, the nonprofit organization behind OpenGL, to create WebGL:
a specification to grant Internet browsers access to Graphic Processing Units
(GPUs) on those computers where they were used.

WebGL was originally based on OpenGL ES 2.0 (ES standing for Embedded Systems),
the OpenGL specification version for devices such as Apple's iPhone and iPad. But as the
specification evolved, it became independent with the goal of providing portability across
various operating systems and devices. The idea of web-based, real-time rendering opened
a new universe of possibilities for web-based 3D environments such as videogames, scientific
visualization, and medical imaging. Additionally, due to the pervasiveness of web browsers,
these and other kinds of 3D applications could be taken to mobile devices such as smart
phones and tablets. Whether you want to create your first web-based videogame, a 3D
art project for a virtual gallery, visualize the data from your experiments, or any other 3D
application you could have in mind, the first step will be always to make sure that your
environment is ready.
In this chapter, you will:
‹‹

Understand the structure of a WebGL application

‹‹

Set up your drawing area (canvas)

‹‹

Test your browser's WebGL capabilities

‹‹

Understand that WebGL acts as a state machine

‹‹

Modify WebGL variables that affect your scene

‹‹

Load and examine a fully-functional scene

Getting Started with WebGL

System requirements
WebGL is a web-based 3D Graphics API. As such there is no installation needed. At the time
this book was written, you will automatically have access to it as long as you have one of the
following Internet web browsers:
‹‹

Firefox 4.0 or above

‹‹

Google Chrome 11 or above

‹‹

Safari (OSX 10.6 or above). WebGL is disabled by default but you can switch it
on by enabling the Developer menu and then checking the Enable WebGL option

‹‹

Opera 12 or above

To get an updated list of the Internet web browsers where WebGL is supported, please check
on the Khronos Group web page following this link:
http://www.khronos.org/webgl/wiki/Getting_a_WebGL_Implementation

You also need to make sure that your computer has a graphics card.
If you want to quickly check if your current configuration supports WebGL, please visit
this link:
http://get.webgl.org/

What kind of rendering does WebGL offer?
WebGL is a 3D graphics library that enables modern Internet browsers to render 3D scenes
in a standard and efficient manner. According to Wikipedia, rendering is the process of
generating an image from a model by means of computer programs. As this is a process
executed in a computer, there are different ways to produce such images.
The first distinction we need to make is whether we are using any special graphics hardware
or not. We can talk of software-based rendering , for those cases where all the calculations
required to render 3D scenes are performed using the computer's main processor, its CPU;
on the other hand we use the term hardware-based rendering for those scenarios where
there is a Graphics Processing Unit (GPU) performing 3D graphics computations in real
time. From a technical point of view, hardware-based rendering is much more efficient than
software-based rendering because there is dedicated hardware taking care of the operations.
Contrastingly, a software-based rendering solution can be more pervasive due to the lack of
hardware dependencies.

[8]

Chapter 1

A second distinction we can make is whether or not the rendering process is happening
locally or remotely. When the image that needs to be rendered is too complex, the render
most likely will occur remotely. This is the case for 3D animated movies where dedicated
servers with lots of hardware resources allow rendering intricate scenes. We called this
server-based rendering. The opposite of this is when rendering occurs locally. We called
this client-based rendering.
WebGL has a client-based rendering approach: the elements that make part of the 3D scene
are usually downloaded from a server. However, all the processing required to obtain an
image is performed locally using the client's graphics hardware.
In comparison with other technologies (such as Java 3D, Flash, and The Unity Web Player
Plugin), WebGL presents several advantages:
‹‹

JavaScript programming: JavaScript is a language that is natural to both web
developers and Internet web browsers. Working with JavaScript allows you to access
all parts of the DOM and also lets you communicate between elements easily as
opposed to talking to an applet. Because WebGL is programmed in JavaScript, this
makes it easier to integrate WebGL applications with other JavaScript libraries such
as JQuery and with other HTML5 technologies.

‹‹

Automatic memory management: Unlike its cousin OpenGL and other technologies
where there are specific operations to allocate and deallocate memory manually,
WebGL does not have this requisite. It follows the rules for variable scoping in
JavaScript and memory is automatically deallocated when it's no longer needed.
This simplifies programming tremendously, reducing the code that is needed and
making it clearer and easier to understand.

‹‹

Pervasiveness: Thanks to current advances in technology, web browsers with
JavaScript capabilities are installed in smart phones and tablet devices. At the
moment of writing, the Mozilla Foundation is testing WebGL capabilities in
Motorola and Samsung phones. There is also an effort to implement WebGL
on the Android platform.

‹‹

Performance: The performance of WebGL applications is comparable to equivalent
standalone applications (with some exceptions). This happens thanks to WebGL's
ability to access the local graphics hardware. Up until now, many 3D web rendering
technologies used software-based rendering.

‹‹

Zero compilation: Given that WebGL is written in JavaScript, there is no need to
compile your code before executing it on the web browser. This empowers you to
make changes on-the-fly and see how those changes affect your 3D web application.
Nevertheless, when we analyze the topic of shader programs, we will understand
that we need some compilation. However, this occurs in your graphics hardware,
not in your browser.

[9]

Getting Started with WebGL

Structure of a WebGL application
As in any 3D graphics library, in WebGL, you need certain components to be present to
create a 3D scene. These fundamental elements will be covered in the first four chapters
of the book. Starting from Chapter 5, Action, we will cover elements that are not required
to have a working 3D scene such as colors and textures and then later on we will move to
more advanced topics.
The components we are referring to are as follows:
‹‹

Canvas: It is the placeholder where the scene will be rendered. It is a standard
HTML5 element and as such, it can be accessed using the Document Object Model
(DOM) through JavaScript.

‹‹

Objects: These are the 3D entities that make up part of the scene. These entities
are composed of triangles. In Chapter 2, Rendering Geometry, we will see how
WebGL handles geometry. We will use WebGL buffers to store polygonal data
and we will see how WebGL uses these buffers to render the objects in the scene.

‹‹

Lights: Nothing in a 3D world can be seen if there are no lights. This element of any
WebGL application will be explored in Chapter 3, Lights!. We will learn that WebGL
uses shaders to model lights in the scene. We will see how 3D objects reflect or
absorb light according to the laws of physics and we will also discuss different light
models that we can create in WebGL to visualize our objects.

‹‹

Camera: The canvas acts as the viewport to the 3D world. We see and explore
a 3D scene through it. In Chapter 4, Camera, we will understand the different
matrix operations that are required to produce a view perspective. We will also
understand how these operations can be modeled as a camera.

This chapter will cover the first element of our list—the canvas. We will see in the coming
sections how to create a canvas and how to set up a WebGL context.

Creating an HTML5 canvas
Let's create a web page and add an HTML5 canvas. A canvas is a rectangular element
in your web page where your 3D scene will be rendered.

[ 10 ]

Chapter 1

Time for action – creating an HTML5 canvas
1.

Using your favorite editor, create a web page with the following code in it:



 WebGL Beginner's Guide - Setting up the canvas 




Your browser does not support HTML5




Downloading the example code
You can download the example code files for all Packt books you have
purchased from your account at http://www.packtpub.com. If you
purchased this book elsewhere, you can visit http://www.packtpub.
com/support and register to have the files e-mailed directly to you.

2.

Save the file as ch1_Canvas.html.

3.

Open it with one of the supported browsers.

4.

You should see something similar to the following screenshot:

[ 11 ]

Getting Started with WebGL

What just happened?
We have just created a simple web page with a canvas in it. This canvas will contain our
3D application. Let's go very quickly to some relevant elements presented in this example.

Defining a CSS style for the border
This is the piece of code that determines the canvas style:


As you can imagine, this code is not fundamental to build a WebGL application. However,
a blue-dotted border is a good way to verify where the canvas is located, given that the
canvas will be initially empty.

Understanding canvas attributes
There are three attributes in our previous example:
‹‹

Id: This is the canvas identifier in the Document Object Model (DOM).

‹‹

Width and height: These two attributes determine the size of our canvas. When
these two attributes are missing, Firefox, Chrome, and WebKit will default to using
a 300x150 canvas.

What if the canvas is not supported?
If you see the message on your screen: Your browser does not support HTML5 (Which was
the message we put between  and ) then you need to make sure that
you are using one of the supported Internet browsers.
If you are using Firefox and you still see the HTML5 not supported message. You might
want to be sure that WebGL is enabled (it is by default). To do so, go to Firefox and type
about:config in the address bar, then look for the property webgl.disabled. If is set to
true, then go ahead and change it. When you restart Firefox and load ch1_Canvas.html,
you should be able to see the dotted border of the canvas, meaning everything is ok.
In the remote case where you still do not see the canvas, it could be due to the fact that
Firefox has blacklisted some graphic card drivers. In that case, there is not much you can
do other than use a different computer.

[ 12 ]

Chapter 1

Accessing a WebGL context
A WebGL context is a handle (more strictly a JavaScript object) through which we can access
all the WebGL functions and attributes. These constitute WebGL's Application Program
Interface (API).
We are going to create a JavaScript function that will check whether a WebGL context can be
obtained for the canvas or not. Unlike other JavaScript libraries that need to be downloaded
and included in your projects to work, WebGL is already in your browser. In other words, if
you are using one of the supported browsers, you don't need to install or include any library.

Time for action – accessing the WebGL context
We are going to modify the previous example to add a JavaScript function that is going to
check the WebGL availability in your browser (trying to get a handle). This function is going
to be called when the page is loaded. For this, we will use the standard DOM onLoad event.

1.

Open the file ch1_Canvas.html in your favorite text editor (a text editor that
highlight HTML/JavaScript syntax is ideal).

2.

Add the following code right below the  tag:


3.

We need to call this function on the onLoad event. Modify your body tag so it looks
like the following:


4.

Save the file as ch1_GL_Context.html.

5.

Open the file ch1_GL_Context.html using one of the WebGL supported browsers.

6.

If you can run WebGL you will see a dialog similar to the following:

What just happened?
Using a JavaScript variable (gl), we obtained a reference to a WebGL context. Let's go back
and check the code that allows accessing WebGL:
var names = ["webgl",
"experimental-webgl",
"webkit-3d",
"moz-webgl"];
for (var i = 0; i < names.length; ++i) {
try {
gl = canvas.getContext(names[i]);
}
catch(e) {}
if (gl) break;
}

The canvas getContext method gives us access to WebGL. All we need to specify a context
name that currently can vary from vendor to vendor. Therefore we have grouped them
in the possible context names in the names array. It is imperative to check on the WebGL
specification (you will find it online) for any updates regarding the naming convention.
[ 14 ]

Chapter 1

getContext also provides access to the HTML5 2D graphics library when using 2d as the
context name. Unlike WebGL, this naming convention is standard. The HTML5 2D graphics
API is completely independent from WebGL and is beyond the scope of this book.

WebGL is a state machine
A WebGL context can be understood as a state machine: once you modify any of its attributes,
that modification is permanent until you modify that attribute again. At any point you can
query the state of these attributes and so you can determine the current state of your WebGL
context. Let's analyze this behavior with an example.

Time for action – setting up WebGL context attributes
In this example, we are going to learn to modify the color that we use to clear the canvas:

1.

Using your favorite text editor, open the file ch1_GL_Attributes.html:


 WebGL Beginner's Guide - Setting WebGL context
attributes 





Your browser does not support the HTML5 canvas element.




2.

You will see that this file is very similar to our previous example. However,
there are new code constructs that we will explain briefly. This file contains
four JavaScript functions:

Function
checkKey

Description

getGLContext

Similar to the one used in the Time for action – accessing the WebGL
context section. In this version, we are adding some lines of code to

This is an auxiliary function. It captures the keyboard input and executes
code depending on the key entered.

obtain the canvas' width and height.
clear

Clear the canvas to the current clear color, which is one attribute of
the WebGL context. As was mentioned previously, WebGL works as
a state machine, therefore it will maintain the selected color to clear
the canvas up to when this color is changed using the WebGL function
gl.clearColor (See the checkKey source code)

initWebGL

This function replaces getGLContext as the function being called on
the document onLoad event. This function calls an improved version
of getGLContext that returns the context in the ctx variable. This
context is then assigned to the global variable gl.

[ 17 ]

Getting Started with WebGL

3.

Open the file test_gl_attributes.html using one of the supported Internet
web browsers.

4.

Press 1. You will see how the canvas changes its color to green. If you want to query
the exact color we used, press 3.

5.

The canvas will maintain the green color until we decided to change the attribute
clear color by calling gl.clearColor. Let's change it by pressing 2. If you look at
the source code, this will change the canvas clear color to blue. If you want to know
the exact color, press 3.

What just happened?
In this example, we saw that we can change or set the color that WebGL uses to clear the
canvas by calling the clearColor function. Correspondingly, we used getParameter
(gl.COLOR_CLEAR_VALUE) to obtain the current value for the canvas clear color.
Throughout the book we will see similar constructs where specific functions
establish attributes of the WebGL context and the getParameter function retrieves
the current values for such attributes whenever the respective argument (in our example,
COLOR_CLEAR_VALUE) is used.

Using the context to access the WebGL API
It is also essential to note here that all of the WebGL functions are accessed through the
WebGL context. In our examples, the context is being held by the gl variable. Therefore,
any call to the WebGL Application Programming Interface (API) will be performed using
this variable.

Loading a 3D scene
So far we have seen how to set up a canvas and how to obtain a WebGL context; the next
step is to discuss objects, lights, and cameras. However, why should we wait to see what
WebGL can do? In this section, we will have a glance at what a WebGL scene look like.

Virtual car showroom
Through the book, we will develop a virtual car showroom application using WebGL. At this
point, we will load one simple scene in the canvas. This scene will contain a car, some lights,
and a camera.

[ 18 ]

Chapter 1

Time for action – visualizing a finished scene
Once you finish reading the book you will be able to create scenes like the one we are going
to play with next. This scene shows one of the cars from the book's virtual car showroom.

1.

Open the file ch1_Car.html in one of the supported Internet web browsers.

2.

You will see a WebGL scene with a car in it as shown in the following screenshot.
In Chapter 2, Rendering Geometry we will cover the topic of geometry rendering
and we will see how to load and render models as this car.

3.

Use the sliders to interactively update the four light sources that have been defined
for this scene. Each light source has three elements: ambient, diffuse, and specular
elements. We will cover the topic about lights in Chapter 3, Lights!.

4.

Click and drag on the canvas to rotate the car and visualize it from different
perspectives. You can zoom by pressing the Alt key while you drag the mouse on
the canvas. You can also use the arrow keys to rotate the camera around the car.
Make sure that the canvas is in focus by clicking on it before using the arrow keys.
In Chapter 4, Camera we will discuss how to create and operate with cameras
in WebGL.

[ 19 ]

Getting Started with WebGL

5.

If you click on the Above, Front, Back, Left, or Right buttons you will see an
animation that stops when the camera reaches that position. For achieving
this effect we are using a JavaScript timer. We will discuss animation in
Chapter 5, Action.

6.

Use the color selector widget as shown in the previous screenshot to change the
color of the car. The use of colors in the scene will be discussed in Chapter 6, Colors,
Depth Testing, and Alpha Blending. Chapters 7-10 will describe the use of textures
(Chapter 7, Textures), selection of objects in the scene (Chapter 8, Picking), how
to build the virtual car show room (Chapter 9, Putting It All Together) and WebGL
advanced techniques (Chapter 10, Advanced Techniques).

What just happened?
We have loaded a simple scene in an Internet web browser using WebGL.
This scene consists of:
‹‹

A canvas through which we see the scene.

‹‹

A series of polygonal meshes (objects) that constitute the car: roof, windows,
headlights, fenders, doors, wheels, spoiler, bumpers, and so on.

‹‹

Light sources; otherwise everything would appear black.

‹‹

A camera that determines where in the 3D world is our view point. The camera can
be made interactive and the view point can change, depending on the user input.
For this example, we were using the left and right arrow keys and the mouse to
move the camera around the car.

There are other elements that are not covered in this example such as textures, colors, and
special light effects (specularity). Do not panic! Each element will be explained later in the
book. The point here is to identify that the four basic elements we discussed previously are
present in the scene.

[ 20 ]

Chapter 1

Summary
In this chapter, we have looked at the four basic elements that are always present in any
WebGL application: canvas, objects, lights, and camera.
We have learned how to add an HTML5 canvas to our web page and how to set its ID, width,
and height. After that, we have included the code to create a WebGL context. We have seen
that WebGL works as a state machine and as such, we can query any of its variables using
the getParameter function.
In the next chapter we will learn how to define, load, and render 3D objects into
a WebGL scene.

[ 21 ]

2

Rendering Geometry
WebGL renders objects following a "divide and conquer" approach. Complex
polygons are decomposed into triangles, lines, and point primitives. Then, each
geometric primitive is processed in parallel by the GPU through a series of
steps, known as the rendering pipeline, in order to create the final scene that is
displayed on the canvas.
The first step to use the rendering pipeline is to define geometric entities. In this
chapter, we will take a look at how geometric entities are defined in WebGL.

In this chapter, we will:
‹‹

Understand how WebGL defines and processes geometric information

‹‹

Discuss the relevant API methods that relate to geometry manipulation

‹‹

Examine why and how to use JavaScript Object Notation (JSON) to define,
store, and load complex geometries

‹‹

Continue our analysis of WebGL as a state machine and describe the attributes
relevant to geometry manipulation that can be set and retrieved from the
state machine

‹‹

Experiment with creating and loading different geometry models!

Vertices and Indices
WebGL handles geometry in a standard way, independently of the complexity and number
of points that surfaces can have. There are two data types that are fundamental to represent
the geometry of any 3D object: vertices and indices.

Rendering Geometry

Vertices are the points that define the corners of 3D objects. Each vertex is represented by
three floating-point numbers that correspond to the x, y, and z coordinates of the vertex.
Unlike its cousin, OpenGL, WebGL does not provide API methods to pass independent
vertices to the rendering pipeline, therefore we need to write all of our vertices in a
JavaScript array and then construct a WebGL vertex buffer with it.
Indices are numeric labels for the vertices in a given 3D scene. Indices allow us to tell WebGL
how to connect vertices in order to produce a surface. Just like with vertices, indices are
stored in a JavaScript array and then they are passed along to WebGL's rendering pipeline
using a WebGL index buffer.
There are two kind of WebGL buffers used to describe and process geometry:
Buffers that contain vertex data are known as Vertex Buffer Objects (VBOs).
Similarly, buffers that contain index data are known as Index Buffer Objects
(IBOs).

Before getting any further, let's examine what WebGL's rendering pipeline looks like and
where WebGL buffers fit into this architecture.

Overview of WebGL's rendering pipeline
Here we will see a simplified version of WebGL's rendering pipeline. In subsequent chapters,
we will discuss the pipeline in more detail.

Let's take a moment to describe every element separately.
[ 24 ]

Chapter 2

Vertex Buffer Objects (VBOs)
VBOs contain the data that WebGL requires to describe the geometry that is going to be
rendered. As mentioned in the introduction, vertex coordinates are usually stored and
processed in WebGL as VBOs. Additionally, there are several data elements such as vertex
normals, colors, and texture coordinates, among others, that can be modeled as VBOs.

Vertex shader
The vertex shader is called on each vertex. This shader manipulates per-vertex data such
as vertex coordinates, normals, colors, and texture coordinates. This data is represented
by attributes inside the vertex shader. Each attribute points to a VBO from where it reads
vertex data.

Fragment shader
Every set of three vertices defines a triangle and each element on the surface of that triangle
needs to be assigned a color. Otherwise our surfaces would be transparent.
Each surface element is called a fragment. Since we are dealing with surfaces that are going
to be displayed on your screen, these elements are more commonly known as pixels.
The main goal of the fragment shader is to calculate the color of individual pixels.
The following diagram explains this idea:

Framebuffer
It is a two-dimensional buffer that contains the fragments that have been processed by
the fragment shader. Once all fragments have been processed, a 2D image is formed and
displayed on screen. The framebuffer is the final destination of the rendering pipeline.

[ 25 ]

Rendering Geometry

Attributes, uniforms, and varyings
Attributes, uniforms, and varyings are the three different types of variables that you will find
when programming with shaders.
Attributes are input variables used in the vertex shader. For example, vertex coordinates,
vertex colors, and so on. Due to the fact that the vertex shader is called on each vertex,
the attributes will be different every time the vertex shader is invoked.
Uniforms are input variables available for both the vertex shader and fragment shader.
Unlike attributes, uniforms are constant during a rendering cycle. For example, lights position.
Varyings are used for passing data from the vertex shader to the fragment shader.
Now let's create a simple geometric object.

Rendering geometry in WebGL
The following are the steps that we will follow in this section to render an object in WebGL:
1. First, we will define a geometry using JavaScript arrays.
2. Second, we will create the respective WebGL buffers.
3. Third, we will point a vertex shader attribute to the VBO that we created in the
previous step to store vertex coordinates.
4. Finally, we will use the IBO to perform the rendering.

Defining a geometry using JavaScript arrays
Let's see what we need to do to create a trapezoid. We need two JavaScript arrays:
one for the vertices and one for the indices.

[ 26 ]

Chapter 2

As you can see from the previous screenshot, we have placed the coordinates sequentially in
the vertex array and then we have indicated in the index array how these coordinates are used
to draw the trapezoid. So, the first triangle is formed with the vertices having indices 0, 1, and
2; the second with the vertices having indices 1, 2, and 3; and finally, the third, with vertices
having indices 2, 3, and 4. We will follow the same procedure for all possible geometries.

Creating WebGL buffers
Once we have created the JavaScript arrays that define the vertices and indices for our
geometry, the next step consists of creating the respective WebGL buffers. Let's see how
this works with a different example. In this case, we have a simple square on the x-y plane
(z coordinates are zero for all four vertices):
var vertices = [-50.0, 50.0, 0.0,
-50.0,-50.0, 0.0,
50.0,-50.0, 0.0,
50.0, 50.0, 0.0];/* our JavaScript vertex array */
var myBuffer = gl.createBuffer(); /*gl is our WebGL Context*/

[ 27 ]

Rendering Geometry

In the previous chapter, you may remember that WebGL operates as a state machine. Now,
when myBuffer is made the currently bound WebGL buffer, this means that any subsequent
buffer operation will be executed on this buffer until it is unbound or another buffer is made
the current one with a bound call. We bind a buffer with the following instruction:
gl.bindBuffer(gl.ARRAY_BUFFER, myBuffer);

The first parameter is the type of buffer that we are creating. We have two options
for this parameter:
‹‹

gl.ARRAY_BUFFER: Vertex data

‹‹

gl.ELEMENT_ARRAY_BUFFER: Index data

In the previous example, we are creating the buffer for vertex coordinates; therefore,
we use ARRAY_BUFFER. For indices, the type ELEMENT_ARRAY_BUFFER is used.
WebGL will always access the currently bound buffer looking for the
data. Therefore, we should be careful and make sure that we have
always bound a buffer before calling any other operation for geometry
processing. If there is no buffer bound, then you will obtain the error
INVALID_OPERATION

Once we have bound a buffer, we need to pass along its contents. We do this with the
bufferData function:
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices),
gl.STATIC_DRAW);

In this example, the vertices variable is a JavaScript array that contains the vertex
coordinates. WebGL does not accept JavaScript arrays directly as a parameter for the
bufferData method. Instead, WebGL uses typed arrays, so that the buffer data can
be processed in its native binary form with the objective of speeding up geometry
processing performance.

The specification for typed arrays can be found at: http://www.khronos.
org/registry/typedarray/specs/latest/

The typed arrays used by WebGL are Int8Array, Uint8Array, Int16Array,
Uint16Array, Int32Array, UInt32Array, Float32Array, and Float64Array.

[ 28 ]

Chapter 2

Please observe that vertex coordinates can be float, but indices are always
integer. Therefore, we will use Float32Array for VBOs and UInt16Array
for IBOs throughout the examples of this book. These two types represent the
largest typed arrays that you can use in WebGL per rendering call. The other
types can be or cannot be present in your browser, as this specification is not
yet final at the time of writing the book.
Since the indices support in WebGL is restricted to 16 bit integers, an index
array can only be 65,535 elements in length. If you have a geometry that
requires more indices, you will need to use several rendering calls. More about
rendering calls will be seen later on in the Rendering section of this chapter.

Finally, it is a good practice to unbind the buffer. We can achieve that by calling the
following instruction:
gl.bindBuffer(gl.ARRAY_BUFFER, null);

We will repeat the same calls described here for every WebGL buffer (VBO or IBO)
that we will use.
Let's review what we have just learned with an example. We are going to code the
initBuffers function to create the VBO and IBO for a cone. (You will find this
function in the file named ch2_Cone.html):
var coneVBO = null; //Vertex Buffer Object
var coneIBO = null; //Index Buffer Object
function initBuffers() {
var vertices = [];
//JavaScript Array that populates coneVBO
var indices = [];
//JavaScript Array that populates coneIBO;
//Vertices that describe the geometry of a cone
vertices =[1.5, 0, 0,
-1.5, 1, 0,
-1.5, 0.809017, 0.587785,
-1.5, 0.309017, 0.951057,
-1.5, -0.309017, 0.951057,
-1.5, -0.809017, 0.587785,
-1.5, -1, 0.0,
-1.5, -0.809017, -0.587785,
-1.5, -0.309017, -0.951057,
-1.5, 0.309017, -0.951057,
-1.5, 0.809017, -0.587785];
//Indices that describe the geometry of a cone
indices = [0, 1, 2,
0, 2, 3,
0, 3, 4,
[ 29 ]

Rendering Geometry
0, 4, 5,
0, 5, 6,
0, 6, 7,
0, 7, 8,
0, 8, 9,
0, 9, 10,
0, 10, 1];
coneVBO = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, coneVBO);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices),
gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
coneIBO = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, coneIBO);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices),
gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}

If you want to see this scene in action, launch the file ch2_Cone.html in your
HTML5 browser.
To summarize, for every buffer, we want to:
‹‹

Create a new buffer

‹‹

Bind it to make it the current buffer

‹‹

Pass the buffer data using one of the typed arrays

‹‹

Unbind the buffer

Operations to manipulate WebGL buffers
The operations to manipulate WebGL buffers are summarized in the following table:
Method

Description

var aBuffer =
createBuffer(void)

Creates the aBuffer buffer

deleteBuffer(Object aBuffer)

Deletes the aBuffer buffer

bindBuffer(ulong target,
Object buffer)

Binds a buffer object. The accepted values for
target are:
‹‹

ARRAY_BUFFER (for vertices)

‹‹

ELEMENT_ARRAY_BUFFER

(for indices)
[ 30 ]

Chapter 2

Method
bufferData(ulong target,
Object data, ulong type)

Description
The accepted values for target are:
‹‹
‹‹

ARRAY_BUFFER (for vertices)
ELEMENT_ARRAY_BUFFER(for

indices)
The parameter type is a performance hint for
WebGL. The accepted values for type are:
‹‹

STATIC_DRAW: Data in the buffer

will not be changed (specified once
and used many times)
DYNAMIC_DRAW: Data will be
changed frequently (specified many
times and used many times)
‹‹

STREAM_DRAW: Data will change on

every rendering cycle (specified once
and used once)

Associating attributes to VBOs
Once the VBOs have been created, we associate these buffers to vertex shader attributes.
Each vertex shader attribute will refer to one and only one buffer, depending on the
correspondence that is established, as shown in the following diagram:

[ 31 ]

Rendering Geometry

We can achieve this by following these steps:
1. First, we bind a VBO.
2. Next, we point an attribute to the currently bound VBO.
3. Finally, we enable the attribute.
Let's take a look at the first step.

Binding a VBO
We already know how to do this:
gl.bindBuffer(gl.ARRAY_BUFFER, myBuffer);

where myBuffer is the buffer we want to map.

Pointing an attribute to the currently bound VBO
In the next chapter, we will learn to define vertex shader attributes. For now, let's assume
that we have the aVertexPosition attribute and that it will represent vertex coordinates
inside the vertex shader.
The WebGL function that allows pointing attributes to the currently bound VBOs is
vertexAttribPointer. The following is its signature:
gl.vertexAttribPointer(Index,Size,Type,Norm,Stride,Offset);

Let us describe each parameter individually:
‹‹

Index: An attribute's index that we are going to map the currently bound buffer to.

‹‹

Size: Indicates the number of values per vertex that are stored in the currently
bound buffer.

‹‹

Type: Specifies the data type of the values stored in the current buffer. It is one
of the following constants: FIXED, BYTE, UNSIGNED_BYTE, FLOAT, SHORT, or
UNSIGNED_SHORT.

‹‹

Norm: This parameter can be set to true or false. It handles numeric conversions
that lie out of the scope of this introductory guide. For all practical effects, we will
set this parameter to false.

‹‹

Stride: If stride is zero, then we are indicating that elements are stored sequentially
in the buffer.

‹‹

Offset: The position in the buffer from which we will start reading values for the
corresponding attribute. It is usually set to zero to indicate that we will start reading
values from the first element of the buffer.
[ 32 ]

Chapter 2

vertexAttribPointer defines a pointer for reading information
from the currently bound buffer. Remember that an error will be
generated if there is no VBO currently bound.

Enabling the attribute
Finally, we just need to activate the vertex shader attribute. Following our example,
we just need to add:
gl.enableVertexAttribArray (aVertexPosition);

The following diagram summarizes the mapping procedure:

Rendering
Once we have defined our VBOs and we have mapped them to the corresponding vertex
shader attributes, we are ready to render!
To do this, we use can use one of the two API functions: drawArrays or drawElements.

The drawArrays and drawElements functions
The functions drawArrays and drawElements are used for writing on the framebuffer.
drawArrays uses vertex data in the order in which it is defined in the buffer to create the
geometry. In contrast, drawElements uses indices to access the vertex data buffers and

create the geometry.
[ 33 ]

Rendering Geometry

Both drawArrays and drawElements will only use enabled arrays. These are the vertex
buffer objects that are mapped to active vertex shader attributes.
In our example, we only have one enabled array: the buffer that contains the vertex
coordinates. However, in a more general scenario, we can have several enabled arrays.
For instance, we can have arrays with information about vertex colors, vertex normals
texture coordinates, and any other per-vertex data required by the application. In this
case, each one of them would be mapped to an active vertex shader attribute.
Using several VBOs
In the next chapter, we will see how we use a vertex normal buffer in addition to
vertex coordinates to create a lighting model for our geometry. In that scenario,
we will have two active arrays: vertex coordinates and vertex normals.

Using drawArrays
We will call drawArrays when information about indices is not available. In most cases,
drawArrays is used when the geometry is so simple that defining indices is an overkill; for
instance, when we want to render a triangle or a rectangle. In that case, WebGL will create
the geometry in the order in which the vertex coordinates are defined in the VBO. So if you
have contiguous triangles (like in our trapezoid example), you will have to repeat these
coordinates in the VBO.
If you need to repeat a lot of vertices to create geometry, probably drawArrays is not the
best way to go. The more vertex data you duplicate, the more calls you will have on the
vertex shader. This could reduce the overall application performance since the same vertices
have to go through the pipeline several times. One for each time that they appear repeated
in the respective VBO.

[ 34 ]

Chapter 2

The signature for drawArrays is:
gl.drawArrays(Mode, First, Count)

Where:
‹‹

Mode: Represents the type of primitive that we are going to render. Possible
values for mode are: gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES,
gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN, and gl.TRIANGLES (more about this
in the next section).

‹‹

First: Specifies the starting element in the enabled arrays.

‹‹

Count: The number of elements to be rendered.
From the WebGL specification:
"When drawArrays is called, it uses count sequential elements from each
enabled array to construct a sequence of geometric primitives, beginning with
the element first. Mode specifies what kinds of primitives are constructed and
how the array elements construct those primitives."

[ 35 ]

Rendering Geometry

Using drawElements
Unlike the previous case where no IBO was defined, drawElements allows us to use the
IBO, to tell WebGL how to render the geometry. Remember that drawArrays uses VBOs.
This means that the vertex shader will process repeated vertices as many times as they
appear in the VBO. Contrastingly, drawElements uses indices. Therefore, vertices are
processed just once, and can be used as many times as they are defined in the IBO. This
feature reduces both the memory and processing required on the GPU.
Let's revisit the following diagram of this chapter:

When we use drawElements, we need at least two buffers: a VBO and an IBO. The vertex
shader will get executed on each vertex in the VBO and then the rendering pipeline will
assemble the geometry into triangles using the IBO.
When using drawElements, you need to make sure that the corresponding
IBO is currently bound.

[ 36 ]

Chapter 2

The signature for drawElements is:
gl.drawElements(Mode, Count, Type, Offset)

Where:
‹‹

Mode: Represents the type of primitive that we are going to render. Possible values
for mode are POINTS, LINE_STRIP, LINE_LOOP, LINES, TRIANGLE_STRIP,
TRIANGLE_FAN, and TRIANGLES (more about this later on).

‹‹

Count: Specifies the number of elements to be rendered.

‹‹

Type: Specifies the type of the values in indices. Must be UNSIGNED_BYTE
or UNSIGNED_SHORT, as we are handling indices (integer numbers).

‹‹

Offset: Indicates which element in the buffer will be the starting point for rendering.
It is usually the first element (zero value).
WebGL inherits without any change this function from the OpenGL ES 2.0
specification. The following applies:
"When drawElements is called, it uses count sequential elements from an
enabled array, starting at offset to construct a sequence of geometric primitives.
Mode specifies what kinds of primitives are constructed and how the array elements
construct these primitives. If more than one array is enabled, each is used."

Putting everything together
I guess you have been waiting to see how everything works together. Let's start with some
code. Let's create a simple WebGL program to render a square.

Time for action – rendering a square
Follow the given steps:

1.

Open the file ch_Square.html in your favorite HTML editor (ideally one that
supports syntax highlighting like Notepad++ or Crimson Editor).

[ 37 ]

Rendering Geometry

2.

Let's examine the structure of this file with the help of the following diagram:

3.

The web page contains the following:
‰‰

‰‰

‰‰

The script 



Navigation menu