You are on page 1of 21

Qt ile OpenGL

Bu derste, Qt nedir ,ne deildir, ne alakadr dan ziyade C++ GUI Programming with Qt 4 adl kitabn OpenGL ile ilgili 20.blmnn direkt tercmesini sunacam. Tm bu giri konular ve kitabn lk 12 blmnn tercmesini Ufuk Uzun arkadamz yapm, sitesinden indirebilirsiniz (http://qtturk.tk) , kitabn geri kalan blmlerinin tercmesine faydanz olursa ne mutlu size ne mutlu Trk genliine. Tabi bu 20.blm, Qt ile OpenGL konusunda ok kapsaml deil(shadera deinilmemi) ama bize bir konsept salayacan mit ediyorum. nternette gerek Red Bookun gerek Nehenin kodlarnn Qte adaptasyonu var ayrca Qt SDKda en son ve geni rnekler mevcut. Kolay gelsin...

20. 3B Grafik

OpenGL Kullanarak izim OpenGL ve QPainter i Birlikte Kullanma Framebuffer Objelerini Kullanarak Bindirme Yapma

OpenGL, 3B grafik sahnelemeleri iin standart bir API'dir. Qt uygulamalar, sistemin OpenGL ktphanesine dayand, QtOpenGL modln kullanarak 3B grafikler izebilir. Modl, OpenGL komutlar kullanlarak izim yapld, kendi widget'larmz gelitirmek iin alt snflandrabildiimiz, QGLWidget snfn salamtr. Birok 3B uygulamas iin bu yeterlidir. Bu blmn ilk ksm, bir drt yzl(tetrahedron) izmek iin bu teknii kullanan ve kullancya fareyi kullanarak onunla etkileime imkan veren basit bir uygulama sunmakta. Qt 4 ile alrken, normal bir QWidget gibi QGLWidget'te QPainter'i kullanmak mmkndr. Bunun byk faydas, dnmler, piksel eleme gibi ou izim ilemi iin OpenGL'den yksek performans salamadr. QPainter'i kullanmann baka bir faydas, 2B grafikler iin daha yksek dzeyli API'lerini kullanabilmemiz ve 3B grafikler iin OpenGL arlaryla onu kombine edebilmemizdir. Bu blmn ikinci ksmnda, QPainter ve OpenGL komutlar karmn kullanarak ayn widget'da 2B ve 3B izimlerin nasl birlikte kullanlacan greceiz. QGLWidget'i ve arkadan OpenGL'i kullanarak, ekranda 3B sahneler izebiliriz. Donanmhzlandrcl ekran d yzeyde sahneleme iin, QGLPixelBuffer ve QGLFramebufferObject snflaryla mmkn olacak, pbuffer ve framebuffer objeleri eklentilerini kullanabiliriz. Bu blmn nc ksmnda, bindirme uygulamak iin framebuffer objesinin nasl kullanldn greceiz.

Bu blm, sizin, OpenGL ile aina olduunuzu farz ediyor. Eer OpenGL'de yeniysen,

http://www.opengl.org/ onu renmeye balamak iin iyi bir yer.

OpenGL Kullanarak izim


Bir Qt uygulamasndan OpenGL ile grafik izimi olduka basit: QGLWidget'i alt snflayp, birka sanal fonksiyon salayp , QtOpenGL ve OpenGL ktphaneleri ile uygulamay linklemeleyiz. QGLWidget, QWidget'ten tretildii iin, hali hazrda bildiimiz ou ey yine uygulanyor. Ana fark, izim yapmak iin QPainter yerine standart OpenGL fonksiyonlarn kullanmamzdr. Bu ilerin nasl olduunu grmek iin, figr 20.1'de gsterilen Tetrahedron uygulamasnn kodunu inceleyeceiz. Uygulama, bir 3B tetrahedron veya drt yzl sunar , her yz farkl renkte izilir. Kullanc, tetrahedronu fare dmesiyle basp srleyip dndrebilir. Kullanc, ift-tklama ile ortaya kan QColorDialog'dan bir renk seip yzn rengini set edebilir.
Figr 20.1. Tetrahedron uygulamas

class Tetrahedron : public QGLWidget { Q_OBJECT public: Tetrahedron(QWidget *parent = 0); protected: void initializeGL(); void resizeGL(int width, int height); void paintGL(); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseDoubleClickEvent(QMouseEvent *event);

private: void draw(); int faceAtPosition(const QPoint &pos); GLfloat rotationX; GLfloat rotationY; GLfloat rotationZ; QColor faceColors[4]; QPoint lastPos; };

Tetrahedron snf, QGLWidget'ten tretilir. nitializeGL(), resizeGL() ve paintGL() QGLWidget'e saladmz fonksiyonlardr. Fare olay ileyicileri alld gibi QWidget'ten salanr.
Tetrahedron::Tetrahedron(QWidget *parent) : QGLWidget(parent) { setFormat(QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer)); rotationX = -21.0; rotationY = -57.0; rotationZ = 0.0; faceColors[0] = Qt::red; faceColors[1] = Qt::green; faceColors[2] = Qt::blue; faceColors[3] = Qt::yellow; }

