OpenGL提供了多種形式的光源,如點光源
、平行光源
和聚光燈光源
等。所有光源都使用 glLight*接口來設置光源屬性,其中包括 glLight{if} 和 glLight{if}v 兩類。
GLfloat ambient[] = {0.3f, 0.3f, 0.3f, 1.0f}; // 環境強度
GLfloat diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f}; // 散射強度
GLfloat specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; // 鏡面強度
// 點光源, GL_POSITION屬性的最後一個參數為1
GLfloat position[] = {-3.0f, -3.4f, -8.8f, 1.0f};
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
// 平行光源, GL_POSITION屬性的最後一個參數為0
GLfloat direction[] = {-3.0f, -3.4f, -8.8f, 0.0f};
glLightfv(GL_LIGHT1, GL_POSITION, direction);
glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
// 聚光燈光源, 需要指定位置、方向、光錐半角
GLfloat spot_direction[] = {-3.0f, -3.4f, -8.8f};
glLightfv(GL_LIGHT2, GL_POSITION, position);
glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, spot_direction);
glLightfv(GL_LIGHT2, GL_SPOT_CUTOFF, 45.0);
glLightfv(GL_LIGHT2, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT2, GL_SPECULAR, specular);
GL_LIGHT0、GL_LIGHT1、GL_LIGHT2、...、GL_LIGHT7、...
等。在片段著色中可通過gl_LightSource[0]、gl_LightSource[1]、gl_LightSource[2]、...、gl_LightSource[7]、...
等內建變量訪問各個光源的參數;glEnable(GL_LIGHTING)
啟用光照機制,然後使用glEnable(GL_LIGHTx)
與glDisable(GL_LIGHTx)
打開或關閉相應光源(其中x代表光源序號);控制光源的矩陣變換和控制圖元的矩陣變換相同,故最終光源表現出來的性質(如點光源位置是固定在世界坐標系某點還是跟隨鏡頭移動,平行光源的方向在世界坐標系下是不變的還是跟隨相機移動等)與提交光源位置或朝向(glLight*())和視點變換(gluLookAt())的先後順序是息息相關的。據此我們可以定義出各式各樣的常見光源,如太陽光、白熾燈、汽車前照燈等。
如果在視點變換後提交光源位置或朝向,那麼光源就可以看作一個普通的幾何對象,提交的坐標是在世界坐標系中度量的,對普通幾何對象的各種變換同樣適用於光源。可通俗的理解為視圖變換矩陣作用於光源的位置或朝向參數上,此過程就如同世界坐標系下的普通物體轉換至觀察坐標系下。
如果程序裡沒有視點變換,說明世界坐標系和攝像機坐標系重合,光源也可以看作一個普通的幾何對象。表現出這種性質的常見光源有太陽光,家裡的白熾燈等。示例代碼如下:
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 0, 0, 0, -1, 0, 1, 0);
GLfloat sun_light_position[] = {-139.5f, -153.4f, -68.8f, 0.0f};
glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position); // 光源的其他參數可在程序初始化時設置
glPushMatrix();
glTranslated(-2.5, 6.9, -184.8);
glRotated(87.4, 0, 0, 1);
drawOBJ();
glPopMatrix();
...
}
注意:
光源位置或朝向的指定不能處於某個模型的模型變換代碼之間(如上例中的glPushMatrix()與glPopMatrix()之間),否則光源參數會受到影響。所以最好將光源位置或朝向設置代碼放在緊跟gluLookAt之後。
如果在視點變換前提交光源位置,視點和光源將捆綁在一起,即二者相對位置不變,一起運動。此時,可以理解為提交的光源位置是在相機坐標系中度量的(位置參數的默認值是(0.0, 0.0, 1.0, 0.0), 就是在攝像機坐標系中度量的)。亦可通俗的理解為視圖變換矩陣未作用於光源的位置或朝向參數上。光源的位置朝向參數在觀察坐標系的值會保持不變。
表現出這種性質的常見光源有汽車前照燈(以駕駛員的視角觀察視角)或礦工頭上的礦燈。示例代碼如下:
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLfloat sun_light_position[] = {-139.5f, -153.4f, -68.8f, 0.0f};
glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position); // 光源的其他參數可在程序初始化時設置
gluLookAt(0, 0, 0, 0, 0, -1, 0, 1, 0);
glPushMatrix();
glTranslated(-2.5, 6.9, -184.8);
glRotated(87.4, 0, 0, 1);
drawOBJ();
glPopMatrix();
...
}
OpenGL 渲染篇 http://www.linuxidc.com/Linux/2011-10/45756.htm
Ubuntu 13.04 安裝 OpenGL http://www.linuxidc.com/Linux/2013-05/84815.htm
OpenGL三維球體數據生成與繪制【附源碼】 http://www.linuxidc.com/Linux/2013-04/83235.htm
Ubuntu下OpenGL編程基礎解析 http://www.linuxidc.com/Linux/2013-03/81675.htm
如何在Ubuntu使用eclipse for c++配置OpenGL http://www.linuxidc.com/Linux/2012-11/74191.htm
《OpenGL超級寶典》學習筆記 http://www.linuxidc.com/Linux/2013-10/91414.htm