第一步:熟悉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 ...