亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Qt下的OpenGL 編程紋理和貼圖

發布時間:2020-07-03 21:02:09 來源:網絡 閱讀:1106 作者:WZM3558862 欄目:開發技術

 

Qt下的OpenGL 編程紋理和貼圖





二、openGL坐標系

     OpenGL使用右手坐標,從左到右,x遞增,從下到上,y遞增,從遠到近,z遞增。
     OpenGL坐標系可分為:世界坐標系和當前繪圖坐標系。

     世界坐標系以屏幕中心為原點(0, 0, 0)。你面對屏幕,你的右邊是x正軸,上面是y正軸,屏幕指向你的為z正軸。長度單位這樣來定: 窗口范圍按此單位恰好是(-1,-1)到(1,1)。

      當前繪圖坐標系是 繪制物體時的坐標系。程序剛初始化時,世界坐標系和當前繪圖坐標系是重合的。當用glTranslatef(),glScalef(), glRotatef()對當前繪圖坐標系進行平移、伸縮、旋轉變換之后, 世界坐標系和當前繪圖坐標系不再重合。改變以后,再用glVertex3f()等繪圖函數繪圖時,都是在當前繪圖坐標系進行繪圖,所有的函數參數也都是相 對當前繪圖坐標系來講的。


三、繪制一個三角錐和正方體
    繪制三角錐的方法就是在空間中連續地繪制四個三角形,最后形成一個封閉的體。
    修改void NeHeWidget::paintGL()。

[cpp] view plain copy Qt下的OpenGL 編程紋理和貼圖Qt下的OpenGL 編程紋理和貼圖

  1. void NeHeWidget::paintGL()  

  2. {  

  3.     // 清除屏幕和深度緩存  

  4.     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );  

  5.     glLoadIdentity();  

  6.     //移到屏幕的左半部分,并且將視圖推入屏幕背后足夠的距離以便我們可以看見全部的場景  

  7.     glTranslatef(-1.0f,0.0f,-6.0f);  

  8.     glRotatef(rTri,1.0,0,0);  

  9.     glBegin( GL_TRIANGLE_STRIP );  

  10.     glColor3f( 1.0, 0.0, 0.0 );  

  11.     glVertex3f(  0.0,  1.0,  0.0 );  

  12.     glColor3f( 0.0, 1.0, 0.0 );  

  13.     glVertex3f(-1.0, -1.0,  1.0 );  

  14.     glColor3f( 0.0, 0.0, 1.0 );  

  15.     glVertex3f(  1.0, -1.0,  1.0 );  

  16.     glColor3f( 0.0, 1.0, 0.0 );  

  17.     glVertex3f(  1.0, -1.0, -1.0 );  

  18.     glColor3f( 1.0, 0.0, 0.0 );  

  19.     glVertex3f(  0.0,  1.0,  0.0 );  

  20.     glColor3f( 0.0, 1.0, 0.0 );  

  21.     glVertex3f(-1.0, -1.0,  1.0 );  

  22.     glEnd();  

  23.     rTri+=2;  

  24. }  



   在寫代碼之前,最好在草稿紙上畫出三角錐的空間模型,算出每個點的坐標。這里,傳給glBegin的是GL_TRIANGLE_STRIP ,
    意思就是連續地繪制多個三角行,前兩個點就和第三個點組成三角形。
    所以一共畫四個面,定義了5個點,最后;兩個點和最開始的兩個點是重合的。
    因為在定義了每個頂點的顏色,所以最后每個面都有很漂亮的過度色。

    我們用同樣的思路來繪制一個正方體。這里傳給glBegin的參數是GL_QUAD_STRIP,意思就是連續地繪制正方形。

