preface

Source code here, if you like, please click star

In this chapter, the interaction between light and object surface is realized. The goal is to add shading capabilities to the rendering pipeline, so only the most basic local lighting model is discussed here. Different from global illumination, in the local illumination model, the color value of the colored point depends only on the material properties of the colored point surface, the local geometric properties of the surface and the position and properties of the light source, but has nothing to do with other surfaces in the scene.

Rendering process and scene definition

Because global illumination is not considered, only the light emitted from the light source is considered, specifically a single interaction between the light source and the surface. So the problem can be broken down into two separate parts:

  • Define light sources in the scene (only point lights are covered here)
  • Define a reflection model (PHong and Blinn-Phong reflection models) that describes the interaction between material and light.

First from a point light source, since the observer sees only the light that ends up in his eye after starting from the source. That is to say, there are two cases:

  • Or the light can travel from the light source directly into the eye of the observer, which is what the color of the light source is.
  • Either the light passes through a complex path and interacts with the object in the scene many times (consider only once here) before entering the eye of the observer, where the light source is seen interacting with the surface material.

In WebGL, projection planes are often used instead of observers. Conceptually, the part of the projection plane inside the clipped window is mapped to the display, so the projection plane can be divided into many small rectangles by straight lines, each facing a pixel on the screen. This means that the color of the light source and the surface of the object determines the color of one or more pixels.

Type of reflected light

I learned physics in junior high school, basically divided into three different types of reflected light.

  • Ambient light: it is characterized by uniform illumination of the scene and is the result of multiple interactions between light and scene objects. This is simply set to a constant to simulate.
  • Diffuse light: It has the characteristic of scattering incident light in all directions, and the intensity of the light scattered in all directions is equal, so that observers in different positions see the reflected light the same.
  • Specular reflection: It is characterized by a shiny appearance, because most of the light reflected is in the direction of the Angle of reflection. The direction of reflected light obeys the law that the Angle of incidence equals the Angle of reflection.

For the sake of simplicity, the illumination below is set up on a point, which is the shading point. And this point should be on the surface of the object, so the light from this point is the effect of the light source on this point.As shown in the figure, let’s first define some unit vectors:

  • The normal line n of the coloring point
  • Illumination direction L
  • Camera observation direction V
  • Some parameters of the surface of the object

Propagation of light and conservation of energy

Light decays as it travels.Let’s say you start with a unit sphere, the innermost sphere, and the energy received at each point on the sphere is the energy of the light divided by the area of the sphere.

When light travels to the sphere of radius R, which is the outermost sphere. According to the law of conservation of energy, the energy received by each point on the outermost ball is smaller than that received by each point. According to the formula, the energy received by the surface of the object is inversely proportional to the square of the distance of light propagation.

In other words, to calculate the energy of the light received by the colored point, we need to calculate the distance between the light and the colored point.

Phong reflection model

The reflection model was first proposed by Phong. In practice, it is not only computationally efficient but also very good at simulating reality, so that it can render well for a variety of lighting conditions and material attributes.

The Phong reflection model takes into account the three interactions described above: ambient, diffuse, and specular. For each color component, there are independent ambient light component, diffuse light component and specular light component. Finally, the three components are added together to form the final color.

Use 4 vectors to calculate the color value of the coloring point P. The unknown is the reflection vector r, which can be determined by n and L

Ambient light reflection

The ambient light intensity LaL_{a}La is the same at all points on the surface. Part of the ambient light is absorbed by the surface, and part is reflected by the surface. The intensity of the reflected part is reflected by the ambient light system Kak_ {a}ka, so that RaR_{a}Ra= Kak_ {a}ka. 0 <= kak_{a}ka <= 1.

So IaI_{a}Ia = kak_{a}ka * LaL_{a}La

Code implementation

Adding ambient light in the code is as simple as setting a small constant and multiplying it by the object color

void main () {
    vec3 ambient = 0.05 * color;
}
Copy the code

Diffuse reflection

When a parallel ray of incident light strikes a rough surface, the surface reflects the light in all directions.It can be seen that the plane normal line has a certain Angle with the direction of light, and according to the Angle of different shading points obtained is not the same.

Suppose each ray has equal energy. Analyzing the image on the left, you can see that all six rays are received when the surface is perpendicular to the direction of the light. The middle image rotates the object to such an Angle that it receives only three rays, so the surface of the object should be darker than on the left.

