電腦遊戲製作開發設計論壇 首頁 電腦遊戲製作開發設計論壇
任何可以在PC上跑的遊戲都可以討論,主要以遊戲之製作開發為主軸,希望讓台灣的遊戲人有個討論、交流、教學、經驗傳承的園地
 
 常見問題常見問題   搜尋搜尋   會員列表會員列表   會員群組會員群組   會員註冊會員註冊 
 個人資料個人資料   登入檢查您的私人訊息登入檢查您的私人訊息   登入登入 

Google
OpenGL入門教學(05)

 
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 遊戲程式高級班:DirectX、OpenGL及各種圖型函式庫
上一篇主題 :: 下一篇主題  
發表人 內容
還是零分
散播福音的祭司


註冊時間: 2007-09-19
文章: 164

653.83 果凍幣

發表發表於: 2008-7-2, PM 3:02 星期三    文章主題: OpenGL入門教學(05) 引言回覆

這篇的新內容是光線的模擬

想要讓OpenGL打光的話,必須設定光源的位置、光源的屬性
設定物質反光的材質屬性、法向量

光源的屬性以及材質屬性都是在設定3種光:環境光(Ambient Light)、散射光(Diffuse Light)、反射光(Specular Light)


環境光:顧名思義是從四面八方照來的光,是不管方向的
散射光:就現實中而言是不光滑表面的反射光,物體有照到光的部分都有散射光散射
反射光:反射光特別亮的話則會顯的很有光澤


物體表現出來的明暗是光源屬性3種光和材質屬性3種光相乘的結果
兩者都是介於0到1的數,相乘後還是介於0到1


//------glNormal3f( x , y , z );
//
//用來設定法向量,需要這項資料才能正確打光
//可以一個面設一個向量或一個點設一個向量
//為了打光更自然還出現過許多奇怪的方法,這裡不贅述


//------glPolygonMode ( 想要顯示的面 , 顯示的模式 );
//
//第一個參數可以填:
//GL_FRONT_AND_BACK
//GL_FRONT
//GL_BACK
//第二個參數可以填:
//GL_FILL
//GL_LINE
//GL_POINT
//若沒設定這一項的話,OpenGL預設是( GL_FRONT_AND_BACK , GL_FILL )
//設定面的時候,看起來以逆時針順序設定點的那一面為正面


//------gluPerspective( 視角, rate , 最近邊界 , 最遠邊界 );
//
//第一個參數是觀察者的視角,若視角給太大的話,視野會變很廣,像是透過魚眼看世界一樣
//第二個參數是畫面寬除以高的比值,只要使用視窗的長寬來計算,投影畫面就不會變形了(跟之前的範例不同)
//最近邊界是視點到最近顯示邊界的距離,通常會給個1或0.1,但就是不可以填0
//最遠邊界設定太小或太大都不好,看情況使用


//------glLightfv( 要使用的光源 , 光源屬性 , RGBA );
//
//第一個參數是指定要改變光源屬性的光源
//在Windows下有八個光源可用,分別是GL_LIGHT0~GL_LIGHT7,省著點用啊,數量有限
//第二個參數指定要修改的是3種光的哪一種
//第三個參數放入一個陣列的指標(就是陣列的名字)
//陣列中有4個數,代表RGBA顏色值
//這種把資料寫在一個結構中,再把結構的指標當參數輸入的做法
//在API中很常見


//------glMaterialfv( 面 , 材質屬性 , RGBA );
//
//第一個參數決定現在要設定的是正面還是反面(還是正反都要)
//第一個參數可以填:
//GL_FRONT_AND_BACK
//GL_FRONT
//GL_BACK
//後面的兩個參數與glLightfv()的使用無異


代碼:

//-----------------------------------------------------------------------------
//                                                              2008/7/1
//                                 光線模擬
//                                                              by還是零分
//-----------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <GL\glut.h>
int WinNumber=NULL;                      //用來放置視窗代碼

int old_rot_x = 0;                       //剛按下滑鼠時的視窗座標
int old_rot_y = 0;

int rot_x = 0;                           //拖曳後的相對座標,用這決定要旋轉幾度
int rot_y = 0;

int record_x = 0;                        //紀錄上一次旋轉的角度
int record_y = 0;

float distance = 0;                      //在平移矩陣(glTranslatef();)中使用
float light_position[] = { -20, 20, 0};  //光源的位置

void WindowSize(int , int );             //負責視窗及繪圖內容的比例
void Keyboard(unsigned char ,int ,int ); //獲取鍵盤輸入
void Mouse(int ,int ,int ,int );         //獲取滑鼠按下和放開時的訊息
void MotionMouse(int ,int );             //獲取滑鼠按下期間的訊息
void Display(void);                      //描繪

void SetLightSource(void);               //設定光源屬性
void SetMaterial(void);                  //設定材質屬性

int main()
{
   printf( "按w和s鍵調整遠近\n用Esc鍵來關閉程式\n" );
   glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB );
   glutInitWindowSize( 400, 400);                     //視窗長寬
   glutInitWindowPosition( 600, 80);                  //視窗左上角的位置
   WinNumber = glutCreateWindow( "這裡是視窗標題" );   //建立視窗

   //下面五個是用來指定Callback函數
   glutReshapeFunc ( WindowSize );
   glutKeyboardFunc( Keyboard );
   glutMouseFunc   ( Mouse );
   glutMotionFunc  ( MotionMouse );
   glutDisplayFunc ( Display );

   SetLightSource();
   SetMaterial();

   glutMainLoop();

   return 0;
}

