1. 程式人生 > >OpenGL光照設置

OpenGL光照設置

sta windows 前三 oop lena 點畫 cti test key

1.設置光源

1)光源的種類

環境光

環境光是一種無處不在的光。環境光源放出的光線被認為來自任何方向。因此,當你僅為場景指定環境光時,所有的物體無論法向量如何,都將表現為同樣的明暗程度。

點光源

由這種光源放出的光線來自同一點,且方向輻射向四面八方。

平行光

平行光又稱鏡面光,這種光線是互相平行的。從手電筒、太陽等物體射出的光線都屬於平行光。

聚光燈

這種光源的光線從一個錐體中射出,在被照射的物體上產生聚光的效果。使用這種光源需要指定光的射出方向以及錐體的頂角α。

2)光的成分

對於每一種光源,都有漫射光和平行光兩種成分。

在OpenGL中,環境光也被作為一種特殊的光源的成分來看待。

漫射光是指在光源中能夠被漫反射的光的顏色成分(白色則包含所有顏色),

而平行光是指光源中所有能夠被鏡面反射的光的顏色成分。

通過指定這兩種成分的顏色,就能決定光源是平行光源還是點光源。

3)設置光源成分

OpenGL可以同時為我們提供8個有效的光源。也就是說,我們最多可以同時啟用8個光源。它們分別是GL_LIGHT0,GL_LIGHT1,GL_LIGHT2 ……其中,GL_LIGHT0是最特殊的一個光源。我們可以為GL_LIGHT0指定環境光成分。

a) 設置環境光

對於GL_LIGHT0,我們可以為其指定環境光成分。 調用

glLightfv(GL_LIGHT0, GL_AMBIENT /*模糊,環境光*/, ambientLight);

來設置場景的環境光。在上述函數調用中,第一個參數表示我們要對GL_LIGHT0進行設置,第二個參數表示我們要設置的是環境光成分,第三個參數則是一個數組,它有4個值,分別表示光源中含有紅、綠、藍三種光線的成分。一般情況下都為1,最後一項為透明度值,一般也為1。

完整的代碼是這樣的:

int AmbientLight[4]={1,1,1,1};
glLightfv(GL_LIGHT0, GL_AMBIENT, AmbientLight);
glEnable(GL_LIGHT0); //允許0#燈使用

glEnable(GL_LIGHTING); //開燈

請註意在上述代碼的第三行和第四行我們分別調用了glEnable函數開啟GL_LIGHT0光源和光照系統。

b)設置漫射光成分

通過對漫射光成分的設置,我們可以產生一個點光源。方法和設置環境光成分相似,只需調用

glLightfv(GL_LIGHT0, GL_DIFFUSE/*漫反射*/, DiffuseLight);

即可。其中DiffuseLight是漫射光的顏色成分。一般情況下也為(1,1,1,1)

c)設置鏡面光成分

通過對鏡面光成分的設置,我們可以產生一個平行光源。方法和設置漫射光成分相似,只需調用

glLightfv(GL_LIGHT0, GL_SPECULAR, SpecularLight);

即可。其中SpecularLight是漫射光的顏色成分。可以根據不同需要指定不同的顏色。

4)設置光源的位置

對於點光源和平行光源,我們常常需要指定光源的位置來產生需要的效果。方法仍然是調用glLightfv函數,僅僅是換換參數而已:

glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);

其中,LightPosition也是一個四維數組,四維數組的前3項依次為光源位置的X,Y,Z分量,第四個值很特殊,一般為1或-1。當LightPosition[4]=-1的時候,表示光源位於距離場景無限遠的地方,無論前面設置的X,Y,Z是什麽值。LightPosition[4]=1時,光源的位置就是前三項所指定的位置。

2.光照模型

OpenGL的光照模型是用來模擬現實生活中的光照的。

3.材質設定

1)材質顏色