[cpp] view plain copy Qt下的OpenGL 編程紋理和貼圖Qt下的OpenGL 編程紋理和貼圖

  1. glLoadIdentity();  

  2. //移到屏幕的右半部分,并且將視圖推入屏幕背后足夠的距離以便我們可以看見全部的場景  

  3. glTranslatef(1.0f,0.0f,-6.0f);  

  4. glRotatef(rTri,1.0,0,0);  

  5. glBegin(GL_QUAD_STRIP);  

  6. //第一面  

  7. glColor3f( 1.0, 0.0, 0.0 );  

  8. glVertex3f(  0.0,  0.0,  0.0 );  

  9. glVertex3f(  0.0,  0.0,  1.0 );  

  10. glVertex3f(  1.0,  0.0,  0.0 );  

  11. glVertex3f(  1.0,  0.0,  1.0 );  

  12. //第二個 面  

  13. glColor3f( 0.0, 1.0, 0.0 );  

  14. glVertex3f(  1.0,  1.0,  0.0 );  

  15. glVertex3f(  1.0,  1.0,  1.0 );  

  16. //第三個面  

  17. glColor3f( 0.0, 0.0, 1.0 );  

  18. glVertex3f(  0.0,  1.0,  0.0 );  

  19. glVertex3f(  0.0,  1.0,  1.0 );  

  20. //第四個面  

  21. glColor3f( 1.0, 0.0, 0.0 );  

  22. glVertex3f(  0.0,  0.0,  0.0 );  

  23. glVertex3f(  0.0,  0.0,  1.0 );  

  24. glEnd();  

  25. //第五個和第六個面  

  26. glBegin(GL_QUADS);  

  27. glColor3f( 0.0, 0.8, 0.8 );  

  28. glVertex3f(0.0,1.0,1.0);  

  29. glVertex3f(0.0,0.0,1.0);  

  30. glVertex3f(1.0,0.0,1.0);  

  31. glVertex3f(1.0,1.0,1.0);  

  32. glVertex3f(0.0,1.0,0.0);  

  33. glVertex3f(0.0,0.0,0.0);  

  34. glVertex3f(1.0,0.0,0.0);  

  35. glVertex3f(1.0,1.0,0.0);  

  36. glEnd();  





代碼比較簡單,最后的效果如下圖:



注意所有的面都是逆時針次序繪制的。這點十分重要,這個和平面的正反面有關,以后應該會涉及到。所以要么都逆時針,要么都順時針,但永遠不要將兩種次序混在一起,除非您有足夠的理由必須這么做。


四、紋理映射
OpenGL紋理的使用分三步:將紋理裝入內存,將紋理發送給OpenGL管道,給頂點指定紋理坐標.
修改nehewidget.h:
首先加入裝載紋理的函數和幾個變量:

//加載紋理函數
void loadGLTextures();
//正方體在三個方向上的旋轉
GLfloat xRot, yRot, zRot;
//texture用來存儲紋理
GLuint texture[1];

在構造函數中加入對旋轉量的初始化:
xRot = yRot = zRot = 0.0;


接下來實現紋理裝載函數:

[cpp] view plain copy Qt下的OpenGL 編程紋理和貼圖Qt下的OpenGL 編程紋理和貼圖

  1. void NeHeWidget::loadGLTextures()  

  2. {  

  3.         QImage tex, buf;  

  4.       if ( !buf.load( ":/data/texture.jpg" ) )  

  5.       {  

  6.         //如果載入不成功,自動生成一個128*128的32位色的綠×××片。  

  7.           qWarning("Could not read p_w_picpath file!");  

  8.           QImage dummy( 128, 128,QImage::Format_RGB32 );  

  9.            dummy.fill( Qt::green );  

  10.              buf = dummy;  

  11.       }  

  12.       //轉換成紋理類型  

  13.         tex = QGLWidget::convertToGLFormat( buf );  

  14.         //創建紋理  

  15.          glGenTextures( 1, &texture[0] );  

  16.         //使用來自位圖數據生成的典型紋理,將紋理名字texture[0]綁定到紋理目標上  

  17.          glBindTexture( GL_TEXTURE_2D, texture[0] );  

  18.          glTexImage2D( GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0,  

  19.                GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() );  

  20.          glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );  

  21.          glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );  

  22. }  




解釋幾個函數:
函數原型:

      void glGenTextures(GLsizei n, GLuint *textures)

參數說明:

      n:用來生成紋理的數量
  textures:存儲紋理索引的
函數說明:
  glGenTextures函數根據紋理參數返回n個紋理索引。紋理名稱集合不必是一個連續的整數集合。 (glGenTextures就是用來產生你要操作的紋理對象的索引的,比如你告訴OpenGL,我需要5個紋理對象,它會從沒有用到的整數里返回5個給你)。