Yapcda, OpenGL gsterim contextini belirtmek iin QGLWidget::setFormat()'i arr ve snfn private deikenlerini ilkleriz.
void Tetrahedron::initializeGL() { qglClearColor(Qt::black); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); }

nitializeGL() fonksiyonu sadece bir defa paintGL() arlmadan nce arlr. Bu, bizim, OpenGL sahneleme contexti kurgulamalar yaptmz, display listleri tanmladmz ve dier ilklemeleri yaptmz yerdir. QGLWidget'nin qglClearColor() fonksiyon ars hari kodlarn hepsi standart OpenGL kodlar. Eer OpenGL'e tamamen bal kalmay istiyor olsaydk, onun yerine RGBA modunda glClearColor()'i renk indeks modunda glClearIndex()'i aracaktk.
void Tetrahedron::resizeGL(int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity();

GLfloat x = GLfloat(width) / height; glFrustum(-x, +x, -1.0, +1.0, 4.0, 15.0); glMatrixMode(GL_MODELVIEW); }

ResizeGL() fonksiyonu, paintGL() ilkez arlmadan nce, ama initializeGL() arldktan sonra arlr. O, her ne zaman widget tekrar boyutlandrlrsa yine arlacak. Bu, bizim, OpenGL viewport'u, projeksiyonu, ve widgetin boyutuna bal olarak herhangi benzer dier durumlarda ayar yaptmz yerdir.
void Tetrahedron::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw(); }

PaintGL() fonksiyonu her ne zaman widget tekrar izime ihtiya duyulursa arlr. Bu, QWidget::paintEvent()'e benzerdir, ama biz QPainter fonksiyonlar yerine, OpenGL fonksiyonlarn kullanyoruz. Asl izim, private fonksiyon draw() ile yaplr.

Kod Grnm:
void Tetrahedron::draw() { static const GLfloat static const GLfloat static const GLfloat static const GLfloat P1[3] P2[3] P3[3] P4[3] = = = = { { { { 0.0, -1.0, +2.0 }; +1.73205081, -1.0, -1.0 }; -1.73205081, -1.0, -1.0 }; 0.0, +2.0, 0.0 };

static const GLfloat * const coords[4][3] = { { P1, P2, P3 }, { P1, P3, P4 }, { P1, P4, P2 }, { P2, P4, P3 } }; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -10.0); glRotatef(rotationX, 1.0, 0.0, 0.0); glRotatef(rotationY, 0.0, 1.0, 0.0); glRotatef(rotationZ, 0.0, 0.0, 1.0); for (int i = 0; i < 4; ++i) { glLoadName(i); glBegin(GL_TRIANGLES); qglColor(faceColors[i]); for (int j = 0; j < 3; ++j) { glVertex3f(coords[i][j][0], coords[i][j][1], coords[i][j][2]); } glEnd(); } }

draw()da, x, y ve z de dndrmeyi hesaba alp ve renkleri faceColors dizisinde depolayarak tetrahedronu izeriz. qglColor() ars dnda her ey standart OpenGL'dir.

Onun yerine, moda bal olarak OpenGL'nin glColor3B() veya glIndex() fonksiyonlarnndan birini kullanabilirdik.
void Tetrahedron::mousePressEvent(QMouseEvent *event) { lastPos = event->pos(); } void Tetrahedron::mouseMoveEvent(QMouseEvent *event) { GLfloat dx = GLfloat(event->x() - lastPos.x()) / width(); GLfloat dy = GLfloat(event->y() - lastPos.y()) / height(); if (event->buttons() & Qt::LeftButton) { rotationX += 180 * dy; rotationY += 180 * dx; updateGL(); } else if (event->buttons() & Qt::RightButton) { rotationX += 180 * dy; rotationZ += 180 * dx; updateGL(); } lastPos = event->pos(); }

mousePressEvent() ve mouseMoveEvent() fonksiyonlar, tklayp srkleyerek grnty dndrmek iin kullancya izin vermek iin QWidget'e saladmz fonksiyonlardr. Sol fare dmesi, x- ve y-eksenleri etrafnda, sa fare dmesi x- ve z-eksenleri etrafnda , dndrme iin kullancya imkan verir. rotationX ve ya rotationY ya da rotationZ deikeni deitikten sonra sahneyi tekrar izmek iin updateGL()'i arrz.
void Tetrahedron::mouseDoubleClickEvent(QMouseEvent *event) { int face = faceAtPosition(event->pos()); if (face != -1) { QColor color = QColorDialog::getColor(faceColors[face], this); if (color.isValid()) { faceColors[face] = color; updateGL(); } } }

