光照Phong模型
顯示一個物體的顏色需要考慮三個使物體產生顏色的緣由。第一是環境光,環境光是物體展示的顏色可以看作物體材料本身的顏色,一般其亮度比較弱。第二是光源發出的光在物體表面進行漫反射使其發光,一般發光面積比較大,產生的視覺顏色是物體材質的顏色加強版。第三是鏡面反射光,鏡面反射光面積比較小,聚焦在一小塊有非常強的亮度,幾乎等同于光源本身的光強。一個物體最終讓人看見的顏色就是上面三種顏色的疊加。
編程實現的思路:
首先要給物體添加一個材質屬性使其能夠具有環境光下,漫反射光,鏡面反射光的反射系數。其次光源本省有坐標位置,光強等屬性,所以光源要獨立作為一個對象。最后使一個將光源與物體材質本省聯系起來的函數來實現上面的光照模型理論公式,也就是公式10-12.
材質屬性類:
#pragma once #ifndef __CMATERIAL__ #define __CMATERIAL__ #include "RGB.h"class CMaterial { public:CMaterial();virtual ~CMaterial();void SetAmbient(const CRGB &Ambient);//設置材質對環境光的反射率void SetDiffuse(const CRGB &Diffuse);//設置材質對漫反射光的反射率void SetSpecular(const CRGB& Specular);//設置材質對鏡面反射的顏色void SetEmit(const CRGB& Emit);//設置自身輻射的顏色void SetExp(double Exp);//設置材質的高光指數CRGB M_Ambient;//材質對環境光的反射率CRGB M_Diffuse;//材質對漫反射光的反射率CRGB M_Specular;// 材質對鏡面光的反射率CRGB M_Emit;// 材質自身的顏色double M_n;//材質的高光指數 };#endif // ! __CMATERIAL__#include "pch.h" #include "CMaterial.h"CMaterial::CMaterial() {M_Ambient = CRGB(0.2, 0.2, 0.2);//默認材質對環境光的反射率M_Diffuse = CRGB(0.8, 0.8, 0.8);//材質對漫反射光的反射率M_Specular = CRGB(0.0, 0.0, 0.0);//材質對鏡面反射光的反射率M_Emit = CRGB(0.0, 0.0, 0.0);//材質自身發散的顏色M_n = 1.0;//高光指數 }CMaterial::~CMaterial() {};void CMaterial::SetAmbient(const CRGB& Ambient) {M_Ambient = Ambient; }void CMaterial::SetDiffuse(const CRGB& Diffuse) {M_Diffuse = Diffuse; }void CMaterial::SetSpecular(const CRGB& Specular) {M_Specular = Specular; }void CMaterial::SetEmit(const CRGB& Emit) {M_Emit = Emit; }void CMaterial::SetExp(const double Exp) {M_n = Exp; }光源對象實現:
#pragma once #ifndef __CLIGHT__ #define __CLIGHT__ #include"RGB.h" #include "CPoint3D.h"class CLight { public:CLight();virtual ~CLight() {};void SetDiffuse(const CRGB& Diffuse);//設置光源的漫反射光void SetSpecular(const CRGB& Specular);//設置光源的鏡面反射光void SetPosition(double x, double y, double z);//設置光源位置void SetCoef(double c0, double c1, double c2);//設置光強的衰減系數void SetOnOff(bool BL);//設置光源狀態CRGB L_Diffuse;//光的漫反射顏色CRGB L_Specular;//光的鏡面高光顏色CPoint3D L_Position;//光源的位置double L_C0;//常數衰減系數double L_C1;//線性衰減系數double L_C2;//二次衰減系數bool L_OnOff;//光源開關 };#endif // ! __CLIGHT__#include "pch.h" #include "CLight.h"CLight::CLight() {L_Diffuse = CRGB(0.0, 0.0, 0.0);//光源的漫反射顏色 L_Specular = CRGB(1.0, 1.0, 1.0);//光源鏡面高光顏色L_Position.x = 0.0, L_Position.y = 0.0, L_Position.z = 1000;//光源位置直角坐標L_C0 = 1.0;//常數衰減系數L_C1 = 0.0;//線性衰減系數L_C2 = 0.0;//二次衰減系數L_OnOff = TRUE;//光源開啟 }void CLight::SetDiffuse(const CRGB& Diffuse) {L_Diffuse = Diffuse; }void CLight::SetSpecular(const CRGB& Specular) {L_Specular = Specular; }void CLight::SetPosition(double x, double y, double z) {L_Position.x = x;L_Position.y = y;L_Position.z = z; }void CLight::SetOnOff(bool BL) {L_OnOff = BL; }void CLight::SetCoef(double c0, double c1, double c2) {L_C0 = c0;L_C1 = c1;L_C2 = c2; }將光源與物體材質屬性結合,計算對應像素的光強顏色:
#pragma once #ifndef __CLIGHTCONTAINER__ #define __CLIGHTCONTAINER__ #include"CMaterial.h" #include "CLight.h" #include "CPoint3D.h" #include <armadillo> //矩陣運算庫class CLightContainer { public:CLightContainer();CLightContainer(int lightNum);~CLightContainer();void SetLightNumber(int lightNum);//設置光源數量//計算頂點光照下的顏色CRGB lighting(const CPoint3D &cameraPosition,const CPoint3D & VetexPosition, CPoint3D faceNormal, CMaterial* Pmaterial) const;int LightNum;//光源數量CLight* Light;//光源數組CRGB Ambient;//環境光 };#endif // ! __CLIGHTCONTAINER__ #include "pch.h" #include "CLightContainer.h" CLightContainer::CLightContainer() {LightNum = 1;Light = new CLight[LightNum];Ambient = CRGB(0.3, 0.3, 0.3);//環境光恒定不變 }CLightContainer::CLightContainer(int lightNum) {this->LightNum = lightNum;Light = new CLight[LightNum];Ambient = CRGB(0.3, 0.3, 0.3);//環境光恒定不變 }CLightContainer::~CLightContainer() {if (Light){delete[]Light;Light = NULL;} }void CLightContainer::SetLightNumber(int lightNum) {if (Light){delete[]Light;}LightNum = lightNum;Light = new CLight[lightNum]; }CRGB CLightContainer::lighting(const CPoint3D &cameraPosition, const CPoint3D &VetexPosition, CPoint3D faceNormal, CMaterial* Pmaterial) const {CRGB lastC = Pmaterial->M_Emit;//材質自身發散色為初始值for (int i = 0; i < LightNum; i++){if (Light[i].L_OnOff){CRGB InitC(0, 0, 0);arma::vec VL({ Light[i].L_Position.x - VetexPosition.x,Light[i].L_Position.y - VetexPosition.y,Light[i].L_Position.z - VetexPosition.z });double d = sqrt(VL[0] * VL[0] + VL[1] * VL[1] + VL[2] * VL[2]);//光傳播的距離arma::vec VLNormal({ VL[0] / d,VL[1] / d,VL[2] / d });//單位化光矢量double n = sqrt(faceNormal.x * faceNormal.x+ faceNormal.y * faceNormal.y+ faceNormal.z * faceNormal.z);arma::vec VNNormal({ faceNormal.x / n,faceNormal.y / n,faceNormal.z / n });//單位化法矢量//第一步加入漫反射光double cosTheta = arma::dot(VLNormal, VNNormal);(cosTheta > 0) ? cosTheta : cosTheta = 0;//只有夾角為正才可以漫反射InitC.red += Light[i].L_Diffuse.red * Pmaterial->M_Diffuse.red * cosTheta;InitC.green += Light[i].L_Diffuse.green * Pmaterial->M_Diffuse.green * cosTheta;InitC.blue += Light[i].L_Diffuse.blue * Pmaterial->M_Diffuse.blue * cosTheta;//第2步,加入鏡面反射光arma::vec VV({ cameraPosition.x - VetexPosition.x,cameraPosition.y - VetexPosition.y ,cameraPosition.z - VetexPosition.z });double v = sqrt(VV[0] * VV[0] + VV[1] * VV[1] + VV[2] * VV[2]);arma::vec VVNormal({ VV[0] / v, VV[1] / v,VV[2] / v });//單位化視矢量arma::vec VH = (VVNormal + VLNormal);double h = sqrt(VH[0] * VH[0] + VH[1] * VH[1] + VH[2] * VH[2]);arma::vec VHNormal({ VH[0] / h, VH[1] / h, VH[2] / h });//平分矢量double cosBeta = dot(VHNormal, VNNormal);(cosBeta > 0) ? cosBeta : cosBeta = 0;double nHN = pow(cosBeta, Pmaterial->M_n);InitC.red += Light[i].L_Specular.red * Pmaterial->M_Specular.red * nHN;InitC.green += Light[i].L_Specular.green * Pmaterial->M_Specular.green * nHN;InitC.blue += Light[i].L_Specular.blue * Pmaterial->M_Specular.blue * nHN;//第3步,光強衰減double c0 = Light[i].L_C0;//c0為常數衰減因子double c1 = Light[i].L_C1;//c1線性衰減因子double c2 = Light[i].L_C2;//c2二次衰減因子 double f = (1.0 / (c0 + c1 * d + c2 * d * d));//光強衰減函數(f < 1.0) ? f : f = 1.0;lastC += InitC * f;}//else//lastC += VetexPosition.rgb;}//第4步,加入環境光CRGB amb(Ambient.red * Pmaterial->M_Ambient.red,Ambient.green * Pmaterial->M_Ambient.green,Ambient.blue * Pmaterial->M_Ambient.blue);lastC += amb;//顏色回到0 - 255之間return lastC * 255; }總結
- 上一篇: SVM SMO方法
- 下一篇: 泛型算法STL中的迭代器,泛型算法,萃取