Tải bản đầy đủ (.pdf) (377 trang)

Ebook Interactive computer graphics (5th edition) Part 2

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (14.42 MB, 377 trang )

-, -V

/--

\"

-'
. . ,\342\200\242
\302\273,<

\342\200\242

'-'-,''
-

,.

developing
In has

a fixed

the

pipeline,

graphics

functionality.

\\



' -, \342\200\242
- .
,

l

we assumed that each
when we wanted

.

.

- .: -\34
. :\342\200\242'fi>.

l . -\342\200\242--1\342\200\242'\\\\\342\200\242\342\
.

l

Consequently,
colors
of an

'
!- .> .i v i - ,;i

\342\200\242-


in the pipeline
light-material
to the modified
the fixed-function

box
to

use

interactions to determine the
object, we were limited
Phong model becauseit was the only lighting model supported
by
pipeline in the OpenGL specification and, until recently, the only model supported
to having
model
available, lighting
by mo st hardware. In addition
only one hghting
calculations were doneonlyfor
each vertex.
The resulting vertex colorswere then inr agmen t processor. If w e wanted
over the primitive
terpolated
by thefixed-functionf
to use some other lighting
or shading model, we had to resort
to an off-line renderer.

Over the past few years, graphics processors have changed dramatically.
Both
the vertex processor and fragment
are
now
user
We
can
processor
programmable.
called vertex shaders and fragment
shaders to achieve complexvisual
writeprograms
i p elin e .
effects
at the same rate as the standardfixed-functionp
In this
we introduce the concept of programmable
shaders.
First, we
chapter,
review some of the efforts to develop languages to describe shaders.These
efforts
in the OpenGLShadingLanguage (GLSL),
culminated
which
is now a standard part
of OpenGL.
We t he n use GLSL t o develop a variety
of vertex shaders that compute

vertex properties, including
their
and colors. Finally,
we develop
positions
fragment
shaders that let us program the calculations
on each fragment and ultiperformed
Our discussion of fragment
shaders
will
mately determine the color of each
pixel.
alsointroduce many new ways of using texture mapping.

9.1

PROGRAMMABLE PIPELINES

we developed
the Phong and modified
6,
Phong hghting models in Chapter
we placed great emphasis
on their efficiency
but much less on how
well they modeled
model is remarkable in
physical light-material interactions. The modified
Phong

that
while it has a very
loose
with
it yields images that
coupling
physical reality,

When

are adequatefor
architectures

of OpenGL

most

developed,

and was

purposes.
it was
implemented

Hence, as graphics

natural

that


this

in commodity

and especially pipeline
was built into the specification

hardware

model

hardware.

451


452

Ch a p t e r9Pr

ogr

Shaders

a m m a ble

Normalized

Object


coordinates
Vertices

\342\200\224\342\200\242?

C l ip
coord i n a te s

JC

d evice

coor d in a tes
lippin g and

^fta^rizer

|_

^F ragm

ent

^Pixe|

s

assemph


primitive

FIGURE 9.1

j

Window

coor a in a re s

Pipeline architecture.

The modified
model is adequate for simulating
smooth
surfaces, such
Phong
as plastic or metal, which have an isotropic
BDRF. That is, the properties
of the
material are the same in all directions. Often, however,
we need a more physically
realistic
model th at can model materials
with
BDRFs that
asymmetric
(anisotropic)
and fluids. When
we

skin, fabrics,
many real world materials, including
with translucent materials, we wan t to incorporate refraction, the bending
of
light as it passes through materials with different properties. We mi ght also want to
account for the fact that howlight isbentbyrefraction is a function
ofth e wavelength

characterize

work

of the

light.

effects. For example, we might
situations, we want nonphotorealistic
the brush strokes ofa painter or we might want to create cartoonlike
effects.
can be achieved onlybyworking with
shading
Many ofth ese effects
fragments
in ways that are not possible-with
i p elin e . For example, in bump
afixed-functionp
a topic that we consider in Section
for each
9.12, we change the normal

mapping,
to
the
of
a
surface
with
that
fragment
give
appearance
great
complexity
appears
correct aseither the lights or the surface move. Many of these algorithms
and effects
were developed more than 20 years ago but were only available
non-realthrough
time Tenderers, such as RenderMan.
Recent advances in graphics
architectures
have
altered this situation
dramatically.
in Figure 9.1. This figure
Consider the pipeline architecture
illustrated
represents the same architecture
we have been discussing since Chapter 1. First,
we

vertices.
Note
that
because
both
the
model-view
and
transforprocess
projection
in eye
mations are applied
vertex processing, the representation
of vertices
during
coordinates occurs only within the vertex processer. At the end of vertex processeach vertex has had its loca tion transformed
ing,
by the model-viewand projection
has
been
a
and
on which options are
matrices,
usually
assigned color,
depending
such as texture coordinates have
been
Vertices

enabled,other attributes
assigned.
are then assembled
into primitives that are clipped.The potentially
visible primitives that are not clipped out are rasterized, generating
the
fragments.
Ultimately,
the final display. What
has changed
is that the
fragments are processedto generate
r o cessor are now programmable
vertex processorand thefragmentp
by applicationcalled
shaders
that
are compiled
and loaded into the graphics
specific programs
In other

want

to simulate

processor.

'



9.2 Shading

9.2

LANGUAGES

SHADING

we can develop a programming
model
for shaders, we need a method
to deAn approach that was inspired
scribe lighting models and shaders.
by the RenderMan
shading lang uag e is to look at shaders as mathematical expressions in a language that

Before

involves variables, constants,
and operations
among these entities. Such expressions
can also be expressedin the form of tree data structures,
and these trees can be traversedby a variety of algorithms to evaluate
the expression
represented by the tree.
between
th at describe
and
Hence,there is a dir ect relationship

languages
expressions
these
algorithms to evaluate
expressions.

Shade Trees

9.2 .1

the

Consider

original

Phong shading

model from

6, without

Chapter

the distance

term:

I = kdLdl-n
a


When

+KLaIa-

+ksLs(*-y)a

evaluates

system

graphics

OpenGLstate,

and r is computedby

r=2(1\342\200\242n)n

-1.

of these

Both

ducting

equations

exponentiation,


resent theseequations
type

are known

nal

nodes

and all
the

child

1

n

1 are

and

known

from

the

inthat involve bot h arithmetic

expressions
operations,
vector operations, such as the dot product.
We can rep2
a tree data structure
as shown in Figure 9.2. Treesof
using
trees.
Variables
and
constants
expression
appear at the termiare

and

as
internal nodes represent operations.Because
tree is a bina ry tree in which all internal
resulting

this

binary,

this expression,

operators are
have exacdy two


all our

nodes

nodes.

to traversing
the correspondEvaluating an arithmetic expression is equivalent
that
node
and
out
the
tree,
is, visiting every
ing
carrying
requisite mathematical
In
at
the
internal
nodes.
this
trees
and
their
associated
traversal
sense,

operations

