還是零分 散播福音的祭司
註冊時間: 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 次修改 |
|