日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Qt实现3D纹理渲染自由旋转空间立方体

發(fā)布時(shí)間:2025/3/21 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt实现3D纹理渲染自由旋转空间立方体 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
昨天七夕,關(guān)于七夕美好的愛情傳說源自于浩瀚銀河星空,又碰巧最近在學(xué)習(xí)QtOpenGL實(shí)現(xiàn)三維紋理防體重建,突發(fā)奇想用Qt實(shí)現(xiàn)一個(gè)立方體星空模型,并且能隨著鼠標(biāo)操作實(shí)現(xiàn)空間自由旋轉(zhuǎn)

??????? 核心思想是用到Qt OpenGL模塊,將二維圖片貼到立方體的六個(gè)面,鼠標(biāo)可以自由旋轉(zhuǎn)立方體,實(shí)現(xiàn)三維星空的動(dòng)態(tài)變換,真正做出來后,感覺效果還挺好的,三維立體星空看起來還是很絢麗的,呵呵

?????? 下面直接從代碼層面分析上述實(shí)例,我用的ubuntu-12.04? Qt-4.8.1

??????? GLFrameWork.pro

[html] view plaincopy
  • #-------------------------------------------------??
  • #??
  • #?Project?created?by?Wangchuan?2014-08-01T10:46:58??
  • #??
  • #-------------------------------------------------??
  • ??
  • QT???????+=?opengl??
  • ??
  • SOURCES?+=?main.cpp\??
  • ????????mainwindow.cpp?\??
  • ????nehewidget.cpp??
  • ??
  • HEADERS??+=?mainwindow.h?\??
  • ????nehewidget.h??
  • ??
  • LIBS+=-lGLU\??
  • ??????? QT += opengl一定不能少,因?yàn)楸纠幸{(diào)用OoenGL模塊,如果沒有此語句,后面的OpenGL模塊中的函數(shù)則不能使用,SOURCES包含了本實(shí)例所需要的源文件:main.cpp, mainwindow.spp, nehewidget.cpp。Headers包含了頭文件mainwindow.h, nehewidget.h。LIBS是附加庫,因?yàn)楹竺娴膅luPerspective()函數(shù)屬于本庫,并且在gluPerspective()函數(shù)所在的頭文件中要包含#include<GL/glu.h>,這兩個(gè)條件缺一不可,否則Qt會(huì)報(bào)錯(cuò):undefined reference to gluPerspective()

    ?????? main.cpp

    [html] view plaincopy
  • #include?<QtGui/QApplication>??
  • #include?"mainwindow.h"??
  • ??
  • int?main(int?argc,?char?*argv[])??
  • {??
  • ????QApplication?a(argc,?argv);??
  • ????MainWindow?w;??
  • ????w.show();??
  • ??????
  • ????return?a.exec();??
  • }??
  • ????? 幾乎所有的Qt在新建工程時(shí),自動(dòng)生成了main.cpp,本實(shí)例中,也幾乎沒改變mian.cpp,只是頭文件加入了#include "mainwindow.h",簡單對(duì)此代碼進(jìn)行分析如下,#include<QtGui/QApplication>中的QApplication類用于管理應(yīng)用程序范圍內(nèi)的資源,對(duì)于Qt開發(fā)GUI通常只有一個(gè)QApplication工程。#include"mainwindow,h",MainWindow主要對(duì)圖形界面交互以及邏輯控制設(shè)置。QApplication a(int argc, char *argv[ ])主要初始化窗口系統(tǒng),重建應(yīng)用工程,并且argc大于0,argv必須至少包含一個(gè)字符型數(shù)據(jù),w.show()顯示最終圖形界面。return a.exec(),進(jìn)入主事件循環(huán),直到exit()函數(shù)被調(diào)用,如果exit()被調(diào)用,則返回0值。

    ????? mainwindow.h

    [cpp] view plaincopy
  • #ifndef?MAINWINDOW_H??
  • #define?MAINWINDOW_H??
  • ??
  • #include?<QtGui/QMainWindow>??
  • #include?<QKeyEvent>??
  • #include?"nehewidget.h"??
  • ??
  • class?MainWindow?:?public?QMainWindow??
  • {??
  • ????Q_OBJECT??
  • ??????
  • public:??
  • ????MainWindow(QWidget?*parent?=?0);??
  • ????~MainWindow();??
  • public?slots:??
  • ????void?setXRotation(int?angle);??
  • ????void?setYRotation(int?angle);??
  • ????void?setZRotation(int?angle);??
  • ??
  • signals:??
  • ????void?xRotationChanged(int?angle);??
  • ????void?yRotationChanged(int?angle);??
  • ????void?zRotationChanged(int?angle);??
  • ??
  • protected:??
  • ????//鼠標(biāo)事件處理??
  • ????void?mousePressEvent(QMouseEvent?*event);??
  • ????void?mouseMoveEvent(QMouseEvent?*event);??
  • private:??
  • ????NeHeWidget??*neheWidget;??
  • ????QPoint?lastPos;??
  • ??
  • ????void?normalizeAngle(int?*angle);??
  • ????int?xRot;??
  • ????int?yRot;??
  • ????int?zRot;??
  • };??
  • ??
  • #endif?//?MAINWINDOW_H??
  • QMainWindow類主要提供主應(yīng)用工程窗口。QKeyEvent類主要描述按鍵觸發(fā)事件。擴(kuò)展一下,C++類當(dāng)中,定義成public的數(shù)據(jù)和函數(shù),是外部可以訪問的,定義成private的數(shù)據(jù)和函數(shù),是私有的,外部不可訪問,定義成protected的數(shù)據(jù)和函數(shù),是保護(hù)的,只有friend友元可以訪問。MainWindow類繼承自QMainWindow類,public成員:MainWindow(QWidget *parent=0),將parent傳遞給QWidget類,QWidget類是用戶界面工程的基礎(chǔ)類,新widget表示新建一個(gè)窗口,~MainWindow()刪除主窗口。public slots:公共信號(hào)槽函數(shù),可以被外界訪問。

    ?????? 擴(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++語言,因此要正確處理信號(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ù)指針,它使得我們編寫這些通信程序更為簡潔命了,信號(hào)和槽能攜帶任意數(shù)量和任意類型的參數(shù),他們是類型完全安全的,不會(huì)像回調(diào)函數(shù)那樣產(chǎn)生core dunps。所有從QObject 或其子類(例如QWidget)派生的類都能購包含信號(hào)和槽,當(dāng)對(duì)象改變其狀態(tài)時(shí),信號(hào)就由該對(duì)象發(fā)射(emit)出去,這就是對(duì)象所要做的全部事情,他不知道另一端是誰在接收這個(gè)信號(hào),這就是真正的信息封裝,它確保對(duì)象被當(dāng)作一個(gè)真正的軟件組件來使用,槽用于接收信號(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í)無論第一個(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ā)射,只有定義過這個(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)限決定類誰能與其相關(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):通過調(diào)用QObject對(duì)象的connect函數(shù)來將某個(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)系起來,當(dāng)指定信號(hào)signal時(shí)必須使用QT的宏SIGNAL(),當(dāng)指定槽函數(shù)時(shí)必須使用宏SLOT()。如果發(fā)射者與接收者屬于同一個(gè)對(duì)象的話,那么在connect調(diào)用中接收者參數(shù)可以省略。當(dāng)信號(hào)與槽沒必要繼續(xù)保持關(guān)聯(lián)時(shí),使用disconnect函數(shù)來斷開鏈接,其定義如下: bool QObject::disconnect(const QObject *sender, const char *signal, const Object *receiver, const char *member)[static]這個(gè)函數(shù)可以斷開發(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語句將其包含到類的源文件中,moc并不擴(kuò)展#include或者#define宏定義,它只是簡單的跳過所遇到的任何預(yù)處理指令。

    ???????? 本實(shí)例中,信號(hào)xRotationChanged(int angle),即就是當(dāng)angle變化的時(shí)候,則信號(hào)開始發(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中的定義編寫實(shí)現(xiàn)具體的函數(shù)實(shí)體,按動(dòng)鼠標(biāo)左鍵可以拖動(dòng)立方體進(jìn)行空間自由旋轉(zhuǎn),按動(dòng)鼠標(biāo)右鍵自動(dòng)退出。

    [html] view plaincopy
  • #include?"mainwindow.h"??
  • #include?"math.h"??
  • ??
  • MainWindow::MainWindow(QWidget?*parent)?:??
  • ????QMainWindow(parent)??
  • {??
  • ????neheWidget?=?new?NeHeWidget();??
  • ????setGeometry(100,100,1000,768);??
  • ????setWindowTitle(tr("Nehe's?OpenGL?Framework"));??
  • ????setCentralWidget(neheWidget);??
  • }??
  • ??
  • MainWindow::~MainWindow()??
  • {??
  • ??
  • }??
  • ??
  • void?MainWindow::normalizeAngle(int?*angle)??
  • {??
  • ????while(*angle?<?0)??
  • ????????????*angle?+=?360?*?16;??
  • ????while(*angle?>?360?*?16)??
  • ????????????*angle?-=?360?*?16;??
  • }??
  • ??
  • void?MainWindow::setXRotation(int?angle)??
  • {??
  • ????normalizeAngle(&angle);??
  • ????if(angle?!=?xRot){??
  • ????????xRot?=?angle;??
  • ????????emit?xRotationChanged(angle);??
  • ????????neheWidget->setxRot(xRot);??
  • ????????neheWidget->?updateGL();??
  • ????}??
  • }??
  • ??
  • void?MainWindow::setYRotation(int?angle)??
  • {??
  • ????normalizeAngle(&angle);??
  • ????if(angle?!=?yRot){??
  • ????????yRot?=?angle;??
  • ????????emit?yRotationChanged(angle);??
  • ????????neheWidget->setyRot(yRot);??
  • ????????neheWidget?->?updateGL();??
  • ????}??
  • }??
  • ??
  • void?MainWindow::setZRotation(int?angle)??
  • {??
  • ????normalizeAngle(&angle);??
  • ????if(angle?!=?zRot){??
  • ????????zRot?=?angle;??
  • ????????emit?zRotationChanged(angle);??
  • ????????neheWidget->setzRot(zRot);??
  • ????????neheWidget?->?updateGL();??
  • ????}??
  • }??
  • ??
  • void?MainWindow::mousePressEvent(QMouseEvent?*event)??
  • {??
  • ????lastPos?=?event?->pos();??
  • }??
  • ??
  • void?MainWindow::mouseMoveEvent(QMouseEvent?*event)??
  • {??
  • ????int?dx?=?event?->?x()?-?lastPos.x();??
  • ????int?dy?=?event?->?y()?-?lastPos.y();??
  • ??
  • ????switch(event?->?buttons())??
  • ????{??
  • ????????case?Qt::LeftButton:??
  • ????????setXRotation(xRot?+?2?*?dy);??
  • ????????setYRotation(yRot?+?2?*?dx);??
  • ????????setZRotation(zRot?+?2?*?dx);??
  • ????????break;??
  • ????????case?Qt::RightButton:??
  • ????????close();??
  • ????????break;??
  • ????}??
  • ????lastPos?=?event?->?pos();??
  • }??
  • nehewidget.h代碼[html] view plaincopy
  • #ifndef?NEHEWIDGET_H??
  • #define?NEHEWIDGET_H??
  • #include?<QGLWidget>??
  • #include?<QtGui>??
  • #include?<QtOpenGL>??
  • ??
  • ??
  • class?NeHeWidget:public?QGLWidget??
  • {??
  • ????Q_OBJECT??
  • public:??
  • ????explicit?NeHeWidget(QWidget?*parent?=?0);??
  • ????~NeHeWidget();??
  • ????void?setxRot(int?x){xRot?=?x;}??
  • ????void?setyRot(int?y){yRot?=?y;}??
  • ????void?setzRot(int?z){zRot?=?z;}??
  • protected:??
  • ????//設(shè)置渲染環(huán)境??
  • ????void?initializeGL();??
  • ????//繪制窗口??
  • ????void?paintGL();??
  • ????//響應(yīng)窗口的大小變化??
  • ????void?resizeGL(int?width,?int?height);??
  • ??
  • ????//加載紋理函數(shù)??
  • ????void?loadGLTextures();??
  • ????//texture用來存儲(chǔ)紋理??
  • ????GLuint?texture[1];??
  • ??
  • private:??
  • ????int?xRot;??
  • ????int?yRot;??
  • ????int?zRot;??
  • ??
  • };??
  • #endif?//?NEHEWIDGET_H??
  • ???? 該頭文件主要用來定義如何調(diào)用OpenGL模塊實(shí)現(xiàn)三維立體渲染。

    ???? 對(duì)具體定義分別介紹:

    ???? #include<QGLWidget>,其中QGLWidget類用來繪制OpenGL圖形的窗口,QGLWidget提供一系列的函數(shù)來在一個(gè)QT應(yīng)用程序里面繪制OpenGL,用起來很簡單,我們可以派生它,然后使用像其他任何窗口一樣使用子類,除非你選擇類使用QPainter和標(biāo)準(zhǔn)的OpenGL繪圖命令,QGLWidget提供三個(gè)方便的虛函數(shù),我們可以在子類中重寫他們,來完成一些典型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ù),用來抑制隱式轉(zhuǎn)換。擴(kuò)展:widget被創(chuàng)建時(shí)都是不可見的,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
  • #include?"nehewidget.h"??
  • #include?<GL/glu.h>??
  • ??
  • ??
  • #define?PI?3.1415926??
  • ??
  • NeHeWidget::NeHeWidget(QWidget?*parent):??
  • ????QGLWidget(parent)??
  • {??
  • }??
  • NeHeWidget::~NeHeWidget()??
  • {??
  • }??
  • ??
  • void?NeHeWidget::initializeGL()??
  • {??
  • ????//啟用陰影平滑??
  • ????glShadeModel(GL_SMOOTH);??
  • ????//黑色背景??
  • ????glClearColor(0.0,0.0,0.0,0.0);??
  • ????//設(shè)置深度緩存??
  • ????glClearDepth(1.0);??
  • ????//啟用深度測(cè)試??
  • ????glEnable(GL_DEPTH_TEST);??
  • ????//所作深度測(cè)試的類型??
  • ????glDepthFunc(GL_LEQUAL);??
  • ????//告訴系統(tǒng)對(duì)透視進(jìn)行修正??
  • ????glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);??
  • ??
  • ????//加載紋理??
  • ????loadGLTextures();??
  • ????glEnable(GL_TEXTURE_2D);??
  • }??
  • ??
  • void?NeHeWidget::paintGL()??
  • {??
  • ????//?清除屏幕和深度緩存??
  • ????glClear(?GL_COLOR_BUFFER_BIT?|?GL_DEPTH_BUFFER_BIT?);??
  • ????glLoadIdentity();??
  • ??
  • ????//移到屏幕的左半部分,并且將視圖推入屏幕背后足夠的距離以便我們可以看見全部的場(chǎng)景??
  • ????glTranslatef(0.0f,0.0f,-5.0f);??
  • ??
  • ????glRotatef(?xRot/16,??1.0,??0.0,??0.0?);??
  • ????glRotatef(?yRot/16,??0.0,??1.0,??0.0?);??
  • ????glRotatef(?zRot/16,??0.0,??0.0,??1.0?);??
  • ??
  • ????//選擇使用的紋理??
  • ??
  • ????glBindTexture(?GL_TEXTURE_2D,?texture[0]?);??
  • ????glBegin(?GL_QUADS?);??
  • ??
  • ????glTexCoord2f(?0.0,?0.0?);?glVertex3f(?-1.0,?-1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?0.0?);?glVertex3f(??1.0,?-1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?1.0?);?glVertex3f(??1.0,??1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?0.0,?1.0?);?glVertex3f(?-1.0,??1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?0.0?);?glVertex3f(?-1.0,?-1.0,?-1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?1.0?);?glVertex3f(?-1.0,??1.0,?-1.0?);??
  • ??
  • ????glTexCoord2f(?0.0,?1.0?);?glVertex3f(??1.0,??1.0,?-1.0?);??
  • ??
  • ????glTexCoord2f(?0.0,?0.0?);?glVertex3f(??1.0,?-1.0,?-1.0?);??
  • ??
  • ????glTexCoord2f(?0.0,?1.0?);?glVertex3f(?-1.0,??1.0,?-1.0?);??
  • ??
  • ????glTexCoord2f(?0.0,?0.0?);?glVertex3f(?-1.0,??1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?0.0?);?glVertex3f(??1.0,??1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?1.0?);?glVertex3f(??1.0,??1.0,?-1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?1.0?);?glVertex3f(?-1.0,?-1.0,?-1.0?);??
  • ??
  • ????glTexCoord2f(?0.0,?1.0?);?glVertex3f(??1.0,?-1.0,?-1.0?);??
  • ??
  • ????glTexCoord2f(?0.0,?0.0?);?glVertex3f(??1.0,?-1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?0.0?);?glVertex3f(?-1.0,?-1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?0.0?);?glVertex3f(??1.0,?-1.0,?-1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?1.0?);?glVertex3f(??1.0,??1.0,?-1.0?);??
  • ??
  • ????glTexCoord2f(?0.0,?1.0?);?glVertex3f(??1.0,??1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?0.0,?0.0?);?glVertex3f(??1.0,?-1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?0.0,?0.0?);?glVertex3f(?-1.0,?-1.0,?-1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?0.0?);?glVertex3f(?-1.0,?-1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?1.0,?1.0?);?glVertex3f(?-1.0,??1.0,??1.0?);??
  • ??
  • ????glTexCoord2f(?0.0,?1.0?);?glVertex3f(?-1.0,??1.0,?-1.0?);??
  • ??
  • ????glEnd();??
  • }??
  • ??
  • //重置OpenGL窗口大小??
  • void?NeHeWidget::resizeGL(int?width,?int?height)??
  • {??
  • ????//防止窗口大小變?yōu)???
  • ????if(height?==?0)??
  • ????{??
  • ????????height?=?1;??
  • ????}??
  • ????//重置當(dāng)前的視口??
  • ????glViewport(0,0,(GLint)width,(GLint)height);??
  • ????//選擇投影矩陣??
  • ????glMatrixMode(GL_PROJECTION);??
  • ????//重置投影矩陣??
  • ????glLoadIdentity();??
  • ????//設(shè)置視口大小??
  • ????gluPerspective(45.0,(GLfloat)width/(GLfloat)height,0.1,100.0);??
  • ????//選擇模型觀察矩陣??
  • ????glMatrixMode(GL_MODELVIEW);??
  • ????glLoadIdentity();??
  • }??
  • ??
  • //紋理裝載函數(shù)??
  • void?NeHeWidget::loadGLTextures()??
  • {??
  • ????QImage?tex,buf;??
  • ????if(!buf.load("/home/wangchuan/qtcreator-2.4.1/bin/Program/GLFrameWork/GLFrameWork/xingkong.jpg"))??
  • ????{??
  • ????????//如果載入不成功,自動(dòng)生成一個(gè)128*128的32位色的綠色圖片??
  • ????????qWarning("Could?not?read?image?file!");??
  • ????????QImage?dummy(128,128,QImage::Format_RGB32);??
  • ????????dummy.fill(Qt::green);??
  • ????????????buf?=?dummy;??
  • ????}??
  • ????//轉(zhuǎn)換成紋理類型??
  • ????tex?=?QGLWidget::convertToGLFormat(buf);??
  • ????//創(chuàng)建紋理??
  • ????glGenTextures(1,?&texture[0]);??
  • ????//使用來自位圖數(shù)據(jù)生成的典型紋理,將紋理名字texture[0]綁定到紋理目標(biāo)上??
  • ????glBindTexture(GL_TEXTURE_2D,?texture[0]);??
  • ????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);??
  • ????glTexParameteri(GL_TEXTURE_2D,?GL_TEXTURE_MAG_FILTER,?GL_LINEAR);??
  • }??
  • nehewidget.cpp主要針對(duì)于nehewidget.h中的定義實(shí)現(xiàn)具體相對(duì)應(yīng)的函數(shù)實(shí)體,對(duì)幾個(gè) 函數(shù)進(jìn)行解釋說明:

    ??????????? glShadeModel函數(shù),用于控制OpenGL中繪制指定兩點(diǎn)間其他點(diǎn)顏色的過渡模式,參數(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)過渡效果,GL_FLAT則只是以指定的某一點(diǎn)的單一色繪制其他的所有點(diǎn);glClearColor函數(shù)來自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的那部分才可見;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)的簡單線性差值計(jì)算,mode:指定所采取行為的符號(hào)常量,GL_NICEST:選擇最高質(zhì)量選項(xiàng)。

    ????????? 紋理裝載函數(shù):LoadGLTextures(),QPixmap和QImge的區(qū)別:QPixmap依賴于硬件,QImage不依賴于硬件,QPixmap主要用于繪圖,針對(duì)屏幕顯示最佳化而設(shè)計(jì),QImage主要是為圖像I/O、圖片訪問和像素修改而設(shè)計(jì)的,當(dāng)圖片小的情況下直接用QPixmap進(jìn)行加載,當(dāng)圖片大的時(shí)候如果直接用QPixmap進(jìn)行加載,會(huì)占很大的內(nèi)存,一般一張幾十k的圖片,用QPixmap加載進(jìn)來會(huì)放大很多倍,所以一般圖片大的情況下,用QImage進(jìn)行加載,然后轉(zhuǎn)乘QPixmap用戶繪制,QPixmap繪制效果是最好的;函數(shù) void glGenTextures(GLsizei n, GLuint *textures)參數(shù)n用來生成紋理的數(shù)量,textures存儲(chǔ)紋理索引的,glGenTextures函數(shù)根據(jù)紋理參數(shù)返回n個(gè)紋理索引,紋理名稱集合不必是一個(gè)連續(xù)的整數(shù)集合,glGneTextures就是用來產(chǎn)生你要操作的紋理對(duì)象的索引的,比如你告訴OpenGL,需要5個(gè)紋理對(duì)象,它會(huì)從沒有用到的整數(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ù)用來創(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ù)是無符號(hào)字節(jié)類型,最后tex.bits()告訴OpenGL紋理數(shù)據(jù)來源;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,過濾的紋理在放大時(shí)候,看起來是斑駁的,因此可以結(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),長度單位定為:窗口范圍按此單位恰好是(-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)系來講的,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ù)所指定的值來清除指定的緩沖區(qū),也可以用glDrawBuffer一次清除多個(gè)顏色緩存,比如:glClear(GL_COLOR_BUFFER_BIT)表示把整個(gè)窗口清除為黑色,glClear()的唯一參數(shù)表示需要被清除的緩沖區(qū),像素檢驗(yàn)、裁剪檢驗(yàn)、抖動(dòng)和緩存的寫屏蔽都會(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)過的角度,Xvector, Yvector, Zvector三個(gè)參數(shù)共同決定旋轉(zhuǎn)軸的方向,(1,0,0)描述矢量經(jīng)過X坐標(biāo)軸的1個(gè)單位處并且方向向右,關(guān)于旋轉(zhuǎn)方向確定符合右手定則,大拇指為旋轉(zhuǎn)矢量方向;glBegin 和 glEnd為一對(duì),標(biāo)志著一組OpenGL操作的開始和結(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ì)接下來做什么進(jìn)行一下聲明,參數(shù)有3種模式GL_PROJECTION投影,GL_MODELVIEW模型視圖,GL_TEXTURE紋理,如果參數(shù)是GL_PROJECTION,這個(gè)就是投影的意思,就是要對(duì)投影進(jìn)行相關(guān)的操作,也就是把物體投影到一個(gè)平面上,就像我們照相一樣,把3維物體投影到2維平面上,這樣接下來的語句跟透視相關(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è)置完成后開始畫圖,需要切換到模型視圖矩陣才能正確畫圖glMatrixMode(GL_MODELVIEW),如果從頭到尾都是畫3D/2D,只需要初始化設(shè)置一次,如果有交替那么就緒要glMatrixMode()切換,這樣設(shè)置很煩人于是就有類glPushMatrix()保存當(dāng)前矩陣。

    ???????? 啊哈,利用兩天的時(shí)間查找和補(bǔ)充資料,終于完成了這篇博客,夜晚浩瀚的星空,世間的一切都顯得如此之渺小,人生數(shù)十載如白駒過隙,轉(zhuǎn)眼光陰即逝,怎樣讓人生過得才有意義?唯有珍惜光陰,不虛度年華,不忘最初的夢(mèng)想,為夢(mèng)想而堅(jiān)持奮斗,這樣的人生才有意義。腦海中想起范范“最初的夢(mèng)想”,唯有“不忘初心,方得始終~”共勉!

    總結(jié)

    以上是生活随笔為你收集整理的Qt实现3D纹理渲染自由旋转空间立方体的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。