OpenGL用材料對光的紅、綠、藍三原色的反射率來近似定義材料的顏色。象光源一樣,材料顏色也分成環境、漫反射和鏡面反射成分,它們決定了材料對環境光、漫反射光和鏡面反射光的反射程度。在進行光照計算時,材料對環境光的反射率與每個進入光源的環境光結合,對漫反射光的反射率與每個進入光源的漫反射光結合,對鏡面光的反射率與每個進入光源的鏡面反射光結合。對環境光與漫反射光的反射程度決定了材料的顏色,並且它們很相似。對鏡面反射光的反射率通常是白色或灰色(即對鏡面反射光中紅、綠、藍的反射率相同)。鏡面反射高光最亮的地方將變成具有光源鏡面光強度的顏色。例如一個光亮的紅色塑料球,球的大部分表現為紅色,光亮的高光將是白色的。

2)材質定義

材質的定義與光源的定義類似。其函數為:

void glMaterial{if}[v](GLenum face, GLenum pname, TYPE param);

定義光照計算中用到的當前材質。face可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,它表明當前材質應該應用到物體的哪一個面上;pname說明一個特定的材質;

pname參數值具體內容見下表。另外,參數GL_AMBIENT_AND_DIFFUSE表示可以用相同的RGB值設置環境光顏色和漫反射光顏色。

___________________________________________________________________

參數名 缺省值 說 明

GL_AMBIENT (0.2,0.2,0.2,1.0) 材料的環境光顏色

GL_DIFFUSE (0.8,0.8,0.8,1.0) 材料的漫反射光顏色

GL_AMBIENT_AND_DIFFUSE 材料的環境光和漫反射光顏色

GL_SPECULAR (0.0,0.0,0.0,1.0) 材料的鏡面反射光顏色

GL_SHINESS 0.0 鏡面指數(光亮度)

GL_EMISSION (0.0,0.0,0.0,1.0) 材料的輻射光顏色

GL_COLOR_INDEXES (0,1,1) 材料的環境光、漫反射光和鏡面光顏色

param是材質的具體數值,若函數為向量形式,則param是一組值的指針,反之為參數值本身。非向量形式僅用於設置GL_SHINESS。

_______________________________________________

3)材質RGB值和光源RGB值的關系

材質的顏色與光源的顏色有些不同。對於光源,R、G、B值等於R、G、B對其最大強度的百分比。若光源顏色的R、G、B值都是1.0,則是最強的白光;若值變為0.5,顏色仍為白色,但強度為原來的一半,於是表現為灰色;若R=G=1.0,B=0.0,則光源為黃色。對於材質,R、G、B值為材質對光的R、G、B成分的反射率。比如,一種材質的R=1.0,G=0.5,B=0.0,則材質反射全部的紅色成分,一半的綠色成分,不反射藍色成分。也就是說,若OpenGL的光源顏色為(LR,LG,LB),材質顏色為(MR,MG,MB),那麽,在忽略所有其他反射效果的情況下,最終到達眼睛的光的顏色為(LR*MR,LG*MG,LB*MB)。同樣,如果有兩束光,相應的值分別為(R1,G1,B1)和(R2,G2,B2),則OpenGL將各個顏色成分相加,得到(R1+R2,G1+G2,B1+B2),若任一成分的和值大於1(超出了設備所能顯示的亮度)則約簡到1.0。

3.示例代碼

//繪制茶壺
#include "stdafx.h"
#include <GL/glut.h>
#include <stdlib.h>

//自定義初始化opengl函數
void init(void)
{
    //材質反光性設置
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };  //鏡面反射參數
    GLfloat mat_shininess[] = { 50.0 };               //高光指數
    GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
    GLfloat white_light[] = { 1.0, 1.0, 1.0, 1.0 };   //燈位置(1,1,1), 最後1-開關
    GLfloat Light_Model_Ambient[] = { 0.2, 0.2, 0.2, 1.0 }; //環境光參數

    glClearColor(0.0, 0.0, 0.0, 0.0);  //背景色
    glShadeModel(GL_SMOOTH);           //多變性填充模式

    //材質屬性
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

    //燈光設置
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);   //散射光屬性
    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);  //鏡面反射光
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Light_Model_Ambient);  //環境光參數

    glEnable(GL_LIGHTING);   //開關:使用光
    glEnable(GL_LIGHT0);     //打開0#燈
    glEnable(GL_DEPTH_TEST); //打開深度測試
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glutSolidTeapot(0.5);

    /*
    glBegin(GL_QUADS);
    glVertex3f(0, 0, 10);
    glVertex3f(0, 0, 10);
    glVertex3f(20, 5, 10);
    glVertex3f(30, 40, -10);
    glEnd();
    */

    glFlush();   //glSwapBuffers();
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);

    //設置投影參數
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //正交投影
    if (w <= h)
        glOrtho(-1.5, 1.5, -1.5*(GLfloat)h / (GLfloat)w, 1.5*(GLfloat)h / (GLfloat)w, -10.0, 10.0);
    else
        glOrtho(-1.5*(GLfloat)w / (GLfloat)h, 1.5*(GLfloat)w / (GLfloat)h, -1.5, 1.5, -10.0, 10.0);

    //設置模型參數--幾何體參數
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("茶壺");

    init();

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);

    glutMainLoop();
    return 0;
}

