光照-05.投光物(Light casters)

定向光(Directional Light)

``````struct Light
{
// vec3 position; // 现在不在需要光源位置了，因为它是无限远的
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
...
void main()
{
vec3 lightDir = normalize(-light.direction);
...
}
``````

``````// Draw the container (using container's vertex attributes)
glBindVertexArray (containerVAO);
for (GLuint i = 0; i < 10; i++)
{
model = glm::mat4 ();
model = glm::translate (model, cubePositions[i]);
GLfloat angle = 20.0f * i;
model = glm::rotate (model, angle, glm::vec3 (1.0f, 0.3f, 0.5f));
glUniformMatrix4fv (modelLoc, 1, GL_FALSE, glm::value_ptr (model));
glDrawArrays (GL_TRIANGLES, 0, 36);
}
glBindVertexArray (0);
``````

``````GLint lightDirPos = glGetUniformLocation (lightingShader.Program, "light.direction");
glUniform3f (lightDirPos, -.02f, -1.0f, -0.3f);
``````

``````if (lightVector.w == 0.0) // Note: be careful for floating point errors
// Do directional light calculations
else if (lightVector.w == 1.0)
// Do light calculations using the light's position (like last tutorial)
``````

定点光(Point Light)

衰减(Attenuation)

• The constant term is usually kept at 1.0 which is mainly there to make sure the resulting denominator never gets smaller than 1 since it would otherwise boost the intensity with certain distances, which is not the effect we're looking for.
• The linear term is multiplied with the distance value that reduces the intensity in a linear fashion.
• The quadratic（二次） term is multiplied with the quadrant of the distance and sets a quadratic decrease of intensity for the light source. The quadratic term will be less significant compared to the linear term when the distance is small, but gets much larger than the linear term as the distance grows.

实现衰减

``````struct Light            // 创建一些光的属性来各自独立的影响每个光照
{
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
// 公式的常量、一次项和二次项
float constant;
float linear;
};
``````

``````glUniform1f (glGetUniformLocation (lightingShader.Program, "light.constant"), 1.0f);
``````

``````float distance = length(light.position - FragPos);
float attenuation = 1.0f / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
``````

、diffuse和specular颜色，包含这个衰减值。

``````ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
``````

聚光灯(Spotlight)

OpenGL中的聚光灯用世界空间位置，一个方向和一个指定聚光灯半径的切光角来表示。我们计算的每个片段，如果片段在聚光灯的切光方向之间（就是在圆锥体内），我们就会把片段照亮。下面的图可以让你明白聚光灯是如何工作的：

• LightDir：从片段指向光源的向量。
• SpotDir：聚光灯所指向的方向。
• Phiφ：定义聚光灯半径的切光角。每个落在这个角度之外的，聚光灯都不会照亮。
• Thetaθ：LightDir向量和SpotDir向量之间的角度。θ值应该比φ值小，这样才会在聚光灯内。

手电筒

``````struct Light
{
vec3 position;
vec3 direction;
float cutOff;
...
};
``````

``````glUniform3f (lightPosLoc, camera.Position.x, camera.Position.y, camera.Position.z);
glUniform3f (lightSpotdirLoc, camera.Front.x, camera.Front.y, camera.Front.z);
``````

``````float theta = dot(lightDir, normalize(-light.direction));
if(theta > light.cutOff)
{
// 执行光照计算
}
else // 否则使用环境光，使得场景不至于完全黑暗
color = vec4(light.ambient*vec3(texture(material.diffuse,TexCoords)
``````

平滑/软化边缘

I=(θ−γ) / ϵ

``````float theta     = dot(lightDir, normalize(-light.direction));
float epsilon   = light.cutOff - light.outerCutOff;
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
...
// We'll leave ambient unaffected so we always have a little light.
diffuse  *= intensity;
specular *= intensity;
...
``````

练习

• 试着修改上面的各种不同种类的光源及其片段着色器。试着将部分矢量进行反向并尝试使用 < 来代替 > 。试着解释这些修改导致不同显示效果的原因。
LearnOpenGL.com