Therefore, the brightness of the colored point is related to the Angle between the illumination direction L and the surface normal n of the object. It can also be observed in reality, for example, that the temperature of the earth’s four seasons is different because the direction of light is related to the Angle of the surface normal.

This relationship is the famous Lamber’s Consine Law: the direction of light is proportional to the cosine of the surface normal:


c o s Theta. = l n Cosine theta is l times n

So diffuse reflection is called Lambertian Shading:

Let’s first define the intensity I of the light, the energy of the light when it reaches the surface of the object is I/r2I /r ^2I/ R2. How much light is absorbed is calculated in terms of the cosine of the Angle between the light vector and the normal vector.


L d = k d ( I / r 2 ) m a x ( 0 . n l ) L_d = k_d(I / r^2)max(0, n * l)

And Max of 0, n times L, means we’re excluding the cases where cosines are negative. Because in real life (when the surface is opaque), light cannot illuminate the surface of an object from a negative Angle. In that case, we assign 0.

And k, it’s an absorption coefficient. It shows how much light is absorbed and reflected from the surface of the object. when
k d = 1 k_d=1
That is, the surface of an object does not absorb light at all, but reflects it out.

Code implementation

In code, the normal vector is given

const aNormal = gl.getAttribLocation(program, 'aNormal');
gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, gl.FALSE, fsize * 8, fsize * 3);
gl.enableVertexAttribArray(aNormal);
Copy the code

From the vertex shader to the fragment shader

// Vertex shader
attribute vec3 aNormal;
varying vec3 Normal;
void main (a) { Normal = aNormal; . }// Fragment shader
varying vec3 Normal;
void main (a) {
    // Normalize
    vec3 norm = normalize(Normal);
}
Copy the code

The incident vector is calculated from the position of pixel and direction of light source. The position of pixel, including vertex, is also known, and the position of light source is uniformly stored with uniform variables

// Vertex shader
attribute vec3 aPos;
varying vec3 FragPos;
void main (a) { FragPos = aPos; . }// Fragment shader
varying vec3 FragPos;
uniform vec3 lightPos;
void main (a) {
    vec3 lightDir = normalize(lightPos - FragPos);
}
Copy the code

Finally, the diffuse reflection component is calculated according to the formula

// Fragment shader
void main (a) {
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * color;
}
Copy the code

Specular reflection

We see highlights when we look at shiny objects. These highlights usually show different colors from ambient and diffuse light reflections. In contrast to diffuse surfaces, which are rough, specular surfaces are smooth. The smoother the surface, the closer it is to a mirror, the more light is reflected around an Angle.

Phong proposed an approximate model that considers the surface as smooth when considering specular reflection. The intensity of the light seen by the observer depends on the Angle α between the direction r of the reflected light and the direction V of the observer.


L s = k s L s c o s p Alpha. L_s = k_sL_scos ^ p alpha

The coefficient of
k s k_s
(0 < =
k s k_s
<= 1) indicates how much of the incident specular reflection is reflected. The exponent P is the specular coefficient. As can be seen from the figure below, as P increases, the reflected light becomes more and more concentrated near the Angle of reflection of the ideal reflector.When p is not added (i.e. P =1), we look at the shading point from the reflection Angle of 60 degrees, which is supposed to be very far away, but it still reflects the highlights. This makes no sense, because in reality the highlights are only visible when they are very close, and not when they are a little further away. That’s why we added an exponent to normalize it.

The advantage of the Phone reflection model is that, if r and V have been normalized to unit vectors, the specular reflection components can be calculated using the dot product operation in the same way as diffuse reflection:


L s = k s L s m a x ( ( r v ) p . 0 ) L_s = k_sL_smax((r * v)^p, 0)

Then you just need to calculate the reflection vector R!

Reflection Angle calculation

The normal vector is given, and the Angle of reflection can be calculated using the normal vector n and the incident vector L. The ideal specular reflection has a nice feature: the Angle of incidence equals the Angle of reflection. As shown in the figure:The Angle of incidence is the Angle between the normal vector and the incident vector, and the Angle of reflection is the Angle between the normal vector and the reflected ray. In the plane, there is only one reflection direction that satisfies the condition that the Angle of incidence is equal to the Angle of reflection. But it doesn’t work in three dimensions, because there’s an infinite number of directions where the Angle of incidence is equal to the Angle of reflection. So one condition is added: at a point P on the surface, the incident ray and the reflected ray must lie in the same plane. These two conditions r can be determined by n and L.

Suppose l and n are already unit vectors:

| | = | l n | = 1.

It is also assumed that r is also a unit vector:

