首先光源分为三种,分别是平行光,点光源,聚光源。
平行光有些类似于我们自然界中见到的太阳。它的角度属性,会对光照的实际渲染效果有一定的影响,但是他的位置属性则完全无法影响光照的实际渲染效果。
点光源则是有点类似于我们的灯泡,就是以一个点向四周发光。与平行光相反,它的角度属性会对光照的实际渲染效果毫无影响,但是他的位置属性则会影响光照的实际渲染效果。
点光源衰减函数图
聚光源则是类似于我们的手电筒,发射一道投射光出去,在这个圆锥体范围内的才会反射光。其实际渲染效果会被聚光源的位置和旋转属性所影响。
三角函数表:
上代码:(提醒一下,这里每个光源都可以拆分出来的。
否则一次性太多了。)
fragmentSrouce.txt
#version 330 core
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
in vec2 Texcoord;
//点光源结构体
struct LightPoint{
vec3 pos;//灯光位置
vec3 color;//灯光颜色
float constant;//衰减公式常量
float linear;//衰减公式一维常量
float quadratic;//衰减公式二维常量
};
//聚光源结构体
struct LightSpot{
vec3 dirToLight;
vec3 pos;//灯光位置
vec3 color;//灯光颜色
float cosPhyInner;//内圆锥体角度
float cosPhyOutter;//外圆锥体角度
};
//平行光源结构体
struct LightDirectional{
vec3 dirToLight;
vec3 pos;//灯光位置
vec3 color;//灯光颜色
};
struct Material{
vec3 ambient;
sampler2D diffuse;
sampler2D specular;
float shininess;
};
uniform Material material;
uniform LightPoint lightP; //输入点光源数据
uniform LightSpot lightS;//输入聚光源数据
uniform LightDirectional lightD;//输入平行光数据
uniform vec3 objColor;//模型颜色
uniform vec3 ambientColor;//环境光颜色
uniform vec3 CameraPos;
//平行光漫反射与镜面效果的计算
vec3 CalclLightDirectional(LightDirectional light,vec3 uNormal,vec3 dirToCamera)
{
//这里面的计算就是我们以前使用的那种。就不做过多介绍了。
vec3 result=vec3(0.0f,0,0);
//diffuse=(max(dot(dl,n),0))
vec3 diffuse=max(dot(uNormal,-light.dirToLight),0)*light.color*texture(material.diffuse,Texcoord).rgb;
//specular=(max(dot(R,C),0))
vec3 R=reflect(light.dirToLight,uNormal);
vec3 specular=pow(max(dot(R,dirToCamera),0),material.shininess)*light.color*texture(material.specular,Texcoord).rgb;
result=diffuse+specular;
return result;
}
//点光源漫反射与镜面效果的计算
vec3 CalclLightPoint(LightPoint light,vec3 uNormal,vec3 dirToCamera)
{
vec3 result=vec3(0.0f,0,0);
//计算一个衰减函数,就是离光源越远的,越暗,可以参考前面的衰减函数图,进行理解
float dist=length(light.pos-FragPos);
vec3 dirToLight=normalize(light.pos-FragPos);
float attenuation=1.0f / (light.constant + light.linear*dist +light.quadratic*(dist*dist));
//diffuse=(max(dot(dl,n),0))
vec3 diffuse=max(dot(uNormal,dirToLight),0)*light.color*texture(material.diffuse,Texcoord).rgb;
//specular=pow((max(dot(R,C),0)),shininess)
vec3 R=reflect(-dirToLight,uNormal);
vec3 specular=pow(max(dot(R,dirToCamera),0),material.shininess)*light.color*texture(material.specular,Texcoord).rgb;
result=(diffuse+specular)*attenuation;//最后将平行光乘上这个衰减函数
return result;
}
//聚光源漫反射与镜面效果的计算
vec3 CalclLightSpot(LightSpot light,vec3 uNormal,vec3 dirToCamera)
{
vec3 result=vec3(0.0f,0,0);
vec3 dirToLight=normalize(light.pos-FragPos);
//diffuse=(max(dot(dl,n),0))
vec3 diffuse=max(dot(uNormal,-normalize(light.dirToLight)),0)*light.color*texture(material.diffuse,Texcoord).rgb;
//specular=(max(dot(R,C),0))
vec3 R=reflect(-light.dirToLight,uNormal);
vec3 specular=pow(max(dot(R,dirToCamera),0),material.shininess)*light.color*texture(material.specular,Texcoord).rgb;
float cosTheta=dot(normalize(FragPos-light.pos),light.dirToLight);
//计算一个圆锥体,我们知道两个向量点乘得到的他两的夹角的Cos值,
//而这里我们计算出外圆锥体0.85和内圆锥体0.90的差,并用当前角度的cos值来减去这个外圆锥体,也就是聚光圆锥体能照射到最远的位置。再使用clamp根据取值来给予0到1的值。其中大于我们预设内圆锥体的值,如1,0.95这些值,都将呈现出1,而在0.9到0.85之间的值则会呈现一个线性的变化,使得光影的转换更加柔和,不至于那么生硬。
//上面有三角函数的表,你可以去看看
float epsilon=(light.cosPhyInner-light.cosPhyOutter);
float intensity=clamp((cosTheta-light.cosPhyOutter)/epsilon,0,1.0f);
result=(diffuse+specular)*intensity;
return result;
}
void main()
{
vec3 result=vec3(0);
vec3 uNormal=normalize(Normal);//将拿过来的法向量归一化
vec3 dirToCamera=normalize(CameraPos-FragPos);//计算相机距离
result+=CalclLightDirectional(lightD,uNormal,dirToCamera)*objColor;//平行光漫反射与镜面效果
result+=CalclLightPoint(lightP,uNormal,dirToCamera)*objColor;//点光源漫反射与镜面效果
result+=CalclLightSpot(lightS,uNormal,dirToCamera)*objColor;//聚广源漫反射与镜面效果
result+=ambientColor*texture(material.diffuse,Texcoord).rgb*objColor;//加上场景光
FragColor = vec4(result,1.0f);
}
LightDirectional.h
#pragma once
#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
class LightDirectional
{
public:
glm::vec3 position;//位置
glm::vec3 angle;//角度
glm::vec3 direction=glm::vec3(0,0,1.0f);
glm::vec3 color;//颜色
LightDirectional(glm::vec3 _position,glm::vec3 _angle,glm::vec3 _color = glm::vec3(1.0f, 1.0f, 1.0f));//构造函数
void UpdateDirection();//刷新灯光方向值
};
LightDirectional.cpp
#include "LightDirectional.h"
LightDirectional::LightDirectional(glm::vec3 _position, glm::vec3 _angle, glm::vec3 _color )
:position(_position),angle(_angle),color(_color)
{
UpdateDirection();
}
void LightDirectional::UpdateDirection()
{
direction = glm::vec3(0,0,1.0f);
direction = glm::rotateZ(direction, angle.z);//转z的角度
direction = glm::rotateY(direction, angle.y);
direction = glm::rotateX(direction,angle.x);
direction = -1.0f * direction;//取负值
}
LightPoint.h
#pragma once
#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
class LightPoint
{
public:
glm::vec3 position;
glm::vec3 angle;
glm::vec3 direction = glm::vec3(0, 0, 1.0f);
glm::vec3 color;
float constant = 1.0f;//衰减公式常量
float linear = 0.09f;//衰减公式一维常量
float quadratic = 0.032f;//衰减公式二维常量
LightPoint(glm::vec3 _position, glm::vec3 _angle, glm::vec3 _color = glm::vec3(1.0f, 1.0f, 1.0f));
};
LightPoint.cpp
#include "LightPoint.h"
LightPoint::LightPoint(glm::vec3 _position, glm::vec3 _angle, glm::vec3 _color)
:position(_position), angle(_angle), color(_color)
{
}
LightSpot.h
#pragma once
#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
class LightSpot
{
public:
glm::vec3 position;
glm::vec3 angle;
glm::vec3 direction = glm::vec3(0, 0, 1.0f);
glm::vec3 color;
LightSpot(glm::vec3 _position, glm::vec3 _angle, glm::vec3 _color = glm::vec3(1.0f, 1.0f, 1.0f));
void UpdateDirection();
float cosPhyInner=0.9f;//聚光源内圆锥体cos值
float cosPhyOutter=0.85f;//聚光源外圆锥体cos值
};
LightSpot.cpp
#include "LightSpot.h"
LightSpot::LightSpot(glm::vec3 _position, glm::vec3 _angle, glm::vec3 _color)
:position(_position), angle(_angle), color(_color)
{
UpdateDirection();
}
void LightSpot::UpdateDirection()
{
direction = glm::vec3(0, 0, 1.0f);
direction = glm::rotateZ(direction, angle.z);
direction = glm::rotateY(direction, angle.y);
direction = glm::rotateX(direction, angle.x);
direction = -1.0f * direction;
}
main.cpp
申请三种光源,分别是平行光,点光源,聚光源,分别以蓝,绿,红三种色彩。
LightDirectional myLightD(glm::vec3(10.0f,10.0f,5.0f),glm::vec3(glm::radians(0.0f), glm::radians(0.0f),0),glm::vec3(0.0f,0.0f,1.0f));
LightPoint myLightP(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(glm::radians(0.0f), glm::radians(0.0f), 0), glm::vec3(0.0f, 1.0f, 0.0f));
LightSpot myLightS(glm::vec3(1.0f, 4.0f, -3.0f), glm::vec3(glm::radians(-90.0f), glm::radians(0.0f), 0), glm::vec3(1.0f, 0.0f, 0.0f));
渲染通道的使用,(傅老师才说这是渲染通道)
其实就是给予shader里面的uniform值。
glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "modelMat"), 1, GL_FALSE, glm::value_ptr(modelMat));
glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "viewMat"), 1, GL_FALSE, glm::value_ptr(viewMat));
glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "projMat"), 1, GL_FALSE, glm::value_ptr(projMat));
glUniform3f(glGetUniformLocation(myShader->ID, "objColor"), 1.0f, 1.0f, 1.0f);
glUniform3f(glGetUniformLocation(myShader->ID, "ambientColor"), 0.1f, 0.1f, 0.1f);
glUniform3f(glGetUniformLocation(myShader->ID, "CameraPos"), myCamera->Position.x, myCamera->Position.y, myCamera->Position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightD.color"), myLightD.color.x, myLightD.color.y, myLightD.color.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightD.pos"), myLightD.position.x, myLightD.position.y, myLightD.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightD.dirToLight"), myLightD.direction.x, myLightD.direction.y, myLightD.direction.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.cosPhyInner"), myLightS.cosPhyInner);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.cosPhyOutter"), myLightS.cosPhyOutter);
glUniform3f(glGetUniformLocation(myShader->ID, "lightS.color"), myLightS.color.x, myLightS.color.y, myLightS.color.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightS.pos"), myLightS.position.x, myLightS.position.y, myLightS.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightS.dirToLight"), myLightS.direction.x, myLightS.direction.y, myLightS.direction.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP.color"), myLightP.color.x, myLightP.color.y, myLightP.color.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP.pos"), myLightP.position.x, myLightP.position.y, myLightP.position.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP.constant"), myLightP.constant);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP.linear"), myLightP.linear);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP.quadratic"), myLightP.quadratic);
最终效果图:
虽然很丑,但是我很开心。