Learn the basic lighting of OpenGL ES

All articles in this series catalog
the code used in this article is in the https://github.com/SquarePants1991/OpenGLESLearn.git branch of chapter9.

This paper describes how to use Shader to achieve the effect of parallel light. What is parallel light? We can take the laser analogy, the direction of the parallel light will not change with the distance from the light source. So we only need to use a light direction in the simulation of parallel light.
we have a light direction, and then we need an important data. If a plane is just facing the light, it is naturally the brightest. Of course, some of the material plane can reflect the light, the intensity of reflected light and the angle of your observation, but these are not introduced in this article. There will be a special introduction to the complex lighting model.
we use the line vector to represent the orientation of the plane, in the concrete implementation, each point will have a normal vector. The normal vector is a three-dimensional vector perpendicular to the plane, as shown in the following figure.

Learn the basic lighting of OpenGL ES

shows that two methods of normal vector, each polygon is on the left there is a normal vector on the right, each point has a normal vector and normal vector sharing point is the point in the plane normal vector and all. Normal vectors should always be normalized to unit vectors. The example in this article is on the left.

If you are not very understanding of vector related knowledge, you can refer to Baidu Encyclopedia

With the normal vector and the direction of illumination, as long as they are multiplied to get the light intensity. Next start analyzing code.

Two unit vector multiplication, the result is cos (vector angle), the greater the angle, the cos (vector angle) smaller, just in line with the previous law.

First we look at Vertex Shader.

Attribute vec4 position; attribute vec3 normal; uniform float elapsedTime; uniform mat4 projectionMatrix; uniform mat4 cameraMatrix; uniform mat4 modelMatrix; varying vec3 fragNormal; void main (void) {mat4 MVP = projectionMatrix * cameraMatrix * modelMatrix; fragNormal = normal; gl_Position = MVP * position;}

I will attribute vec4 color; replaced by the attribute vec3 normal; no longer pass the color data, instead of the normal vector. The normal vector is then passed to Fragment ShaderfragNormal = normal;.

Next is Fragment Shader.

Precision highp float; varying vec3 fragNormal; uniform float elapsedTime; uniform vec3 lightDirection; uniform mat4 normalMatrix; void main (void) {vec3 normalizedLightDirection = normalize (-lightDirection); vec3 (transformedNormal = normalize (normalMatrix * vec4 (fragNormal, 1)).Xyz); float diffuseStrength = dot (normalizedLightDirection, transformedNormal); = diffuseStrength clamp (diffuseStrength, 0, 1); vec3 diffuse = vec3 (diffuseStrength); vec3 ambient = vec3 (0.3); vec4 finalLightStrength = vec4 (ambient + diffuse, materialColor = 1); vec4 vec4 (1, 0, 0, 1); gl_FragColor = finalLightStrength * materialColor;}

I added the direction of light uniform vec3 lightDirection, the normal transformation matrix uniform mat4 normalMatrix;.

Normal can not be directly used in modelMatrix transform, inverse transpose matrix using modelMatrix, reference Wikipedia

Because the light is in the direction of the plane, and the normal is from the direction of the plane, so they need to be in the direction of light before the multiplication, and to standardize.

Vec3 normalizedLightDirection = normalize (-lightDirection);

Then we transform the normal and then normalized, we get the two key vectors. Here is the sketch map.

Learn the basic lighting of OpenGL ES

multiplies them and finally gets diffuse, which can be called diffuse reflectance. Diffuse reflection is the reflection of light that is projected on a rough surface. We solve diffuse is the simulation of diffuse reflection. The
code finally has a vec3 ambient = vec3 (0.3); what is it? According to the formula of diffuse reflection, there will always be a strength of 0 place, in order to make the scene is not so dark, it adds a basic light intensity, also known as ambient light intensity.
ambient light intensity plus diffuse reflectance is the final light intensity finalLightStrength. Light intensity multiplied by the color of the material itself materialColor get the final color, the color of the material itself is red.

After Shader, we go back to the OC code. First, I will bind the Shader property color code to bind normal.