函數原型:

      void glBindTexture(GLenum target,   GLuint texture);

參數說明:

target:   紋理被綁定的目標,它只能取值GL_TEXTURE_1D或者GL_TEXTURE_2D;
texture :紋理的名稱,并且,該紋理的名稱在當前的應用中不能被再次使用。

函數說明:
glBindTexture實際上是改變了OpenGL的這個狀態,它告訴OpenGL下面對紋理的任何操作都是對它所綁定的紋理對象的,比如glBindTexture(GL_TEXTURE_2D,1)告訴OpenGL下面代碼中對2D紋理的任何設置都是針對索引為1的紋理的。

函數原型:

      void glTexImage2D(GLenum target,GLint level,GLint components,GLsizei width, glsizei height,GLint border,GLenum format,GLenum type, const GLvoid *pixels);

函數說明:
    創建一個紋理。以我們使用的那個函數為例,GL_TEXTURE_2D告訴OpenGL此紋理是一個2D紋理。數字零代表圖像的詳細程度,通常就由它為零去了。數字三是數據的成分數。因為圖像是由紅色數據,綠色數據,藍色數據三種組分組成。 tex.width()是紋理的寬度。tex.height()是紋理的高度。數字零是邊框的值,一般就是零。GL_RGBA 告訴OpenGL圖像數據由紅、綠、藍三色數據以及alpha通道數據組成,這個是由于QGLWidget類的converToGLFormat()函數的原因。 GL_UNSIGNED_BYTE 意味著組成圖像的數據是無符號字節類型的。最后tex.bits()告訴OpenGL紋理數據的來源。


        最后的glTexParameteri()告訴OpenGL在顯示圖像時,當它比放大得原始的紋理大(GL_TEXTURE_MAG_FILTER)或縮小得比原始得紋理小(GL_TEXTURE_MIN_FILTER)時OpenGL采用的濾波方式。通常這兩種情況下我都采用GL_LINEAR。這使得紋理從很遠處到離屏幕很近時都平滑顯示。使用GL_LINEAR需要CPU和顯卡做更多的運算。如果您的機器很慢,您也許應該采用GL_NEAREST。過濾的紋理在放大的時候,看起來斑駁的很。您也可以結合這兩種濾波方式。在近處時使用GL_LINEAR,遠處時GL_NEAREST。

       插一句QPixmap和QImag的區別:
       QPixmap依賴于硬件,QImage不依賴于硬件。QPixmap主要是用于繪圖,針對屏幕顯示而最佳化設計,QImage主要是為圖像I/O、圖片訪問和像素修改而設計的。當圖片小的情況下,直接用QPixmap進行加載,畫圖時無所謂,當圖片大的時候如果直接用QPixmap進行加載,會占很大的內存,一般一張幾十K的圖片,用QPixmap加載進來會放大很多倍,所以一般圖片大的情況下,用QImage進行加載,然后轉乘QPixmap用戶繪制。QPixmap繪制效果是最好的。

修改paintGL():
      在這里向大家推薦一個很有意思的東東,就是Sumo Paint,它是Chrome瀏覽器里的一個繪圖應用,用來在Ubuntu中進行圖片編輯還是非常不錯的,我們可以用它來編輯紋理貼圖。

