Qt实现3D纹理渲染自由旋转空间立方体
??????? 核心思想是用到Qt OpenGL模塊,將二維圖片貼到立方體的六個(gè)面,鼠標(biāo)可以自由旋轉(zhuǎn)立方體,實(shí)現(xiàn)三維星空的動(dòng)態(tài)變換,真正做出來(lái)后,感覺(jué)效果還挺好的,三維立體星空看起來(lái)還是很絢麗的,呵呵
?????? 下面直接從代碼層面分析上述實(shí)例,我用的ubuntu-12.04? Qt-4.8.1
??????? GLFrameWork.pro
[html] view plaincopy?????? main.cpp
[html] view plaincopy????? mainwindow.h
[cpp] view plaincopy?????? 擴(kuò)展介紹:信號(hào)和槽機(jī)制是Qt的核心機(jī)制,信號(hào)和槽是一種高級(jí)接口,應(yīng)用于對(duì)象之間的通信,它是Qt的核心特征,也是Qt區(qū)別與其它工具包的重要地方,信號(hào)和槽是Qt自行定義的一種通信機(jī)制,它獨(dú)立于標(biāo)準(zhǔn)C/C++語(yǔ)言,因此要正確處理信號(hào)和槽,必須借助一個(gè)成為moc(Meta Object Compiler)的Qt工具,該工具是一個(gè)C++預(yù)處理程序,它為高層次的事件處理自動(dòng)生成所需要的附加代碼,在我們熟知的很多GUI工具中窗口小部件(widget) 都有一個(gè)回調(diào)函數(shù)用于響應(yīng)他們能觸發(fā)的每個(gè)動(dòng)作,這個(gè)回調(diào)函數(shù)通常是一個(gè)指向某個(gè)函數(shù)的指針,但是在Qt中信號(hào)和槽取代了這種l凌亂的函數(shù)指針,它使得我們編寫(xiě)這些通信程序更為簡(jiǎn)潔命了,信號(hào)和槽能攜帶任意數(shù)量和任意類型的參數(shù),他們是類型完全安全的,不會(huì)像回調(diào)函數(shù)那樣產(chǎn)生core dunps。所有從QObject 或其子類(例如QWidget)派生的類都能購(gòu)包含信號(hào)和槽,當(dāng)對(duì)象改變其狀態(tài)時(shí),信號(hào)就由該對(duì)象發(fā)射(emit)出去,這就是對(duì)象所要做的全部事情,他不知道另一端是誰(shuí)在接收這個(gè)信號(hào),這就是真正的信息封裝,它確保對(duì)象被當(dāng)作一個(gè)真正的軟件組件來(lái)使用,槽用于接收信號(hào),但他們是普通的對(duì)象成員函數(shù),一個(gè)槽并不知道是否有任何信號(hào)與自己相鏈接,而且,對(duì)象并不了解具體的通信機(jī)制。你可以將很多信號(hào)與單個(gè)槽進(jìn)行連接,也可將單個(gè)信號(hào)與很多槽進(jìn)行連接,甚至將一個(gè)信號(hào)與另外一個(gè)信號(hào)連接也是可能的,這時(shí)無(wú)論第一個(gè)信號(hào)什么時(shí)候發(fā)射,系統(tǒng)都會(huì)立刻發(fā)射第二個(gè)信號(hào),總之信號(hào)與槽構(gòu)造類一個(gè)強(qiáng)大的部件編程機(jī)制。
??????? 信號(hào):當(dāng)某個(gè)信號(hào)對(duì)其客戶或者所有者發(fā)生的內(nèi)部狀態(tài)發(fā)生改變,信號(hào)被一個(gè)對(duì)象發(fā)射,只有定義過(guò)這個(gè)信號(hào)的類以及其派生類能夠發(fā)射這個(gè)信號(hào),當(dāng)一個(gè)信號(hào)被發(fā)射時(shí),與其相關(guān)聯(lián)的槽會(huì)被立刻執(zhí)行,就像一個(gè)正常的函數(shù)調(diào)用一樣,信號(hào)-槽機(jī)制完全獨(dú)立于任何GUI事件循環(huán),只有當(dāng)所有的槽返回以后發(fā)射函數(shù)(emit)才返回,如果存在多個(gè)槽與某個(gè)信號(hào)相關(guān)聯(lián),那么當(dāng)這個(gè)信號(hào)被發(fā)射時(shí),這些槽會(huì)一個(gè)接一個(gè)地執(zhí)行,但是它們執(zhí)行順序是隨機(jī)的、不確定的,我們不能人為的指定那個(gè)先執(zhí)行、哪個(gè)后執(zhí)行。信號(hào)的聲明在頭文件中進(jìn)行的,QT的signals關(guān)鍵字指出進(jìn)入類信號(hào)聲明區(qū),隨后即可聲明自己的信號(hào)。
???????? 槽:槽是普通的C++成員函數(shù),可以被正常調(diào)用,他們唯一的特殊性就是很多信號(hào)可以與其關(guān)聯(lián),當(dāng)與其關(guān)聯(lián)信號(hào)被發(fā)射時(shí),這個(gè)槽就會(huì)被調(diào)用。槽可以有參數(shù),但槽的參數(shù)不能有缺省值。既然槽是普通成員函數(shù),因此與其他函數(shù)一樣,他們也有存取權(quán)限,槽的存取權(quán)限決定類誰(shuí)能與其相關(guān)聯(lián),同普通的C++成員函數(shù)一樣,槽函數(shù)也分為三種類型,public slots, private slots, protected slots。public slots:在這個(gè)區(qū)內(nèi)聲明的槽意味著任何對(duì)象都可將信號(hào)與之相連,這對(duì)于組件編程非常有用,你可以創(chuàng)建彼此互補(bǔ)了解的對(duì)象,將它們的信號(hào)與槽進(jìn)行鏈接以便信息能夠正確的傳遞。protected slots:在這個(gè)區(qū)內(nèi)聲明的槽意味著當(dāng)前類以及其子類可以將信號(hào)與之相鏈接,這適用于那些槽,他們是類實(shí)現(xiàn)的一部分,但其界面接口卻面向外部。private slots:在這個(gè)區(qū)內(nèi)聲明的槽意味著只有類字節(jié)可以將信號(hào)與之相連接,這適用于聯(lián)系非常緊密的類。槽也能夠聲明為虛函數(shù),這也是非常有用的,槽的聲明也是在頭文件中進(jìn)行的。
???????? 信號(hào)與槽的關(guān)聯(lián):通過(guò)調(diào)用QObject對(duì)象的connect函數(shù)來(lái)將某個(gè)對(duì)象的信號(hào)與另外一個(gè)對(duì)象的槽函數(shù)相關(guān)聯(lián),這樣當(dāng)發(fā)射者發(fā)射信號(hào)時(shí),接收者的槽函數(shù)將被調(diào)用,該函數(shù)定義如下:bool QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)[static]這個(gè)函數(shù)作用就是將發(fā)射者sender對(duì)象中的信號(hào)signal與接收者receiver中的member槽函數(shù)聯(lián)系起來(lái),當(dāng)指定信號(hào)signal時(shí)必須使用QT的宏SIGNAL(),當(dāng)指定槽函數(shù)時(shí)必須使用宏SLOT()。如果發(fā)射者與接收者屬于同一個(gè)對(duì)象的話,那么在connect調(diào)用中接收者參數(shù)可以省略。當(dāng)信號(hào)與槽沒(méi)必要繼續(xù)保持關(guān)聯(lián)時(shí),使用disconnect函數(shù)來(lái)斷開(kāi)鏈接,其定義如下: bool QObject::disconnect(const QObject *sender, const char *signal, const Object *receiver, const char *member)[static]這個(gè)函數(shù)可以斷開(kāi)發(fā)射者中的信號(hào)與接收者中槽函數(shù)之間的關(guān)聯(lián)。在disconnect函數(shù)中0可以用作一個(gè)通配符,分別表示任何信號(hào)、任何接收對(duì)象、接收對(duì)象中的任何槽函數(shù)。但是發(fā)射者sender不能為0,其他三個(gè)參數(shù)值可以為0.
????????? 元對(duì)象編譯器moc(mete object compiler)對(duì)C++文件中的類聲明進(jìn)行分析并產(chǎn)生用于初始化元對(duì)象的C++代碼,元對(duì)象包含全部信號(hào)和槽的名字以及指向這些函數(shù)的指針,moc讀C++源文件,如果發(fā)現(xiàn)有Q_OBJECT宏聲明類,它會(huì)生成另外一個(gè)C++源文件,這個(gè)新生成的文件中包含該類的元對(duì)象代碼,例如,假如我們有一個(gè)頭文件mysignal.h,在這個(gè)文件中包含有信號(hào)或者槽的聲明,那么在編譯之前moc 工具就會(huì)根據(jù)該文件自動(dòng)生成一個(gè)mysignal.moc.h的C++源文件并將其提交給編譯器,類似地,對(duì)應(yīng)與mysignal.cpp文件moc工具自動(dòng)生辰mysignal.moc.cpp文件提交給編譯器,元對(duì)象代碼是signal/slot機(jī)制所必須的,用moc 產(chǎn)生C++源文件必須與類實(shí)現(xiàn)一起進(jìn)行編譯和連接,或者用#include語(yǔ)句將其包含到類的源文件中,moc并不擴(kuò)展#include或者#define宏定義,它只是簡(jiǎn)單的跳過(guò)所遇到的任何預(yù)處理指令。
???????? 本實(shí)例中,信號(hào)xRotationChanged(int angle),即就是當(dāng)angle變化的時(shí)候,則信號(hào)開(kāi)始發(fā)射給對(duì)應(yīng)的槽,MainWindow類中的受保護(hù)成員函數(shù)mousePressEvent(QMouseEvent *event)用于處理鼠標(biāo)按下時(shí)的事件響應(yīng),mouseMoveEvent(QMouseEvent *event)用于處理鼠標(biāo)移動(dòng)時(shí)的事件相應(yīng),私有成員函數(shù)以及參數(shù)不能被外部調(diào)用,只能內(nèi)部使用,包括函數(shù)normalizeAngle(int *angle)主要用于標(biāo)準(zhǔn)調(diào)整鼠標(biāo)旋轉(zhuǎn)角度,neheWidget, lastPos, xRot, yRot, zRot都是私有參數(shù)。
???????? mainwindow.cpp主要對(duì)應(yīng)于mainwindow.h中的定義編寫(xiě)實(shí)現(xiàn)具體的函數(shù)實(shí)體,按動(dòng)鼠標(biāo)左鍵可以拖動(dòng)立方體進(jìn)行空間自由旋轉(zhuǎn),按動(dòng)鼠標(biāo)右鍵自動(dòng)退出。
[html] view plaincopy???? 該頭文件主要用來(lái)定義如何調(diào)用OpenGL模塊實(shí)現(xiàn)三維立體渲染。
???? 對(duì)具體定義分別介紹:
???? #include<QGLWidget>,其中QGLWidget類用來(lái)繪制OpenGL圖形的窗口,QGLWidget提供一系列的函數(shù)來(lái)在一個(gè)QT應(yīng)用程序里面繪制OpenGL,用起來(lái)很簡(jiǎn)單,我們可以派生它,然后使用像其他任何窗口一樣使用子類,除非你選擇類使用QPainter和標(biāo)準(zhǔn)的OpenGL繪圖命令,QGLWidget提供三個(gè)方便的虛函數(shù),我們可以在子類中重寫(xiě)他們,來(lái)完成一些典型OpenGL任務(wù):1. paintGL()函數(shù),繪制OpenGL圖像,當(dāng)窗口需要被刷新時(shí)候被調(diào)用;2.resizeGL()函數(shù),建立OpenGL的視圖窗口等一系列,當(dāng)窗口大小改變時(shí)候被調(diào)用,(當(dāng)?shù)谝淮物@示時(shí)候也會(huì)被調(diào)用,因?yàn)樗行聞?chuàng)建的窗口都自動(dòng)得到一個(gè)改變的大小事件);3.intializeGL()建立OpenGL繪圖的上下文環(huán)境,聲明播放列表等等,在第一次調(diào)用resizeGL()或paintGL()調(diào)用前使用。
????? #include<Qtgui>,因?yàn)橐瑑蓚€(gè)類的定義,所以使用該聲明,NeHeWidget類繼承于QGLWidget類。
????? Q_OBJECT宏作用,只有加入此宏定義,你才能使用QT中的signal和slot機(jī)制。
????? NeHeWidget類的公共成員函數(shù):explicit NeHeWidget(QWidget *parent=0),explicit用于構(gòu)造函數(shù),用來(lái)抑制隱式轉(zhuǎn)換。擴(kuò)展:widget被創(chuàng)建時(shí)都是不可見(jiàn)的,widget中可容納其它widget,Qt中的widget在用戶行為或者狀態(tài)改變時(shí)會(huì)emit signal, QWidget類的構(gòu)造函數(shù)需要一個(gè)QWidget*指針作為參數(shù),表示其parent widget(默認(rèn)值為0,即不存在parent widget ),在parent widget被刪除時(shí),Qt會(huì)自動(dòng)刪除其所有的child widget,Qt中有三種Layout Manager類:QHBoxLayout, QVBoxLayOut, QGridLayOut,基本模式是將widget添加進(jìn)LayOut,由Layout自動(dòng)接管widget的尺寸和位置。
??????? nehewidget.cpp
[html] view plaincopy??????????? glShadeModel函數(shù),用于控制OpenGL中繪制指定兩點(diǎn)間其他點(diǎn)顏色的過(guò)渡模式,參數(shù)一般為GL_SMOOTH(默認(rèn)),GL_FLAT,OpenGL默認(rèn)是將制定的兩點(diǎn)顏色進(jìn)行插值,繪制之間的其他點(diǎn),如果兩點(diǎn)顏色相同,使用兩個(gè)參數(shù)效果相同,如果兩點(diǎn)顏色不同,GL_SMOOTH會(huì)出現(xiàn)過(guò)渡效果,GL_FLAT則只是以指定的某一點(diǎn)的單一色繪制其他的所有點(diǎn);glClearColor函數(shù)來(lái)自O(shè)PENGL,為顏色緩沖區(qū)指定確定的值,指定red,green,blue,alpha(透明)的值,當(dāng)顏色緩沖區(qū)清空時(shí)使用,默認(rèn)值都是0,其取值范圍在0~1之間;glClearDepth函數(shù),設(shè)置深度緩存的清除值,depth--指定清除深度緩存時(shí)使用的深度值,該值在[0,1]之間,如果設(shè)定為0.5,那么物體只有像素深度小于0.5的那部分才可見(jiàn);glDepthFunc(GLenum func)函數(shù),func:指定“目標(biāo)像素與當(dāng)前像素在z方向值大小比較”的函數(shù),符合此函數(shù)關(guān)系的目標(biāo)像素才進(jìn)行繪制,否則目標(biāo)像素不予繪制,該函數(shù)只有啟用“深度測(cè)試時(shí)”glEnable(GL_DEPTH_TEST)和glDisable(GL_DEPTH_TEST)時(shí)才有效,參數(shù):GL_LEQUAL如果目標(biāo)像素z值<=當(dāng)前像素z值,則繪制目標(biāo)像素;函數(shù)glHint(GLenum target,GLenum mod),該函數(shù)控制OpenGL在某一方面有解釋的余地時(shí),所采取的操作行為,target:指定所控制行為的符號(hào)常量,GL_PERSPECTIVE_CORRECTION_HINT指定顏色和紋理坐標(biāo)的差值質(zhì)量,如果OpenGL不能有效的支持透視修正參數(shù)差值,那么GL_DONT_CARE和CL_FASTEST可以執(zhí)行顏色、紋理坐標(biāo)的簡(jiǎn)單線性差值計(jì)算,mode:指定所采取行為的符號(hào)常量,GL_NICEST:選擇最高質(zhì)量選項(xiàng)。
????????? 紋理裝載函數(shù):LoadGLTextures(),QPixmap和QImge的區(qū)別:QPixmap依賴于硬件,QImage不依賴于硬件,QPixmap主要用于繪圖,針對(duì)屏幕顯示最佳化而設(shè)計(jì),QImage主要是為圖像I/O、圖片訪問(wèn)和像素修改而設(shè)計(jì)的,當(dāng)圖片小的情況下直接用QPixmap進(jìn)行加載,當(dāng)圖片大的時(shí)候如果直接用QPixmap進(jìn)行加載,會(huì)占很大的內(nèi)存,一般一張幾十k的圖片,用QPixmap加載進(jìn)來(lái)會(huì)放大很多倍,所以一般圖片大的情況下,用QImage進(jìn)行加載,然后轉(zhuǎn)乘QPixmap用戶繪制,QPixmap繪制效果是最好的;函數(shù) void glGenTextures(GLsizei n, GLuint *textures)參數(shù)n用來(lái)生成紋理的數(shù)量,textures存儲(chǔ)紋理索引的,glGenTextures函數(shù)根據(jù)紋理參數(shù)返回n個(gè)紋理索引,紋理名稱集合不必是一個(gè)連續(xù)的整數(shù)集合,glGneTextures就是用來(lái)產(chǎn)生你要操作的紋理對(duì)象的索引的,比如你告訴OpenGL,需要5個(gè)紋理對(duì)象,它會(huì)從沒(méi)有用到的整數(shù)里返回5個(gè)給你;函數(shù)void glBindTexture(GLenum targt, GLuint texture)參數(shù)target紋理被綁定的目標(biāo),它只能取值GL_TEXTURE_1D 或者GL_TEXTURE_2D,texture紋理名稱,并且該紋理名稱在當(dāng)前的應(yīng)用中不能被再次使用,該函數(shù)實(shí)際上改變了OpenGL的這個(gè)狀態(tài),告訴OpenGL下面對(duì)紋理的任何操作都是對(duì)它所綁定的紋理對(duì)象的,比如glBindTexture(GL_TEXTURE_2D,1)告訴OpenGL下面代碼中對(duì)2D紋理的任何設(shè)置都是針對(duì)索引為1紋理的;函數(shù)void glTexImage2D(GLenum target, GLint level, GLint components, GLsizei wifth, glsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels),該函數(shù)用來(lái)創(chuàng)建一個(gè)紋理,本例中GL_TEXTURE_2D告訴OpenGL此紋理是一個(gè)2D紋理,數(shù)字零代表圖像的詳細(xì)程度,通常為0,數(shù)字3是數(shù)據(jù)的成分?jǐn)?shù),因?yàn)閳D像由紅綠藍(lán)三色組成,tex.width()是紋理的寬度,tex.height()紋理的高度,數(shù)字0是邊框值一般為0,GL_RGBA告訴OpenGL圖像由宏綠藍(lán)以及alpha通道組成,這是由于QGLWidget類的converToGLFormat()函數(shù)原因,GL_UNSIGNES_BYTE表示組成圖像數(shù)據(jù)是無(wú)符號(hào)字節(jié)類型,最后tex.bits()告訴OpenGL紋理數(shù)據(jù)來(lái)源;glTexParameteri()告訴OpenGL在顯示圖像時(shí),當(dāng)它比原始紋理放的大(GL_TEXTURE_MAG_FILTER)或比原始紋理縮的小(GL_TEXTURE_MIN_FILTER)時(shí)OpenGL采用的濾波方式,通常這兩種情況下都采用GL_LINEAR,這使得紋理從很遠(yuǎn)處到離屏幕很近時(shí)都能平滑顯示,使用GL_LINEAR需要CPU和顯卡做更多運(yùn)算,如果機(jī)器很慢,應(yīng)該采用GL_NEAREST,過(guò)濾的紋理在放大時(shí)候,看起來(lái)是斑駁的,因此可以結(jié)合這兩種濾波方式,在近處時(shí)使用GL_LINEAR,遠(yuǎn)處時(shí)用GL_NEAREST。
???????? OpenGL坐標(biāo)系,OpenGL使用右手坐標(biāo)系,從左到右,x遞增,從下到上,y遞增,從遠(yuǎn)到近,z遞增,OpenGL坐標(biāo)系可分為:世界坐標(biāo)系和當(dāng)前繪圖坐標(biāo)系,世界坐標(biāo)系以屏幕原點(diǎn)(0,0,0),長(zhǎng)度單位定為:窗口范圍按此單位恰好是(-1,-1)到(1,1),當(dāng)前繪圖坐標(biāo)系是繪制物體時(shí)坐標(biāo)系,程序初始化時(shí),世界坐標(biāo)系和當(dāng)前繪圖坐標(biāo)系是重合的,當(dāng)用glTranslatef(),glScalef(),glRotatef()對(duì)當(dāng)前繪圖坐標(biāo)系進(jìn)行平移、伸縮、旋轉(zhuǎn)變換后,世界坐標(biāo)系和當(dāng)前繪圖坐標(biāo)系不再重合,改變以后,再用glVertex3f()等繪圖函數(shù)繪圖時(shí),都是在當(dāng)前繪圖坐標(biāo)系進(jìn)行繪圖,所有的函數(shù)參數(shù)也都是相對(duì)當(dāng)前繪圖坐標(biāo)系來(lái)講的,OpenGL紋理使用分三步:將紋理裝入內(nèi)存,將紋理發(fā)給OpenGL管道,給生成的紋理頂點(diǎn)指定紋理坐標(biāo),在paintGL()中定義映射目標(biāo)物體的頂點(diǎn)時(shí)候,我們只需要用glTexCoord2f()將紋理綁定到相應(yīng)的目標(biāo)頂點(diǎn)就可以了。
???????? 假設(shè)紋理坐標(biāo)如圖:
???????? 要將其映射到下圖正方形形狀的物體上(地面),那么就需要按照紋理坐標(biāo),為正方形每個(gè)頂點(diǎn)指定坐標(biāo),也稱為UV坐標(biāo),橫向?yàn)閟軸,縱向?yàn)閠軸,將紋理與映射目標(biāo)綁定。
?????????? glClear()函數(shù)作用是用當(dāng)前緩沖區(qū)清除值,也就是glClearColor或者glClearDepth、glClearIndex、glClearStencil、glClearAccum等函數(shù)所指定的值來(lái)清除指定的緩沖區(qū),也可以用glDrawBuffer一次清除多個(gè)顏色緩存,比如:glClear(GL_COLOR_BUFFER_BIT)表示把整個(gè)窗口清除為黑色,glClear()的唯一參數(shù)表示需要被清除的緩沖區(qū),像素檢驗(yàn)、裁剪檢驗(yàn)、抖動(dòng)和緩存的寫(xiě)屏蔽都會(huì)影響glClear的操作,其中,裁剪范圍限制了清除的區(qū)域,而glClear命令還會(huì)忽略alpha函數(shù)、融合函數(shù)、邏輯操作、模板、紋理映射和Z緩存;glLoadIdentity()這個(gè)函數(shù)類似于一個(gè)復(fù)位操作:X坐標(biāo)、Y坐標(biāo)、Z坐標(biāo)均復(fù)位,OpenGL屏幕中心位于原點(diǎn),在適當(dāng)?shù)奈恢檬褂迷摵瘮?shù)可以復(fù)位坐標(biāo),否則下一步的坐標(biāo)操作就基于上一步的坐標(biāo)了;glTranslatef(x,y,z)移動(dòng)時(shí)候并不是相對(duì)屏幕中心移動(dòng),而是相對(duì)于當(dāng)前所在屏幕的位置,其作用就是將你匯點(diǎn)坐標(biāo)的原點(diǎn)在當(dāng)前原點(diǎn)的基礎(chǔ)上平移一個(gè)(x,y,z)向量;旋轉(zhuǎn)所用的函數(shù)為glRotatef(Angle, Xvector, Yvector, Zvector),它負(fù)責(zé)讓對(duì)象繞某個(gè)軸旋轉(zhuǎn),這個(gè)函數(shù)有很多用處,Angle通常是個(gè)變量代表對(duì)象轉(zhuǎn)過(guò)的角度,Xvector, Yvector, Zvector三個(gè)參數(shù)共同決定旋轉(zhuǎn)軸的方向,(1,0,0)描述矢量經(jīng)過(guò)X坐標(biāo)軸的1個(gè)單位處并且方向向右,關(guān)于旋轉(zhuǎn)方向確定符合右手定則,大拇指為旋轉(zhuǎn)矢量方向;glBegin 和 glEnd為一對(duì),標(biāo)志著一組OpenGL操作的開(kāi)始和結(jié)束,并且在參數(shù)中告訴了OpenGL下面的操作是針對(duì)什么圖形進(jìn)行的,GL_QUADS表示四邊形;glVertex3f()確定了矩形的頂點(diǎn)坐標(biāo)。
????????? 重置OpenGL窗口大小函數(shù):resizeGL():其中函數(shù)gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)這個(gè)函數(shù)定義類觀察的視景體在世界坐標(biāo)系中的具體大小,一般aspect應(yīng)該與窗口的寬高比相同,fovy視野角度,跟照相機(jī)原理相似,數(shù)值越小相當(dāng)于將鏡頭拉的越近,數(shù)值越大,鏡頭越遠(yuǎn),鏡頭的東西就越小,aspect實(shí)際窗口的寬高比x/y,zNear表示近處的裁面,zFar表示遠(yuǎn)處的裁面;glViewport函數(shù)主要負(fù)責(zé)把視景體截取的圖像按照怎樣的高和寬顯示到屏幕上,該函數(shù)還可以調(diào)整圖像分辨率;glMatrixMode()函數(shù)其實(shí)就是對(duì)接下來(lái)做什么進(jìn)行一下聲明,參數(shù)有3種模式GL_PROJECTION投影,GL_MODELVIEW模型視圖,GL_TEXTURE紋理,如果參數(shù)是GL_PROJECTION,這個(gè)就是投影的意思,就是要對(duì)投影進(jìn)行相關(guān)的操作,也就是把物體投影到一個(gè)平面上,就像我們照相一樣,把3維物體投影到2維平面上,這樣接下來(lái)的語(yǔ)句跟透視相關(guān)的函數(shù),如glFrustum()或者gluPerspective(),在操作投影矩陣以前,需要調(diào)用函數(shù)glMatrixMode(GL_PROJECTION)將當(dāng)前矩陣指定為投影矩陣,然后把矩陣設(shè)為單位矩陣glLoadIdentity(),然后調(diào)用glFrustum()或者gluPerspective(),他們生成的矩陣會(huì)與當(dāng)前的矩陣相乘,生成透視的效果,GL_MODELVIEW是對(duì)模型視圖矩陣進(jìn)行操作,前面GL_PROJECTION設(shè)置完成后開(kāi)始畫(huà)圖,需要切換到模型視圖矩陣才能正確畫(huà)圖glMatrixMode(GL_MODELVIEW),如果從頭到尾都是畫(huà)3D/2D,只需要初始化設(shè)置一次,如果有交替那么就緒要glMatrixMode()切換,這樣設(shè)置很煩人于是就有類glPushMatrix()保存當(dāng)前矩陣。
???????? 啊哈,利用兩天的時(shí)間查找和補(bǔ)充資料,終于完成了這篇博客,夜晚浩瀚的星空,世間的一切都顯得如此之渺小,人生數(shù)十載如白駒過(guò)隙,轉(zhuǎn)眼光陰即逝,怎樣讓人生過(guò)得才有意義?唯有珍惜光陰,不虛度年華,不忘最初的夢(mèng)想,為夢(mèng)想而堅(jiān)持奮斗,這樣的人生才有意義。腦海中想起范范“最初的夢(mèng)想”,唯有“不忘初心,方得始終~”共勉!
總結(jié)
以上是生活随笔為你收集整理的Qt实现3D纹理渲染自由旋转空间立方体的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 二叉树实现
- 下一篇: windows下使用开源gSOAP技术调