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…