- (void) bindAttribs: (GLfloat * triangleData) {/ / two / / Shader enabled attribute in attribute vec4 position; / / attribute vec4 color; GLuint positionAttribLocation = glGetAttribLocation (self.shaderProgram, position); glEnableVertexAttribArray (positionAttribLocation); GLuint colorAttribLocation = glGetAttribLocation (self.shaderProgram, normal); glEnableVertexAttribArray (colorAttribLocation); / / shader position and color glVertexAttribPointer (GLuint / indx, the assignment of GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* PTR) Get Location / / indx: / / size: above to have several types of type data, such as location x, y, Z three GLfloat elements, the value is 3 A / / type: Just like elements in an array data type / / normalized: / / stride: temporarily not every point contains several byte, is 6 GLfloat, in the case of the X, y, Z, R, G, B / ptr: data pointer at the beginning of the position is to start over, color skip 3 GLFloat size glVertexAttribPointer (positionAttribLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof (GLfloat), (char * triangleData)); glVertexAttribPointer (colorAttribLocation, 3, GL_FLOAT, GL_FALSE, 6 * sizeof (GLfloat), (char * triangleData) + 3 * sizeof (GLfloat));}

Then prepare the normal vector data.

- (void) drawXPlanes static GLfloat {triangleData[] = {/ / X 0.5 axis plane 0.5, -0.5, 0.5f, 1, 0, 0, 0.5, -0.5f, -0.5f, 1, 0, 0, 0.5, 0.5f, -0.5f, 1, 0, 0, 0.5, 0.5, 1, 0, -0.5f. 0, 0.5, 0.5f, 0.5f, 1, 0, 0, 0.5, -0.5f, 0.5f, 1, 0, 0, -0.5 / / X axis plane -0.5, -0.5, 0.5f, -1, 0, 0, -0.5, -0.5f, -0.5f, -1, 0, 0, -0.5, 0.5f, -0.5f, -1 0, 0, 0.5, -0.5, -0.5f, -1, 0, 0, -0.5, 0.5f, 0.5f, -1, 0, 0, -0.5, -0.5f, 0.5f, -1, 0, 0}; [self bindAttribs:triangleData]; glDrawArrays (GL_TRIANGLES, 0, 12);}

Take the two planes on the X axis as an example, the plane normal direction of the X axis is the X axis forward, and the plane normal direction at the axis of X -0.5 is the reverse of the X axis. So we can get the light from the outside. A normal is a three – dimensional vector, so it fills the previous color data.

The next step is to prepare a 3D vector to store the direction of light.

@property (assign, nonatomic) GLKVector3 lightDirection; / / parallel light illumination direction

And assign it. Let it down, so the vector is -Y axis (0, -1, 0).

/ / set the direction of parallel light self.lightDirection = GLKVector3Make (0, -1, 0);

Finally, assign the uniform illumination direction and the normal transformation matrix.

Bool canInvert; GLKMatrix4 normalMatrix = GLKMatrix4InvertAndTranspose (self.modelMatrix, & canInvert); if (canInvert) {GLuint modelMatrixUniformLocation = glGetUniformLocation (self.shaderProgram, normalMatrix); glUniformMatrix4fv (modelMatrixUniformLocation, 1, 0, normalMatrix.m);} GLuint lightDirectionUniformLocation = glGetUniformLocation (self.shaderProgram, lightDirection); glUniform3fv (lightDirectionUniformLocation, 1, self.lightDirection.v);

Here we use the GLKit GLKMatrix4InvertAndTranspose to compute the inverse transpose of modelMatrix and then pass it on to Shader. Transfer the direction of illumination when using glUniform3fv to transfer a three-dimensional array.

Here, the basic parallel light illumination model is completed. Here is the renderings.

Learn the basic lighting of OpenGL ES

The next chapter is the last chapter of the article, describes the loading and use of texture. Follow up will introduce advanced lighting, 3D model loading, particle systems, and more in-depth knowledge in the advanced articles.