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

Google
[轉貼自程式設計俱樂部]glut 教學 - 把我的圖放到視窗上!! (進階)

 
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 遊戲程式高級班:DirectX、OpenGL及各種圖型函式庫
上一篇主題 :: 下一篇主題  
發表人 內容
satanupup
喜歡上這裡的冒險者


註冊時間: 2007-05-29
文章: 80

68.10 果凍幣

發表發表於: 2007-6-28, PM 2:14 星期四    文章主題: [轉貼自程式設計俱樂部]glut 教學 - 把我的圖放到視窗上!! (進階) 引言回覆

作者 : ma_hty(白老鼠(Gary))
其實我真的不是很鼓勵單純用平面貼圖來併湊功能的, 但是, 網友們總是想要這個, 好吧, 這一次就把正確的做法完完整整的講述一次, 所謂正確, 就是把圖檔上載到顯示卡成 texture, 然後繪圖長方形做貼圖.

之前也有兩課平面貼圖的範例, 但是, 那個只是容易了解, 而完全得不到 顯示卡 的強勁計算功能的好處的.

好, 差不多了, 我們去寫程式吧.

這一個範例, 會用到 "glut 教學 - 讀取 bmp圖檔" 的 g_bmp.h 和 g_bmp.cpp, 這兩個檔案的原碼可以在以下連結找到的.

http://www.programmer-club.com/pc2020v5/Forum/ShowSameTitleN.asp?URL=N&board_pc2020=opengl&id=774
------------------------------
/////////////////////////
// glutTest09.cpp
//
// Created by Gary Ho, ma_hty@hotmail.com, 2005
//
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "glut.h"

#include "g_bmp.h"

float sw, sh;
float tw, th;
GLuint tex0 = 0;
float szoom = 1;

void prepare_tex0( const char *spath );
void display();
void keyboard( unsigned char key, int x, int y );

void main()
{
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB );
glutInitWindowSize( 512, 512 );
glutCreateWindow( "glutTest09" );

glutDisplayFunc(display);
glutKeyboardFunc(keyboard);

prepare_tex0( "a.bmp" );

glutMainLoop();
}

void keyboard( unsigned char key, int x, int y )
{
switch( key )
{
case '+':
case '=':
szoom += .05;
glutPostRedisplay();
break;
case '_':
case '-':
szoom -= .05;
glutPostRedisplay();
break;
}
}

void display()
{
float w0, h0;
float w1, h1;
w0 = sw / glutGet(GLUT_WINDOW_WIDTH) * szoom;
h0 = sh / glutGet(GLUT_WINDOW_HEIGHT) * szoom;
w1 = sw / tw;
h1 = sh / th;

glClear( GL_COLOR_BUFFER_BIT );

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glScalef( szoom, szoom, 1 );
glBindTexture( GL_TEXTURE_2D, tex0 );
glEnable( GL_TEXTURE_2D );
glBegin( GL_QUADS );
glTexCoord2f( 0, 0 ); glVertex2f(-w0,-h0);
glTexCoord2f( w1, 0 ); glVertex2f( w0,-h0);
glTexCoord2f( w1, h1 ); glVertex2f( w0, h0);
glTexCoord2f( 0, h1 ); glVertex2f(-w0, h0);
glEnd();
glDisable( GL_TEXTURE_2D );
glutSwapBuffers();
}

void prepare_tex0( const char *spath )
{
GBmp bmp;
bmp.load( spath );
sw = bmp.w;
sh = bmp.h;

GBmp tmp;
tw = pow( 2, ceil(log(bmp.w-1)/log(2)) );
th = pow( 2, ceil(log(bmp.h-1)/log(2)) );
tmp.load( tw, th );
for( int j=0; j<bmp.h; j++ )
memcpy( &tmp.rgb[j*tmp.w*3], &bmp.rgb[j*bmp.w*3], bmp.w*3 );

glGenTextures( 1, &tex0 );
glBindTexture( GL_TEXTURE_2D, tex0 );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, tmp.w, tmp.h, 0, GL_RGB, GL_UNSIGNED_BYTE, tmp.rgb );
}

----------------------------
這個程式的功能其實是很簡單的, 它會讀取一個叫 a.bmp 的檔案, 把它上載到顯示卡成 texture, 然後繪圖長方形做貼圖. 在執行時, 使用者可以用 加號鍵/減號鍵 去把圖像 放大/縮小.
------------------------
讀取圖檔 和 上載至顯示卡 的工序, 都是在 prepare_tex0() 這個函式完成的.

texture, 這一件工具有很多仔細的設定的, 這些設定的關係 千絲百結 環環相扣, 需要你全都正確的設定, 才能達到預祈的效果. 大概, 這也是為什麼初學者們對它敬而遠之... ...

第一個 texture 設定問題, 就是 2^n 長闊, 就是說, 每 texture 的長和闊, 都必須要能被寫成 2 的次方, 較新的顯示卡, 已經於硬體的層次除掉這個限制, 但是, 我們是不能夠依賴這個的, 因為有這個限制的低檔顯示卡還是佔多數.

一般的圖檔, 大概也不會是 2^n 長闊 吧, 因此, 我們就只好多佔一點空間, 把圖檔先貼在另一較大的 2^n 長闊圖檔上, 然後才再上載到顯示卡.

以下的就是廣大圖檔至最接近 2^n 長闊的工序,

GBmp tmp;
tw = pow( 2, ceil(log(bmp.w-1)/log(2)) );
th = pow( 2, ceil(log(bmp.h-1)/log(2)) );
tmp.load( tw, th );
for( int j=0; j<bmp.h; j++ )
memcpy( &tmp.rgb[j*tmp.w*3], &bmp.rgb[j*bmp.w*3], bmp.w*3 );