void Display(void)
{
   glClearColor(1.0, 1.0, 1.0, 1.0);                            //用白色塗背景
   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
   glPolygonMode (GL_BACK, GL_LINE);                            //設定面的背面用線條顯示
   
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();

   gluLookAt( 0, 0, 30.0, 0, 0, 0, 0, 1, 0);                    //視線的座標及方向
   glTranslatef( 0, 0, distance);                               //沿著z軸平移
   glRotatef( (float)rot_y + (float)record_y, 1.0, 0.0, 0.0);   //以x軸當旋轉軸
   glRotatef( (float)rot_x + (float)record_x, 0.0, 1.0, 0.0);   //以y軸當旋轉軸
   
   //畫一個沒有底面的box
   glBegin(GL_QUADS);
      //正面
      glNormal3f(0,0,1);        //設定法向量
         glVertex3f(-7, 7, 7);
         glVertex3f(-7,-7, 7);
         glVertex3f( 7,-7, 7);
         glVertex3f( 7, 7, 7);
      //背面
      glNormal3f(0,0,-1);
         glVertex3f(-7, 7,-7);
         glVertex3f( 7, 7,-7);
         glVertex3f( 7,-7,-7);
         glVertex3f(-7,-7,-7);
      //右側面
      glNormal3f(1,0,0);
         glVertex3f( 7, 7, 7);
         glVertex3f( 7,-7, 7);
         glVertex3f( 7,-7,-7);
         glVertex3f( 7, 7,-7);
      //左側面
      glNormal3f(-1,0,0);
         glVertex3f(-7, 7,-7);
         glVertex3f(-7,-7,-7);
         glVertex3f(-7,-7, 7);
         glVertex3f(-7, 7, 7);
      //上面
      glNormal3f(0,1,0);
         glVertex3f(-7, 7,-7);
         glVertex3f(-7, 7, 7);
         glVertex3f( 7, 7, 7);
         glVertex3f( 7, 7,-7);
   glEnd();
   
   glutSwapBuffers();
}

void Keyboard(unsigned char key, int x, int y)
{
   switch (key)
   {
   case 'w':
      distance+=1;
      break;
   case 's':
      distance-=1;
      break;
   case 27:
      glDisable(GL_LIGHT0);
      glDisable(GL_LIGHTING);
      glDisable(GL_DEPTH_TEST);
      glutDestroyWindow(WinNumber);
      exit(0);
      break;
   }
   glutPostRedisplay();            //令視窗重繪
}

void WindowSize(int w, int h)
{
   float rate;
   if( h==0 ) h = 1;                        //阻止h為零,分母可不能為零啊
   glViewport( 0, 0, w, h);                 //當視窗長寬改變時,畫面也跟著變
   rate = (float)w/(float)h;                //畫面視野變了,但內容不變形
   
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective( 45, rate, 1.0, 500.0);   //透視投影
   
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}

void Mouse(int button, int state, int x, int y)
{
   if(state)
   {
      record_x += x - old_rot_x;
      record_y += y - old_rot_y;
     
      rot_x = 0;   //沒有歸零會有不理想的結果
      rot_y = 0;
   }
   else
   {
      old_rot_x = x;
      old_rot_y = y;
   }
}

void MotionMouse(int x, int y)
{
   rot_x = x - old_rot_x;
   rot_y = y - old_rot_y;
   glutPostRedisplay();
}

void SetLightSource()
{
   float light_ambient[]  = { 1.0, 1.0, 1.0, 1.0};
   float light_diffuse[]  = { 1.0, 1.0, 1.0, 1.0};
   float light_specular[] = { 1.0, 1.0, 1.0, 1.0};

   glEnable(GL_LIGHTING);                                 //開燈

   // 設定發光體的光源的特性
   glLightfv( GL_LIGHT0, GL_AMBIENT, light_ambient);      //環境光(Ambient Light)
   glLightfv( GL_LIGHT0, GL_DIFFUSE, light_diffuse);      //散射光(Diffuse Light)
   glLightfv( GL_LIGHT0, GL_SPECULAR,light_specular);     //反射光(Specular Light)
   
   glLightfv( GL_LIGHT0, GL_POSITION,light_position);     //光的座標

   glEnable(GL_LIGHT0);   
   glEnable(GL_DEPTH_TEST);                               //啟動深度測試
}

void SetMaterial()
{
   float material_ambient[]  = { 0.2, 0.2, 0.2, 1.0};
   float material_diffuse[]  = { 0.3, 0.3, 0.3, 1.0};
   float material_specular[] = { 0.2, 0.2, 0.2, 1.0};

   glMaterialfv( GL_FRONT, GL_AMBIENT,  material_ambient);
   glMaterialfv( GL_FRONT, GL_DIFFUSE,  material_diffuse);
   glMaterialfv( GL_FRONT, GL_SPECULAR, material_specular);
}





除了加上光線模擬之外
我把正交投影矩陣換成透視投影了,用'w'和's'鍵把鏡頭拉近拉遠時,物體會變大變小
並且啟動深度測試了,終於比較像現實世界了!
關閉視窗可以用Esc鍵了,這在全螢幕模式下是必備的
拉扯視窗也不會讓圖形跟著變形了
回頂端
檢視會員個人資料 發送私人訊息 參觀發表人的個人網站
從之前的文章開始顯示:   
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 遊戲程式高級班:DirectX、OpenGL及各種圖型函式庫 所有的時間均為 台灣時間 (GMT + 8 小時)
1頁(共1頁)

 
前往:  
無法 在這個版面發表文章
無法 在這個版面回覆文章
無法 在這個版面編輯文章
無法 在這個版面刪除文章
無法 在這個版面進行投票
可以 在這個版面附加檔案
可以 在這個版面下載檔案


Powered by phpBB © 2001, 2005 phpBB Group
正體中文語系由 phpbb-tw 維護製作