hello everyone and welcome back to
another video tutorial on webg
programming this is tutorial number five
and I believe this is going to be if
this isn't the last one this is going to
be um one of the last ones that is an
incremental tutorial you know 1 2 3 4
five the rest of them after this I'm
going to try to do just more interesting
topics that don't necessarily build off
of each other so this one is applying
Lighting in webgl and so the last thing
that we did is we made something like
this where we had a model that we loaded
it from a file took all the information
got it over Ajax uh and it's just this
smear of brown with you know the
occasional shape to lend us a clue that
it's a
monkey in video games we have a lot more
quality than that so we're going to
introduce lighting to give us something
more like this so now you can see the
shape of it you can tell the details you
can notice some that it's like roughly
roundish shape and this one you can even
see the detail of the individual
polygons switch in a lot of games it's
an artistic Choice that's really cool in
this one it's just because we're using a
really low poly mesh you could make a
mesh that's much higher quality than
this and that's perhaps one of the
things we're going to go into later is
uh how to load much more elaborate
models from
file um we're going to be using the Fong
lighting model but we're only going to
be using part of it we're going to be
using the ambient and diffuse terms and
just to cover super quickly what all
this is is here's Wikipedia page that is
an excellent read on the Fong reading
model as you can see it's like maybe two
pages worth of reading and there are
three different types of lighting that
it adds them all together to give you
this nice goodlooking image in this case
it's just like a blob in the shape of an
X that happens to be shiny the first one
is the ambient term and this simulates
light that's bouncing around the entire
scene and it
like just kind of dimly illuminates the
entire object equally
you also have diffuse light which comes
from what parts of the object are facing
towards the light as you can see in this
one the light seems to be coming from
the right side over here um so you can
see vertices on the or faces on the far
side of the object aren't lit at all
with the with the light and vertices on
the complete other close side are very
nearly completely lit and everything in
the middle is a function of how tilted
away from the light it is
you finally have the specular light
which gives you a lot of insight into
where the light actually is in the scene
the specular light is you can imagine
some light that has bounced directly
from the light source onto the object
and then back into your eye it's the
shiny spot that you see on shiny
things we are just going to be using
ambient and diffuse for this video
though I intend to make another video
later on specular lighting so here is
the lighting formula I'm not going to
get into it you can read all this pretty
much the important thing is ambient
light you just kind of multiply it by
the ambient term we're going to be using
just the texture for the ambient color
at that spot and then you multiply the
diffuse term which we're also just going
to be using the texture again for that
value and you multiply via DOT product
the normal Vector this is a vector that
points directly out from the model at
that pixel fragment vertex whatever uh
fragment in our case um and you do a DOT
product of that onto the direction
towards the light from that surface
so um I brought up a little image right
here so
imagine oops that's not what I wanted to
do okay so imagine that we have a box
down here you know it goes from like
there there there there and we're
drawing a point on that box and this is
the normal Vector that points straight
away from the box this Vector represents
from the box to the light and this one
happens to be
pointing actually this one is pointing
in the correct direction
um so when you take a DOT product I'm
not going to get too heavy into this but
if the light is perpendicular so it's
facing completely away then you can see
we have no light at all I can't get it
exactly perpendicular but um you would
have zero light but if it's pointing you
can see as I bring it around in a circle
towards our normal Vector the value is
increasing until we get perfectly lined
up where it's maximized at in this case
three is how long this line is and any
everything in between is some value in
the
middle now we are going to have to get
rid of negative values because anything
pointing away is negative so we're just
going to call these zero that this has
strength zero it's not going to cause it
to be less lit if a face is pointing
away from a light source I will put both
of these links in the description and
let's
see I believe this one was yes so this
one is from my notes which we don't need
need great and then this one was from
the actual repository I
believe yes so this one is serving from
the actual repository so let's get this
going so let me bring up my code right
here so the first thing we need to do is
we need to grab the normals information
from the model let me zoom in just a
little bit right there is
good now I can't remember exactly what
the name is so let's take a look at it
model do I remember it is meshes zero is
what has all of our
information and it looks like the
normals information yes it's just in a
normals array right there and you can
see that there's just as many normals in
this case way too many as there are
vertices meaning that for every vertex
which has three values in X Y and Z we
also have a normal which is going to be
an X Y and Z value these ones are all
going to be normalized vectors so if you
were to find the length of the vector it
would be one um so if it pointed
straight in the y- axis it' be 0 1 0o
and so on and so forth and the
implications of that become a lot more
clearer if you study linear algebra
which I highly recommend if you're
interested in game
programming um but when you take the dot
product of two unit vectors you're going
to get a value between zero or one which
also happens to be the minimum to
maximum intensity that we need for our
colors so it works out really
nice so let's follow kind of this same
model that we've been doing for
everything else you can see we have
position vertex buffer object text
record vertex buffer object index buffer
object let's make another one for our
normal object so Susan
normal equals Susan model. meshes 0.
normals
yes and then here after we do the index
buffer object our Susan normal buffer
object equals J.C create buffer jail.
bind buffer
we're going to use an array
buffer and we want to bind the normal
buffer object then we want to set the
buffer
data to gl. array buffer new float 32
same thing as we've been doing before
Susan
normals Susan
normals that one g. static draw because
again we're not changing any of these
vertices once they are uploaded to the
GPU great so that's uploading that so
now let's actually add the attribute to
our vertex
Shader attribute VC 3 vert
normal and then we're going to add
varying V 3 frag
normal and here I'm just going to say
frag normal equals vert
normal now there's two different types
of lighting there's per vertex lighting
where you figure out all the lighting
information in the vert Tex Shader and
then you only pass the light intensity
and light color to the fragment Shader
those values are then interpolated
across the entire triangle to give you
lighting values at every point that is a
lot more efficient but it's also much
lower quality um than the alternative
which is per fragment lighting where you
only pass the normal information to the
fragment Shader and then using these
normals the fragment Shader then does
all of the work for
lighting on this particular mesh it's
actually going to be the exact same and
that's just because I know something
about the mesh I know that every face
every vertex the normals are going to be
pointing in the same direction directly
outside of that face without respect to
the other values when you're doing more
complicated rounder shapes cylinders
curves that kind of thing um your artist
will usually give you assets or you will
usually provide assets if you're good at
Art like I am not um you'll get assets
that will have the normal kind of adjust
it a little bit to look more natural
when lighting is
applied so let's copy this normal over
let's make sure everything H we'll we'll
do that in just a
second and what I'm going to do is I'm
just going to ignore the fragment color
for now uh the texal anyways and I'm
just going to grab the frag
normal and so I'm just going to color it
with the normals to see what it looks
like to make sure we're getting
everything so it looks like we're not
getting everything and the reason for
that is I completely forgot that we need
to bind the um the vertex attribute so
let's again follow this same model that
we've been doing with all these
before
oops bind buffer g. array
buffer and we want the Susan normal
buffer
object
our normal attri R location equals g.
get at trib location
program vert
noral program get normal great sounds
good and then gl. vertex atrib
pointer and I want this we want to be
setting which vertex buffer object we're
going to be or we're going to be setting
the input for the verts normal attribute
which we're getting from here each
attribute L each element in that
attribute has three floats so three g.
float you know what I'm actually going
to put these up on the same line because
they correspond to the same data this is
normalized information so let's let's go
over here if we look at webgl vertex
atrib pointer I'm just going to look up
something really quick in the
documentation because I believe this gl.
false is describing if it's normalized
data or not values are normalized to an
access fixed to floating Point okay so I
think this we'd be safe to say gl. true
because the information is normalized
meaning it has a unit length of one
there are three elements and there's
nothing else so float 32 bytes per
element and zero for the
offset finally last thing is we need to
enable the attribute normal attri
location and if we do that okay great so
now this is
um what all of our normals look like
and it's very colorful because it's
useful to visualize things like this
sometimes X corresponds to Red y
corresponds to Green Z corresponds to
Blue so you can kind of get an idea for
which way all the vertices are facing
like these bright red ones are facing
straight in the X Direction the Bri
bright Zoo ones blue ones straight in
the Z Direction however you can see that
that is all still in mod model space
that's not in our world space that we're
interested in so that's something we
have to adjust in our vertex Shader our
frag normal equals vert normal right
here our vertex normal is just going to
be in the model space we need to
transform it to the world space so we're
going to do something very similar to
what we're doing right
here um except for we're not going to
apply the projection Matrix because we
want to keep it in World space our
lighting information is also going to be
in World space so let's take care of M
world times
for normal now M world is going to
expect a four-dimensional vector I
believe so this shouldn't work
y so we need to give it very similar to
what we did down here we need to give it
a four-dimensional vector however this
one and I believe I I mentioned in an
earlier video I was going to explain the
1.0 when you're translating positions
this 1.0 takes in Translation
information into effect so if you have
an object in model space at 0000 and you
want that object translated three units
up um you would apply a 030 translation
to it and this 1.0 the way the Matrix
matrices are all laid out enables that
to happen however normals we don't want
to translate so I'm going to leave that
as
0.0 this I believe shouldn't work yep
we're not quite there and the reason for
that is frag normal is expecting a
three-dimensional Vector this is going
to give us a four-dimensional Vector is
a result so I'm going to grab just the X
Y and Z components of it and that is the
threedimensional vector great so now you
can see the normals are all transformed
um and on the left side we have the red
up here we have green and then behind
the monkey we have blue and so you can't
exactly see it right now um so let's
reverse the Z Direction really quick
just to show you 1 one negative
1 let's make those Point O's because uh
openl is actually pretty picky about
type so great now you can see the things
pointing straight at us are more
blue
cool um so anyways so now that our
normals are translated accordingly and
the they're pointing in the correct
direction let's start applying lighting
information and what we're going to need
is we're going to need an ambient light
which for now I'm just going to make all
of this information in the fragment
Shader main so ambient light intensity
equals VC 3 let's make it a very soft
bluish light um so 0.2 0.2
0.3 and you know what I might even
actually change these to 0.1s and 0.2
instead we'll see this is I'm just
picking numbers I have no good reason
other than those are small the next
thing we're going to want is we're going
to want our sunlight
intensity equals VC 3 and let's say that
the sun is giving us a nice 0.7 0.6 0.3
light so it's a
yellow whitish yellow light I imagine I
don't know I don't know what those
colors actually mean um and which way is
the sunlight shining so sunlight
Direction equals V 3 it is
shining a little bit to the right but
mostly down
and nothing in the
z-axis um so for the direction we're
actually also going to want a normal
Vector so
normalize that to give us a normal unit
Vector um and I suppose I should stop
here to say that traditionally in video
games there are three different kinds of
lights that we use there's ambient light
which is you can imagine if that is just
if it's a bright day there's High
ambient light if it's a dark room
there's low ambient light so it's how
much light is permeating the entire
scene including the
Shadows you then have directional lights
which simulate a bright light coming
from an object that's functionally
infinitely far away so imagine the sun
um it the sun is pretty much Infinity
distance away for all of our purposes
it's much further than we're ever going
to be able to calculate using our float
or our scene arithmetic um and then so
it's only shining we only care really
about which direction it's pointing um
and then how brightly it is to our scene
there's also two other kinds of Lights
which I'm not going to cover in this
video called Point lights which um or
the first one is called a point light
and the point light has a location in
space as well as an intensity and an
attenuation or how far it goes before it
stops being bright
um and those you can place anywhere in a
scene and it affects objects objects
different differently you can imagine
that is like a light bulb or a lamp
floating somewhere in a scene finally
you have a spotlight which behaves like
a street light or a flashlight something
where the light comes out in a narrow
cone from a
source we're only going to be using
directional and ambient light in this
video so let's make sure I didn't do any
stupids and it still compiles it still
compiles
great so now we're going to be applying
this and this and because we are using
only one light so we don't have to do
any
summation and the ambient light and the
or the ambient material and diffuse
material are going to be the same color
it's just going to be our texal let's
grab that texal color that is
A4 Texel equals
F texture 2D sampler frag text cord so
this is just going to be grabbing the
color that previously we were sending
straight to GL frag color and this is
going to be both our K A and KD term and
because we're only using one light and
these are the same thing our light
intensity is just going to be be our
ambient light intensity plus this whole
thing right here so let's get that right
now so float light intensity
equals I don't want to float do
I no no I do
not I want a vect three light intensity
equals ambient light intensity
plus and then here we're going to
put our sunlight
intensity
times the dotproduct of our frag normal
and our sunlight
Direction I believe that's good now this
is going to give us a number between
negative 1 and one depending on which
way everything's facing and we
definitely don't want negative numbers
so I'm just going to do a Max on 0.0 so
that the smallest it can be is zero so
now this will give us a number between
zero and one great so this might
run no because we're still doing GL frag
color equals all that ay okay so now
what we're going to do is we're going to
take that texal color that we have and
we're going to multiply it by our light
intensity and when you do a
multiplication like this in openg GL in
glsl it multiplies per component so if
we had 1 2 3 * 222 that would would give
us 2
46 so if we do that now we get a
compiler great line 18 so it's right
here okay it's
expecting okay it's expecting a v four
and this is this right here the texal
color is a VC four but this is a VC
three so what I'm going to do is I'm
going to get the red green and blue
components from that Texel multiply it
by the Light intensity and then I'm just
going to say whatever the alpha
component of our exxel is that's what
we're going to use as the alpha for this
whole result so now if I run it great so
now we see our monkey is like kind of
dimly lit from the bottom so let's
adjust these numbers a little bit kind
of get them lit better so if I do 1.0
have it that that looks like it's in the
wrong direction doesn't
it let's make sure that it's negative
direction we want it to shine yes it
is so
then apparently we want it to come from
positive y yep okay looks
good something like that that looks like
a good direction let's also make our
ambient light just a little bit brighter
so we'll say two two
and five maybe what does that give us
okay ah so you can see his eyes are kind
of blue because that ambient light is a
very Stark blue
color um let's make our sunlight A
Little Bit Stronger too why don't we do
0.9 0.9 0.9
great starting to look better I'm not
sure I dig the blue eyes so I'm going to
change that I'm going to bring that
ambient light back down to a very soft
blue
light you know what I'm not even going
to make it blue at all I'm just going to
do
that great and so now you can definitely
see there is much more of a lighting
effect going on now there is one more
thing I'm going to point out in this
example it doesn't really hurt us but
the rasterization process tends to
denormalize vectors so I'm going to say
um that our V 3 surface normal equals
normalize the fragment normal so you
shouldn't see any change but I am going
to point out that this is a good idea
because this is likely no longer a
normalized vector especially in more
complicated
objects great so let me just make sure
that I've got everything in order
yes I do good so this is looking good so
this is kind of the final result we
wanted for this video hooray great but I
do have a problem with the fact that I'm
specifying all the lights inside of our
Shader I don't like that so we're going
to work to specify them outside of the
Shader um and I'm going to introduce A
New Concept here because what we could
do is we could just make all of these
uniform values and actually you know
what let's start with that let's make
all those uniforms so
uniform ambient light intensity uniform
sunlight intensity uniform sunlight
direction oh and I suppose I want uh vck
three on all of those
huh
great surface normal we do want to keep
there but I can get rid of all these now
I'm just going to comment that out
should be black if I refresh it yes it
is so let's go in our code right here to
where we're getting all of our
uniforms and let's actually do all this
after we do our rotation information so
lighting information we'll make a new
segment for it I'm going to save
our oh well for good practice let's use
the program program just in case we
change this code later to be using
different
programs let's say VAR ambient light
intensity uniform location equals G.G
uniform location
program and I'm calling this one
that let's make this a shorter variable
name ambient light
intensity UL for uniform
location um
now I do like to use the word uniform
actually so that I can search over
everything later when I need to change a
whole bunch of things at
once sunlight dur uniform
location and then bar
sunlight intensity uniform
location
great so now let's actually set those
values and for now let's just set them
to the same thing we had before so we
will say GL dot oh I believe you
say just
uniform how many other components are in
it
f and then I do want to set them
individually so we'll say v as well
ambient uniform location and I wanted to
set that to 0.2 0.2
0.2 great so if I were to refresh that
now it fails no function to is it 3F
just 3F then yep apparently it was just
3F CU now you can see we have our
ambient light it's very dull but it's
there so if I were to bring this up to
1.0 on all these
components you would see that it would
just be the same thing that we had
before so this is our ambient
component yes and I like that that looks
pretty good very dull very dim but
that's okay let's set our sunlight
intensity and Direction so uniform 3F
sunlight dur sunlight dur uniform
location and we wanted that set to
3.0 4.0 and
-2.0 but we wanted that normalized
which so let's do this
back back
three Norm Sun Direction equals
normalize
sunlight Direction and then I want to
use that in that computation so now we
can set that as you can see nothing's
changed because we still haven't set the
intensity uniform 3F sunlight
in uniform location and I want the
intensity to be 0.9 across the
board so now if I refresh it you can see
we got the exact same thing that we had
before looks great
awesome cool um so this is kind of the
better practice one thing I'm going to
introduce is the idea of structs in glsl
they behave pretty much the same way
they do in
C++
um though setting them is kind of wonky
so we're going to make one but I'm also
going to show that at least at my
knowledge of how to use them they aren't
that helpful
anyways so to define a struct you define
struct and then what you want the name
of it to be so this is going to be a
directional
light we're putting that information
together and the components of a
directional light are going to be the
direction and the color great so then in
here instead of saying uniform VC 3
sunlight intensity and uniform VC 3
sunlight direction we're just going to
grab one uniform and it's going to be a
directional light and I'm going to call
it
sun and then instead of using sunlight
Direction I'm going to say sun.
Direction instead of saying sunlight
intensity I'm going to say Sun
Dot
color and I think everything else stays
the
same yeah it does great so now in here
these two uniforms no longer exist they
are both encapsulated in Sun so what we
do is we say that the direction is going
to be under
whoops Sun what am I doing
wrong why am I still in
here why what what what what did I
do why can I not type in here okay well
it's better now it's going to be sun.
Direction and this one is going to be
sun. color so as you can see everything
works the exact same nothing changed at
all if we misspell it I can show that we
actually did it right that it's not
complaining because we did everything
everything properly um so I like this
personally just because it gives you
kind of a more object the approach so I
can use structs now um and if I were
writing something a little bit more
elaborate I could write a directional
light class that then would take care of
all these shading uniforms and taking
care of all that stuff for me uh so I
didn't have to worry about setting these
properties manually because at this
point it just makes a little bit more
complicated but say I had five
directional lights in the scene this
might might be a lot better to express
um so anyways I really think that's all
that I had for this tutorial
so uh I hope you enjoyed it if there's
anything else you'd like to see about
how to program in webg let me know in
the comments and I will look at making a
video about that so here's our lovely
rotating shaded
monkey anyways thanks for watching