---------------------------
得到 2^n 長閣圖檔後, 我們就可以把它上載到顯示卡,

// 指令 OpenGL 建立一個新的 texture, 並把索引值存到 tex0
glGenTextures( 1, &tex0 );

// 把 tex0 連結到 GL_TEXTURE_2D
//
// 這個工序, 很多初學者都會很疑惑, 或者, 我仔細的解釋一下,
// 在 OpenGL 控制 texture 做任何動作, 也必須要透過預定
// 好的 texture target, 你可以指令 OpenGL 建立很多 texture
// 但是 texture target 只有幾個而已, 因此, 我們只好每次控
// 制texture 之先, 把需要的 texture 索引值 連結到相關的
// texture target.
// 好的習慣, 連結的步驟應該在每一次使用前做的, 因為, 其
// 它工序也可能會用到同一個 texture target.
glBindTexture( GL_TEXTURE_2D, tex0 );

// 設定 放大/縮小 取值方法
//
// 這個比較抽象, 舉例說, 我有一個 16 x 16 的圖檔, 在畫面放大
// 了 3倍 的顯示, 這麼, 多出了這麼多的像素, 應該如果填上資料呢???
// 最直接的方法, 放大圖的每像素根據位置找尋在原圖最接近的像素.
// ( 即 GL_NEAREST ). 但是, 這個取值方法不太好, 因為放大圖
// 會有很多清晰可見的方格. 這個範例用 GL_LINEAR 作取值方法,
// 這個比起 GL_NEAREST 好很多的.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

// 界外處理
// 這個沒什麼特別了, 意思就是, 如果 貼圖座標 在 texture 之外,
// 應該如何處理.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

// 上載圖檔資料
// ( ~~" 終於可以上載了... ... )
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, tmp.w, tmp.h, 0, GL_RGB, GL_UNSIGNED_BYTE, tmp.rgb );

-----------------------
在實際繪畫時, 我們需要先 bind 和 enable texture target. 然後只需要如常畫形狀, 不過, 每 頂點 都加上 貼圖座標.

顯示卡的記憶體, 不僅是很有限, 而且是全系統共用的, 因此, 你上載了的 texture, 並不一定在顯示卡記憶體的, 顯示卡記憶體管理, 都是由 OpenGL 代理的, 對於一般編程人員, 最多只能提供最好的資料給 OpenGL, 然後, 祈禱求神沒有問題 ( 寫程式的人, 真的要對神有很大的信心... ).

提供最好的資料的意思, 就是當你真的需要用某 texture 時才說要用 ( 即 glEnable( GL_TEXTURE_2D ) ) , 用完了就馬上說 用完了 ( 即 glDisable( GL_TEXTURE_2D ) ).


void display()
{
// 運算對應視窗大小的 頂點座標 和 貼圖座標
float w0, h0;
float w1, h1;
w0 = sw / glutGet(GLUT_WINDOW_WIDTH) * szoom;
h0 = sh / glutGet(GLUT_WINDOW_HEIGHT) * szoom;
w1 = sw / tw;
h1 = sh / th;

//...

// 連結 tex0 到 GL_TEXTURE_2D
glBindTexture( GL_TEXTURE_2D, tex0 );

// 指令 OpenGL 使用 GL_TEXTURE_2D
glEnable( GL_TEXTURE_2D );

// 繪圖一四邊形, 並補上相應的 貼圖座標
glBegin( GL_QUADS );
glTexCoord2f( 0, 0 ); glVertex2f(-w0,-h0);
glTexCoord2f( w1, 0 ); glVertex2f( w0,-h0);
glTexCoord2f( w1, h1 ); glVertex2f( w0, h0);
glTexCoord2f( 0, h1 ); glVertex2f(-w0, h0);
glEnd();

// 指令 OpenGL 不使用 GL_TEXTURE_2D
glDisable( GL_TEXTURE_2D );

//...

}

--------------------------------
雖然說了很多很多東西, 可是, 關於 texture 的應用, 只是冰山一小角而已.

先勉勵一下初學者們, texture 這件複雜的工具, 無疑要花很多時間才能夠掌握, 不過, 這個時間投資, 絕對將會是值回票價的.

這一次, 也做一點功課吧, 上面用的取值方法, 是 GL_LINEAR, 把它改成 GL_NEAREST, 然後把圖放大, 看看有何分別.


最後... 如果你完成了這個功課, 就在這簽個名吧, 謝謝.
回頂端
檢視會員個人資料 發送私人訊息
kkman2006
稍嫌羞澀的路人


註冊時間: 2007-11-15
文章: 1

0.00 果凍幣

發表發表於: 2007-11-15, AM 9:50 星期四    文章主題: 引言回覆

請問如果想在一個圓柱體或一個圓上貼圖, 那應該怎麼辦?

請大大赐教~
回頂端
檢視會員個人資料 發送私人訊息
還是零分
散播福音的祭司


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

653.83 果凍幣

發表發表於: 2007-11-17, AM 12:04 星期六    文章主題: 引言回覆

是像這樣嗎?

一顆球的模型
可以用滑鼠轉動

這是用glut寫的
貼圖用LithUnwrap貼的
從程式裡設定貼圖座標會瘋掉吧


感覺在XP上用openGL寫遊戲會很麻煩
後來就沒碰了
但我對directX卻也不得其門而入
回頂端
檢視會員個人資料 發送私人訊息 參觀發表人的個人網站
從之前的文章開始顯示:   
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 遊戲程式高級班:DirectX、OpenGL及各種圖型函式庫 所有的時間均為 台灣時間 (GMT + 8 小時)
1頁(共1頁)

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


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