討論區快速選單
知識庫快速選單
程式設計俱樂部Facebook粉絲團 最新Microsoft免費研討會行事曆
[ 回上頁 ] [ 討論區發言規則 ]
glut 教學 - 把我的圖放到視窗上!! (進階)
更改我的閱讀文章字型大小
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2079 | 人氣 89850 | 評價 9950 | 評價/貼文 4.79 | 送出評價 78 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/15 上午 12:54:36
其實我真的不是很鼓勵單純用平面貼圖來併湊功能的, 但是, 網友們總是想要這個, 好吧, 這一次就把正確的做法完完整整的講述一次, 所謂正確, 就是把圖檔上載到顯示卡成 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

作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2079 | 人氣 89850 | 評價 9950 | 評價/貼文 4.79 | 送出評價 78 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/15 上午 12:57:18
/////////////////////////
// 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 );
}

作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2079 | 人氣 89850 | 評價 9950 | 評價/貼文 4.79 | 送出評價 78 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/15 上午 01:04:35
這個程式的功能其實是很簡單的, 它會讀取一個叫 a.bmp 的檔案, 把它上載到顯示卡成 texture, 然後繪圖長方形做貼圖. 在執行時, 使用者可以用 加號鍵/減號鍵 去把圖像 放大/縮小.
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2079 | 人氣 89850 | 評價 9950 | 評價/貼文 4.79 | 送出評價 78 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/15 上午 01:30:26
讀取圖檔 和 上載至顯示卡 的工序, 都是在 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 );




作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2079 | 人氣 89850 | 評價 9950 | 評價/貼文 4.79 | 送出評價 78 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/15 上午 02:04:02
得到 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 );
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2079 | 人氣 89850 | 評價 9950 | 評價/貼文 4.79 | 送出評價 78 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/15 上午 02:26:50
在實際繪畫時, 我們需要先 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 );

  //...

}
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2079 | 人氣 89850 | 評價 9950 | 評價/貼文 4.79 | 送出評價 78 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/15 上午 02:45:41
雖然說了很多很多東西, 可是, 關於 texture 的應用, 只是冰山一小角而已.

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

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


最後... 如果你完成了這個功課, 就在這簽個名吧, 謝謝.
作者 : geolin(90)
[ 貼文 15 | 人氣 3076 | 評價 20 | 評價/貼文 1.33 | 送出評價 2 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/3/14 上午 10:40:48
我試過了...
圖好像會變成馬賽克吧...
作者 : hfuman(王子麵)
[ 貼文 17 | 人氣 2829 | 評價 0 | 評價/貼文 0 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/12/15 上午 09:50:10
不知道為什麼
出現了錯誤
 error LNK2001: unresolved external symbol ___glutCreateWindowWithExit@8
Debug/g_bmp.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

作者 : hfuman(王子麵)
[ 貼文 17 | 人氣 2829 | 評價 0 | 評價/貼文 0 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/12/15 上午 09:50:22
不知道為什麼
出現了錯誤
 error LNK2001: unresolved external symbol ___glutCreateWindowWithExit@8
Debug/g_bmp.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

作者 : ada10390(流羽)
[ 貼文 1 | 人氣 0 | 評價 0 | 評價/貼文 0 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/6/18 下午 06:42:32
終於成功了∼!
大大教的程式寫出來囉∼
小弟是個剛接觸程式語言的新手。
在大學修到OPENGL這東東,實在很多疑惑=.=
拜讀大大文章至此,覺得教的真的很詳盡,(我跟電腦白癡只有一線之隔>"<)
感謝教導
...繼續了解如何應用去!



作者 : uranus0206(uranus)
[ 貼文 2 | 人氣 582 | 評價 0 | 評價/貼文 0 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/6/23 上午 02:52:56
請問,我是在Linux上使用OpenGL

我把程式碼以及g_bmp.h , g_bmp.c , glutTest01.c , 圖檔
都放在一個資料夾裡
然後下了指令...結果出現以下錯誤:

g++ -o test test.c -lm -lGL -lglut

在包含自 test.c:6 的檔案中:
g_bmp.c:64:21: 警告: 多位元組字元常數
g_bmp.c:149:18: 警告: 多位元組字元常數
g_bmp.c:34: 警告: 「#pragma pack(pop[, id])」 格式錯誤 - 已忽略
glutTest01.c:9: 錯誤: 「::main」 必須回傳 「int」
test.c:18: 錯誤: 「::main」 必須回傳 「int」
test.c: In function 「int main()」:
test.c:18: 錯誤: redefinition of 「int main()」
glutTest01.c:9: 錯誤: 「int main()」 已在此定義過
test.c: In function 「void prepare_tex0(const char*)」:
test.c:84: 警告: 將 「float」 做為引數 1 傳遞給 「void GBmp::load(int, int)」
test.c:84: 警告: 將 「float」 做為引數 2 傳遞給 「void GBmp::load(int, int)」

怎麼辦...難道真的就沒辦法讀圖檔嗎?
作者 : dorkas(aming) VC++優秀好手遊戲程式設計卓越專家DirectX頂尖高手C++優秀好手貼文超過2000則
[ 貼文 2625 | 人氣 4536 | 評價 11810 | 評價/貼文 4.5 | 送出評價 2 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2007/6/23 上午 09:31:54

>請問,我是在Linux上使用OpenGL
>
>我把程式碼以及g_bmp.h , g_bmp.c , glutTest01.c , 圖檔
>都放在一個資料夾裡
>然後下了指令...結果出現以下錯誤:
>
>g++ -o test test.c -lm -lGL -lglut
>
>在包含自 test.c:6 的檔案中:
>g_bmp.c:64:21: 警告: 多位元組字元常數
>g_bmp.c:149:18: 警告: 多位元組字元常數

//中文註解後要用 "." 結尾.

>g_bmp.c:34: 警告: 「#pragma pack(pop[, id])」 格式錯誤 - 已忽略

vc的指令 g++不適用


>glutTest01.c:9: 錯誤: 「::main」 必須回傳 「int」
>test.c:18: 錯誤: 「::main」 必須回傳 「int」
>test.c: In function 「int main()」:
>test.c:18: 錯誤: redefinition of 「int main()」
>glutTest01.c:9: 錯誤: 「int main()」 已在此定義過

要符合 int main()的規定 void main ()用法不適用新的c標準
改成
int main()
{
....
return 0;// keep complie happy
}

>test.c: In function 「void prepare_tex0(const char*)」:
>test.c:84: 警告: 將 「float」 做為引數 1 傳遞給 「void GBmp::load(int, int)」
>test.c:84: 警告: 將 「float」 做為引數 2 傳遞給 「void GBmp::load(int, int)」
>怎麼辦...難道真的就沒辦法讀圖檔嗎?

 tmp.load( (int)tw,(int) th );


不過我認為你副檔名 改成.cpp比較好一點.c 不能用到 oo功能
很明顯 GBmp 是個物件




 板主 : 白老鼠(Gary)
 > OpenGL - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - OpenGL - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
OpenGL
1 白老鼠(Gary) 2680 
2 CROMAYEN2000 1530 
3 aming 500 
4 東昇 380 
5 PLAYER 120 
6 富伯 110 
7 qq 100 
8 NDark 80 
9 ozzy 60 
10 simula 60 
OpenGL
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2014 程式設計俱樂部 http://www.programmer-club.com.tw/
0.1411133