mouseDoubleClickEvent(), ift-tklama ile bir tetrahedron yznn rengini set etmek iin kullancya imkan vermek iin QWidget'e saladmz fonksiyondur. Varsa, imlecin altnda hangi yzn olduuna kararlatrmak iin private fonksiyon faceAtPosition() salanmtr. Eer bir yz, ift-tklanrsa, o yz iin yeni bir rengi elde etmek iin QColorDialog::getColor()'u arrz. Sonra, yeni renkle faceColors dizisini gnceller ve sahneyi tekrar izmek iin updateGL()'i arrz.

Kod Grnm:
int Tetrahedron::faceAtPosition(const QPoint &pos) { const int MaxSize = 512;

GLuint buffer[MaxSize]; GLint viewport[4]; makeCurrent(); glGetIntegerv(GL_VIEWPORT, viewport); glSelectBuffer(MaxSize, buffer); glRenderMode(GL_SELECT); glInitNames(); glPushName(0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPickMatrix(GLdouble(pos.x()), GLdouble(viewport[3] - pos.y()), 5.0, 5.0, viewport); GLfloat x = GLfloat(width()) / height(); glFrustum(-x, x, -1.0, 1.0, 4.0, 15.0); draw(); glMatrixMode(GL_PROJECTION); glPopMatrix(); if (!glRenderMode(GL_RENDER)) return -1; return buffer[3]; }

faceAtPosition() fonksiyonu, widgette belirli bir konumdaki yzn numaras dndrr veya eer o konumda hibir yz yoksa -1. OpenGL'de bunu saptayacak kod biraz karktr. Aslnda, biz, OpenGL'nin seim yeteneinden faydalanmak iin GL_SELECT modunda sahneyi sahneleriz ve sonra OpenGL vuru kaydndan yzn numarasn ("ismi") elde ederiz. tm kodlar standart OpenGL kodudur, doru OpenGL contextini kullanyor olduumuzu garanti etmek iin gerekli olan balangtaki QGLWidget::makeCurrent() ars hari. (QGLWidget, initializeGL(), resizeGL() veya paintGL()'i armadan nce otomatik olarak bunu yapar, bundan dolay Tetrahedron uygulamasnda baka herhangi bir yerinde bu arya ihtiya duymayz.) Buradaki, uygulamann main() fonksiyonu:
int main(int argc, char *argv[]) { QApplication app(argc, argv); if (!QGLFormat::hasOpenGL()) { std::cerr << " Bu sistem OpenGL desteine sahip deil" << std::endl; return 1; } Tetrahedron tetrahedron; tetrahedron.setWindowTitle(QObject::tr("Tetrahedron")); tetrahedron.resize(300, 300); tetrahedron.show(); return app.exec();

Eer kullancnn sistemi OpenGL'i desteklemiyorsa, konsola bir hata mesajn basar ve geri dneriz. QtOpenGL modl ve sistemin OpenGL ktphanesi iin uygulamay linklemek iin, .pro dosyas u girie ihtiya duyar:
QT += opengl

Bu Tetrahedron uygulamasn tamamlar.

OpenGL ve QPainteri Birlikte Kullanma


nceki ksmda, QGLWidget'te bir 3B sahneyi izmek iin OpenGL komutlarn kullanmann nasl olduunu grdk. QGLWidget'te 2B grafikleri izmek iin QPainter'i kullanmak da ayn ekilde mmkn. Bu ksmda, Vowel Cube rneinde, OpenGL arlar ve QPainter'i birlikte kullanlmasna bakacaz , iki dnyann en iyisini elde etmenin nasl olduu grlecek. Bu rnek ayn zamanda, bir 3B sahnenin tepesinde dntrlmemi metinsel aklayc notlar izmemize imkan veren QGLWidget::renderText() fonksiyonunun kullanmn gsterir. Uygulama, figr 20.2'de gsterilmekte.
Figr 20.2. Vowel Cube uygulamas

Vowel Cube, sk sk Trke gramer ve dilbilgisi kitaplarnda karlalan bir imaj - bir kp olarak trk dilinin sekiz sesli harfiyle bir pencereyi gsterir. n planda, bir yaz, sesli harf kategorisiyle listeler ve hangi sesli harfler hangi kategorinin olduunu. Kp, bu bilgiyi daha grsel yapar; rnein, front sesli harfler, kpn nnde ve back sesli harfler arkada gsterilir. Zemin iin, radyal bir eim kullanyoruz.

Kod Grnm:
class VowelCube : public QGLWidget { Q_OBJECT public: VowelCube(QWidget *parent = 0); ~VowelCube(); protected: void paintEvent(QPaintEvent *event); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void wheelEvent(QWheelEvent *event); private: void createGradient(); void createGLObject();

void drawBackground(QPainter *painter); void drawCube(); void drawLegend(QPainter *painter); GLuint glObject; QRadialGradient gradient; GLfloat rotationX; GLfloat rotationY; GLfloat rotationZ; GLfloat scaling; QPoint lastPos; };

VowelCube snf QGLWidget'ten tretilir. Zemin eimi iin QPainter'i kullanyor, sonra, OpenGL arlarn kullanarak kp izer, sonra, renderText()'i kullanarak kpn kelerinde sekiz sesli harfi izer ve sonunda QPainter ve QTextDocument' kullanarak yazy izer. Kullanc, fare dmesine bastrarak ve srkleyerek kp dndrebilir ve fare tekerlei kullanlarak byltme kltme yapabilir. nceki ksmn Tetrahedron rneinden farkl olarak QGLWidget'e saladmz initializeGL() , resizeGL() ve paintGL() yerinebu sefer geleneksel QWidget ileyicilerini salarz. Bu bize OpenGL framebufferi gncelletirme zerinde daha ok kontrol salar.. Buradaki VowelCube yapcs:
VowelCube::VowelCube(QWidget *parent) : QGLWidget(parent) { setFormat(QGLFormat(QGL::SampleBuffers)); rotationX rotationY rotationZ scaling = = -38.0; = -58.0; = 0.0; 1.0;

createGradient(); createGLObject(); }

Yapcda, antialiasing'i destekleyen OpenGL gsterim contextini belirtmek iin QGLWidget::setFormat()' ararak balarz. Sonra, snfn private deikenlerini ilkleriz. Sonda, OpenGL kp nesnesini yaratmak iin createGLObject()'i ve arka plan doldurmada kullanlacak QRadialGradient kurgulamas iin createGradient()'i arrz. Yapcda bunlarn hepsini yaparak, sahneyi tekrar izmeye ihtiya duyduumuz zaman sonra daha k sonular elde ederiz..
void VowelCube::createGradient() { gradient.setCoordinateMode(QGradient::ObjectBoundingMode); gradient.setCenter(0.45, 0.50); gradient.setFocalPoint(0.40, 0.45); gradient.setColorAt(0.0, QColor(105, 146, 182)); gradient.setColorAt(0.4, QColor(81, 113, 150));

gradient.setColorAt(0.8, QColor(16, 56, 121)); }

createGradient()'de, basite, farkl mavi tonlar kullanmak iin QRadialGradient kurdulamas yapar. setCoordinateMode()'e ar, merkez ve odak noktalar iin belirtilmi kordinatlarn widgetin boyutuna ayarlamay salar. Konumlar, 0-1 aras float deerler olarak belirtilik, 0 odak noktasna karlk geliri ve 1 eim ile tanmlanan emberin hattna karlk gelir.
void VowelCube::createGLObject() { makeCurrent(); glShadeModel(GL_FLAT); glObject = glGenLists(1); glNewList(glObject, GL_COMPILE); qglColor(QColor(255, 239, 191)); glLineWidth(1.0); glBegin(GL_LINES); glVertex3f(+1.0, +1.0, -1.0); ... glVertex3f(-1.0, +1.0, +1.0); glEnd(); glEndList(); }

createGLObject(), vowel cubeyi temsil eden hatlarn izimini depolayan bir OpenGL display list yaratr. Doru OpenGL contexti kullanyor olduumuzu garanti eden balangtaki QGLWidget::makeCurrent() ars dnda tm kod standart OpenGL kodudur.
VowelCube::~VowelCube() { makeCurrent(); glDeleteLists(glObject, 1); }

yok edicide, yapcda yarattmz OpenGL kp nesnesini silmek iin glDeleteLists()'i arrz. Yeniden, makeCurrent()'i armalyz.
void VowelCube::paintEvent(QPaintEvent * /* event */) { QPainter painter(this); drawBackground(&painter); drawCube(); drawLegend(&painter); }

paintEvent()'de, normal olarak sade bir QWidget iin yapacak olduumuz gibi QPainter'in kurgulamasn yaparz; Sonra, arka plan, kp ve yazy izeriz.
void VowelCube::drawBackground(QPainter *painter)

{ painter->setPen(Qt::NoPen); painter->setBrush(gradient); painter->drawRect(rect()); }

Arka plan izmek, basite uygun bir frayla drawRect()'i armak meselesidir. drawCube() fonksiyonu, zel widgetin kalbidir. ki ksmda onu inceleyeceiz:
void VowelCube::drawCube() { glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); GLfloat x = 3.0 * GLfloat(width()) / height(); glOrtho(-x, +x, -3.0, +3.0, 4.0, 15.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glTranslatef(0.0, 0.0, -10.0); glScalef(scaling, scaling, scaling); glRotatef(rotationX, 1.0, 0.0, 0.0); glRotatef(rotationY, 0.0, 1.0, 0.0); glRotatef(rotationZ, 0.0, 0.0, 1.0); glEnable(GL_MULTISAMPLE);

Biz, QPainter'i kullanan iki kod paras arasnda baz OpenGL kodlarna sahip olduumuz iin, zellikle dikkatli olmalyz, fonksiyonda deitirdiimiz ve i bittikten sonra eski haline getirdiimiz OpenGL state'i kaydetmeliyiz. Bundan dolay , onlar deitirmeden nce OpenGL nitelikleri, projeksiyon matrisi ve modelview matrisini kaydederiz. Sonda, antialiasingi aktif etmek iin GL_MULTISAMPLE seeneini set ederiz.
glCallList(glObject); setFont(QFont("Times", 24)); qglColor(QColor(255, 223, 127)); renderText(+1.1, renderText(-1.1, renderText(+1.1, renderText(-1.1, renderText(+1.1, renderText(-1.1, renderText(+1.1, renderText(-1.1, +1.1, +1.1, +1.1, +1.1, -1.1, -1.1, -1.1, -1.1, +1.1, +1.1, -1.1, -1.1, +1.1, +1.1, -1.1, -1.1, QChar('a')); QChar('e')); QChar('o')); QChar(0x00F6)); QChar(0x0131)); QChar('i')); QChar('u')); QChar(0x00FC));

glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_PROJECTION);

glPopMatrix(); glPopAttrib(); }

Sonra, kp nesnesini izmek iin glCallList()'i arrz. sonra, yaz tipini ve rengi ayarlarz ve kpn kelerinde sesli harfleri izmek iin QGLWidget::renderText()'i arrz. ASCII karakter ermini dna den Trke sesli harfler iin Unicode deerler kullanlaca belirtilir. renderText() fonksiyonu, modelview koordinatlarda metni konumlamak iin koordinat (x, y, z ) alr. Metnin kendi dntrlmez.

Kode Grnm:
void VowelCube::drawLegend(QPainter *painter) { const int Margin = 11; const int Padding = 6; QTextDocument textDocument; textDocument.setDefaultStyleSheet("* { color: #FFEFEF }"); textDocument.setHtml("<h4 align=\"center\">Vowel Categories</h4>" "<p align=\"center\"><table width=\"100%\">" "<tr><td>Open:<td>a<td>e<td>o<td>&ouml;" ... "</table>"); textDocument.setTextWidth(textDocument.size().width()); QRect rect(QPoint(0, 0), textDocument.size().toSize() + QSize(2 * Padding, 2 * Padding)); painter->translate(width() - rect.width() - Margin, height() - rect.height() - Margin); painter->setPen(QColor(255, 239, 239)); painter->setBrush(QColor(255, 0, 0, 31)); painter->drawRect(rect); painter->translate(Padding, Padding); textDocument.drawContents(painter); }

drawLegend()'de, Trke sesli harf kategorileri ve sesli harfleri listeleyen HTML metniyle bir QTextDocument nesnesi kurgulamasn yaparz ve yar-saydam mavi dikdrtgenin tepesinde onu sahneleriz. VowelCube widget'de ayn ekilde, mousePressEvent(), mouseMoveEvent(), ve wheelEvent() salanmtr, Ama bunlar hakknda hibir zel ey yoktur. Standart bir Qt zel widget'daki gibi, her ne zaman tekrar boyama zamann istiyorsak update()'i arrz. rnein, wheelEvent() iin kod buradadr:
void VowelCube::wheelEvent(QWheelEvent *event) { double numDegrees = -event->delta() / 8.0; double numSteps = numDegrees / 15.0; scaling *= std::pow(1.125, numSteps);

update(); }

Bu, bizim rnek incelememizi tamamlar. VowelCube'nin paintEvent() ileyicisinde, takip eden genel ablonu kullandk:

1. Bira QPainter yarat. 2. Arka plan izmek iin QPainter kullan. 3. OpenGL statei kaydet. 4. OpenGL ilemleri kullanlarak sahneyi iz. 5. OpenGL statei eski hale getir. 6. n plan izmek iin QPainter kullan. 7. QPainter yok et.

Dier olaslklar vardr. rnein, eer biz, bir arka plan izmesek, yle yapabilirdik:

1. OpenGL ilemlerini kullanarak sahneyi iz. 2. Bir QPainter yarat. 3. n plan izmek iin QPainter kullan. 4. QPainter yok et.

Bu, takip eden koda uyar:


void VowelCube::paintEvent(QPaintEvent * /* event */) { drawCube(); drawLegend(); } void VowelCube::drawCube() { ... } void VowelCube::drawLegend() { QPainter painter(this); ... }

Bu sefer , yerel olarak drawLegend()'de QPainter nesnesini yarattmza dikkat. Bu yaklamn ana avantaj, OpenGL state'i kaydetmek ve eski haline getirmeye ihtiya duymadmzdr. Bununla birlikte, paket dnda, bu almayacak, nk QPainter otomatik olarak, OpenGL sahnesinin zerine yazp boyamaya balamadan nce arka plan temizler. Bunu engellemek iin, widgetin yapcsnda setAutoFillBackground(false)'i armalyz. Baka bir ilgin ablon, eer n plansz arka plan ve bir kp izersek oluur:

1. Bir QPainter olutur. 2. Arka plan izmek iin QPainter kullan. 3. QPainter yok et. 4. OpenGL ilemlerini kullanarak sahneyi iz.

OpenGL state'i kaydetmek ve eski haline getirmekten kurtulabiliriz. Bununla birlikte, bu, olduu gibi almayacak, nk QPainter , izimi grnr yapmak iin otomatik olarak onun imha edicisinde QGLWidget::swapBuffers()'i arr , QPainter ykcsndan sonra vukulanan herhangi Opengl ars ekran-dna gidecek ve grntlenmeyecek. Bunu engellemek iin, widgetin yapcsnda setAutoBufferSwap(false)'i armalyz ve paintEvent()'in sonunda swapBuffer()'i armalyz. rnein:
void VowelCube::paintEvent(QPaintEvent * /* event */) { drawBackground(); drawCube(); swapBuffers(); } void VowelCube::drawBackground() { QPainter painter(this); ... } void VowelCube::drawCube() { ... }

zetle, En genel yaklam, paintEvent()'de bir QPainter'i yaratmak ve her ne zaman i OpenGL ilemleri yaparsak state'i kaydetmek ve eski haline getirmektir. Baz state kaydetmelerinden kurtulmak mmkndr, takip eden noktalar aklda tutmak artyla:

QPainter'in yapcs (Veya QPainter::begin()) otomatik olarak eer nceden widgette setAutoFillBackground(false)'i biz armadka glClear()' arr. QPainter'in yok edicisi (Veya QPainter::end()) otomatik olarak, eer nceden widgette setAutoBufferSwap(false)'i biz armadka grnr tampon ve ekran-d tamponunu dei toku etmek iin QGLWidget::swapBuffers()'i arr.

QPainter aktif iken i OpenGL komutlar salnmadan nce OpenGL stateyi kaydettiimiz ve sonra OpenGL stateyi eski haline getirdiimiz srece, i OpenGL komutlarn kartrabiliriz.

Bu noktalar akldan karmadan, OpenGL ve QPainter kombinasyonu kolay ve QPainter ve OpenGL'in grafik kabiliyetlerinin en iyisi salanr.

Framebuffer Objeleri Kullanarak Bindirmeler Yapma


Genellikle , basit ek aklamalar, karmak 3B sahnelerin stne izmek gerekir. Sahne ok karmak ise, onu sahnelemek birka saniye srebilir. Sahnenin tekrar tekrar olumasn nlemek iin, ne zaman bir aklama deiirse X11 bindirmeleri iin tmleik OpenGL desteini kullanabilirsiniz. Daha yakn zamanlarda, pbuffers ve framebuffer nesnelerinin mevcudiyetiyle bindirmeleri yapmann daha uygun ve daha esnek bir yolu saland .Temel konsept, bir dokuya balandmz ekran-d yzey zerinde 3B sahneyi sahnelemektir. Doku bir dikdrtgen izerek ekrana eletirilir ve ek aklamalar stne izilir. Ek aklamalarda bir deiiklikte, sadece dikdrtgen ve ek aklamalar yeniden izmek gerekir. Kavramsal olarak, bu 2B Plotter widget iin Blm 5 yaptklarmza ok benzerdir. Bu teknii gstermek iin, ekil 20.3 'de gsterilen Teapots uygulamas kodlar gzden geirilecektir.Uygulama, bir dizi aydanlik gsteren ve kullanc zerlerinde fareyi tklayp srkleyerek bir ereve izmesini salayan bir OpenGL penceresi oluturur. aydanlklar, pencere yeniden boyutlandrlmak hari herhangi bir ekilde tanmas veya degitirilmesi yok. Uygulama aydanlk sahnesini saklamak iin bir framebuffer nesne bazldr. Benzer bir etki QGLFramebufferObject yerine QGLPixelBuffer pbuffer kullanlarak uygulanabilir.
Figr 20.3. Teapots uygulamas

Kod Grnm:
class Teapots : public QGLWidget { Q_OBJECT public: Teapots(QWidget *parent = 0); ~Teapots(); protected: void initializeGL(); void resizeGL(int width, int height); void paintGL(); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); private: void createGLTeapotObject(); void drawTeapot(GLfloat x, GLfloat y, GLfloat ambientR, GLfloat ambientG, GLfloat ambientB, GLfloat diffuseR, GLfloat diffuseG, GLfloat diffuseB, GLfloat specularR, GLfloat specularG, GLfloat specularB, GLfloat shininess); void drawTeapots(); QGLFramebufferObject *fbObject; GLuint glTeapotObject;

QPoint rubberBandCorner1; QPoint rubberBandCorner2; bool rubberBandIsShown; };

Teapots snf QGLWidget'den tretilir ve OpenGL ileyicileri olarak initializeGL(), resizeGL() ve paintGL() fonksiyonlarn saladk. Ayrca kullancnn bir kesikli ereve izmesini saglayacak mousePressEvent(), mouseMoveEvent(), ve mouseReleaseEvent() fonksiyonlarn saladk. private fonksiyonlar Teapots nesnesini oluturma ve aydanlklarn izimini halleder. Bu kod olduka karmak ve OpenGL Programming Guide by Jackie Neider, Tom Davis, and Mason Woo (Addison-Wesley, 1993) kitabnn teapots rneine dayanmaktadir. Amacmzla dorudan ilgili olmad iin burada deinmeyecegiz. private deikenler framebuffer nesnesini, Teapots nesnesini, kesikli ereve kelerini ve erevenin grnr olup olmadn depolar.
Teapots::Teapots(QWidget *parent) : QGLWidget(parent) { rubberBandIsShown = false; makeCurrent(); fbObject = new QGLFramebufferObject(1024, 1024, QGLFramebufferObject::Depth); createGLTeapotObject(); }

Teapots yapcs, rubberBandIsShown private deikenini ilkler, framebuffer nesnesi ve Teapots nesnesini oluturur. Olduka uzun ve Qt ile ilgili herhangi bir kod iermediinden dolay createGLTeapotObject() fonksiyonunu atlayacagiz.
Teapots::~Teapots() { makeCurrent(); delete fbObject; glDeleteLists(glTeapotObject, 1); }

Ykcda, teapots ve framebuffer nesne ile ilgili kaynaklar serbest brakrz.


void Teapots::initializeGL() { static const GLfloat ambient[] = { 0.0, 0.0, 0.0, 1.0 }; static const GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; static const GLfloat position[] = { 0.0, 3.0, 3.0, 0.0 }; static const GLfloat lmodelAmbient[] = { 0.2, 0.2, 0.2, 1.0 }; static const GLfloat localView[] = { 0.0 };

glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_POSITION, position); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodelAmbient); glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, localView); glFrontFace(GL_CW); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); }

