在這一課當中,我將會學到如何使用光照,如何使用鍵盤控制,其次還增加兩種紋理映射的濾波方式.而主要內容將會放在光照上.
為了在場景中增加光照,需要執行下面的這些步驟:
1. 定義每個物體的每個頂點的法線向量.這些法線決定了物體相對于光源的方向
glNormal3f() //這是這節課當中必須用得到的 指定方向方向
2. 創建或選擇一個或多個光源,并設置他們的位置
glLightfv() //這個函數將會創建某號光源,并設置它的一些屬性,如環境光強度,漫反射光強度,及位置等.
光強度其實也是類似顏色值的四個分量組成的...R G B A
3. 創建或選擇一種光照模型,它定義了全局環境光的層次以及觀察點的有效位置(便于進行光照計算).
而該Lesson當初我們并為用到這個函數 glLightModelfv() .因為在opengl當中其實許多值都是具有默認值的.
4. 定義場景中的物體的材料屬性
glMaterialfv() //這課當中我們也沒有用到.
5. 啟用創建的光源,啟用光照..
glEnable(光源號)
glEnable(GL_LIGHTING) //這個則是關鍵.只有啟用它才能達到啟用光照的效果.
glut 當中負責處理鍵盤事件注冊的有兩個函數glutSpecialFunc() 負責處理特殊按鍵,glKeyboardFunc() 負責處理普通按鍵.故而在鍵盤處理事件當中我們只需在這些事情函數中寫入相關代碼就行.
而其他的內容我只是全部在將在代碼注釋當中給出

Code

#include "openglglut.h"


/**//**
** NEHE lesson_7
** 1.紋理映射的學習(三種濾波方式)
** 2.鍵盤控制的學習
** 3.光照配置的學習(環境光 點光源)
*/

GLfloat xRot=0; /**//** 正方體繞x軸旋轉角度*/

GLfloat yRot=0; /**//** 正方體繞y軸旋轉角度*/
GLfloat z=-6.0;

static GLuint texnum[3]; /**//** 定義存儲紋理*/
bool light=false;

int filter=0; /**//** 定義選擇的濾波方式*/


GLfloat light_ambient[]=
{0.5,0.5,0.5,1.0}; /**//** 定義環境光強度*/

GLfloat light_diffuse[]=
{1.0,1.0,1.0,1.0}; /**//** 定義漫反射光強度*/

GLfloat light_position[]=
{0.0,0.0,5.0,1.0}; /**//** 定義光源的位置*/


/**//** 這是一個通過WIN API 載入一張bmp格式圖片的方法*/
bool LoadBmpTexture(LPTSTR filename)


{

HBITMAP bBmp; /**//** 位圖文件的句柄*/

BITMAP bmp; /**//** 位圖的結構*/

/**//** 通過API LoadImage 讀入bmp文件,獲得句柄*/
bBmp=(HBITMAP)LoadImage(GetModuleHandle(NULL),filename,IMAGE_BITMAP,0,0,
LR_CREATEDIBSECTION | LR_LOADFROMFILE);

if(!bBmp)
return false;

/**//** 獲得圖像數據對象*/
GetObject(bBmp,sizeof(bmp),&bmp);


glPixelStorei(GL_UNPACK_ALIGNMENT,4); /**//** ? */


glGenTextures(3,&texnum[0]); /**//** 創建三個紋理 分別存儲于texnum[0],texnum[1],texnum[2]*/


/**//** Nearest濾波*/

glBindTexture(GL_TEXTURE_2D,texnum[0]); /**//** 為它指定第一個紋理 設置紋理濾波方式*/

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); /**//** 線性濾波 */

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); /**//** 線性濾波 */
gluBuild2DMipmaps(GL_TEXTURE_2D, 3,bmp.bmWidth,bmp.bmHeight
,GL_BGR_EXT,GL_UNSIGNED_BYTE,bmp.bmBits);


/**//** 線性濾波*/

glBindTexture(GL_TEXTURE_2D,texnum[1]); /**//** 為它指定第一個紋理 設置紋理濾波方式*/
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3,bmp.bmWidth,bmp.bmHeight
,GL_BGR_EXT,GL_UNSIGNED_BYTE,bmp.bmBits);


/**//** MipMapped 濾波*/

glBindTexture(GL_TEXTURE_2D,texnum[2]); /**//** 為它指定第一個紋理 設置紋理濾波方式*/
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3,bmp.bmWidth,bmp.bmHeight
,GL_BGR_EXT,GL_UNSIGNED_BYTE,bmp.bmBits);



DeleteObject(bBmp); /**//** 刪除對象,釋放內存*/

return true;
}
int main(int argc,char** argv)