and implementing
mathematical
algorithms provide a means of both representing
expressions,such as that for the Phong shader.
The more interesting
of expression trees is in designing
new shaders.
application
in a graphics system and
Given a setof variables
that might be available
operations
that are supported by the system, we can form collectionsof trees;
each collection
of one or more treesdefines
a different
method for shading
a surface. This approach

is taken

in the

RenderMan

shading

language.


Variables,

such

as normals

*
wherethefactor/
max(0,1 \342\200\242
n) and max(0, r \342\200\242v)
1.Thecomputationactuallyuses/
positive and 0 otherwise to guard against the effects of negative dot products.
2. We consider the use oftreesin greater depth in Chapter 10.

and

light

is1 if1

\342\200\242
nis

Languages

453


454


Chapter 9

Shaders

Programmable

FIGURE 9.2
vector.

Expression trees, (a)

are assumed

For

Phong

shading,

reflection

environment
and can be
From basic data structures,
we know that arithmetic expressionsand
are equivalent Thus, wecan
use standard
tree-traversal algorithms for the evaluation
of expressions that define

shaders. Looking at shade trees slightly
we see that shade trees can be
differently,
that can be executedbygraphicsprocessors.
The
replacedbyprograms
programming
to developing shaders is supported
approach
by high-level
languages that we canuse
to program
the graphics pipeline on the latest graphics cards.

source parameters,

combined using

9.3

a set

of scalar

to

and

be available
vector


from

(b) For

the

operations.
trees
binary

EXTENDING OPENGL

into the details of programmable
which add a new level of
shaders,
getting
to examine
the mechanisms by which OpenGL
complexity to OpenGL, we pause
has evolved to incorporate advancesin graphics
hardware
and software. Graphics
such as OpenGL, developed as a way to p rovide application programmers with
APIs,
access
to hardware features that were being provided by the latest
hardware.
graphics
Before



9.3

As
and

mo re

and more hardware
features
became
re memory was provided on graphics
became
possible and even routine.

available, processor

as mo

techniques

programmers

Theproblem
through

expect such

would


processors,

only natural that application
supported by graphics APIs.
is how to support such
features

API developers must confront
API
while
not forcing programmers

that

an existing

speedsincreased,
complex graphics

It was
to be

techniques

more

Extending OpenGL

to replaceexisting


code.

One

add newfeatures
but arebackward
approach istoreleasenewversionsoftheAPIthat
compatible so that older code is guaranteed to run on newer versions. Anot her approach is t o add optional extensions to the API that allow application programs to
accessparticular
hardware
features. OpenGL has used both
these m echanism s. However,in order to access the new features of programmable graphics processors,a new
set of programming
tools is required.

9.3.1 OpenGL Versionsand

Extensions

API
has been very stable. Therewere
OpenGL 1.5that were released over a 10-year
period,each of which was compatible with previous releases. OpenGL 2.0, which
in 2004, was a major
was released
but still retains code compatibility
with
upgrade
earlier versions. The current

release
is OpenGL2.1.Thus,
written on an
any
program
older version of OpenGLruns as expected on a later version.
Changes to OpenGL
in hardware that became common to many
reflect
advances
graphics
processors.
For example, as hardware
for texture mapping increased, newer
versions
support
of OpenGL contained many
new functions
for using texture maps. Features
such as
texture objects, mipmapping, and three-dimensional
textures were added to the early
versions of Open GL.
Whereas
versions
users
and hardware
OpenGL
represent a consensus of many
card or high-end workstation

is likely to support feaproviders, a given graphics
tures
that
are not generally available
on other hardware. Such is especially the case
with commodity
cards that are used for computer games. Nevertheless, programmers
who
have access to a particular
of hardware want to be ableto access
piece
its features through OpenGL functions,
even
these features are not general
though
version ofth eAPI. One solution
to thisdilemma
enough to be supported
bythelatest
is to have an extension
mechanism
within OpenGL. Individual
hardware
providers
can provide accesst o (or expose) hardware features
new Open GL functions
through
that may only work on a particular
manufacturer's
hardware.

OpengGL extensions
have names that identify the provider. For example, an extension
with a name such
as glCommandNV
identifies it as provided by NVIDIA.
Other manufacturers
could
then
the same extension. Extensions
that have been widely
used
are apimplement
Review
Board (ARB) and are designated
as ARB
proved by the OpenGLArchitectural

One of

the main

upgrades from

features

OpenGL

of OpenGL

is that the


1.0 through

3. In 2006, the ARB w a s replaced by the
Seewww.opengl.org.

OpenGL

Working

Group under

the

Kronos

Consortium.

455


456

Ch a p te r

9

Shaders

Programmable


When programmable vertex shaders first became
the ARB approved
available,
for low-level
vertex p ro g ra ms . Later extensions
low-level fragsupported
ment programs. However,
the original
interfaces to programmable hardware
were
somewhat
for programmable
hardware was
unwieldy. The first software
support
much
like assembly language interfaces
for general
purpose computers. Application
had to write moderately long
that kept track of low-level
programmers
programs
and moving data bedetails, such as register assignments in the graphics
processor
tween
and memory. The OpenGL extensions provided
a mechanism
for

registers
loading this assembly-like code into a programmable
pipeline. Although this mechanism allowed users to work
with
shaders, it had all the faults of an
programmable
assemblylanguageprogram. AsGPUsbecame more sophisticated,itbecameincreasIn a manner similar
ingly more difficult to program shaders using
assemblylanguage.
to the development
of st an d ard programming languages,
higher-level
programming
interfaces and compilersfor shader code have now replaced assembly
language
p ro

extensions

for

gramming

most users.

GLSL and

9.3.2

Cg


to us are the
shading languages of most interest
(GLSL) a nd Cg, w hich is an acronym for Cfor Graphics.
Language
but have different targeted users. Both
are based on the C programming
include most ofits programming
constructsbut
add languagefeatures
that make it easier t o program
shaders.
two

The

high-level

The main differences
portable acrossmultiple

is virtually

arise

because

platforms,

Cg is


including

designed to

support

OpenGL Shading
They are

similar

and

language

and data
shaders

OpenGL and Microsoft's

types

that

are

DirectX.Cg

(HLSL) and thus

High LevelShading
Language
that
it
allows
them
to
advantage
developers
developshadersfor
both DirectX and OpenGL at the same time. However, the interface
between OpenGL
and Cg sh ader s is m ore sophisticated
than
the interface between OpenGLand GLSL
is. GLSL is part
of OpenGL
2.0 and thus is supported
by multiple vendors and on
multipleplatforms.
BecauseGLSLispart
ofOpe n GL, itis simpler todevelopOpenGL
shaders with GLSL than with Cg. Hence, wewill focus on GLSL, understanding that
the two approaches have far more
similarities
tha n differences.

has the

9.4


identical

to Microsoft's

for Windows

THE OPENGLSHADING

LANGUAGE

is a C-like language that
allows
the programmer
OpenGL Shading Language
both
vertex and fragment shaders. It is incorporated
into OpenGL 2.0. In
GLSL,there is little distinction in the syntax between a vertex program and a fragment program, although
the two are used in different
contexts.
Before we examine the GLSL lan guag e, first we examine the different tasks that these shaders must

The

to

write

perform.