initializeGL() fonksiyonu, aydnlatma modeli kurma ve esitli Opengl zelliklerini amak iin salanmtr. Bu kod, nceden adn zikrettigimiz OpenGL Programming Guide'da anlatlan teapots rneginden alnmadr.
void Teapots::resizeGL(int width, int height) { fbObject->bind(); glDisable(GL_TEXTURE_2B); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width <= height) { glOrtho(0.0, 20.0, 0.0, 20.0 * GLfloat(height) / GLfloat(width), -10.0, 10.0); } else { glOrtho(0.0, 20.0 * GLfloat(width) / GLfloat(height), 0.0, 20.0, -10.0, 10.0); } glMatrixMode(GL_MODELVIEW); drawTeapots(); fbObject->release(); }

Teapot widget ne zaman yeniden boyutlandrlrsa resizeGL() fonksiyonu aydanlik sahnesini yeniden izmek iin salanmtr. framebuffer nesnesi zerinde aydanlklar sahnelemek iin, fonksiyonunun banda QGLFramebufferObject::bind()'i arrz. Sonra, baz OpenGL zellikleri ve projeksiyon ve modelview matrislerini ayarlarz. Sonlara dogru drawTeapots() ars aydanlklar framebuffer nesne zerinde izer. Son olarak, release() ars daha sonraki OpenGL izim ilemlerinin framebuffer nesnesine gitmemesini salamak iin, framebuffer nesnesine olan balanmay kaldrr. Kod Grnm:
void Teapots::paintGL()