[cpp] view plain copy Qt下的OpenGL 編程紋理和貼圖Qt下的OpenGL 編程紋理和貼圖

  1. void NeHeWidget::paintGL()  

  2. {  

  3.     // 清除屏幕和深度緩存  

  4.     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );  

  5.     glLoadIdentity();  

  6.     //移到屏幕的左半部分,并且將視圖推入屏幕背后足夠的距離以便我們可以看見全部的場景  

  7.     glTranslatef(0.0f,0.0f,-5.0f);  

  8.     glRotatef( xRot,  1.0,  0.0,  0.0 );  

  9.     glRotatef( yRot,  0.0,  1.0,  0.0 );  

  10.     glRotatef( zRot,  0.0,  0.0,  1.0 );  

  11.     //選擇使用的紋理  

  12.     glBindTexture( GL_TEXTURE_2D, texture[0] );  

  13.     glBegin( GL_QUADS );  

  14.     glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0, -1.0,  1.0 );  

  15.     glTexCoord2f( 1.0, 0.0 ); glVertex3f(  1.0, -1.0,  1.0 );  

  16.     glTexCoord2f( 1.0, 1.0 ); glVertex3f(  1.0,  1.0,  1.0 );  

  17.     glTexCoord2f( 0.0, 1.0 ); glVertex3f( -1.0,  1.0,  1.0 );  

  18.     glTexCoord2f( 1.0, 0.0 ); glVertex3f( -1.0, -1.0, -1.0 );  

  19.     glTexCoord2f( 1.0, 1.0 ); glVertex3f( -1.0,  1.0, -1.0 );  

  20.     glTexCoord2f( 0.0, 1.0 ); glVertex3f(  1.0,  1.0, -1.0 );  

  21.     glTexCoord2f( 0.0, 0.0 ); glVertex3f(  1.0, -1.0, -1.0 );  

  22.     glTexCoord2f( 0.0, 1.0 ); glVertex3f( -1.0,  1.0, -1.0 );  

  23.     glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0,  1.0,  1.0 );  

  24.     glTexCoord2f( 1.0, 0.0 ); glVertex3f(  1.0,  1.0,  1.0 );  

  25.     glTexCoord2f( 1.0, 1.0 ); glVertex3f(  1.0,  1.0, -1.0 );  

  26.     glTexCoord2f( 1.0, 1.0 ); glVertex3f( -1.0, -1.0, -1.0 );  

  27.     glTexCoord2f( 0.0, 1.0 ); glVertex3f(  1.0, -1.0, -1.0 );  

  28.     glTexCoord2f( 0.0, 0.0 ); glVertex3f(  1.0, -1.0,  1.0 );  

  29.     glTexCoord2f( 1.0, 0.0 ); glVertex3f( -1.0, -1.0,  1.0 );  

  30.     glTexCoord2f( 1.0, 0.0 ); glVertex3f(  1.0, -1.0, -1.0 );  

  31.     glTexCoord2f( 1.0, 1.0 ); glVertex3f(  1.0,  1.0, -1.0 );  

  32.     glTexCoord2f( 0.0, 1.0 ); glVertex3f(  1.0,  1.0,  1.0 );  

  33.     glTexCoord2f( 0.0, 0.0 ); glVertex3f(  1.0, -1.0,  1.0 );  

  34.     glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0, -1.0, -1.0 );  

  35.     glTexCoord2f( 1.0, 0.0 ); glVertex3f( -1.0, -1.0,  1.0 );  

  36.     glTexCoord2f( 1.0, 1.0 ); glVertex3f( -1.0,  1.0,  1.0 );  

  37.     glTexCoord2f( 0.0, 1.0 ); glVertex3f( -1.0,  1.0, -1.0 );  

  38.     glEnd();  

  39.     xRot += 0.3;  

  40.       yRot += 0.2;  

  41.       zRot += 0.4;  

  42. }  




最后,在initializeGL()中加入

loadGLTextures();
 glEnable( GL_TEXTURE_2D );


編譯,運行!


它確實跑起來了,不過我們忘記了一個東西,就是紋理坐標。
紋理坐標如下圖所示:

假設圖中的正方向就是我們要將紋理映射上去的物體(地面),那么我們需要按照圖中的表示,為每個頂點指定一個紋理坐標,也稱之為UV坐標,它的橫向為s軸,縱向圍t軸,如下圖所示。關于st和uv坐標可以參考一些3D圖形學相關知識。

在paintGL()中定義頂點的時候,我們只需用glTexCoord2f()將紋理綁定到相應的頂點就可以了


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

常山县| 蓬溪县| 麻栗坡县| 栾城县| 武鸣县| 玉田县| 磐安县| 涪陵区| 巴塘县| 华亭县| 新疆| 图木舒克市| 漳州市| 南丰县| 嫩江县| 高邑县| 错那县| 台中市| 宜都市| 肇东市| 顺义区| 桂东县| 建昌县| 额敏县| 微山县| 南投县| 德化县| 金平| 天长市| 邻水| 西乌珠穆沁旗| 巩留县| 新干县| 芦山县| 类乌齐县| 绥中县| 北宁市| 阿城市| 章丘市| 安陆市| 利辛县|