The original article was first published on the wechat official account Byteflow

OpenGLES base lighting model

OpenGLES is currently unable to simulate the complex effects of real-world lighting. In order to strike a balance between performance requirements and implementation difficulties, it often uses simplified models to simulate lighting effects.

Phong Lighting Model is a common Lighting Model, which consists of three elements of light. Ambient Lighting; Diffuse Lighting; Specular Lighting.

The ambient light

Ambient light refers to the light that shines on the object from all directions and is uniform in all directions. It does not depend on the position of the light source and has no direction.

To add ambient light to a scene, simply multiply the color of the light by a small constant ambient factor, multiply it by the color of the object, and use it as the color of the fragment:

void main(a)
{
    float ambientStrength = 0.1 f; // Constant environment factor
    vec3 ambient = ambientStrength * lightColor; // Ambient light intensity

    vec3 result = ambient * objectColor;
    color = vec4(result, 1.0 f);
}
Copy the code

The scattered light

Scattered light represents light reflected evenly from the surface of an object in all directions. The intensity of scattered light is closely related to the intensity and incidence Angle of incident light, so when the position of light source changes, the scattered light effect will also change significantly.

Final intensity of scattered light = reflection coefficient of material × intensity of scattered light × Max (cos(incident Angle), 0)

The incident Angle represents the included Angle between the irradiation direction of the current fragment light source and the normal vector. Fragment shader script for scattering light:

out vec3 fragPos;// Current fragment coordinates
out vec3 normal; // Current fragment normal vector
uniform vec3 lightPos;// Light source position
void main(a)
{
    float diffuseStrength = 0.5 f; // Material reflection coefficient

	vec3 norm = normalize(normal); / / normalization
	vec3 lightDir = normalize(lightPos - fragPos);// Direction vector of current fragment light source

    float diff = max(dot(norm, lightDir), 0.0);// dot represents the dot product of two vectors
    vec3 diffuse = diffuseStrength * diff * lightColor; // Final intensity of scattered light

    vec3 result = diffuse * objectColor;
    color = vec4(result, 1.0 f);
}
Copy the code

Specular light

Specular light is concentrated light reflected from the smooth surface. The intensity of specular light depends not only on the Angle between the incident light and the normal vector, but also on the position of the observer.

Final intensity of mirror light = material mirror brightness factor × mirror light intensity × Max (cos(Angle between reflected light vector and line of sight vector), 0)

The modified model can also be expressed as follows: final intensity of mirror light = luminance factor of material mirror × intensity of mirror light × Max (cos(Angle between half vector and normal vector), 0), where the half vector is the half vector of reflected light vector of mirror and sight direction vector (from fragment to observer).

Implement specular light fragment shader script:

out vec3 fragPos;// Current fragment coordinates
out vec3 normal; // Current fragment normal vector
uniform vec3 lightPos;// Light source position
void main(a)
{
    float specularStrength = 0.5 f;

    vec3 norm = normalize(normal); / / normalization
    vec3 viewDir = normalize(viewPos - FragPos); // View direction vector
    vec3 reflectDir = reflect(-lightDir, norm); // Mirror reflected light vector

    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); 
    // The line of sight vector is dotted with the mirror light vector to the 32th power. This 32 is the Shininess of the speckles. The higher the luminous value of an object, the better its ability to reflect light, the less it scatters and the smaller its highlights.
    vec3 specular = specularStrength * spec * lightColor; // Final intensity of mirror light

    vec3 result = specular * objectColor;
    color = vec4(result, 1.0 f);
}
Copy the code

Basic illumination model implementation

Vertex shaders that implement the base lighting model:

#version 300 es
precision mediump float;
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec2 a_texCoord;
layout(location = 2) in vec3 a_normal;
uniform mat4 u_MVPMatrix;
uniform mat4 u_ModelMatrix;
uniform vec3 lightPos;
uniform vec3 lightColor;
uniform vec3 viewPos;
out vec2 v_texCoord;
out vec3 ambient;
out vec3 diffuse;
out vec3 specular;
void main(a)
{
gl_Position = u_MVPMatrix * a_position;
vec3 fragPos = vec3(u_ModelMatrix * a_position);

// Ambient
float ambientStrength = 0.1;
ambient = ambientStrength * lightColor;

// Diffuse
float diffuseStrength = 0.5;
vec3 unitNormal = normalize(vec3(u_ModelMatrix * vec4(a_normal, 1.0)));
vec3 lightDir = normalize(lightPos - fragPos);
float diff = max(dot(unitNormal, lightDir), 0.0);
diffuse = diffuseStrength * diff * lightColor;

// Specular
float specularStrength = 0.9;
vec3 viewDir = normalize(viewPos - fragPos);
vec3 reflectDir = reflect(-lightDir, unitNormal);
float spec = pow(max(dot(unitNormal, reflectDir), 0.0), 16.0);
specular = specularStrength * spec * lightColor;
v_texCoord = a_texCoord;
}
Copy the code

Corresponding fragment shader:

#version 300 es
precision mediump float;
in vec2 v_texCoord;
in vec3 ambient;
in vec3 diffuse;
in vec3 specular;
layout(location = 0) out vec4 outColor;
uniform sampler2D s_TextureMap;
void main(a)
{
vec4 objectColor = texture(s_TextureMap, v_texCoord);
vec3 finalColor = (ambient + diffuse + specular) * vec3(objectColor);
outColor = vec4(finalColor, 1.0);
}
Copy the code

Effect:

Implementation code path: github.com/githubhaoha…

Contact and exchange