{

createWindow("opengl lesson_7",&argc,argv); /**//** 初始化并創建窗口*/


glutDisplayFunc(glutDisplay); /**//** 注冊重繪函數*/

glutIdleFunc(glutIdle); /**//** 注冊空閑回調函數*/

glutReshapeFunc(glutResize); /**//** 注冊窗口調整函數*/

glutSpecialFunc(glutSpecial); /**//** 注冊特殊按鍵窗口*/

glutKeyboardFunc(glutKeyboard); /**//** 注冊鍵盤處理函數*/


InitOpenGL(); /**//** 初始化opengl*/

InitTexture(); /**//** 初始化啟用紋理映射并加載紋理*/

InitLight(); /**//** 初始化光照*/

glutMainLoop(); /**//** 仿真循環*/
}
void InitTexture(void)


{

/**//** 讀入工程目錄下data文件中的bmp文件*/
if(!LoadBmpTexture(L"..\\Data\\image.bmp"))

{
printf("load texture error!\n");
exit(0);
}

/**//** 若載入紋理成功 則啟用紋理映射*/
glEnable(GL_TEXTURE_2D);
}
void InitLight(void)


{

/**//** 創建并啟用1號光源*/
glLightfv(GL_LIGHT1,GL_AMBIENT,light_ambient); /** 初始化光源1環境光*/

glLightfv(GL_LIGHT1,GL_DIFFUSE,light_diffuse); /**//** 初始化光源1散射光*/

glLightfv(GL_LIGHT1,GL_POSITION,light_position); /**//** 初始化光源1位置*/


/**//** liggt_position 包含(x,y,z,w) w為0 表示方向性光源,w非0表示位置性光源*/
glEnable(GL_LIGHT1);
}
void glutIdle(void)


{
glutPostRedisplay();
}

void glutDisplay(void) /**//** 重繪函數*/


{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);/**//** 清除顏色緩存和深度緩存*/

glLoadIdentity(); /**//** 初始化當前矩陣為單位矩陣*/


glPushMatrix(); /**//** 保存當前矩陣*/


glTranslatef(0.0,0.0,z); /**//** 往左移動和往屏幕內部移動,繪制正方體*/

glRotatef(xRot,1.0,0.0,0.0); /**//** 正方體繞x軸旋轉xRot角度*/

glRotatef(yRot,0.0,1.0,0.0); /**//** 正方體繞y軸旋轉yRot角度*/

glBindTexture(GL_TEXTURE_2D,texnum[filter]); /**//** 選擇一個紋理*/

glBegin(GL_QUADS); /**//** 通過繪制六個正方形組成正方體,并為每一面都貼上紋理*/
// 前側面
glNormal3f( 0.0f, 0.0f, 1.0f); // 法線指向觀察者
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
// 后側面
glNormal3f( 0.0f, 0.0f,-1.0f); // 法線背向觀察者
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
// 頂面
glNormal3f( 0.0f, 1.0f, 0.0f); // 法線向上
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
// 底面
glNormal3f( 0.0f,-1.0f, 0.0f); // 法線朝下
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// 右側面
glNormal3f( 1.0f, 0.0f, 0.0f); // 法線朝右
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// 左側面
glNormal3f(-1.0f, 0.0f, 0.0f); // 法線朝左
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd(); // 四邊形繪制結束
glutSwapBuffers();

}

void glutKeyboard(unsigned char key,int x,int y)


{
switch(key)

{

case 27: /**//** Esc按鍵按下后退出程序 */
exit(0);
break;

case 'l': /**//** 按鍵L 光源開關*/
light=!light;
light?glEnable(GL_LIGHTING):glDisable(GL_LIGHTING);
break;

case 'f': /**//** 選擇濾波方式*/
filter+=1;
filter%=2;
break;
case 'a':

yRot-=1.0; /**//** 繞y旋轉角度遞減*/
break;
case 'd':

yRot+=1.0; /**//** 繞y旋轉角度遞增*/
break;
case 's':

xRot+=1.0; /**//** 繞x旋轉角度遞增*/
break;
case 'w':

xRot-=1.0; /**//** 繞y旋轉角度遞增*/
case 'z':

z-=0.02; /**//** z軸移動位置遞減,即向屏幕外移動*/
break;

case 'x': /**//** z軸移動位置遞增,即向屏幕內移動*/
z+=0.02;
break;
default:
break;
}
}
最后實現的效果圖如下所示:

末尾總結:
熟悉了光照的配置,以及鍵盤函數處理的一些功能.其次我在讀取紋理過程當中發現了以個bug..使用win API 并不能讀取 8-bit的bmp格式圖像..所以相對于讀取文件其實也應當是個麻煩的事情..
posted on 2009-07-26 14:21
米游 閱讀(487)
評論(0) 編輯 收藏 引用 所屬分類:
OpenGL/OSG