{ glDisable(GL_LIGHTING); glViewport(0, 0, width(), height()); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_TEXTURE_2B); glBindTexture(GL_TEXTURE_2B, fbObject->texture()); glColor3f(1.0, 1.0, 1.0); GLfloat s = width() / GLfloat(fbObject->size().width()); GLfloat t = height() / GLfloat(fbObject->size().height()); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, -1.0); glTexCoord2f(s, 0.0); glVertex2f(1.0, -1.0); glTexCoord2f(s, t); glVertex2f(1.0, 1.0); glTexCoord2f(0.0, t); glVertex2f(-1.0, 1.0); glEnd();

paintGL()'de, projeksiyon ve modelview matrislerinin sfirlanmasyla balarz. Sonra bir dokuya framebuffer nesnesini balar ve tm widget'i kapsayacak sekilde doku ile bir dikdrtgen izeriz. Kod Grnm:
if (rubberBandIsShown) { glMatrixMode(GL_PROJECTION); glOrtho(0, width(), height(), 0, 0, 100); glMatrixMode(GL_MODELVIEW); glDisable(GL_TEXTURE_2B); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glLineWidth(4.0); glColor4f(1.0, 1.0, 1.0, 0.2); glRecti(rubberBandCorner1.x(), rubberBandCorner1.y(), rubberBandCorner2.x(), rubberBandCorner2.y()); glColor4f(1.0, 1.0, 0.0, 0.5); glLineStipple(3, 0xAAAA); glEnable(GL_LINE_STIPPLE); glBegin(GL_LINE_LOOP); glVertex2i(rubberBandCorner1.x(), glVertex2i(rubberBandCorner2.x(), glVertex2i(rubberBandCorner2.x(), glVertex2i(rubberBandCorner1.x(), glEnd(); glLineWidth(1.0); glDisable(GL_LINE_STIPPLE); glDisable(GL_BLEND);

rubberBandCorner1.y()); rubberBandCorner1.y()); rubberBandCorner2.y()); rubberBandCorner2.y());

} }

