根据教程:ogldev一步步开始,记录学习历程
之前学习了三个基于平行光的光照模型,相关博文如下:
平行光没有起点,通过方向向量来表示,不会随着距离增大而衰减
点光源
点光源即为有起点的光源,有衰减现象(即离光源越远光线越弱)。生活中常见的点光源为电灯泡。
点光源的衰减:
光线强度离光源的距离平方成反比,数学原理公式如下:
我们可以根据这个公式来计算点光源的亮度,但是在3D图形中,这样的效果并不是很好。如果距离很近时,光强便接近无限大,所以将公式进行微整:
- 分母上添加了三个衰减参数:一个常量参数、一个线性参数和一个指数参数
- 当常量参数设为1,此时就算距离很小,也不会产生无限大的光强,起到滤波的作用,过滤掉不正常数据
- 线性参数用来控制缓慢的衰减效果
- 指数因子可以控制迅速的衰减 效果
点光源的结构体表示:
struct BaseLight
{
Vector3f Color;
float AmbientIntensity;
float DiffuseIntensity;
};
struct PointLight : public BaseLight
{
Vector3f Position;
struct
{
float Constant;
float Linear;
float Exp;
} Attenuation;
};
- 首先是跟平行光共同拥有的元素:光的颜色,环境光强度和漫射光强度
- 其次是点光源自身的位置
- 还有上面讲到的为了计算衰减后的光强的三个参数
实现点光源
因为之前所有光源实现部分都是在我们的主程序中实现,使得主程序有些臃肿,现在把光源实现部分都放在opengl_light.h中。
首先定义光源的结构体,用来表示光源:
struct BaseLight
{
Vector3f Color;
float AmbientIntensity;
float DiffuseIntensity;
BaseLight()
{
LoadVector3(Color,0.0f, 0.0f, 0.0f);
AmbientIntensity = 0.0f;
DiffuseIntensity = 0.0f;
}
};
struct DirectionalLight:public BaseLight
{
Vector3f Direction;
DirectionalLight()
{
LoadVector3(Direction,0.0f, 0.0f, 0.0f);
}
};
struct PointLight : public BaseLight
{
Vector3f Position;
struct
{
float Constant;
float Linear;
float Exp;
} Attenuation;
PointLight()
{
LoadVector3(Position, 0.0f, 0.0f, 0.0f);
Attenuation.Constant = 1.0f;
Attenuation.Linear = 0.0f;
Attenuation.Exp = 0.0f;
}
};
- 点光源和平行光都有的部分用BaseLight结构体来封装
- 平行光的特殊参数是方向向量,而点光源是光源位置,点光源通过自身位置和物体位置,在着色器中计算光线方向
定义一个Light类,用来获得Uniform变量的索引,传递Uniform变量的值。
class Light
{
public:
Light(GLuint ShaderProgram)
{
m_shaderProg = ShaderProgram;
}
bool GetUniformLocations();
void SetDirectionalLight(const DirectionalLight& Light);
void SetEyeWorldPos(const Vector3f& EyeWorldPos);
void SetMatSpecularIntensity(float Intensity);
void SetMatSpecularPower(float Power);
void SetPointLights(unsigned int NumLights, const PointLight* pLights);
private:
static const unsigned int MAX_POINT_LIGHTS = 2;
GLuint m_shaderProg;
GLuint m_eyeWorldPosLocation;
GLuint m_matSpecularIntensityLocation;
GLuint m_matSpecularPowerLocation;
GLuin