|
電腦遊戲製作開發設計論壇 任何可以在PC上跑的遊戲都可以討論,主要以遊戲之製作開發為主軸,希望讓台灣的遊戲人有個討論、交流、教學、經驗傳承的園地
|
上一篇主題 :: 下一篇主題 |
發表人 |
內容 |
還是零分 散播福音的祭司
註冊時間: 2007-09-19 文章: 164
653.83 果凍幣
|
發表於: 2008-7-4, AM 12:36 星期五 文章主題: OpenGL入門教學(06) |
|
|
這篇的新內容是材質貼圖
既然是材質貼圖當然要載入圖檔了
而我只會載入BMP點陣圖而已,因為這夠普遍,資料結構又簡單
下面提供的範例會載入一張名為"Itachi"的BMP點陣圖,長寬是512×512
它的長寬都是2的n次方,這是OpenGL的規矩(規矩有辦法可以破例,但還是不要違反的好)
這個範例的目的只有載入一張圖片而已,然後根據材質座標貼到四邊形上面
裡頭那個能載入BMP點陣圖的副程式LoadBitmapFile()裡頭的資料結構需要標入windows.h和wingdi.h
沒有的話就要自己生一個結構出來,幸好VC++和DevC++都有!好家在
LoadBitmapFile()會先載入圖片,之後將bmp圖的BGR順序改為RGB
這樣glTexImage2D()的第七個參數才能填"GL_RGB"
要是BGR順序不改,就要用擴充功能"GL_BGR_EXT"取代"GL_RGB"
VC++可以使用"GL_BGR_EXT"
可惜DevC++的GL函式庫沒有這個擴充功能
"GL_BGR_EXT"和"GL_BGRA_EXT"在OpenGL1.2中為標準格式"GL_BGR"和"GL_BGRA"
微軟提供的GL函式庫還停在1.1吧
為避免又遇到格式問題
非RGB格式的圖檔統一都先改成RGB順序再交給glTexImage2D()
將BGR轉成RGB的這動作其實還蠻實用的
下一篇還會把RGB改成RGBA,使用bmp圖檔沒提供的透明色
//------glTexImage2D( GL_TEXTURE_2D , level , component , 圖片寬度 , 圖片高度 , border , GL_RGB , GL_UNSIGNED_BYTE , image );
//
//這個函式能將圖檔讀進顯示卡的記憶體
//有9個參數
//第一個參數幾乎是內定的了,有興趣就去OpenGL官網查吧
//
//level:目前設為零,下下篇使用到多解析度材質時會用到,level是其他解析度材質的編號
//component:填1、2、3、4其中一個數字的話代表在RGBA四個顏色中你用到幾個顏色,真正決定用色的是第七個參數
//border:上面講到圖檔長寬都必須是2的n次方,要破例也行,改成滿足"2的n次方再加上兩倍border"就好了,border是正整數
//image:是個陣列指標,陣列內容就是圖檔,陣列的資料型態由第八個參數決定
//------glTexCoord2f( s , t );
//
//設定材質座標
//載入的圖就擠在材質座標系的(0,0)(1,0)(0,1)(1,1)四個點圍成的四邊形上
//藉由設定材質座標,你能擷取圖片的某部分來使用(所以glTexImage2D()的border真的不需要用)
//如果你設定的材質座標超過那四個點的範圍的話,並沒有關係
//OpenGL會使用圖片的內容來補齊,補齊的方法要用glTexParameteri()來設定
//------glTexParameteri(GL_TEXTURE_2D, pname , param );
//
//第一個參數使用和glTexImage2D()相同的
//
//第二個參數是"GL_TEXTURE_MAG_FILTER"的話,表示要決定圖片放大時的處理(按'w'鍵拉近圖片時)
//處理方法用第三個參數決定,第三個參數有兩個可選
//GL_NEAREST:採用位置靠近的顏色來處理,放大效果像馬賽克,一般看圖程式也是這麼做,效率好又誠實
//GL_LINEAR:用線性內插法處理,比較耗運算資源,放大後就有點模糊感,這個做法比較適合遊戲
//
//
//第二個參數如果是用"GL_TEXTURE_MIN_FILTER"的話,則是表示要決定圖片縮小時的處理
//處理方法用第三個參數決定,一樣有"GL_NEAREST","GL_LINEAR"兩個可選
//除了那兩個之外,縮小時的處理還有其他方法可選,不過那是多解析度材質的選項了,下下篇再講
//
//
//第二個參數如果是用"GL_TEXTURE_WRAP_S"和"GL_TEXTURE_WRAP_T"的話
//就是上面glTexCoord2f()提到的補齊方法的設定
//S和T就是材質座標的s軸和t軸(想成x軸y軸就行了)
//相對應的第三個參數可以選"GL_CLAMP"和"GL_REPEAT"
//使用效果請自行品嘗
範例碼很長
代碼: |
//-----------------------------------------------------------------------------
// 2008/7/3
// Texture
// 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圖檔讀入
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軸當旋轉軸
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();
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; //得到圖案,是能直接讓OpenGL使用的資料了
BITMAPINFO bmpinfo; //用來存放HEADER資訊
image = LoadBitmapFile("Itachi.bmp", &bmpinfo);
width = bmpinfo.bmiHeader.biWidth;
height = bmpinfo.bmiHeader.biHeight;
glTexImage2D(GL_TEXTURE_2D,0,3,width,height,0,GL_RGB,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_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
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;
}
|
範例裡的"Itachi.bmp"是張512*512的24bit點陣圖
自己隨便拿張圖來用吧
讀取bmp圖的code短短的
所以也不怎麼完整
也許你儲存時選了某選項會超出LoadBitmapFile()能處理的範圍
當我使用Paint.net時就有出過這種問題
還是零分 在 2011-8-24, PM 4:15 星期三 作了第 4 次修改 |
|
回頂端 |
|
|
半路 對這略感興趣的新人
註冊時間: 2008-02-05 文章: 21
41.07 果凍幣
|
發表於: 2008-7-4, AM 10:24 星期五 文章主題: |
|
|
滿用心的教學文章~
推一下! |
|
回頂端 |
|
|
還是零分 散播福音的祭司
註冊時間: 2007-09-19 文章: 164
653.83 果凍幣
|
發表於: 2008-7-4, PM 12:40 星期五 文章主題: |
|
|
半路 寫到: | 滿用心的教學文章~
推一下! |
謝謝!! |
|
回頂端 |
|
|
k387259 稍嫌羞澀的路人
註冊時間: 2009-04-07 文章: 2
14.00 果凍幣
|
發表於: 2009-4-7, PM 2:57 星期二 文章主題: 讀取不到 |
|
|
image = LoadBitmapFile("Itachi.bmp", &bmpinfo);
讀取不到圖片
我用Dev C+專案開啟你的程式碼 編譯之後
會出現錯誤...
你有MSN或者及時通東西能夠及時問你嗎!?
很想學OPENGL |
|
回頂端 |
|
|
還是零分 散播福音的祭司
註冊時間: 2007-09-19 文章: 164
653.83 果凍幣
|
發表於: 2009-4-8, PM 11:21 星期三 文章主題: Re: 讀取不到 |
|
|
k387259 寫到: | image = LoadBitmapFile("Itachi.bmp", &bmpinfo);
讀取不到圖片
我用Dev C+專案開啟你的程式碼 編譯之後
會出現錯誤...
你有MSN或者及時通東西能夠及時問你嗎!?
很想學OPENGL |
我猜編譯錯誤的原因是出在glut的package上吧?
你有裝glut的package嗎?
glut的package不只一個版本
"http://freeglut.sourceforge.net/"有一個
"http://www.xmission.com/"也有
"http://www.openglut.org/"我程式碼是用這個
以至於標頭檔是
#include <GL\openglut.h>
你若是使用xmission提供的package的話
改成"#include <GL\glut.h>"應該就正常了 |
|
回頂端 |
|
|
k387259 稍嫌羞澀的路人
註冊時間: 2009-04-07 文章: 2
14.00 果凍幣
|
發表於: 2009-4-28, PM 9:38 星期二 文章主題: |
|
|
不知道您有沒有可能寫
Direct3D入門教學(01)呢
我很想學Direct3D看看
雖然跟openGL差不多...
希望你能寫出來@@你講的都很詳細 |
|
回頂端 |
|
|
還是零分 散播福音的祭司
註冊時間: 2007-09-19 文章: 164
653.83 果凍幣
|
發表於: 2009-4-30, PM 10:47 星期四 文章主題: |
|
|
k387259 寫到: | 不知道您有沒有可能寫
Direct3D入門教學(01)呢
我很想學Direct3D看看
雖然跟openGL差不多...
希望你能寫出來@@你講的都很詳細 |
我不會Direct3D...sorry
其實版上早有D3D的教學了(npcgamer)
不過尚未出現有系統連貫的教學
就算有人願意寫
D3D恐怕教起來費力,學起來也費力吧 |
|
回頂端 |
|
|
jashilk16 偶而上來逛逛的過客
註冊時間: 2009-07-20 文章: 7
68.05 果凍幣
|
發表於: 2009-7-20, PM 3:29 星期一 文章主題: |
|
|
內容十分精采。
感謝您的分享! |
|
回頂端 |
|
|
pigtwoyes 稍嫌羞澀的路人
註冊時間: 2009-12-29 文章: 1
6.75 果凍幣
|
發表於: 2009-12-29, PM 10:48 星期二 文章主題: |
|
|
謝謝,你的解說很詳細,最近剛在學習opengl,看到你的教學受益良多,
不過檔案好像連結錯誤,無法下載,
不知道是否可以修改呢 |
|
回頂端 |
|
|
還是零分 散播福音的祭司
註冊時間: 2007-09-19 文章: 164
653.83 果凍幣
|
發表於: 2010-1-16, PM 8:06 星期六 文章主題: |
|
|
pigtwoyes 寫到: | 謝謝,你的解說很詳細,最近剛在學習opengl,看到你的教學受益良多,
不過檔案好像連結錯誤,無法下載,
不知道是否可以修改呢 |
好像是免空終於倒了...
這些教學是大學時寫的了
我現在人在外島當兵
實在沒什麼心思再搞這個了
初學OpenGL去nehe已經很夠了
我的教學很鳥
不用看了
我記得有本名字叫"3D遊戲程式設計/基礎篇"的入門書還不錯
在程設俱樂部的OpenGL區頗受好評
http://janusbooks.myweb.hinet.net/
這本書教的少但是觀念清楚易懂 |
|
回頂端 |
|
|
vladdracula 稍嫌羞澀的路人
註冊時間: 2011-08-22 文章: 1
34.15 果凍幣
|
發表於: 2011-8-22, PM 10:43 星期一 文章主題: |
|
|
請問有沒有朋友可以發第六章起的source code給我呀
我用VS2010 上邊不完整的source code ...
代碼: | #include "stdafx.h"
#include "wingdi.h"
#include "windows.h"
#include "stdio.h"
#include <stdlib.h>
#include <GL\glut.h>//使用DevC++的話要改為標入 #include <GL\openglut.h>
void texture(void)
{
int width;
int height;
unsigned char *image; //得到圖案,已經不是BMP圖了,是能直接讓OpenGL使用的資料了
BITMAPINFO bmpinfo; //用來存放HEADER資訊
image = LoadBitmapFile("c:\\Itachi.bmp", &bmpinfo);
width = bmpinfo.bmiHeader.biWidth;
height = bmpinfo.bmiHeader.biHeight;
glTexImage2D(GL_TEXTURE_2D,0,3,width,height,0,GL_RGB,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_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
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;
}
int main()
{
return 0;
} |
[/code] |
|
回頂端 |
|
|
還是零分 散播福音的祭司
註冊時間: 2007-09-19 文章: 164
653.83 果凍幣
|
發表於: 2011-8-24, PM 4:18 星期三 文章主題: |
|
|
>>vladdracula
code完整貼出來了 |
|
回頂端 |
|
|
junyuan 稍嫌羞澀的路人
註冊時間: 2012-05-13 文章: 2
17.15 果凍幣
|
發表於: 2012-5-13, PM 4:42 星期日 文章主題: help~ |
|
|
請問我出現了"於 0x00412538 的 Sample4.exe 中第一個可能發生的例外狀況: 0xC0000005: 讀取位置 0x003f9000 時發生存取違規
於 0x00412538 的 Sample4.exe 中發生未處理的例外狀況: 0xC0000005: 讀取位置 0x003f9000 時發生存取違規"這種狀況,是否是在RGB交換那邊出錯??
我一樣是自己用一個512*512pixel的BMP圖檔
不知道版大能不能幫我解答。 |
|
回頂端 |
|
|
還是零分 散播福音的祭司
註冊時間: 2007-09-19 文章: 164
653.83 果凍幣
|
發表於: 2012-5-18, PM 10:15 星期五 文章主題: |
|
|
>>junyuan
聽起來是讀取超出範圍的陣列元素
讀取陣列元素的地方最好設一些訊息在超出範圍時跳出來以方便除錯
副檔名同樣是bmp也有可能格式不同
如果圖片是用小畫家存成24位元那就不是格式問題(範例只針對讀取這種bmp)
你只是想寫遊戲嗎?
那麼去找個引擎會快非常多 |
|
回頂端 |
|
|
junyuan 稍嫌羞澀的路人
註冊時間: 2012-05-13 文章: 2
17.15 果凍幣
|
發表於: 2012-5-19, AM 1:23 星期六 文章主題: |
|
|
還是零分 寫到: | >>junyuan
聽起來是讀取超出範圍的陣列元素
讀取陣列元素的地方最好設一些訊息在超出範圍時跳出來以方便除錯
副檔名同樣是bmp也有可能格式不同
如果圖片是用小畫家存成24位元那就不是格式問題(範例只針對讀取這種bmp)
你只是想寫遊戲嗎?
那麼去找個引擎會快非常多 |
因為期末要做一個專題,要載入3D模型然後貼材質,發現opengl所有上圖方法都是用texture的方式,不是單純的載入就好,所以有點麻煩,現在是想要先載入背景,但還是要用texture嗎,還是大大有更好的方法直接載入? |
|
回頂端 |
|
|
|
|
您 無法 在這個版面發表文章 您 無法 在這個版面回覆文章 您 無法 在這個版面編輯文章 您 無法 在這個版面刪除文章 您 無法 在這個版面進行投票 您 可以 在這個版面附加檔案 您 可以 在這個版面下載檔案
|
|