Kesikli ereve hali hazrda grnyor ise, dikdrtgenin stne onu izeriz. Kod standart OpenGL.
void Teapots::mousePressEvent(QMouseEvent *event) { rubberBandCorner1 = event->pos(); rubberBandCorner2 = event->pos(); rubberBandIsShown = true; } void Teapots::mouseMoveEvent(QMouseEvent *event) { if (rubberBandIsShown) { rubberBandCorner2 = event->pos(); updateGL(); } } void Teapots::mouseReleaseEvent(QMouseEvent * /* event */) { if (rubberBandIsShown) { rubberBandIsShown = false; updateGL(); } }

Fare olay ileyicileri, ereveyi temsil eden rubberBandCorner1 rubberBandCorner2 ve rubberBandIsShown deikenlerini gnceller ve sahnenin yeniden boyanmasn iin updateGL()i arr. paintGL () sadece onun stnde ereve ve dokulu dikdrtgeni izdiinden sahnenin yeniden boyanmas, ok hzldr. resizeGL()'de, sahne, kullanc pencereyi boyutlandrdnda sadece yeniden sahnelenir. Buradaki, uygulamann main() fonksiyonu:
int main(int argc, char *argv[]) { QApplication app(argc, argv); if (!QGLFormat::hasOpenGL()) { std::cerr << " Bu sistem OpenGL desteine sahip deil" << std::endl; return 1; } if (!QGLFramebufferObject::hasOpenGLFramebufferObjects()) { std::cerr << " Bu sistem framebuffer obje desteine sahip deil" << std::endl; return 1; } Teapots teapots;

teapots.setWindowTitle(QObject::tr("Teapots")); teapots.resize(400, 400); teapots.show(); return app.exec(); }

fonksiyon , hata mesaj verir ve sistem OpenGL desteine ya da framebuffer obje desteine sahip deilse hata kodu ile uygulamay sonlandrr. Teapots rnei bize bir dokuya ekran-d yzeyi balama ve OpenGL komutlar kullanlarak bu yzeyde izimin basl olduunu gsterdi. Birok varyasyon mmkndr; rnein ,
QGLFramebufferObject veya QGLPixelBuffer'de izim iin OpenGL komutlar yerine QPainter'i kullanabilirdik. Bu, bir OpenGL sahnesinde dntrlm metni sahnelemek iin bir yol salar. Baka bir kullanm, bir sahneyi sahnelemek iin bir framebuffer objesini kullanmak ve sonra QImage'i retmek iin sonu iin toImage() arlr. Qt ile gelen rnekler, Framebuffer objeleri ve pbuffer iin bir ok uygulama gsteriyor.

You might also like