当前位置:网站首页>OpenGL - Lighting
OpenGL - Lighting
2022-07-05 09:18:00 【Farmer er】
We see in real life that the color of an object is not the color that the object really has , But what it reflects (Reflected) Color . let me put it another way , Those that cannot be absorbed by objects (Absorb) The color of is the color of the object we can perceive .
The simple understanding is RGB
Multiplication of components :
glm::vec3 lightColor(0.33f, 0.42f, 0.18f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor; // = (0.33f, 0.21f, 0.06f);
To simulate a more realistic lighting effect , according to Feng's illumination model (Phong Lighting Model)
It is divided into The ambient light (Ambient Lighting)
、 Diffuse reflection (Diffuse Lighting)
and Specular reflection (Specular Lighting)
.
Ambient lighting
One property of light is , It can diverge in many directions and bounce , So that we can reach points that are not very directly adjacent . therefore , Light can be reflected on other surfaces , Have an indirect effect on an object . We use a small constant ( light ) Color , Add to the final color of the object segment , In this way, even if there is no direct light source in the scene, it can appear that there is some divergent light .
// fragment shader
void main()
{
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
vec3 result = ambient * objectColor;
FragColor = vec4(result, 1.0);
}
Diffuse lighting
For calculating diffuse reflection , We need to know :
- The normal vector (
Normal vector
): A vector perpendicular to the vertex surface . - Directional light (
The directed light ray
): The direction vector as the vector difference between the position of the light source and the position of the clip .
For specific calculation examples, please refer to ->
The normal vector acts in the world coordinate system , In order to solve the problem that the normal vector is not perpendicular to the surface caused by the non proportional scaling of the object , Can pass Normal matrix (Normal Matrix)
Correct this behavior :
Normal = mat3(transpose(inverse(model))) * aNormal;
Specular Lighting
Just like diffuse lighting , Specular illumination also depends on the direction vector of light and the normal vector of the object , But it also depends on the direction of observation , For example, in what direction does the player look at this clip . We calculate the reflection vector by inverting the direction of the incident light according to the normal vector . Then we calculate the angle difference between the reflection vector and the viewing direction , The smaller the angle between them , The greater the effect of mirror light . The result is , When we look at the reflection direction of the incident light on the surface , You'll see a little highlights .
To calculate the reflection vector, you can use reflect( The light source points to the vector of the clip , The normal vector )
, To calculate the mirror component, you can use :
// This 32 value is the shininess value of the highlight.
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = specularStrength * spec * lightColor;
Integrate three lighting effects to superimpose , The final code can refer to ->
Materials
In the real world, different objects behave differently under the same light source , The reason is that the materials are different :
#version 330 core
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
For light sources , The influence proportions of the three attributes on objects are also different :
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
Combine the two structures , The actual color of the object is calculated as follows :
in vec3 FragPos;
in vec3 Normal;
uniform vec3 viewPos;
uniform Material material;
uniform Light light;
void main()
{
// ambient
vec3 ambient = light.ambient * material.ambient;
// diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * (diff * material.diffuse);
// specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * (spec * material.specular);
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
Lighting maps
In the last section, the color of diffuse and specular reflection in the material is the same for the whole object , If you apply texture to reflection , It can be called diffuse map and specular map . The ambient color is equal to the diffuse color in almost all cases , So we don't need ambient light mapping .
For specific examples, please refer to ->
Light casters
In the real world , We have many kinds of light , Each performance is different . Project light (Cast) The light source to the object is called Projector (Light Caster)
.
Directional Light
When a light source is far away , Each ray from the light source will be approximately parallel to each other , Only the direction of the light source is needed to simulate the directional light .
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);
...
}
Point lights
A point light is a light at a certain position in the world , It will shine in all directions , But as the distance of light propagation increases , Will gradually reduce the intensity of light , be called attenuation (Attenuation)
, Rules are as follows :
Due to the existence of quadratic terms , Light will decay in a linear manner most of the time , Until the distance becomes large enough , Let the second term exceed the first term , The intensity of light decreases at a faster rate . This is the result , Light is very bright at close range , But as the distance increases, the brightness decreases rapidly , Finally, the brightness will be reduced at a slower speed . The picture below shows the following in 100 The effect of attenuation within a distance :
As for how to choose these constant terms , You can refer to ->
The code implementation is as follows :
#version 330 core
out vec4 FragColor;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform Material material;
uniform Light light;
void main()
{
// ambient
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
// diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
// specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
// attenuation
float distance = length(light.position - FragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
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 . A good example of spotlight is a street lamp or flashlight .
For each clip , We calculate whether the clip is between the tangent directions of the spotlight ( That is, in the cone ), Computation LightDir
Vector and SpotDir
Dot product between vectors , And connect it with Cutting angle ϕ
Value comparison , If it meets the requirements , We will illuminate the fragment accordingly .
To create a spotlight that looks smooth at the edges , We need to simulate a spotlight Inner cone (Inner Cone)
And a Outer cone (Outer Cone)
. We can set the inner cone to the one in the previous section , But we also need an outer cone , To darken the light from the inner cone , To the boundary of the 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.
The code implementation is as follows :
#version 330 core
out vec4 FragColor;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 direction;
float cutOff;
float outerCutOff;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform Material material;
uniform Light light;
void main()
{
// ambient
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
// diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
// specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
// spotlight (soft edges)
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = (light.cutOff - light.outerCutOff);
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
diffuse *= intensity;
specular *= intensity;
// attenuation
float distance = length(light.position - FragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
Combine the above three light sources , The effect can refer to ->
边栏推荐
- OpenGL - Model Loading
- 2310. The number of bits is the sum of integers of K
- [technical school] spatial accuracy of binocular stereo vision system: accurate quantitative analysis
- Global configuration tabbar
- 2309. The best English letters with both upper and lower case
- 嗨 FUN 一夏,与 StarRocks 一起玩转 SQL Planner!
- Jenkins Pipeline 方法(函数)定义及调用
- 图神经网络+对比学习,下一步去哪?
- 2311. Longest binary subsequence less than or equal to K
- Summary of "reversal" problem in challenge Programming Competition
猜你喜欢
What is a firewall? Explanation of basic knowledge of firewall
Rebuild my 3D world [open source] [serialization-2]
OpenGL - Coordinate Systems
3D reconstruction open source code summary [keep updated]
信息与熵,你想知道的都在这里了
利用请求头开发多端应用
nodejs_ 01_ fs. readFile
Svg optimization by svgo
An article takes you into the world of cookies, sessions, and tokens
Introduction Guide to stereo vision (3): Zhang calibration method of camera calibration [ultra detailed and worthy of collection]
随机推荐
一文详解图对比学习(GNN+CL)的一般流程和最新研究趋势
Newton iterative method (solving nonlinear equations)
Applet (global data sharing)
An article takes you into the world of cookies, sessions, and tokens
[code practice] [stereo matching series] Classic ad census: (4) cross domain cost aggregation
C language - input array two-dimensional array a from the keyboard, and put 3 in a × 5. The elements in the third column of the matrix are moved to the left to the 0 column, and the element rows in ea
阿里十年测试带你走进APP测试的世界
Kotlin introductory notes (III) kotlin program logic control (if, when)
LeetCode 556. 下一个更大元素 III
2309. 兼具大小写的最好英文字母
OpenGL - Lighting
Codeforces Round #648 (Div. 2) E.Maximum Subsequence Value
Can't find the activitymainbinding class? The pit I stepped on when I just learned databinding
【阅读笔记】图对比学习 GNN+CL
一篇文章带你走进cookie,session,Token的世界
【PyTorch Bug】RuntimeError: Boolean value of Tensor with more than one value is ambiguous
一题多解,ASP.NET Core应用启动初始化的N种方案[上篇]
2011-11-21 training record personal training (III)
My experience from technology to product manager
Kotlin introductory notes (IV) circular statements (simple explanation of while, for)