当前位置:网站首页>Learnopongl notes (II) - Lighting
Learnopongl notes (II) - Lighting
2022-07-05 16:49:00 【Small margin, rush】
Catalog
Ten 、 Basic lighting - Feng's illumination model
11、 ... and 、 texture of material
fourteen 、 Multiple light sources
Nine 、 Color
Define the color of the object as The size of each color component reflected by an object from a light source .
Create a lighting scene
First, we need an object as the projected light (Cast the light) The object of , The light source .
Create a new... For the lamp VAO
unsigned int lightVAO;
glGenVertexArrays(1, &lightVAO);
glBindVertexArray(lightVAO);
// Just bind VBO Don't set it again VBO The data of , Because of the box VBO The data already contains the correct cube vertex data
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// Set the vertex properties of the Light Cube ( For our lights, only position data )
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
Define a fragment shader
#version 330 core
out vec4 FragColor;
uniform vec3 objectColor;
uniform vec3 lightColor;
void main()
{
FragColor = vec4(lightColor * objectColor, 1.0);// Compare the color of the light source with the object ( The reflection of the ) Multiply colors
}
// Before that, don't forget to first use Corresponding shader program ( To set uniform)
lightingShader.use();
lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
The fragment shader of the lamp defines a constant white for the lamp , Ensure that the color of the lamp is always bright :
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0); // Set all four components of the vector to 1.0
}
Declare a global vec3
Variable to represent the position of the light source in the world space coordinates of the scene
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
Move the light here , Then shrink it a little , Make it less obvious
model = glm::mat4();
model = glm::translate(model, lightPos);
model = glm::scale(model, glm::vec3(0.2f));
Ten 、 Basic lighting - Feng's illumination model
The main structure of Feng's illumination model consists of 3 It's made up of two components : Environmental Science (Ambient)、 Diffuse reflection (Diffuse) And mirror (Specular) light
Ambient light (Ambient Lighting): Even in the dark , There is usually still some light in the world ( The moon 、 Distant light ) Diffuse illumination (Diffuse Lighting): Simulate the directional influence of light source on object (Directional Impact). It is the most significant visual component in Feng's illumination model . The more part of the object is facing the light source , The brighter it will be . Specular illumination (Specular Lighting): Simulate bright spots on shiny objects .
Ambient light
Light can be on other surfaces Reflection , Have an indirect effect on an object . The algorithm that takes this into account is called global illumination (Global Illumination) Algorithm .
We use a small constant ( light ) Color , Add to the final color of the object segment
void main()
{// Multiply the color of the light by a small constant environmental factor , Multiplied by the color of the object
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
vec3 result = ambient * objectColor;
FragColor = vec4(result, 1.0);
}
Diffuse illumination
There is a light source at the top left of the figure , The light it emits falls on a segment of the object .
What is needed to calculate diffuse illumination ?
- The normal vector : A vector perpendicular to the vertex surface .
layout (location = 1) in vec3 aNormal;
Pass the normal vector from the vertex shader to the clip shader
out vec3 Normal;
void main()
{
Normal = aNormal;
}
Define the corresponding input variables in the clip shader
in vec3 Normal;
- Directional light : The direction vector as the vector difference between the position of the light source and the position of the clip .
Since the position of the light source is a static variable , Declare it as... In the fragment shader uniform
uniform vec3 lightPos;
// In the rendering loop ( The outside of the rendering loop can also , Because it won't change ) to update uniform
lightingShader.setVec3("lightPos", lightPos);
The location of the clip : Do all lighting calculations in world space , So we need a vertex position in world space .
out vec3 FragPos;
FragPos = vec3(model * vec4(aPos, 1.0));
// The direction vector of light is the vector difference between the light source position vector and the segment position vector .
vec3 norm = normalize(Normal);// Normalize both the normal and the final direction vector
vec3 lightDir = normalize(lightPos - FragPos);
// Yes norm and lightDir Vector dot multiplication , Calculates the effect of the light source on the actual diffuse emission of the current clip
float diff = max(dot(norm, lightDir), 0.0);
// If the angle between two vectors is greater than 90 degree , The result of dot multiplication becomes negative
// The resulting value is multiplied by the color of the light , Get the diffuse component
vec3 diffuse = diff * lightColor;
Ambient light component and diffuse reflection component , Let's add them up , Then multiply the result by the color of the object
vec3 result = (ambient + diffuse) * objectColor;
FragColor = vec4(result, 1.0);
Normal matrix
The normal vector is just a direction vector , Cannot express a specific location in space . meanwhile , The normal vector has no homogeneous coordinates ( In vertex position w component ). It means , The displacement should not affect the normal vector .
secondly , If the model matrix performs an unequal scaling , The change of vertices will cause the normal vector to no longer be perpendicular to the surface .
Normal matrix (Normal Matrix), It uses some linear algebraic operations to remove the effect on the wrong scaling of the normal vector .
In the vertex shader , We can use inverse and transpose The function generates the normal matrix itself , These two functions are valid for all types of matrices .( Note that we also have to cast the processed matrix into 3×3 matrix , To ensure that it loses its displacement attribute and can be multiplied by vec3
The normal vector of .)
Normal = mat3(transpose(inverse(model))) * aNormal;
Specular illumination
Specular illumination is also determined by the direction vector of light and the normal vector of the object , But it also depends on the direction of observation , For example, from what direction does the player look at this clip . Specular illumination is based on the reflection characteristics of light .
The observation vector is an additional variable of specular illumination , We can use the observer's world space position and the position of the fragment to calculate it .
uniform vec3 viewPos;// The world space coordinates of the observer , Simply use the position coordinates of the camera object instead of
lightingShader.setVec3("viewPos", camera.Position);
// Mirror strength
float specularStrength = 0.5;
// Calculate the line of sight direction vector , And the corresponding reflection vector along the normal axis
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
//reflect The function requires that the first vector is the vector from the light source to the position of the clip , So reverse
// Calculate the mirror component
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);//32 Is the reflectivity of the highlight (Shininess)
vec3 specular = specularStrength * spec * lightColor;
Add to the ambient light component and diffuse reflection component , Then multiply the result by the color of the object
vec3 result = (ambient + diffuse + specular) * objectColor;
FragColor = vec4(result, 1.0);
11、 ... and 、 texture of material
stay OpenGL Simulate many types of objects in , We must define a material for each object (Material) attribute .
Material color (Material Color): Ambient light (Ambient Lighting)、 Diffuse illumination (Diffuse Lighting) And mirror light (Specular Lighting).
Create a structure (Struct) To store the material properties of the object , Make a statement uniform Variable .
struct Material {
vec3 ambient;// Usually this is the same color as the object color
vec3 diffuse;// The color of an object in diffuse light
vec3 specular;// The influence of specular illumination on the color of objects
float shininess;// Affects the scattering of specular highlights / radius
};
uniform Material material;
void main()
{
// The ambient light
vec3 ambient = lightColor * material.ambient;
// Diffuse reflection
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = lightColor * (diff * material.diffuse);
// Specular light
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = lightColor * (spec * material.specular);
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
// For each individual uniform Set it up , But this time we need to prefix the structure name
lightingShader.setVec3("material.ambient", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);
lightingShader.setFloat("material.shininess", 32.0f);
Modify the diffuse and specular intensity of the light source
struct Light {
vec3 position;//
vec3 ambient;// Ambient lighting is usually set to a lower intensity
vec3 diffuse;// The diffuse component is usually set to the color of the light
vec3 specular;// The specular component is usually maintained at vec3(1.0), Shine with maximum intensity
};
uniform Light light;
Twelve 、 The light map
introduce Diffuse reflection and Specular light Mapping (Map)
Diffuse map
Use an image that covers the object , Let's index their independent color values segment by segment . It's usually called a diffuse map (Diffuse Map).
The method of using diffuse map in shader is exactly the same as that in texture tutorial . But this time we will save the texture as Material One of the structures sampler2D
. The previously defined vec3
Diffuse color vector replaced with diffuse map .
struct Material {
sampler2D diffuse;
vec3 specular;
float shininess;
};
...
in vec2 TexCoords;
// Sample the diffuse color value of the clip from the texture
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
// Assign the texture unit to be used to material.diffuse This uniform Sampler
lightingShader.setInt("material.diffuse", 0);
...
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, diffuseMap);
Vertex data now contains vertex positions 、 Normal vector and texture coordinates at cube vertices .
layout (location = 2) in vec2 aTexCoords;
...
out vec2 TexCoords;
void main()
{
...
TexCoords = aTexCoords;
}
Specular map
Texture mapping specifically for specular highlights , Generate a black and white ( It can also be colored if you want ) texture , To define the specular light intensity of each part of the object . The intensity of specular highlights can be obtained by the brightness of each pixel of the image .
Specular map Diffuse map
Black represents the color vector vec3(0.0)
, Gray represents the color vector vec3(0.5)
. In the fragment shader , We will then sample the corresponding color value and multiply it by the specular intensity of the light source . The more a pixel 「 white 」, The greater the product , The brighter the specular component of the object .
lightingShader.setInt("material.specular", 1);
...
glActiveTexture(GL_TEXTURE1);// Bind to the appropriate texture unit
glBindTexture(GL_TEXTURE_2D, specularMap);
// Update the material properties of the clip shader
struct Material {
sampler2D diffuse;
sampler2D specular;//new
float shininess;
};
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
13、 ... and 、 Projector
Put the light Project (Cast) The light source to an object is called a projector (Light Caster).
Parallel light - The sun
When a light source is far away , Each ray from the light source will be approximately parallel to each other . When we use a hypothetical light source in Infinite A distant model , It's called directional light , Because all its rays have the same direction , It has nothing to do with the position of the light source .
Define a light direction vector instead of a position vector to simulate a directional light . Using light directly direction vector
struct Light {
// vec3 position; // Using directional light is no longer needed
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
...
void main()
{
vec3 lightDir = normalize(-light.direction);
//vec3 lightDir = normalize(lightPos - FragPos); Don't use this
...
}
lightingShader.setVec3("light.direction", -0.2f, -1.0f, -0.3f);
Point source
A point light is a light at a certain position in the world , It will shine in all directions , But the light fades with distance .
Decreasing the intensity of light as it travels longer is often called attenuation (Attenuation). In the real world , The light is usually very bright near , But with the increase of distance, the brightness of the light source will decline very quickly at first , But at a distance, the remaining light intensity will decline very slowly .
d Represents the distance from the clip to the light source .
Achieve attenuation
In order to achieve attenuation , We also need three additional values in the fragment shader : That is, the constant term in the formula 、 Primary and secondary terms . They are best stored in previously defined Light In the structure .
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};
// Calculate the attenuation value according to the formula
float distance = length(light.position - FragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance +
light.quadratic * (distance * distance));
// Times the ambient light 、 Diffuse and specular colors
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
lightingShader.setFloat("light.constant", 1.0f);
lightingShader.setFloat("light.linear", 0.09f);
lightingShader.setFloat("light.quadratic", 0.032f);// The table shows
Spotlight
A spotlight is a light source located somewhere in the environment , It shines light in only one direction, not all directions . The result is that only objects within a specific radius in the direction of the spotlight will be illuminated , Other objects will remain dark .
OpenGL The central spotlight uses a world space position 、 One direction and one cutting angle (Cutoff Angle) To represent the , The tangent angle specifies the radius of the spotlight . Calculation LightDir Vector and SpotDir Dot product between vectors
LightDir
: The vector from the clip to the light source .SpotDir
: The direction in which the spotlight points .- : The tangent angle of the condensing radius . Objects falling outside this angle will not be illuminated by this spotlight .
- :LightDir Vector and SpotDir The angle between vectors
Flashlight
A flashlight is an ordinary spotlight , But its position and direction will be updated with the player's position and orientation .
struct Light {
vec3 position;
vec3 direction;
float cutOff;
...
};
lightingShader.setFloat("light.cutOff", glm::cos(glm::radians(12.5f)));
// A cosine value is calculated from the angle value
// In the fragment shader , We will calculate LightDir and SpotDir The dot product of vectors , This dot product will return a cosine value instead of an angle value
float theta = dot(lightDir, normalize(-light.direction));
if(theta > light.cutOff)
{
// Perform lighting calculations
}
else // otherwise , Use ambient light , So that the scene will not be completely dark when it is outside the spotlight
color = vec4(light.ambient * vec3(texture(material.diffuse, TexCoords)), 1.0);
smooth / Softening edge
To create a spotlight that looks smooth at the edges , We need to simulate that the spotlight has an inner cone (Inner Cone) And an outer cone (Outer Cone). To create an outer cone , We only need to define a cosine value to represent the focusing direction vector and the outer cone vector ( Equal to its radius ) The angle between . then , If a clip is between the inner and outer cones , I'll give it a 0.0 To 1.0 Strength value between . If the fragment is within the inner cone , Its strength is 1.0, If outside the outer cone, the strength value is 0.0.
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.cutOff - light.outerCutOff;
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
//clamp function , It constrains the first parameter to (Clamp) In the 0.0 To 1.0 Between
...
// It will not affect the ambient light , Let it always have a little light
diffuse *= intensity;
specular *= intensity;
fourteen 、 Multiple light sources
In order to use multiple lights in the scene , We want to encapsulate illumination computing into GLSL Function , We create a different function for each lighting type : Directional light 、 Point light and spotlight .
void main()
{
// attribute
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos - FragPos);
// The first stage : Directional illumination
vec3 result = CalcDirLight(dirLight, norm, viewDir);
// The second stage : Point source
for(int i = 0; i < NR_POINT_LIGHTS; i++)
result += CalcPointLight(pointLights[i], norm, FragPos, viewDir);
// The third stage : Spotlight
//result += CalcSpotLight(spotLight, norm, FragPos, viewDir);
FragColor = vec4(result, 1.0);
}
Directional light
struct DirLight {
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform DirLight dirLight;
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
{
vec3 lightDir = normalize(-light.direction);
// Diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// Specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// Consolidated results
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
return (ambient + diffuse + specular);
}
Point source
struct PointLight {
vec3 position;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
#define NR_POINT_LIGHTS 4
uniform PointLight pointLights[NR_POINT_LIGHTS];
// The preprocessing instruction is used to define the number of point lights in our scene
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
// Diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// Specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance +
light.quadratic * (distance * distance));
// Consolidated results
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return (ambient + diffuse + specular);
}
Sets the of the point light uniform value , Point light source uniform Now it's a PointLight It's an array of
lightingShader.setFloat("pointLights[0].constant", 1.0f);
glossary
- Feng's illumination model (Phong Lighting Model): By calculating the ambient light , Diffuse reflection , And the value of specular light component to estimate the real illumination model .
- Normal matrix (Normal Matrix): One 3x3 matrix , Or a model without translation ( Or the model - Observe ) matrix .
- attenuation (Attenuation): The process by which light decreases in intensity with distance .
- Spotlight (Spotlight): A light source defined as a cone in one direction .
边栏推荐
- Enterprise backup software Veritas NetBackup (NBU) 8.1.1 installation and deployment of server
- Cartoon: what is service fusing?
- 【刷題篇】鹅廠文化衫問題
- 阿掌的怀念
- How to use FRP intranet penetration +teamviewer to quickly connect to the intranet host at home when mobile office
- Record a 'very strange' troubleshooting process of cloud security group rules
- What is the difference between EDI license and ICP business license
- Can you help me see what the problem is? [ERROR] Could not execute SQL stateme
- If you can't afford a real cat, you can use code to suck cats -unity particles to draw cats
- 2020-2022两周年创作纪念日
猜你喜欢
2020-2022 two-year anniversary of creation
PSPNet | 语义分割及场景分析
Games101 notes (II)
Jarvis OJ 简单网管协议
[61dctf]fm
Jarvis OJ Flag
Bs-xx-042 implementation of personnel management system based on SSM
Cs231n notes (bottom) - applicable to 0 Foundation
Hiengine: comparable to the local cloud native memory database engine
Intel 13th generation Raptor Lake processor information exposure: more cores, larger cache
随机推荐
[61dctf]fm
Jarvis OJ shell traffic analysis
【刷题篇】有效的数独
[echart] resize lodash to realize chart adaptation when window is zoomed
Flet教程之 12 Stack 重叠组建图文混合 基础入门(教程含源码)
详解SQL中Groupings Sets 语句的功能和底层实现逻辑
DenseNet
Explain in detail the functions and underlying implementation logic of the groups sets statement in SQL
Summary of PHP pseudo protocol of cisp-pte
Jarvis OJ webshell analysis
Solution of vant tabbar blocking content
Dare not buy thinking
[js] skill simplification if empty judgment
數據訪問 - EntityFramework集成
文件操作--I/O
为季前卡牌游戏 MotoGP Ignition Champions 做好准备!
Apple 已弃用 NavigationView,使用 NavigationStack 和 NavigationSplitView 实现 SwiftUI 导航
OneForAll安装使用
How was the middle table destroyed?
【深度学习】深度学习如何影响运筹学?