光照的实现主要是通过环境光,漫反射光,镜面反射光和材质属性的不同确定的,因此首先通过CLightSource类保存光源,CMaterial类保存材质属性,CLight类进行光照。
CLightSource类:
#include"P3.h"
class CLightSource
{
public:
CLightSource(void);
virtual ~CLightSource(void);
void SetDiffuse(CRGB diffuse);//设置光源的漫反射光
void SetSpecular(CRGB specular);//设置光源的镜面反射光
void SetPosition(double x, double y, double z);//设置光源的位置
void SetAttenuationFactor(double c0, double c1, double c2);//设置光强的衰减因子
void SetOnOff(bool onoff);//设置光源开关状态
public:
CRGB L_Diffuse;//漫反射光颜色
CRGB L_Specular;//镜面反射光颜色
CP3 L_Position;//光源位置
double L_C0;//常数衰减因子
double L_C1;//线性衰减因子
double L_C2;//二次衰减因子
bool L_OnOff;//光源开启或关闭
};
#include "pch.h"
#include "LightSource.h"
CLightSource::CLightSource(void)
{
L_Diffuse = CRGB(1.0, 1.0, 1.0);//光源的漫反射颜色
L_Specular = CRGB(1.0, 1.0, 1.0);//光源镜面高光颜色
L_Position.x = 1000.0, L_Position.y = 1000.0, L_Position.z = 1000.0;//光源位置直角坐标
L_C0 = 1.0;//常数衰减系数
L_C1 = 0.0;//线性衰减系数
L_C2 = 0.0;//二次衰减系数
L_OnOff = TRUE;//光源开启
}
CLightSource::~CLightSource(void)
{
}
void CLightSource::SetDiffuse(CRGB difuse)
{
L_Diffuse = difuse;
}
void CLightSource::SetSpecular(CRGB specular)
{
L_Specular = specular;
}
void CLightSource::SetPosition(double x, double y, double z)
{
L_Position.x = x;
L_Position.y = y;
L_Position.z = z;
}
void CLightSource::SetOnOff(bool onoff)
{
L_OnOff = onoff;
}
void CLightSource::SetAttenuationFactor(double c0, double c1, double c2)
{
L_C0 = c0;
L_C1 = c1;
L_C2 = c2;
}
CMaterial类:
#include"RGB.h"
class CMaterial
{
public:
CMaterial(void);
virtual~CMaterial(void);
void SetAmbient(CRGB c);//设置环境光的反射率
void SetDiffuse(CRGB c);//设置漫反射光的反射率
void SetSpecular(CRGB c);//设置镜面反射光的反射率
void SetExponent(double n);//设置高光指数
public:
CRGB M_Ambient;//环境光的反射率
CRGB M_Diffuse;//漫反射光的反射率
CRGB M_Specular;//镜面反射光的反射率
double M_n;//高光指数
};
#include "pch.h"
#include "Material.h"
CMaterial::CMaterial(void)
{
M_Ambient = CRGB(0.175, 0.012, 0.012);//材质的环境反射率
M_Diffuse = CRGB(0.614, 0.041, 0.041);//材质的漫反射率
M_Specular = CRGB(0.728, 0.527, 0.527);//材质的镜面反射率
M_n = 1.0;//高光指数
}
CMaterial::~CMaterial(void)
{
}
void CMaterial::SetAmbient(CRGB c)
{
M_Ambient = c;
}
void CMaterial::SetDiffuse(CRGB c)
{
M_Diffuse = c;
}
void CMaterial::SetSpecular(CRGB c)
{
M_Specular = c;
}
void CMaterial::SetExponent(double n)
{
M_n = n;
}
CLight类:
#include"LightSource.h"
#include"Material.h"
#include"Vector3.h"
class CLighting
{
public:
CLighting(void);
CLighting(int nLightNumber);
virtual ~CLighting(void);
void SetLightNumber(int nLightNumber);//设置光源数量
void SetLightSource(CLightSource[]);//设置光源
CRGB Illuminate(CP3 ViewPoint, CP3 Point, CVector3 ptNormal, CMaterial* pMaterial);//计算光照
void DeleteLight();//删除光源
public:
int nLightNumber;//光源数量
CLightSource* LightSource;//光源数组
CRGB Ambient;//环境光
};
#include "pch.h"
#include "Lighting.h"
CLighting::CLighting(void)
{
nLightNumber = 1;
LightSource = new CLightSource[nLightNumber];
Ambient = CRGB(0.3, 0.3, 0.3);//环境光是常数
}
CLighting::CLighting(int nLightNumber)
{
this->nLightNumber = nLightNumber;
LightSource = new CLightSource[nLightNumber];
Ambient = CRGB(0.3, 0.3, 0.3);
}
CLighting::~CLighting(void)
{
}
void CLighting::SetLightNumber(int nLightNumber)
{
if (LightSource != NULL)
delete[]LightSource;
this->nLightNumber = nLightNumber;
LightSource = new CLightSource[nLightNumber];
}
void CLighting::SetLightSource(CLightSource LightSource[]) {
for (int i = 0;i < this->nLightNumber;i++) {
this->LightSource[i] = LightSource[i];
}
}
CRGB CLighting::Illuminate(CP3 ViewPoint, CP3 Point, CVector3 ptNormal, CMaterial* pMaterial)
{
CRGB ResultI = CRGB(0.0, 0.0, 0.0);//反射光强初始值
for (int loop = 0; loop < nLightNumber; loop++)//检查光源开关状态
{
if (LightSource[loop].L_OnOff)//光源开
{
CRGB I = CRGB(0.0, 0.0, 0.0);// I代表“反射”光强
CVector3 L(Point, LightSource[loop].L_Position);// L为光向量
double d = L.Magnitude();// d为光传播的距离
L = L.Normalize();//规范化光向量
CVector3 N = ptNormal;
N = N.Normalize();//规范化法向量
//第1步,加入漫反射光
double NdotL = max(DotProduct(N, L), 0);
I += LightSource[loop].L_Diffuse * pMaterial->M_Diffuse * NdotL;
//第2步,加入镜面反射光
CVector3 V(Point, ViewPoint);//V为观察向量
V = V.Normalize();//规范化观察向量
CVector3 H = (L + V) / (L + V).Magnitude();//H为中值向量
double NdotH = max(DotProduct(N, H), 0);
double Rs = pow(NdotH, pMaterial->M_n);
I += LightSource[loop].L_Specular * pMaterial->M_Specular * Rs;
//第3步,光强衰减
double c0 = LightSource[loop].L_C0;//c0为常数衰减因子
double c1 = LightSource[loop].L_C1;//c1为线性衰减因子
double c2 = LightSource[loop].L_C2;//c2为二次衰减因子
double f = (1.0 / (c0 + c1 * d + c2 * d * d));//光强衰减函数
f = min(1.0, f);
ResultI += I * f;
}
else
ResultI += Point.c;//物体自身颜色
}
//第4步,加入环境光
ResultI += Ambient * pMaterial->M_Ambient;
//第5步,光强规范化到[0,1]区间
ResultI.Normalize();
//第6步,返回所计算顶点的最终的光强颜色
return ResultI;
}
void CLighting::DeleteLight() {
if (LightSource != NULL)
{
delete[]LightSource;
LightSource = NULL;
}
}