9.4 The OpenGLShading
9.4.1 Vertex
A

vertex

Shaders

or vertex shader, replacesthe fixed-function
program,
the vertex processor with
defined in the
operations

operations

per-

shader. If a vertex
shader
is not provided by the application,
a programmable vertex processor carries
out
the standard
e rtex processor.A vertex
operations of the OpenGLfixed-functionv
shader is executed on each vertex
as i t passes down

the pipeline.
Every vertex shader
must
the information that the rasterizer
needs
to do its j ob . At a minimum,
output
must
for the rasterizer. For each vertex,
every vertex shader
output a vertex position
the input to the vertex
can use the vertex position
defined
program
by the application
and most of th e information
that is in the OpenGL state, including the
program
current
ma teri al properties,
and transformation matrices.
color, te xtu re coordinates,
In addition,
the application program can p ass other application-specific
information
on a per-vertex basisto the vertex
shader.
There are a few operations
that virtually every vertex program must

out.
carry
Recall that most application
programs
specify vertex positions in object
space, and
the vertex processor transforms
these
first by the model-viewmatrix
into
positions
matrix into clip coordinates.
Because
eye coordinates and then
by the projection
an application-supplied vertex shader replacesthefixed-functionv
e r tex operations,
one of the jobs that almost all vertex programs must carry out is to transform the
vertex
from object coordinatesto clip coordinates.
Because
the vertex
input
position
transformation
state, it has accessto the standard
program can accessthe OpenGL
matrices or it can compute its own transformations.
formed


Here

/*

pass

by

is a

simple,

but

vertex

through

complete,

shader

vertex

program:

*/

void main(void)


{

gl_Position = gl_ProjectionMatrix*(gl_ModelViewMatrix*gl_Vertex);

}

in object coordinates
shader simply takes each vertex'sposition
(gl_Vertex)
it
first
the
model-view
matrix
and
then
the
matrix
multiplies
by
by
projection
in
in the
to obtain the position
coordinates.
The
four
variables
(gl_Position)

clip
shader are all part of the OpenGL state and thus do not have to be declaredin the
shader. Each execution of g lV er t e x in an application triggers
the execution
of the
shader. This shader is so simple
that it does not even set a color
or any other vertex
such matters to the fragment
Because this shader does
attribute,
leaving
processor.
but
send
on
the
of
the
it
is
sometimes
calleda pass-through
vertex,
nothing
position
This
and

shader.


A slightly
follows:

more complexversi

on that

also assigns

a red colorto

each

vertex

is as

Language

457


458

C h a pt e r 9

Shaders

Programmable


/* simple vertex shader
*/
vec4 red = vec4(1.0,

const

0.0, 0.0, 1.0);/* C++

style

constructor

*/

void main(void)

{

gl_Position = gl_ModelViewProjectionMatrx*gl_Vertex;
= r ed ;

gl_FrontColor

}
This program does two things. It transforms the input
vertex
position
(gl_
of the projection and model-view

matrices
to a new
Vertex) by the concatenation
4
in clip coordinates (gl_Position)
and
colors
each vertex red. Because
position
the
conversion
of a vertex's position
from
object to clip coordinatesis so common,
GLSL
of the projection
and model-viewmatrices
provides the precomputed product
Notethatnames
variablegl_ModelViewProjectionMatrix.
refer to variables that are part of the OpenGLstate. Suppose
that
program that uses this vertex shader contains the code

throughthebuilt-in

that begin
the

with


gl_

application

glBegin(GL_P0LYGON);

glVertex3fv(v0);

glVertex3fv(vl);

glVertex3fv(v2);

glEndO;
in the application
have been defined previously
er t e x invokes our shader with a new value of
of the vertex in
gl_Vertex, which is the internal four-dimensional representation
h
Each
execution
oft
e
vertex
a
color
glVertex.
program outputs
(gl_FrontColor)

and
a new vertex position (gl_Posit ion) that
are passed on for primitive
assembly.
in Figure 9.3. In this shader, we could have
This process is illustrated
a
computed
color so that each vertex could be assigned a different
color.
We also could have set
in the application for each vertex using g lCol or and had the shader pass
the
color
on these colorsto the rasterizer by using the code

where

the

program.

vertices

vO, v l ,

and

v2


of glV

execution

Each

= gl_Color;

gl_FrontColor

has a main function
and can call
designation
The sameis t r u e for fragment
shaders.
GLSL includes new data types and the associated operations among them. Thus,
the
model-view
matrices are oftype
mat4
thevertex position
, whereas
andprojection
* is overloadedso that matrix-vector
isa vec4 datatype.
The multiplication
operator
in

the


other

shader.

Note that a

functions

4. We are assuming
because back faces

our shader should

written

that

vertex

shader

in GLSL.

two-sided lighting has not been enabled. If we need two-sided lighting
different
front and back properties, then

are visible and materials might have
also compute gl_BackColor.



9.4 The

OpenGL Shading

-Application

, program

glColor

glOrtho

glLoadMatrix

F r o n t Colo r
~\302\261
n
Positio
~

gl_Vertex

gl_

ModelViewMatrix

gl_ProjectionMartrix
9.3


FIGURE

Vertex

shader architecture.

as we

are defined

multiplications

would

Hence,

expect.

the code

in

our

simple

vertex

shader


gl_Position =

gl_ModelViewProjectionMatrix*gl_Vertex;

yieldsthefinalpositionthatisavec4datatype.
than
now, we have used the terms column matrix and row matrix rather
so as not to confuse the vector geometric type with its representation
using
row
and column
matrices. GLSL defines
a vector
data type that is a one-dimensional
C-style array. GLSL reserves the matrix data type for square matrices that are twoin this chapter.
dimensional C-style arrays.
We will use th e GLSLterminology
In our example,we usedbuilt-in
ion
variablesgl_FrontColor
andgl_Posit
for the output of the vertex program. Thefront colorisinterpolated
by the rasterizer
and the interpolated
colors are available to either
a fragment
program or the fixedfunction
for each vertex is used by the rasterizer
to

fragment processor. The position
for each fragment it produces. Note that
the red color has a const
assign a position
and will be the same for each
invocation
of the program. In general,
the
qualifier
of the vertex program.
output position and color can change with each invocation
Also
note the use of a C++-style
constructor
to initialize
the red colorvector.

Until

vector

9.4.2 Fragment Shaders
Fragment
ever,

shaders

written

programs

rather
than on

fragment

fragment

Considerour

in GLSL have the
are executed after

same
the

syntax
rasterizer

as vertex programs. Howand thus operate on each

each vertex.

in which the front
color
is passed onto primitive
If
the
vertex
is
not

eliminated
it goes on
assembly
stages.
by clipping,
to primitive
and
then
to
the
which
rasterizer,
assembly
generates fragments that
are then processed by the fragment
processor
using either fixed-function fragment
or an application-defined fragment
or fragment shader. Vertex
processing
program,
such as vertex colors and positions,
are interpolated
attributes,
by the rasterizer
In the simplest
across
a primitive to generate the corresponding
attributes.
fragment

trivial

and clipping

example

Language

4 59


460

Ch a p t e r9Pr

