This article focuses on webGL lighting, not basic WebGL knowledge. If you are not familiar with the basic webGL knowledge, you can consult the relevant basic information first!

Realization of cube

Let’s briefly draw a cube to see what it looks like without light and shadow. Here I briefly enumerate some examples of code:

// Vertex shader const vertexShaderSource = 'attribute vec4 a_pos; attribute vec4 a_color; varying vec4 v_color; Void main(){float radian = radians(25.0); // Rotate 25 degrees float cos = cos(radian); Float sine = sine (radian); float sine = sine (radian); // Create a rotation matrix about the X-axis // 1 0 0 // 0 cosα sinα 0 // 0 -sinα cosα 0 // 0 0 0 1 mat4 mx = Mat4 (1,0,0,0,0, cosine, sine, 0, 0, sine, cosine, 0,0,0,0,1); // create rotation matrix about y axis // cosβ 0 sinβ 0 // 0 1 0 0 //-sinβ 0 cosβ 0 // 0 0 0 1 mat4 my = Mat4 (cos, 0, - sin, 0,0,1,0,0, sin, 0, cos, 0,0,0,0,1); gl_Position = mx*my*a_pos; v_color = a_color; } '// Fragshader const fragShaderSource =' precision lowp float; varying vec4 v_color; void main(){ gl_FragColor = v_color; } `Copy the code

After passing in the vertex data, the rendered result looks like this:

From the rendering result above we can only see the rough shape of the cube, it does not show the obvious 3D style, from which we can introduce the concept of lighting to explain the reason.

Realization of illumination

Physical models of illumination

In life, we can see an object because it’s hit by light and reflects some of that light back into our eyes. Because of the light source and the direction of the light and other factors, the final object you see is different in light and shade. It is precisely because of these differences in light and shade that we can feel the three-dimensional sense of the object. The cube drawn above is not obvious three-dimensional because it does not take into account the shadow of the light.

Now we are trying to implement lighting in WebGL. Before we do this, we need to distinguish the types of light sources: parallel light (usually refers to sunlight), electric light (such as light bulbs), and ambient light (light emitted by the light source and reflected by the wall or other objects), as shown below:

It is also necessary to distinguish between the types of reflections, which in general physics are generally divided into two categories: diffuse and specular. The physical model is shown in the figure below:

Obtaining computing model

These are all physics models that you’ve seen in junior high school physics, and they’re very easy to understand. Now I’ll explain how to integrate the above physics model into WebGL and use algorithms to achieve real physics. Here’s an example of diffuse reflection:

By physical model can be seen that we get to the incoming light and vertex normal vector Angle, if the incident Angle is perpendicular to the vertex normals is 90 degrees, then with the vertex plane are parallel, the incoming light also can’t illuminate to the vertex or can’t be reflected light to our eyes, so at this time of vertex color no matter what color should be pure black, RGB is the same thing as RGB (0,0,0).

It is obvious from the above analysis that the color calculation model is the following formula

Color of diffuse reflected light = primary color of geometry surface x ray color X ray incident Angle cosine

Implementation in WebGL

With this calculation model in place, we are ready to implement lighting in WebGL.

Again, let’s write the shader code first

// Vertex shader const vertexShaderSource = 'attribute vec4.a_pos; // Attribute vec4 a_color; // Vertex color variable attribute vec4 a_normal; // Normal vector uniform vec3 u_lightColor; // Uniform color vec3 u_lightDirection; // Parallel to the light direction varying VEC4 V_color; Void main(){float radian = radians(25.0); // Rotate 25 degrees float cos = cos(radian); Float sine = sine (radian); float sine = sine (radian); // Create a rotation matrix about the X-axis // 1 0 0 // 0 cosα sinα 0 // 0 -sinα cosα 0 // 0 0 0 1 mat4 mx = Mat4 (1,0,0,0,0, cosine, sine, 0, 0, sine, cosine, 0,0,0,0,1); // create rotation matrix about y axis // cosβ 0 sinβ 0 // 0 1 0 0 //-sinβ 0 cosβ 0 // 0 0 0 1 mat4 my = Mat4 (cos, 0, - sin, 0,0,1,0,0, sin, 0, cos, 0,0,0,0,1); gl_Position = mx*my*a_pos; vec3 normal = normalize((mx*my*a_normal).xyz); Float dot = Max (dot(u_lightDirection, normal), 0.0); float dot = Max (dot(u_lightDirection, normal), 0.0); Vec3 reflectedLight = u_lightColor * a_color.rgb * dot; vec3 reflectedLight = u_lightColor * a_color.rgb * dot; V_color = vec4(reflectedLight, a_color.a); // Transparency interpolation} '// fragShaderSource const fragShaderSource =' precision lowp float; varying vec4 v_color; void main(){ gl_FragColor = v_color; } `Copy the code

According to the shader code, we need to pass in the vertex normal vector, the direction of incident light and the color of incident light to get the illuminated rendering model, as shown below:

Perfect!