OpenGL_Qt学习笔记之_05(纹理映射)
? ? ?
紋理映射基礎知識
什么叫紋理映射,一開始我也不明白,感覺這個詞好專業(畢竟沒有學過圖形學),后面經過網上查找資料和這次實驗稍微理解了點。紋理映射簡單的講,就是把一個紋理(其實說白了,紋理可以理解為一幅圖像)映射到空間物體的表面上,因此紋理映射也叫貼圖,這個表明不一定是矩形,比如說我可以是球面,或者是任意曲面。在上一篇文章OpenGL_Qt學習筆記之_04(3D圖形的繪制和旋轉)中,我們繪制的空間體的表面都是一些光滑的顏色,如果要在其表面采用那種方法繪制圖像的話,則必須利用微分的思想,一個一個的繪制小圖像,然后拼接起來,可想而知,這個過程是多么的復雜,opengl的紋理映射就可以很好的解決這一問題。
? ? ?下面來看看紋理映射的一個示意圖片(百度百科上的):
?
這個示意圖說明,將中間的紋理(即圖片)映射到左邊的茶壺曲面上,就形成了右邊的圖了。在右邊的圖中,可以看到茶壺的表面上布滿了圖片,這就像中國古代的陶器繪圖一樣。
紋理映射另外一個好處是能夠保證在變換多邊形時,多邊形上的紋理也會隨之變化。
?
紋理映射相關函數
要進行紋理映射,得先了解下opengl中有關紋理映射的一些相關函數。
void glGenTextures(GLsizei n, GLuint *textures);
該函數的作用是開辟存儲紋理的內存空間,其中參數n為開辟紋理內存的個數,texture為存儲紋理的地址索引。
?
void glBindTexture(GLenum target,?? GLuint texture);
該函數的作用是把存儲紋理的對象texture綁定到紋理目標target上,在opengl中紋理目標分為GL_TEXTURE_1D和GL_TEXTURE_2D。該句代碼運行完后,對target的操作也對應于對texture指向的內容的操作。
?
void glTexImage2D(GLenum target,GLint level,GLint components,GLsizei width, glsizei height,GLint border,GLenum format,GLenum type, const GLvoid *pixels);
參數1為紋理目標;參數2為目標的層次,即目標的詳細程度,一般情況采用0即可;參數3表示的是數據成分的個數,如果數據由RGB構成,則將該參數設置為3;參數4和5分別為創建紋理數據的長和寬;參數6為邊框的值,一般也設為0;參數8為數據的通道格式;參數9為紋理的數據元素類型;參數10為紋理的數據內容。
這個函數的功能是創建一個紋理,并為該紋理分配了數據。
?
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
該函數表示的是當所顯示的紋理比加載進來的紋理小時,采用GL_LINEAR的方法來處理。
?
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
和上面的函數類似,注意該函數的參數2為GL_TEXTURE_MAG_FILTER,不要誤認為是GL_TEXTURE_MAG_FILTER。
?
glTexCoord2f(x, y);
第一個參數是X坐標。 0.0f 是紋理的左側。 0.5f 是紋理的中點, 1.0f 是紋理的右側。第二個參數是Y坐標。0.0f 是紋理的底部。0.5f 是紋理的中點,1.0f 是紋理的頂部。
?
給定一張紋理圖,它的坐標示意圖如下:
?
其中紋理的中心點坐標為(0.5, 0.5).
?
實驗說明:
這個實驗室在上一篇博文OpenGL_Qt學習筆記之_04(3D圖形的繪制和旋轉) 繪制的立方體上貼每個面上貼上一張紋理(即圖片)。
我們需要在GLWidget這個類中添加一個函數來加載紋理數據,該函數為loadTextures().
另外,在QGLWidget這個類中,initializeGL(), paintGL(), resizeGL()這3個函數的執行順序是該類啟動時就執行initializeGL(),主要用于初始化opengl,通常用來設置一些前期的背景色,光照參數等等。paintGL()用于渲染整個場景;resizeGL()用于在widget大小變化的時候產生合理view。
注意,本實驗給的圖片長和寬必須是2的n次方,最大不要超過256,最小也不要小于64。我這里采用的是256*256像素的圖片。
?
實驗結果:
加載紋理的圖像為:
?
紋理映射后的效果如下:
?
?
實驗主要部分代碼及注釋(附錄有工程code下載地址):
#include "glwidget.h" #include "ui_glwidget.h"#include <QtGui> #include <QtCore> #include <QtOpenGL>GLWidget::GLWidget(QGLWidget *parent) :QGLWidget(parent),ui(new Ui::GLWidget) {// setCaption("The Opengl for Qt Framework");ui->setupUi(this);fullscreen = false;rotate_angle = 0.0; }//這是對虛函數,這里是重寫該函數 void GLWidget::initializeGL() {setGeometry(300, 150, 500, 500);//設置窗口初始位置和大小 loadTextures();glEnable(GL_TEXTURE_2D);//允許采用2D紋理技術glShadeModel(GL_SMOOTH);//設置陰影平滑模式glClearColor(0.0, 0.0, 0.0, 0);//改變窗口的背景顏色,不過我這里貌似設置后并沒有什么效果glClearDepth(1.0);//設置深度緩存glEnable(GL_DEPTH_TEST);//允許深度測試glDepthFunc(GL_LEQUAL);//設置深度測試類型glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);//進行透視校正 }void GLWidget::paintGL() {//glClear()函數在這里就是對initializeGL()函數中設置的顏色和緩存深度等起作用glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);/*下面開始畫立方體,并對其進行紋理映射*/glLoadIdentity();glRotatef(rotate_angle, -0.2f, 0.2f, -0.3f);glBegin(GL_QUADS);//上頂面glTexCoord2f(0.0, 1.0);//將2D的紋理坐標映射到3D的空間物體表面上glVertex3f(-0.3f, 0.3f, -0.3f);glTexCoord2f(0.0, 0.0);glVertex3f(-0.3f, 0.3f, 0.3f);glTexCoord2f(1.0, 0.0);glVertex3f(0.3f, 0.3f, 0.3f);glTexCoord2f(1.0, 1.0);glVertex3f(0.3f, 0.3f, -0.3f);//下頂面glTexCoord2f(0.0, 1.0);glVertex3f(-0.3f, -0.3f, -0.3f);glTexCoord2f(0.0, 0.0);glVertex3f(-0.3f, -0.3f, 0.3f);glTexCoord2f(1.0, 0.0);glVertex3f(0.3f, -0.3f, 0.3f);glTexCoord2f(1.0, 1.0);glVertex3f(0.3f, -0.3f, -0.3f);//正前面glTexCoord2f(0.0, 1.0);glVertex3f(-0.3f, 0.3f, 0.3f);glTexCoord2f(0.0, 0.0);glVertex3f(-0.3f, -0.3f, 0.3f);glTexCoord2f(1.0, 0.0);glVertex3f(0.3f, -0.3f, 0.3f);glTexCoord2f(1.0, 1.0);glVertex3f(0.3f, 0.3f, 0.3f);//右側面glTexCoord2f(0.0, 1.0);glVertex3f(0.3f, 0.3f, 0.3f);glTexCoord2f(0.0, 0.0);glVertex3f(0.3f, -0.3f, 0.3f);glTexCoord2f(1.0, 0.0);glVertex3f(0.3f, -0.3f, -0.3f);glTexCoord2f(1.0, 1.0);glVertex3f(0.3f, 0.3f, -0.3f);//背后面glTexCoord2f(0.0, 1.0);glVertex3f(-0.3f, 0.3f, -0.3f);glTexCoord2f(0.0, 0.0);glVertex3f(0.3f, 0.3f, -0.3f);glTexCoord2f(1.0, 0.0);glVertex3f(0.3f, -0.3f, -0.3f);glTexCoord2f(1.0, 1.0);glVertex3f(-0.3f, -0.3f, -0.3f);//左側面glTexCoord2f(0.0, 1.0);glVertex3f(-0.3f, 0.3f, -0.3f);glTexCoord2f(0.0, 0.0);glVertex3f(-0.3f, -0.3f, -0.3f);glTexCoord2f(1.0, 0.0);glVertex3f(-0.3f, -0.3f, 0.3f);glTexCoord2f(1.0, 1.0);glVertex3f(-0.3f, 0.3f, 0.3f);rotate_angle -= 3;glEnd(); }//該程序是設置opengl場景透視圖,程序中至少被執行一次(程序啟動時). void GLWidget::resizeGL(int width, int height) {if(0 == height)height = 1;//防止一條邊為0glViewport(0, 0, (GLint)width, (GLint)height);//重置當前視口,本身不是重置窗口的,只不過是這里被Qt給封裝好了glMatrixMode(GL_PROJECTION);//選擇投影矩陣glLoadIdentity();//重置選擇好的投影矩陣// gluPerspective(45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0);//建立透視投影矩陣glMatrixMode(GL_MODELVIEW);//以下2句和上面出現的解釋一樣 glLoadIdentity();} void GLWidget::keyPressEvent(QKeyEvent *e) {switch(e->key()){//F1鍵為全屏和普通屏顯示切換鍵case Qt::Key_F1:fullscreen = !fullscreen;if(fullscreen)showFullScreen();else{setGeometry(300, 150, 500, 500);showNormal();}updateGL();break;//Ese為退出程序鍵case Qt::Key_Escape:close();} }/*裝載紋理*/ void GLWidget::loadTextures() {QImage tex, buf;if(!buf.load("../opengl_nehe_05/cherry.jpg")){qWarning("Cannot open the image...");QImage dummy(128, 128, QImage::Format_RGB32);//當沒找到所需打開的圖片時,創建一副128*128大小,深度為32位的位圖 dummy.fill(Qt::green);buf = dummy;}tex = convertToGLFormat(buf);//將Qt圖片的格式buf轉換成opengl的圖片格式texglGenTextures(1, &texture[0]);//開辟一個紋理內存,內存指向texture[0]glBindTexture(GL_TEXTURE_2D, texture[0]);//將創建的紋理內存指向的內容綁定到紋理對象GL_TEXTURE_2D上,經過這句代碼后,以后對//GL_TEXTURE_2D的操作的任何操作都同時對應與它所綁定的紋理對象glTexImage2D(GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());//開始真正創建紋理數據glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//當所顯示的紋理比加載進來的紋理小時,采用GL_LINEAR的方法來處理glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//當所顯示的紋理比加載進來的紋理大時,采用GL_LINEAR的方法來處理 }GLWidget::~GLWidget() {delete ui; }?
?
總結:
了解了opengl中的紋理映射機制后,對空間體的表面進行貼圖還是比較方便的。
?
? ?參考資料:
?http://nehe.gamedev.net/?
?http://www.owlei.com/DancingWind/
?http://blog.csdn.net/qp120291570/article/details/7853513
? ? ?http://www.qiliang.net/old/nehe_qt/
?
附錄:
實驗工程code下載。
?
?
?
轉載于:https://www.cnblogs.com/tornadomeet/archive/2012/08/24/2654719.html
總結
以上是生活随笔為你收集整理的OpenGL_Qt学习笔记之_05(纹理映射)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 810D - 如何写学术论文
- 下一篇: ASP.NET MVC 3 RTM