ogr

a m m a ble

Shaders

state

Vertices

Position

gl

g l FrontColor


.-

.

(per vertex)
9.4

FIGURE

(

gl_Fron t C o l or
olat e d )

g l _ Fragm

i n t er p

architecture.

processor uses theseattributes
fragment program is as follows:
/*

A minimal

modification.

without


shader */

fragment

pass-through

void

olor

r

Fragment shader

the fragment

case,

e n tC

mainO

\342\200\242C

gl_FragColor\342\200\242gl_Color;
}

as this


As trivial

a vertex
the

vertex

appears,

program

The values

function.

program

Rather,

program.

the

values

there is a major
of gl _Color
of gl_Color

difference

are

not

in the

between

the values
fragment

how it and

produced

program

by

have

interpolating the vertex values of gl_FrontColor
over
(and
gl_BackColor
lighting is enabled) from thevertex
processor
the primitive
to produce
the values used in the fragment

unless
all
Thus,
program.
the vertex colors are identical,
each tim e that the fragment
executes, it uses a
program
different
value
color produced by the fragment
ofg l _ C olor . The fragment
program
is then used to modify
the color of a pixel in theframe
buffer. Thisprocess
is shown in
the main features of GLSLand then develop some more
Figure 9.4. We now present

been produced

by

rasterizer

the

iftwo-sided


sophisticated

THE

9.5
The

shaders.

OPENGL

SHADING LANGUAGE

Shading Language is basedon the C programming
language. GLSL has
data
and
control
structures.
conventions,
However, because
naming
types,
and
shaders execute in a very
different
environment
than normal
fragment


OpenGL

similar

vertex

programs, including
significant

differences

the

from

OpenGL

C.

application

that invokes them, there

are some


9.5 The

9.5 .1 GLSL Execution
Let'sconsider

what
when a typical
happens
OpenGL
Most OpenGLfunctions
the OpenGL state
change
down the pipeline

flow

can

that

change

application
do not

but

the display.

However,

OpenGLShading Language

program executes.
cause anything

to
once
we execute any

OpenGL function that
the fixed-function
pipeline,

generates vertices\342\200\224the pipeline
into
action.
With
various calculations
are made
goes
in the pipeline to determine if the primitive
to which the vertex
is visible
belongs
These
calculations
and, if i t is, to color the corresponding
pixels in the frame buffer.
the OpenGL state. Subsequent
executions
of glV er t e x
generally do not change
if any state
invoke the same calculations
but use updated values of state

variables
in
have
been
made
between
the
calls
to
changes
glVertex.
If welook at these calculations as the work of the software and hardware
that
the
vertex
we
see
that
there
must
be
of
variables
implement
processor,
multiple types
involved in the execution of this code. Some variables will change
as the output
vertex attributes,
such

as the vertex color, are computed.
whose values are
Others,
determined by the OpenGL state, cannot be changed
by the calculation. Most internal
variables
must be initialized to their
values
after each vertex is processed
original
so that the calculation for the next vertex will be identical. Other variables must be
and passed
onto the next stage of the pipeline. Consequently,
when
we
computed
substitute a user-written
vertex
for thefixed-functionv
ert e x processor, we
program
function\342\200\224or

glVertex

mustbeableto

any

thesedifferent


identify

typesofvariables.

A fragment program also has input
internal
variables,
variables, and output
variables.
The major difference between
a fragment
program and a vertex
program
is that a fragment
will
be
executed
for
each
Some values will be
program
fragment.
in the shader. Others will
provided
by the OpenGLstate and thus cannot be changed
be changed
basis.
Most shader variables must
be

only on a fragment-by-fragment
initialized
for each fragment.
A typical
not only will change
state variables and entities
such
as
application
texture maps, but also may use multiple vertex and fragment
shaders. Hence, we also
must
examine
how t o load in shaders,
how t o link them into an GLSL program, and
how to set this GLSLprogram
to be the one that
uses. This process is not
OpenGL
but is accomplished
that are now
part of the GLSL language
using a set of functions
part of th e OpenGL core.
Because each vertex triggers an execution of the current vertex shader independent
of any other vertex and, likewise, each fragment
the execution of the
triggers
current
for extensive parallelism to speed the

shader, there is the potential
fragment
ofbo th vertices andfragments.
now contain
processing
High-end
graphicsprocessors
shader
cores that can executevertex
and fragment
shaders in parallel.
multiple

9.5 .2 Data
GLSL

are

int,

has

Types and Qualifiers

basic data

types

presently


limited to

and a

Booleantype,

C manner.

a

are

that
single

b o

to C

similar

floating-point

o l . Arrays

and

and

C++.


The scalar

types,

type, float,
asingle
structures
are declared in

integer

the

however,

type,

standard

4 6 1


462

Ch a p t e r

9

Progra


Shaders

mmable

for working
with the 2 x 2,
types
are special onecomputer graphics.Vectors
dimensional arrays.
We can use floating-point (vec2, vec3,vec4),
(ivec2,
integer
ivec3, ivec4), or Boolean(bvec2,bve c3, bvec4)
types. Because the vector types
can be usedto storevertex
can
colors, or texture coordinates,the elements
positions,
be indexed by position
coordinates
(x, y, z, w), color (r, g, b, a),ortexture
(s, t , p,
q).Thus,ifc is a vector, then c[1], c. y, c . g, and c.t allrefer tothesecondelement
of c. Note that thisflexibilityi
s there only to create more readablecodeand carries
no semantic information. Hence, there is n o reason that c. y cannot
contain color or

GLSLintroduces


3x3, and

and matrix

vector

new

4 matrices

4 x

that

we

use in

information.

texture

matrices in GLSL are

and floating-point
(mat2, mat3,
always
square
the usual

However,
OpenGL matrices, storage is by columns.
If m is a matrix,
m [1] is its second row
C/C++ referencing
and m [1] [2] is
applies.
in row 2, column 3. GLSLsupports
the
element
standard
C one-dimensional
arrays.
Multi-dimensional
can
be
obtained
structures in
array
functionality
using
C-type
Presendy,

mat4). As

other

with


GLSL.

GLSLusesC++-style
as in

the

vec3 a =

also

b =

vec2

uses

which

the vectors and

matrix

types,

such

.0);

