The previous article implemented a simple lighting model, and the lighting used came from a point in space.
But in the real world, we have many types of lighting, such as:
1. Directional Light
2.Point Light
3. Spotlight
The purpose of this article is to implement these light sources respectively.
1. Directional light (also called parallel light)
Example: sunlight
When a light source is far away, each ray from the light source will be approximately parallel to each other.
Because all light rays are parallel, the relative position of the object to the light source is unimportant
You can define a light direction vector instead of a position vector to simulate a directional light
data structure
struct DirLight {<!-- --> vec3 direction; //direction vec3 ambient; //ambient intensity vec3 diffuse; //diffuse intensity vec3 specular; //specular intensity };
Lighting formula
//Calculate the color of parallel light vec3 CalcDirLight(DirLight light) {<!-- --> //Texture vec3 diffuseCol = texture(material.diffuse, uv).rgb; vec3 specularCol = texture(material.specular, uv).rgb; //Ambient light vec3 ambient = light.ambient * diffuseCol; //diffuse reflection vec3 lightDir = (light.direction); vec3 normalDir = normalize(normalWS); vec3 diffuse = max(0.0, dot(normalDir, lightDir)) * light.diffuse * diffuseCol; //High light reflection vec3 viewDir = normalize(cameraPos - positionWS); vec3 halfDir = normalize(viewDir + lightDir); vec3 specular = pow(max(0.0, dot(normalDir, halfDir)), material.shininess) * light.specular * specularCol; vec3 result = ambient + diffuse + specular; return result; }
2. Point light source
Example: light bulb
Points scattered in the scene will emit light in all directions, gradually attenuating with distance.
Attenuation: Gradually reducing the intensity of light as the distance it travels is usually called attenuation.
Attenuation formula: 1 / (constant term + linear term * distance + quadratic term + distance squared)
Generally, it is set according to the distance you want to cover. You can look up the table:
http://www.ogre3d.org/tikiwiki/tiki-index.php?page=-Point + Light + Attenuation
data structure
struct PointLight{<!-- --> vec3 position; //position vec3 ambient; //ambient intensity vec3 diffuse; //diffuse intensity vec3 specular; //specular intensity float constant; //Attenuation public constant term float linear; //attenuation formula linear term float quadratic;//attenuation formula quadratic term };
Lighting formula
//Calculate point light color vec3 CalcPointLight(PointLight light) {<!-- --> //Calculate the distance from the light source float distance = length(light.position - positionWS); //Attenuation formula float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance) ); //Texture vec3 diffuseCol = texture(material.diffuse, uv).rgb; vec3 specularCol = texture(material.specular, uv).rgb; //Ambient light vec3 ambient = light.ambient * diffuseCol; //diffuse reflection vec3 lightDir = normalize(light.position - positionWS); vec3 normalDir = normalize(normalWS); vec3 diffuse = max(0.0, dot(normalDir, lightDir)) * light.diffuse * diffuseCol; //High light reflection vec3 viewDir = normalize(cameraPos - positionWS); vec3 halfDir = normalize(viewDir + lightDir); vec3 specular = pow(max(0.0, dot(normalDir, halfDir)), material.shininess) * light.specular * specularCol; vec3 result = (ambient + diffuse + specular) * attenuation; return result; }
3. Spotlight
A light source located somewhere in the environment that emits light in only one specific direction rather than in all directions
Represented by a world space position, a direction and a cutoff angle (Cutoff Angle)
Principle: Calculate the dot product between the LightDir vector and the SpotDir vector, and compare it with the light cut angle value
data structure
struct SpotLight {<!-- --> vec3 position; vec3 direction; //direction vec3 ambient; //ambient intensity vec3 diffuse; //diffuse intensity vec3 specular; //specular intensity float cutOff; //The light cutting angle of the radius. Objects outside this angle will not be illuminated by this spotlight. float outerCutOff;//larger light cutting angle, used for gradients };
Calculate lighting
//Calculate spotlight color vec3 CalcSpotLight(SpotLight light) {<!-- --> //Point in the direction of the spotlight vec3 lightDir = normalize(light.position - positionWS); //Do dot multiplication with the direction of the light source (reverse to ensure the direction is consistent) float theta = dot(-lightDir, normalize(light.direction)); //Cosine value comparison for performance //The closer the cosine value is to 1.0, the smaller its angle is if (theta > light.cutOff) {<!-- --> //Texture vec3 diffuseCol = texture(material.diffuse, uv).rgb; vec3 specularCol = texture(material.specular, uv).rgb; //Ambient light vec3 ambient = light.ambient * diffuseCol; //diffuse reflection vec3 normalDir = normalize(normalWS); vec3 diffuse = max(0.0, dot(normalDir, lightDir)) * light.diffuse * diffuseCol; //High light reflection vec3 viewDir = normalize(cameraPos - positionWS); vec3 halfDir = normalize(viewDir + lightDir); vec3 specular = pow(max(0.0, dot(normalDir, halfDir)), material.shininess) * light.specular * specularCol; vec3 result = (ambient + diffuse + specular); //To create a spotlight that looks smooth around the edges // It is necessary to simulate the spotlight with an inner cone (Inner Cone) and an outer cone (Outer Cone) float intensity = clamp((theta - light.cutOff) / (light.cutOff - light.outerCutOff), 0.0, 1.0); result *= intensity; return vec3(result); } else {<!-- --> //Not within the area, currently black return vec3(0.0); } }
Declare these in a shader to superimpose all lights
void main() {<!-- --> vec3 dirLightResult = CalcDirLight(dirLight); vec3 result = dirLightResult; for(int i = 0; i < NR_POINT_LIGHTS; i + + ) {<!-- --> vec3 pointLightResult = CalcPointLight(pointLights[i]); result + = pointLightResult; } vec3 spotLightResult = CalcSpotLight(spotLight); result + = spotLightResult; FragColor = vec4(result * objectColor, 1.0); }
The effect is as shown in the figure: