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

Google
OpenGL入門教學(07)

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


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

653.83 果凍幣

發表發表於: 2008-7-10, PM 4:40 星期四    文章主題: OpenGL入門教學(07) 引言回覆

這一篇只有透明色的混和
對透明色沒興趣可以先跳到下一篇


範例程式和上一篇的沒太大差別
差就差在我在LoadBitmapFile()之外又加了一些手續



在texture()裡不直接用LoadBitmapFile()載入圖檔

而是用TransIntoRGBA()來代替,在TransIntoRGBA()裡面才使用LoadBitmapFile()

反正就是用LoadBitmapFile()載入圖檔

在使用RGB圖之前用TransIntoRGBA()把圖改為RGBA

glTexImage2D(,,4,,,,GL_RGBA,,)也改了兩個參數



最後
貼上含有透明色的材質貼圖仍然不能顯現半透明的效果
還必須啟動混和(Blending)效果,把一部分的材質顏色和背景顏色混和


glEnable(GL_BLEND);//啟動混和功能
glBlendFunc( 來源顏色 , 背景顏色 );
glDisable(GL_BLEND);//關閉混和


glBlendFunc(,)的參數我用這個寫
空格才不會被吃掉
代碼:

來源顏色

GL_ZERO                   將來源顏色設為0,0,0,0
GL_ONE                    用原本的顏色(原本的貼圖)
GL_DST_COLOR              = 來源顏色×背景顏色
GL_ONE_MINUS_DST_COLOR    = 來源顏色×(1,1,1,1-背景顏色)
GL_SRC_ALPHA              = 來源顏色×自己的Alpha值
GL_ONE_MINUS_SRC_ALPHA    = 來源顏色×(1-自己的Alpha值)



背景顏色

GL_ZERO                   將背景顏色設為0,0,0,0
GL_ONE                    用背景的顏色
GL_SRC_COLOR              = 來源顏色×背景顏色
GL_ONE_MINUS_SRC_COLOR    = 目標顏色×(1,1,1,1-來源顏色)
GL_SRC_ALPHA              = 來源顏色×(來源顏色的Alpha值)
GL_ONE_MINUS_SRC_ALPHA    = 來源顏色×(1-來源顏色的Alpha值)


要注意到用來當背景的要先畫
否則會蓋掉背景失去透明的效果
深度測試也幫不上忙

場景中的不透明物體要先畫



順便附上BMP的資料結構
代碼:

// 用來儲存標頭檔的結構

typedef struct tagBITMAPFILEHEADER
{
        WORD  bfType;
        DWORD bfSize;
        WORD  bfReserved1;
        WORD  bfReserved2;
        DWORD bfOffBits;
} BITMAPFILEHEADER;

// 用來儲存資訊的結構

typedef struct tagBITMAPINFOHEADER
{
        DWORD biSize;
        LONG  biWidth;
        LONG  biHeight;
        WORD  biPlanes;
        WORD  biBitCount;
        DWORD biCompression;
        DWORD biSizeImage;
        LONG  biXPelsPerMeter;
        LONG  biYPelsPerMeter;
        DWORD biClrUsed;
        DWORD biClrImportant;
} BITMAPINFOHEADER

// 用來儲存點陣圖資料的結構

typedef struct
{
        DWORD reserve;
        DWORD r;
        DWORD g;
        DWORD b;
}structRGB;


代碼:

//-----------------------------------------------------------------------------
//                                                              2008/7/10
//                                 Alpha
//                                                              by還是零分
//-----------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <wingdi.h>
#include <math.h>
#include <GL\glut.h>

int WinNumber = 0;                              //用來放置視窗代碼

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;                              //在平移矩陣中使用
float light_position[] = { 0, 0, 30};               //光源的位置

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);                           //設定材質屬性
void texture(void);                              //處理材質貼圖的相關指令
unsigned char *LoadBitmapFile(char *, BITMAPINFO *);   //用來將BMP圖檔讀入
unsigned char *TransIntoRGBA(char *, BITMAPINFO *);      //將載入的BMP加上透明色

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

   texture();

   //下面五個是用來指定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軸當旋轉軸
   
   glEnable(GL_BLEND);//啟動混和功能
   glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
   
   glBegin(GL_QUADS);
      glNormal3f(0,0,1);
         glTexCoord2f(0,1);glVertex3f(-11, 11,-6);
         glTexCoord2f(0,0);glVertex3f(-11,-11,-6);
         glTexCoord2f(1,0);glVertex3f( 11,-11,-6);
         glTexCoord2f(1,1);glVertex3f( 11, 11,-6);
   glEnd();
   
   glBegin(GL_QUADS);
      glNormal3f(0,0,1);
         glTexCoord2f(0,1);glVertex3f(-11, 11,-3);
         glTexCoord2f(0,0);glVertex3f(-11,-11,-3);
         glTexCoord2f(1,0);glVertex3f( 11,-11,-3);
         glTexCoord2f(1,1);glVertex3f( 11, 11,-3);
   glEnd();
   
   glBegin(GL_QUADS);
      glNormal3f(0,0,1);
         glTexCoord2f(0,1);glVertex3f(-11, 11,0);
         glTexCoord2f(0,0);glVertex3f(-11,-11,0);
         glTexCoord2f(1,0);glVertex3f( 11,-11,0);
         glTexCoord2f(1,1);glVertex3f( 11, 11,0);
   glEnd();

   glDisable(GL_BLEND);
   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);
      glDisable(GL_TEXTURE_2D);
      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);
}

void texture(void)
{
   int width;
   int height;
   unsigned char *image;         //得到圖案,已經不是BMP圖了,是能直接讓OpenGL使用的資料了
   BITMAPINFO bmpinfo;            //用來存放HEADER資訊
   
   image = TransIntoRGBA("Itachi.bmp", &bmpinfo);
   width = bmpinfo.bmiHeader.biWidth;
   height = bmpinfo.bmiHeader.biHeight;
   
   glTexImage2D(GL_TEXTURE_2D,0,4,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,image);
   glEnable(GL_TEXTURE_2D);
   
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}

unsigned char *LoadBitmapFile(char *fileName, BITMAPINFO *bitmapInfo)
{
   FILE            *fp;
   BITMAPFILEHEADER   bitmapFileHeader;   // Bitmap file header
   unsigned char       *bitmapImage;      // Bitmap image data
   unsigned int      lInfoSize;         // Size of information
   unsigned int      lBitSize;         // Size of bitmap
   
   unsigned char change;
    int pixel;
    int p=0;
       
   fp = fopen(fileName, "rb");
   fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);         //讀取 bitmap header
   
   lInfoSize = bitmapFileHeader.bfOffBits - sizeof(BITMAPFILEHEADER);   //Info的size
   fread(bitmapInfo, lInfoSize, 1, fp);
   
   
   lBitSize = bitmapInfo->bmiHeader.biSizeImage;                  //配置記憶體
   bitmapImage = new BYTE[lBitSize];
   fread(bitmapImage, 1, lBitSize, fp);                        //讀取影像檔
   
   fclose(fp);
   
   //此時傳回bitmapImage的話,顏色會是BGR順序,下面迴圈會改順序為RGB
   pixel = (bitmapInfo->bmiHeader.biWidth)*(bitmapInfo->bmiHeader.biHeight);

   for( int i=0 ; i<pixel ; i++, p+=3 )
   {
      //交換bitmapImage[p]和bitmapImage[p+2]的值
      change = bitmapImage[p];
      bitmapImage[p] = bitmapImage[p+2];
      bitmapImage[p+2]  = change;
   }
   
   return bitmapImage;
}

unsigned char *TransIntoRGBA(char *fileName, BITMAPINFO *bitmapInfo)
{
   unsigned char *rgb;         //儲存剛從bmp載來的RGB圖
   unsigned char *rgba;      //儲存最後完成的RGBA圖並回傳
   int x,y;
   
   unsigned char *rgb_ptr;
   unsigned char *rgba_ptr;
   rgb = LoadBitmapFile("Itachi.bmp", bitmapInfo);
   rgba= (unsigned char *)malloc(bitmapInfo->bmiHeader.biWidth*bitmapInfo->bmiHeader.biHeight*4*sizeof(unsigned char));

   for( y=0 ; y<bitmapInfo->bmiHeader.biWidth ; y++ )
   {
      rgb_ptr = rgb+y*bitmapInfo->bmiHeader.biWidth*3;
      rgba_ptr= rgba+y*bitmapInfo->bmiHeader.biWidth*4;
      
      for( x=0 ; x<bitmapInfo->bmiHeader.biWidth ; x++, rgb_ptr+=3, rgba_ptr+=4 )
      {
         rgba_ptr[0]=rgb_ptr[0];
         rgba_ptr[1]=rgb_ptr[1];
         rgba_ptr[2]=rgb_ptr[2];
         rgba_ptr[3]=0x70;//透明值
      }
   }
   free(rgb);
   return rgba;
}


"Itachi.bmp"跟上一篇的一樣是512*512的24bit點陣圖



我在書上看到這行令我不解的code

length = (bitmapInfo->bmiHeader.biWidth*3+3)&~3;

bitmapInfo->bmiHeader.biWidth只是bmp的寬
我搞不懂"&"和"~"在這裡的意義
希望有人給我解惑,講一下那兩個運算怎麼用

這行code執行出來的結果沒有問題
我因為看不懂就照自己的意思寫別的代替
結果也正常,執行出來的結果一樣

實在看不出上面那行究竟做了什麼(我自己寫的沒比較長)


還是零分 在 2011-8-24, PM 4:26 星期三 作了第 1 次修改
回頂端
檢視會員個人資料 發送私人訊息 參觀發表人的個人網站
babu61509
散播福音的祭司


註冊時間: 2007-08-26
文章: 142

681.01 果凍幣

發表發表於: 2008-7-10, PM 6:34 星期四    文章主題: 引言回覆

& 是指 用二進位的 AND 運算
~ 是指 求二進位的一的補數( 1 和 0 交換就對了)

--------------------------------------------------------------------------------

稍微想了一下 (應該沒有錯吧= =?)
因為 ~ 優先還滿高的 所以會變成

(bitmapInfo->bmiHeader.biWidth*3+3)
AND
11111111 11111111 11111111 11111100 (假設是INT型別,現在大部分都是4 Bytes)

這樣出來的值會是 4 的倍數,就是 小於 (bitmapInfo->bmiHeader.biWidth*3+3) 裡最大的 4 倍數值.

(應該是用來對應bmp的資料 ? bmp好像是4個位元組一組?)

還沒仔細看程式碼,不知道為什麼這樣做 (打

---------------------------------------------------------------------------------

參考資料
http://zh.wikipedia.org/wiki/C%E5%92%8CC%2B%2B%E9%81%8B%E7%AE%97%E5%AD%90

_________________
已經畢業了!!
回頂端
檢視會員個人資料 發送私人訊息
還是零分
散播福音的祭司


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

653.83 果凍幣

發表發表於: 2008-7-10, PM 9:39 星期四    文章主題: 引言回覆

babu61509 寫到:
& 是指 用二進位的 AND 運算
~ 是指 求二進位的一的補數( 1 和 0 交換就對了)

--------------------------------------------------------------------------------

稍微想了一下 (應該沒有錯吧= =?)
因為 ~ 優先還滿高的 所以會變成

(bitmapInfo->bmiHeader.biWidth*3+3)
AND
11111111 11111111 11111111 11111100 (假設是INT型別,現在大部分都是4 Bytes)

這樣出來的值會是 4 的倍數,就是 小於 (bitmapInfo->bmiHeader.biWidth*3+3) 裡最大的 4 倍數值.

(應該是用來對應bmp的資料 ? bmp好像是4個位元組一組?)

還沒仔細看程式碼,不知道為什麼這樣做 (打

---------------------------------------------------------------------------------

參考資料
http://zh.wikipedia.org/wiki/C%E5%92%8CC%2B%2B%E9%81%8B%E7%AE%97%E5%AD%90

謝啦!! Very Happy

那行程式碼是從OpenGL超級手冊上看到的
看來目的只是確保圖片的寬度至少是4的倍數

唉~
基礎沒打好

p.s.
bmp是3個位元組一組
回頂端
檢視會員個人資料 發送私人訊息 參觀發表人的個人網站
從之前的文章開始顯示:   
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 遊戲程式高級班:DirectX、OpenGL及各種圖型函式庫 所有的時間均為 台灣時間 (GMT + 8 小時)
1頁(共1頁)

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


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