vec3(1.0, -2.0,5


Constructors

to initialize

constructors

example:

following

can be

used

for

types as in

between

conversion

vec2(a);
w o componentsof the

thefirstt
be

vec3


variable

a to form

b.

those
ways. Ordinary (nonlocal)variables,
that are not function
or
function
can
be
as
atparameters
temporaries,
qualified
tribute,
uniform, varying, or const. The const qualifier is similar to but more
restrictive
than in C and makes the variable unchangeable by the shader. Thus, we
can create a constant
scalar and vector as follows:
Variables

float

const


can

qualified

in different

one = 1.0;

const vec3 origin =

2.0,3

vec2(1.0,

are used by

variables

Attribute-qualified

.0 ) ;

vertex shaders

for

variables

that change


once pervertex in the vertex shader. There aretwo types of attribute-qualified
variables. Thefirstt y p e includes the OpenGL state va riables that we associatewith
at most

vertex,

such as its

color,

as built-in
variables.
gl_Color are built-in

position,

texture coordinates,

and

normal.

These

a

are known

variables
and

gl_Vertex
Built-in variables need not be
in the apdeclared in shaders. GLSLallows
additional
vertex attributes to be defined
so
that
it
can
other
information
on
a
basis
to the
plication program
convey
per-vertex
shader.
For example, in a scientific
visualization
we mi gh t want to assoapplication,
ciate a scalar temperature
or a flow velocity
vector with each vertex. Only
floatingIn our

simple example, the

attribute-qualified


variables.

state


9.5

point

can be

types

declaredasin
attribute

attribute
Because

the

attribute

following

qualified.

User-defined


The OpenGL Shading

variables are

attribute-qualified

code:

float tei^perature;
vec3

velocity;

they vary on a vertex-by-vertex basis, vertex
shader. Attribute variables are aligned

a fragment

attributes
with

be declared
in the application

cannot

variables

in


a
through
OpenGL functions that we will explain in Section 9.6. When
shader is executed,the values of the attribute variables are those that were set
in the application
and cannot be changed in the shader.
Uniform qualifiers are used for variables
t hat are set in the application
program
for an entire batch of primitives; th at is, variables
whose
values are assigned outside
the
of a glBe gi n and a glEnd. Uniform variables
a mechanism for
scope
provide
data among
an application program, vertex
and fragment shaders.
shaders,
sharing
in a shader. Hence, we
Likeattribute
uniform
variables cannot be changed
variables,
useuniform
variables
t o pass information

that is constant over a batch
of primitives
into shaders. For example, we might
want
to compute the bounding
box of a set
of verticesthat define a primitive in the application
and send this information to a
shader
to simplify its calculations.
a var iabl e as a varying
variable
at first,
Although
naming
may seem a bit strange
program

vertex

for conveying data from
a vertex
varying-qualified variables provide the mechanism
shader to a fragment
shader.
These variables are defined
on a per-vertex basis but are
over the primitive
variables,
interpolated

by th e rasteri zer. As with attribute-qualified
variables
can be either built-in
or user defined.
varying
i p elin e .
how colors are determined in thefixed-functionp
Consider, for example,
Thevertex processor computes a color or shade for each vertex. The color of a fragment
is determined by interpolating the vertex
colors. Likewise, texture coordinates
for each
are determined by interpolating
texture coordinates at the vertices.
fragment
In our simple vertex
Both
vertex
colors and texture coordinatesarevarying
variables.
o l or is a built-in
variable. If we created a more complex
shader,
gl_FrontC
varying
vertex
shader
that computed a different
color
for each vertex, using

the varyingr
n
r
variable
o
t
C
ol
o
would
ensure
that
there
is
an
color
qualified
gl_F
interpolated
for each fragment, whether
or not we write our own fragment
program.
User-defined varying
variables
that are set in the vertex program are automatia varying
variable
cally interpolated
bythe rasterizer. It does not make sense to define
in a vertex shader and not use it in a fragment
shader.

Hence, a user-defined varyif
should appear in both the vertex and fragment
shaders.
ing variable
Consequendy,
we define such a variable in the vertex shader, we should
write
a corresponding
fragment shader. Thus, while our simple ve rt ex shader did not need the simple fragment
th e functionally
vertex shader is as follows:
shader,
equivalent
const

varying

vec4
vec4

red

= vec4(1.0,

color_out;

0.0, 0.0, 1.0);

/* varying


variable

*/

Language

463


464

C h a pt e r 9

Shaders

Programmable

void main(void)
i

gl_M o delVi

=

gl_Position

e w Pr o

jectio n Mat


r ix*gl_V

er te x

;

= red;

color_out

>
This

shader

vertex

at a

requires

the

minimum

pass-through

fragment

shader as fol-


lows:

vec4

varying

color_out;

void mainO

{

gl_FragColor= color_out

;

>

y

9.5 .3
For

and Functions
part, the operatorsareas in C with the same precedencerules.However,
internal format of thefloatan d integer types is not specified
by GLSL, bit

Operators

most

the

the

because

operations are not
The

operations

overloaded so that
example,
mat4

the

5

allowed.

among

the

matrix-vector

usual


C types

operators

and

the

can be

vector

and matrix

used as we

would

types are

expect.

For

code

a;

vec4 b,


c , d;

c =b*a;

d=a*b;

GLSL computes c treating
b as a row matrix,
whereas
a
column
matrix.
c
and
d
are
the
same
Hence,
computed treating
although
type, they will have different values.
GLSL has a swizzling
that is a variant
of the C selection operator (.).
operator
allows
us to select multiple
from the vector types. We can use

Swizzling
components
and write maskingto
select and rearrange
elements
ofv ect o r s . For example,
swizzling
we can change selected elements as in
sense.

makes

In

the first

d is

a =

vec4

a.x

a.yz

5.Bit

cas e,


b as

=

vec4(1.0 ,2

.0, 3.0, 1.0);

2.0;

=vec2(-1.0,

operations

are

4 .0);

supported

through

extensions on many GPUs.


9.6

or

swap


as in the

elements,

Linking

with

Shaders

code:

following

.yx;

a.xy=a

Notethatwecanuseanyoftheformats(x,y,z,w;r,g,b,a;s,t,p,q)aslongaswe

do not

mix

in singleselection.

them

GLSLhas many


functions
(sin,
including the trigonometric
and
mathematical
acos,
(asin,
atan),
trigonometric
functions
ticul ar importance are functions
(pow, log2, sqrt, abs, max, min).Ofpar
in computer
that help with geometric calculations
vectors that are required
involving
isa length function,
adistance
adot product
function,
graphics.Hence,there
anormalize
and a reflect
function.
Most
ofthese
functions
function,
function,

are overloadedso tha t they work with both floats and vectors. We will see examples
of these and other built-in functions in the examples.We will delay our discussion of
the
texture
functions
until Section 9.10.

cos, t an),

built-in

functions

functions

inverse

Variables
that are function parameters necessitatea few additional
options. Because ofhowvertexandfragment
shadersare
GLSL
executedandthelackofpointers,
uses a mechanism
known
as callbyvalue-return.
Function parameters are qualified
as in (the default), out,
or inout.
GLSL functions have return

Returned
varitypes.
ables are copiedback to the calling function. Input parameters
are copied from the
If a variable is qualified
as in, it is copied in but is not copied out,
calling
program.
even though
its value may be changed
within
the function. A function
that
parameter
is qualified
as o u t is undefined
on entry to the function
but can be set in the function and is copied back to the calling function. A parameter that is inout-qualified
is copied in and also copied out.
in GLSL. Because vectors and
Note that there are presently no pointers
matrices
are basic types, they can be copied into and copied
from functions.

9.6

LINKING SHADERS WITH

With GLSL, we can write


development

shaders
exist

environments

OPENGL

PROGRAMS

of any OpenGL
independent
that let users write
and test

Various
application.
shaders. However, at
application.
how to create vertex and

point, we have t o link the shaders with the OpenGL
There is a set of OpenGL
functions
that deals with
shader
an OpenGL
objects, link them with

application, and enable the
variables among the OpenGL
and the shaders.
program
Thereare usually eight steps in initializing
one or more shaders in
some

tion:

1. Read t he

shader

source.

2. Create a program

object.

3. Create

shader objects.

4. Attach

th e

5. Compile


the

shader objects to
shaders.

the

program

object.

passing

the

of

applica-

OpenGL

Programs

465


466

C h a p te r


9

Shaders

Programmable

6.

Link

together.

everything

7. Select current

object.

program

and

8. Align uniform

the application

between

variables


attribute

the

and

shaders.

Usually, our shaders

as null-terminated

in files

stored

be

will

common

most

The

application.

shaders are


code

The following

strings.

as sourcecodethat

the

that

way

afilea

read

will

will
used

then

nd

be read by
by OpenGL


create the

the
is

desired

string:

<stdio.h>

#include

static char* readShaderSource(const
char*
{

/*

shaderFile)

reader */

shader

/* creates null
FILE* fp =
char*

buf;


long

size;

terminated

from

string

*/

file

fopen(shaderFile, \"r\;

return(NULL);

if(fp==NULL)

OL, SEEK.END);/*

fseek(fp,

size =ftell(fp);

/*

fseek(fp, OL,SEEK_SET);


/*

go to
go to

+ 1)

= (char*) malloc((size
1 , size,
fread(buf,
fp);

buf

end

size

get

of

of

file

file

beginning


*

*/

*/
of file

*/

sizeof(char));

buf[size] = ' ';

fclose(fp);
return

buf;

Cfilef u n c ti on s

uses the

Thiscode

n t o the

and readsthefilei

Suppose that


to obtain

string,finallyt

two shaderfilesa

our

thesize ofthefilei topens,allocates

e r min a t in g

re given

itwith

as follows:

GLchar vShaderFile[]

=

GLchar

= \"myFragmentShader.glsl\";

fShaderFile[]

We can read the


shaders

GLchar *vSource,

\"myVertexShader.glsl\";

and check

if

thefilese

x i st as follows:

*fSource;

vSource= readShaderSource(vShaderFile);
if(vSource
\342\200\242C

==

NULL)

a null

character.

space



9.6

printf(\"failed

to

vertex

read

Shaders

Linking

with

shader\;

exit(EXIT_FAILURE);
}

fSource = readShaderSource(fShaderFile);

if(fsource ==

NULL)

{


to read

printf(\"failed

shader\;

fragment

exit(EXIT_FAILURE);
}

We now can
GLunit

create a program

and get

object

a name (or identifier)

for

it:

myProgObj;
=


myProgObj

glCreateProgramO;

The program object is a container
functions. We createour shader
GLuint

vShader,

that
objects

multiple shaders
similar way as follows:

can hold
in a

and

GLSL

other

fShader;

vShader

= glCreateShader(GL_VERTEX_SHADER);


fShader

= glCreateShader(GL_FRAGMENT_SHADER);

We can add these shadersto our

program

glAttachShader(program,

vShader);

glAttachShader(program,

fShader);

object

by attaching them

as follows:

Note that at this point the actual shader code has not been associated
with
gram object.We create this association as follows:
glShauerSource(vShader,

1,


glShaderSource(fShader,

1,

(const
(const

GLchar**)
GLchar**)

fevSource,
&fSource,

the

pr o-

NULL);
NULL);

of the shader object into
which
the source will
parameter is the name
The second parameter is the number
of string buffers from which
the
shader source will be loaded. In our example,we have read the source into a single
buffer
with our ReadShaderSource

function.
The third parameter
is a pointer
to
The

first

be loaded.

an array

of pointers
to the string buffers, which
for our example is simply
a pointer
usedwithReadShaderSource.
TheNULLfor
thefourth
arraysthatwe
indicates that the stri ngs are null terminated. Alternately,
it could point to
of buffer
values. We can now compile
the shaders as follows:
length

tooursource
parameter
an


array

glCompileShader(vShader);

glCompileShader(fShader);

At this
that

point,

it compiled

to make sure that there
without errors. The function

we want

are no

errors

in

our

shader

code and


OpenGL

Programs

4 67


468

C h a pt e r 9

Shaders

Programmable

static void

c on s t

status,

checkError(GLint

char

*msg)

{


if

!=GL_TRUE)

(status

{

printf(\"7.s\",msg);
exit(EXIT_FAILURE);

}

>

will write

a messageand

get the status
parameters.In

through

exit

the query

glGetShaderiv(vShader,


glGetShaderiv(fShader,

checkError(status,
Now we

can link

\"Failed

status and

together

everything

exit

ftstatus);

to compile the

GL_COMPILE_STATUS,
to
compile

6

GLJTRUE. We
which returns shader
if is not GLJTRUE:

is not

variable

glGetShaderiv,

e compile

GL_COMPILE_STATUS,

\"Failed

checkError(status,

function

check th

case, we

this

the status

whenever

vertex shader.\;
ftstatus);

the


fragment

shader.

\"

);

as follows:

glLinkProgram(myProgObj);

Because

use.For

the

we can
program

create

program

multiple

object that we just


created,

objects, we m u s t identify
we execute the function

which one to

glUseProgram(myProgObj);

asfollows:

and checkitsstatususingglGetProgramiv

glGetProgramiv(program, GL_LINK_STATUS,
checkError(status,

\"

Failed

to

link

festatus);

the shader

program


object.\;

The error checking we used for compiling
and linking does not give the information we needifth er e are any errors. We can get more detailbyusing
the functions
and glGetShaderInfoLog for shaders and glGetProgramiv
glGetShaderiv
and glGetProgramlnf oLogfor the program object. The mechanismis similar
for
shader and program objects.We use glGetShaderiv
or glGetProgramiv
to deif there has been an error
termine
and the length of the error
message
string. We
canthen gettheerror stringsusingglGetShaderInf oL og andglGetProgramlnf oLog. The sample
in Appendix A uses thesefunctions.
program
in the shaders with
in the proThe next step is associating
variables
variables
in
in
Vertex
attributes
the
shader
are

indexed
the
main
gram.
program through tables

6.For
for

general OpenGL functions, we can query
the returned status GL_NQ_ERRQR.

for errors

with the function

glGetError

and check


9.6

Linking

w i th OpenGL

Shaders

are set up during linking.

We obtain
the needed indices through
the function
These indices arelater used to obtain values computed in
glGetAttribLocation.
the shader using the various
forms
of the function glVertexAttrib.
For example,
supposethat we set an RGBA color in the shader in a variable named myColor. We
get its index as follows:

that

GLuint

colorAttr;

colorAttr = glGetAttribLocation(myProgObj,
we can

Later,

use itsvaluein

the

\"myColor\;

as


OpenGLprogram

GLfloat color[4];

color);

glVertexAttrib4fv(colorAttr,
set the

will

which

A similar
variable

form

in the

of myColor

value

initial

shader.

vertex


Suppose that we compute a uniand want to send it to the shader. We get an

process holds for uniform
a ngle in the application

variables.

index

GLint

angleParam;

angleParam =
and later

can compute a value

GLfloat

my_angle;

= 5.0;

my_angle

and send

it


to the

/* or

and

version

GLfloat

other

some

program

application

*/

value

by

my_angle);

glUnif orm has one- to
can b e used to set scalarand


red[4]

GLint

in the

the shaders

glUniformlf(angleParam,

The function

\"angle\;

glGetUniformLocationCmyProgObj,

vector

a pointer

and

For example,

values.

the

(v)


code

0.0, 0.0, 1.0};

={1.0,

ColorParam;
\"

= glGetUniformLocation(myProg0bj,
red)
glUniform4fv(colorParam,
colorParam

sets the

nif

forms

four-dimensional

uniform

ormMatrix

shader

variable redColor.


are u se d

to set uniform
value of a uniform

redColor\

The various

matrices

forms

of the function

glU-

in shaders.

We can query the
variable
from a shader through
the functions glGetUnif ormlfv and glUnif
ormliv.
variables
However, because uniform
cannot be changed in the shader, we rarely need these functions
and will not discuss
them


further.

Programs

4 69


470

C h a pt e r 9

Shaders

Programmable

functions here, most of them are
n o t change much from
does
only
usage
application to application. Ifw e look at what we have to do in a typical application program,
link them to program
there
are two basic parts. First,
we set up various shaders and
objects.This part can be put in an initialization function in the OpenGL program.
we either get values from
Second,
during the execution of the OpenGL
program,

shaders
or send values to shaders.Usually,
we do these operations where we would
set valuesfor colors, texture
and other program varicoordinates,
normals,
normally
ableswith an application that uses thefixed-functionp ip elin e .
A contains a full program
with a basic vertex shader and a basic fragAppendix
ment
shader. Next, we focus on what
we can do with vertex shaders.
there

Although

used

is a

fair

9.7

of OpenGL

number

dur i ng initialization


and

their

VERTICES

MOVING

develop someexamplesofvertex shaders.Thefirst
examplesinvolve
moving
that
is p a r t of many animation
strategies. In each case, we must
because
the execution
generate an initial vertex position in the OpenGL program
In
of the function
initiates
the
vertex
shader.
these
first
glVertex
examples, the
work
done by the vertex shaders could have been done in your

application
program.
However, we often want to do this work in the vertex shader because it frees up the
CPU for other tasks. The second set of examplesinvolves
vertex col ors.
determining
We will see that by writing our own vertex shaders we gain more control over the
vertex
and transfer much of the computation
from the CPU to the GPU.
processing

We now

vertices, something

9.7 .1

Scaling

Vertex Positions
vertex

program that changes thelocation
we must remember that once we
use a vertex program of our own, we must do all the functions
of the fixed-function
In particular, we are responsiblefor converting
vertex
vertex locations

processor.
ofthe

One

of each

simplest examplesofa
vertex that triggers the

shader.

is a

shader

However,

from object coordinatesto clip coordinates.In our simplest examples, we can do
this
matrices
that are part of the
operation
by using th e model-viewand projection
we could compute the clip spaceposition
of each vertex
OpenGL state. Alternately,
in the shader
without
using the built-in matrices.

In our first example, we scale eachvertex
so that the object appears to expand
and
contract.
The scale factor varies sinusoidally,
based
on a time parameter that is
in
if
as
a
un
orm
variable
from
the
as follows:
passed
OpenGL
program
/*

vertex

uniform

shader

float


void mainO

{
float

s;

that

time;

moves

vertex

locations

/* value provided

by

sinusoidally

application

program

*/

*/



9.7

s = 1.0

+0.5*sin(time);
s,

=gl_ModelViewProjectionMatrix*(vec4(s,

gl_Position

s,

1 .0)

*gl_Vertex);

>

model-view and projection
matrices
from the
the scalefactor only to the first three components
of the vector (see Exercise 9.19). By applying
the scaling to gl_Vertex
before the
vertex
is transformed by the projection

and model-view
is done
matrices, t he scaling
in object coordinates rather
in clip coordinates. In the application
than
program, we
set up the time variable as follows:
we use

that

Note

OpenGL

GLuint

and

state

the

of the

product

that we apply


timeParameter;

=

timeParam

callback can either

The idle

\"time\;

glGetUniformLocationGnyProgObj,

the time

increment

or use the

elapsed

time in

glUnif orm

as follows:
IdleO

void


{

glUniformlf(timeParam,

glutGet(GLUT_ELAPSED_TIME));

glutPostRedisplayO;

}

Note that elapsed time is in milliseconds,
so we probably want to scale it in the shader
the scale factor in the shader. For example, if we usethe line
changing

by

1.0 +

s =

0.5*sin(0.001*time);

is converted

time

We can make
depend


to seconds.
this

example

somewhat

position of eachvertex.
value
of each vertex is

on the

which the

y

Section 5.7, we displayed
of the form

such

more

Suppose
the

data with


height

a display

if we let the variation
we start with a height field in
In
and we change only
this value.
callback
or idle callback using
code
interesting

that

int. i.j;
glBegin(GL_QUADS)

for(i=0;

i
i++) for(j=0;

j
{
glVertex3f((float)i/N, data[i][j], (float)j/N);
glVertex3f((float)i/N,


glVertex3f((float)(i+l)/N,

data[i][j],

(float)(j+l)/N);

data[i][j],

glVertex3f((float)(i+l)/N, data[i][j],
}

glEndO;

(float)(j+l)/N);

(floa t)(j)/N);

Moving

Vertices

47 1


472

Ch a p te r

9


Shaders

Programmable

where the height data is in the array d a t a and x and z are defined
(0,1). We can vary the heights with the vertex shader as follows:
/*

program for

vertex

float

uniform

vo:id
{

a height

varying

field

float

s=


float

xf

*/

time;

yf

5.0;

// x

=

5.0;

//

=0 . 1 / /
t =gl_Vertex;

factor

scale

0.001; //time
=


h

vec4

frequency

z frequency
scale

height

t.y =gl_Vertex.y +h*sin(s

*time

+

xf*gl_Vertex.x)

+ zf*gl_Vertex.z);

sin(s*time

gl_Position =gl_ModelViewProjectionMatrix

>
that

Note


y component

is a built-in
uniform
gl_Vertex
in the shader. We createa temporary

t;

we cannot change
variable,
variable t that is initial-

because

and canbe

asa copyofgl_Vertex

9.7.2

*

= gl_Color;

gl_FrontColor

ized

the range


mainO

float
float

its

over

shader

altered.

Morphing

in animation
is known as keyframing.In this techin
of
our
scene at a set of times
or in a set
positions
objects
of positions, thus defining the key frames. We then interpolate
between
successive
frames or positions
to get the in-between frames or positions.
in which we smoothly change

One
variant
of this idea is morphing, a technique
one object into another. One way to accomplishthis change is to have the set of
vertices that define one objectchange
t h e i r locations (and
other
to those
attributes)
ofth
e other object. Let's look at a simpleexamplewhere
we have the same number of

standard

of the

One

nique, we

define

vertices in

two

techniques

the


arrays.

Suppose that we have

The first specifies object A and the
want to morph object A into object B, we
of vertices
and that corresponding vertices
are matched.
vertex k in the first array of vertices should morph into vertex k
Thus,
in the second array. In general, these sets are formed
by the animator with the aid of
software
that can create extra verticest o ensure
that the two sets are of th e same size
two

sets

of vertices.

second specifiesobjectB as polygons.
assumethat they have the same number

with

another


matching

vertices.

two-dimensional

Figure 9.5
polygon.

a two-dimensional

shows

The vertex shader needsto output
between
two vertices provided
is that we can pass in only a single
However, we can pass in
gl_Vertex.
lating

If w e

asinglevertex

that is

polygon morphing

into


constructed byinterpo-

program. The main problem
vertex
the built-in uniform
variable
through
the corresponding
vertex using an applicationby

the

OpenGL


9v7

(b)

M
9.5

FIGURE

B. (c)

(c)

Morphing.(a)ObjectA.(b)

A 2/3 morphed to object

Object

vertex attribute.
much of eachvertex's
denned

We
location

Id)

Object A 1/3morphed to

B. (d)

also pass in
we should

a uniform
use in

object

B.

Object

determines how

Here is a vertex

that

variable
the

interpolation.

shader:

vec4 vertices2;

attribute

float

uniform

blend;

void main()

{

vec4 t =vec4(mix(gl_Vertex.xyz,
gl_Position = gl_ModelViewProjectionMatrix*t;

blend),


vertices2.xyz,

1 .0);

\342\200\242

gl_FrontColor

gl_C61or;

}

The GLSL function

mix

forms

the

affine

forexample,
component
ofmix(gl_Vertex,
blend)*gl_Vertex.x +blend*vertices2.x .
can define
as follows:
GLuint


the

vertices2,

vertices2Parant

In

vertex attribute v er t i c e s 2

mydisplayO

parameter

blend\;
\"

=glGetAttribLocation(program,

callback,we should

see code

vertices2\;

something like the

N50 /*number of vertices*/
GLfloat vertices_two[N][3], vertices[N][3];
void


uniform

\"
glGetllniformLocation(program,

the display

fdefine

the
and

vertices2Param;

blendParam,

blendParam =

Within

required

two vertices. Thus,
blend) is(1application
program, we

of the

combination


thefirst

following:

blend

Moving

Vertices

473


474

C h a pt e

r 9

Shaders

Programmable

{

blend =

;


value

set

/*

of

blend

*/

glBegin(GL_TRIANGLES)

ford

i< N; i++)

=0;

-C

blend);

glUniform(blendParam,

/*

set color and other vertex attributes
*/

glVertexAttrib3fv(vertices2Param_location, vertices_two[i]);

}

glVertex3fv(vertices[i]);

glEndO;

glutSwapBuffersO;

}

We probably want
coordinates, and

to embellish
vertex

other

this program quite
a bit by ble nding
(see Exercise 9.1).

colors,

texture

attributes


9.7 .3 ParticleSystems
Particle

provide

systems

plex real-world objects,

of many

one of
such

the

most

as clouds,

important

trees, water,

approaches
and

hair.

to


Particle

simulating

com-

systems are one

used in computer graphics, a topic to which
we will reidea in all particle systems is that
we can model the
in space either using realistic
motion of points
or by creating our own physphysics
ics. For each time step, we determine a new location
for each particle. We can then
For example, if we want to create
display
any object that we desire at these locations.
use a collection of translucent
each of which would be
clouds, we might
polygons,
centeredat the location of a particle. For a pieceof cloth, we can start with an array
oflocationsthatdeterminea
mesh, eachofwhoseverticesis aparticlewhoselocation
methods

procedural


12. The basic

turn in Chapter

time.

with

changes

for particle systems. One reasonis that we can have
work involved in positioning
each particle much faster
than
the CPU can. Becausevertex
shaders
cannot
create new vertices the OpenGL
at a minimum,
must
so as t o trigger
the
program,
generate each particle as a vertex
vertex shader. A particularly
but one that can be extended easily
simple
example,


Vertex shaders

the shader do

work

much

well

of the

(Exercise 9.2),is to generateparticlesthat are subject only to the forces of g rav ity .
Consider
an ideal point
to Newton's laws. Supposethat it has an initial
subject
such
(XQ, y0, ZQ), and an initial
(vx, vy, vz). If we ignore effects
position
velocity
constant g, its position
at time t is given
friction, using the gravitational
by
x(t)=x0

y(0=y0+
z(t)=z0


+vxt,

y
+vgt.

Sf2
+*'.
2

as


9.8 Vertex

Thus, we can
the

that

vertex. Because the
shad er

vertex

variableis

updated bythe
shader computes new


for

such

a particle

each

application,

vertex

positions.

time through the
Here is a simple

system:

vec3 vel;

attribute

float

uniform

time

the vertex


callback,

display

and eachparticle'sinitial velocityto
the shader as uniform
Each time
particles'sinitial position through gl_Vertex.
is executed, it then computes the present position
of the

the time

pass

and pass in the
vertex program

variables

Lighting

time,

void mainO

g;

{

vec4

= gl_Vertex;

temp_position

temp_position.x

=temp_position.x +vel.x*time;

temp_position.y

=temp_position.y
=

gl_Position

+ g/(2.0)*time*time;

+vel.y*time

temp_position.z =temp_position.z

+ vel.z*time;
*

gl_ModelViewProjectionMatrix

Here we use attribute-qualified
shader because we may use


variables

to pass

and glEndO

single glBegin(GL_POINTS)
The time and gravity
velocity.

are

per particle

callback that

a display

assumed

and

to be

temp_position);

information

all the


generates

particles

particle may have a
same for all particles.

each
the

We can extend this example in many ways. One simple
createwith this shader is to simulatefireworksb
each
yhaving

to
within

the
a

different

that we can
vertex render as a point
for each particle
position

the

shader
with the same initial
a slightly
different
initial velocity. In addition, we can change
the
color
as time progresses and even make particles disappear (see Exercise
9.3).
Ifth
e vertices are part of a more
the entire object is
complex
object than a point,
now
to gravity. One interesting
va ri ant is to create a bouncing
effect by using
subject
ther e flect function
thevertexlocation
tochangethevelocitywhen
hitstheground
(see Exercise9.5).

and

sending

but


giving

9.8

each vertex

Perhaps

the

WITH

LIGHTING

VERTEX

models
and

each vertex to

application

most

SHADERS

use of vertex shaders is to generate alternate
lighting

odified Phong model. We start by writing the Phong
models
as vertex shaders. We do so
(Blinn-Phong) lighting
the structure and functions
used to compute lighting
with
a

important

to thefixed-functionm

modified

primarily

Phong

to introduce

vertex shader. Then we will

examine

alternate

lighting methods.

9.8.1 Phong Lighting

The

for

modified
Phong lighting model that we developed
a front-facing surface, without
the distance
terms,

/=kdLd\\

\342\200\242n+
^I,(n

+ kttLaIa.
\342\200\242h)a

in Chapter

as

6 can be written

with

Shaders

4 75



×