技術分享

修改鏡面反射參數、環境光參數、燈的位置和背景色後:

技術分享

//繪制太陽系
#include "stdafx.h"
#include <GL/glut.h>
#include <stdlib.h>

static int year = 0, day = 0, moon = 0;

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_SMOOTH);
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    glPushMatrix();
    glColor3f(1.0, 0.0, 0.0);
    glutSolidSphere(1.0, 20, 16); /* draw sun */

    glRotatef((GLfloat)year, 0.0, 1.0, 0.0);
    glTranslatef(2.0, 0.0, 0.0);
    glRotatef((GLfloat)day, 0.0, 1.0, 0.0);
    glColor3f(0.0, 0.0, 1.0);
    glutSolidSphere(0.3, 10, 8); /* draw earth */

    glTranslatef(1.0, 0.0, 0.0);
    glRotatef((GLfloat)moon, 0.0, 1.0, 0.0);
    glColor3f(1.0, 1.0, 1.0);
    glutSolidSphere(0.2, 10, 8); /* draw moon */
    glPopMatrix();
    glutSwapBuffers();
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
    case d:
        day = (day + 10) % 360;
        moon = (moon + 5) % 360;
        glutPostRedisplay();
        break;
    case D:
        day = (day - 10) % 360;
        glutPostRedisplay();
        break;
    case y:
        year = (year + 5) % 360;
        day = (day + 10) % 360;
        moon = (moon + 5) % 360;
        glutPostRedisplay();
        break;
    case Y:
        year = (year - 5) % 360;
        glutPostRedisplay();
        break;
    case m:
        moon = (moon + 5) % 360;
        glutPostRedisplay();
        break;
    case 27:
        exit(0);
        break;
    default:
        break;
    }
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(800, 600);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    return 0;
}

開始時效果:

技術分享

動畫效果:

技術分享

加入光照條件:

    //材質反光性設置
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };  //鏡面反射參數
    GLfloat mat_shininess[] = { 50.0 };               //高光指數
    GLfloat light_position[] = { 3.0, 3.0, 3.0, 0.0 };
    GLfloat white_light[] = { 1.0, 1.0, 1.0, 1.0 };   //燈位置(1,1,1), 最後1-開關
    GLfloat Light_Model_Ambient[] = { 0.8 , 0.2 , 0.2 , 1.0 }; //環境光參數

    //材質屬性
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

    //燈光設置
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);   //散射光屬性
    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);  //鏡面反射光
    glLightModelfv( GL_LIGHT_MODEL_AMBIENT , Light_Model_Ambient );  //環境光參數

    glEnable(GL_LIGHTING);   //開關:使用光
    glEnable(GL_LIGHT0);     //打開0#燈
    glEnable(GL_DEPTH_TEST); //打開深度測試

註意:記得要在glClear後加一個深度測試

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

加入光照後的效果如下

剛開始:

技術分享

動畫效果:

技術分享

總結

  此次學習了OpenGL的光照設置後,讓我對二維到三維產生了新的認識,同時也愈發感到有趣。記得前段時間我和女友聊起光照,她說她當時畫立體畫的時候也要故意把一個點畫的特別亮,另外一些地方要進行暗處理,這樣才能顯示出立體的效果。聊天期間還給我介紹了一些專業術語...看來圖形學和繪畫,總是存在著一些異曲同工之妙的!相信後面的劇情發展會越來越精彩的。

OpenGL光照設置