新手思路 phong簡單光照模型繪製

2021-06-07 18:43:35 字數 3570 閱讀 8085

第一步:熟悉opengl 程式設計。

製作乙個會旋轉的圓錐體,並加入貼圖。

第二步:讀取複雜物體表面的頂點資訊。已知複雜物體表面是由乙個個三角麵片構成的三角網格圖形。

讀出點、線、面 資訊,然後繪製頂點。

第三步:在給定模型的基礎上,在取消光照情況下,首先嘗試自己計算漫反射光照的值。

設定光源位置lightposition(三維座標)、光源顏色值lightshiness、漫反射係數值diffuse(rgb格式),同時可由函式求出每個頂點的屬性(包括頂點座標pvertex,頂點法線向量等),然後將lightposition與頂點座標pvertex的各座標軸的值想減,求得光源向量,然後與頂點法線向量求點積,得到cos值,然後利用公式i=diffuse*cos*lightshiness求得作用於頂點的漫反射光照值i(rgb格式)。

為了簡化計算,光源使用平行光。初始位置為(0,0,1)。

首先在cscenegraph3d類中定義了光源位置、光源顏色值(即光強)、漫反射係數三個變數,並在cscenegraph3d類的建構函式cscenegraph3d::cscenegraph3d()中初始化。為了能在cmesh3d類中訪問到這三個變數,需要編寫乙個函式實現傳值操作,這個函式是新增在cmesh3d類中,命名為drawme(glfloat* fdiffuse,glfloat* flightness,glfloat*flightpos);

然後在cscenegraph3d類中的gldraw()函式中新增如下**:

glfloat m_lightpos = ;

((cmesh3d*)pobject3d)->drawme(m_fdiffu,m_flightness,m_lightpos);

pobject3d->gldraw();

最後在cmesh3d類中的glbuildlist()函式中實現計算漫反射光照值。

第四步:光源位置不變,物體旋轉。

物體旋轉時,法向改變,則有多少個頂點cpu需要重複計算多少次,這樣耗時巨大,所以想到另一種方法,就是在利用glrotate()進行物體旋轉時求出其旋轉矩陣,然後求其逆矩陣,再和光源方向做點積,這種方法保證只計算一次光源方向,提高了cpu利用率。

在cmeshview::ontimer()函式中求旋轉物體時轉換矩陣的逆矩陣inv_matrix,將上面的glrotatef順序倒著寫,並使旋轉角度求反,即由正變負。然後將inv_matrix傳遞到cmesh3d類。

傳值:cmeshdoc* pdoc = getdocument();

cmesh3d *pmesh = (cmesh3d *)pdoc->m_scenegraph.getat(0);

pmesh->sendinversematrix(inv_matrix);

其中sendinversematrix 函式為:

void sendinversematrix(glfloat *inv_matrix)

memcpy(m_finvmatrix, inv_matrix, 16 * sizeof(glfloat));//記憶體拷貝

第五步:讓光源位置移動,使其圍繞物體旋轉

在cscenegraph3d類中新增成員函式spindisplay()使光源繞y軸旋轉,則 x 、z 值改變。然後在cmeshview::ontimer()中呼叫此函式。

為了清晰地看到光源是如何移動的,繞著什麼方向移動的,我設定了一條紅色的線(從原點到光源位置),當光源繞y軸旋轉時若從正前方看模型,則此條線在螢幕上會顯示為一條直線,所以我將平面(x,0,z)轉換為(x,-z,0)平面,即是將俯檢視向上旋轉90度,使我們能在螢幕正前方看到俯檢視,此時繪製的線移動時顯示為移動乙個圓周。

glcolor3f(1,0,0);

glbegin(gl_lines);

glvertex3f(0,0,0);

glvertex3f(10*m_light_parallel.x(),-10*m_light_parallel.z(),0);//保證看到俯檢視

glend();

第六步:計算鏡面反射光照,最後通過數學計算公式,在計算機上程式設計實現phong模型(簡單光照模型)。

在使用phong模型時不考慮環境光,因為環境光對物體的影響很小,可以忽略。所以最終顏色是漫反射光照和鏡面反射光照構成的phong模型。

cvector3d pv = *pvector; // 賦值,得到cvector3d型別的pv,而非cvector3d*型別!

pv.normalizel2(1); //法向單位化,歸一化

glfloat fcos = (glfloat)scalar(&pv,&m_light_parallel); //點積求得cos角

if (fcos<0.0f) fcos=0.0f;

glfloat fxx1 = m_fdiffuse[0] * m_flightness[0]*fcos;

glfloat fyy1 = m_fdiffuse[1] * m_flightness[1]*fcos;

glfloat fzz1 = m_fdiffuse[2] * m_flightness[2]*fcos;

glfloat m_specular[3]=; //鏡面反射係數

cvector3d m_eye; //觀察方向

m_eye.set(0.0,0.0,1.0);//從螢幕裡面指向外面,為z軸正向

glfloat l_v; //光源方向和觀察方向

l_v=sqrt(pow(m_eye.x()+m_light_parallel.x(),2) +

pow(m_eye.y()+m_light_parallel.y(),2) +

pow(m_eye.y()+m_light_parallel.y(),2) );

cvector3d m_h_specular; // 公式 h=(l+v)/ | l+v |

m_h_specular.set((m_light_parallel.x()+m_eye.x())/l_v,

(m_light_parallel.y()+m_eye.y())/l_v,

(m_light_parallel.z()+m_eye.z())/l_v);

m_h_specular.normalizel2(1);

glfloat v_r=(glfloat)scalar(&m_h_specular,&pv); //求點積

if (v_r<0.0f) v_r=0.0f;

glfloat n=5;//鏡面高光係數 (0--2000) n越大,光斑越暗

glfloat m_v_r=pow(v_r,n); // v_r的n次方

glfloat fxx2=m_flightness[0]*m_specular[0]*m_v_r;

glfloat fyy2=m_flightness[1]*m_specular[1]*m_v_r;

glfloat fzz2=m_flightness[2]*m_specular[2]*m_v_r;

glfloat fxx= fxx1+fxx2;

glfloat fyy=fyy1+fyy2;

glfloat fzz=fzz1+fzz2;

if (fxx>255) fxx=255;

if (fyy>255) fyy=255;

if (fzz>255) fzz=255;

::glcolor3ub(fxx,fyy,fzz);

新手思路 phong簡單光照模型繪製

第一步 熟悉opengl 程式設計。製作乙個會旋轉的圓錐體,並加入貼圖。第二步 讀取複雜物體表面的頂點資訊。已知複雜物體表面是由乙個個三角麵片構成的三角網格圖形。讀出點 線 面資訊,然後繪製頂點。第三步 在給定模型的基礎上,在取消光照情況下,首先嘗試自己計算漫反射光照的值。設定光源位置lightpo...

Phong和Blinn Phong光照模型

phong和 blinn phong 是計算鏡面反射光的兩種光照模型,兩者僅僅有很小的不同之處。1.phong模型 phone模型計算中的乙個關鍵步驟就是反射向量r的計算 上圖中的位於表面 下面 的向量 i 是原始 i 向量的拷貝,並且二者是一樣的,現在我們的目標計算出向量 r 根據向量相加原則,向...

高光反射Phong光照模型

高光反射是一種經驗模型,並不完全符合真實世界中的高光反射現象。先根據表面法線 視角方向 光源方向計算出反射方向。通過 phong 模型來計算高光反射的部分。一般都用逐畫素,得到更平滑的高光效果。公式 高光反射光線強度 入射光線顏色 高光反射顏色 max 0,視角方向 反射方向 高光反光度 case ...