|r| = 1

If theta I theta _I theta I= theta r theta _r theta r then

Cosine theta icos theta _icos theta I = cosine theta rcos theta _rcos theta r

The dot product operation can be used to obtain:

Cos theta icos theta _icos theta I = L * n = cos theta rcos theta _rcos theta r = n * r

The coplanar condition implies that r can be written as a linear combination of L and n:

R = αl + βn (1)

Take the dot product of both sides with n to get equation (2) :

N * r = αl * n + β = l * n (2)

Since r is a unit vector, equation (3) can be obtained by substituting equation (1) :

1 = r * r = α2α 2 + 2αβl * n + β2β^2β2 (3)

Equation (2) and equation (3) can be obtained

r = 2(l * n))n – l

Code implementation

The above formula for calculating the Angle of reflection is implemented in GLSL with a built-in function called Reflect. So it’s very simple to implement in code, and the line of sight vector is known.

// Fragment shader
uniform vec3 viewPos;
void main (a) {
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    vec3 specular = vec3(0.3) * pow(max(dot(viewDir, reflectDir), 0.0), 8.0);
}
Copy the code

Phong reflection model results

Add these three components together to form the Phong reflection model

L = La + Ld + LsL = L_a + L_d + L_sL = La + Ld + Ls = kaIa + kd (I/r2) Max (0, n) ∗ L + ksLsmax (∗ (r v) p, 0) = k_aI_a + k_d (I/r ^ 2) Max (0, N * l) + k_sL_smax (v) (r * ^ p, 0) = kaIa + kd (I/r2) Max (0, n) ∗ l + ksLsmax (∗ (r v) p, 0)

gl_FragColor = vec4(ambient + diffuse + specular, 1.0);
Copy the code

The renderings are as follows

The Phong reflection model not only has a good approximation to real illumination, but also has high performance. But its specular reflection can be problematic in some cases, especially when objects have very low reflectance, resulting in large specular areas.

The reason for this problem is that the Angle between the observation vector and the reflection vector cannot be greater than 90 degrees. If the dot product is negative, the specular reflection goes to 0. You might think that when the Angle of light is greater than 90 degrees, you should not receive any light at all. This idea applies only to diffuse reflection.

However, in specular reflection, the measured Angle is not the Angle between the light source and the normal, but the Angle between the line of sight and the reflected ray vector, as shown in the figure below.In the figure on the right, the Angle between the line of sight and the direction of reflection is significantly greater than 90 degrees, in which case the mirror light component is 0. This is fine in most cases, because the direction of observation is very far from the direction of reflection. However, when an object’s reflectance is very small, the specular radius it produces is large enough for these opposing rays to have a large enough effect on the brightness that their contribution to the specular component cannot be ignored.

And the Angle of reflection is harder to calculate.

So Blinn expanded on Phong by introducing the Blinn-Phong reflection model.

Blinn-phong reflection model

The only difference between this model and Phong model is the processing of mirror light component. The Blinn-Phong reflection model no longer relies on an Angle of reflection, but instead uses a half-range vector, a unit vector in the direction of half the Angle between the ray and the line of sight.

Half vector

When the observation direction is close to the mirror reflection direction, the normal direction of the object surface is close to the half-range vector.The so-called half-range vector is the light direction vector and the observation direction vector you add up by the parallelogram rule and divide by its length.


h = ( v + l ) / v + l h = (v + l) / |v + l|

If h is close to n, v and R are close, which is what makes blinn-Phong’s model special. Because the Angle between r and V is hard to calculate, it’s a lot easier to calculate with this little trick.

It is almost the same as the diffuse reflection principle, except that the Angle between the light direction and the normal direction is replaced by the Angle between the half vector and the normal direction


L s = k s ( I / r 2 ) m a x ( 0 . n h ) p L_s = k_s(I / r^2)max(0, n * h)^p

Code implementation

vec3 halfwayDir = normalize(lightDir + viewDir);
vec3 specular = vec3(0.3) * pow(max(dot(norm, halfwayDir), 0.0), 32.0);
Copy the code

The renderings are as follows

At the end

Ben 4. – Front end. – Guangzhou, you got a good spot, guys

Creation is not easy, please move your hands to point out a praise.

The code is on github, if you like, please click star, which is also a kind of encouragement to the author.

This paper quotes the following information:

  • learnOpengl
  • Interactive Computer Graphics: A Top-down Approach Based on WEBGL
  • Games101 – Introduction to modern Computer Graphics