第二章:Hello World幻燈片 在前一章中,我給出了圖像管線(xiàn)的整體概述,F在是時(shí)候將它付諸行動(dòng)了。在我嘗試渲染任何有趣的3D場(chǎng)景之前,我將像標準的教程那樣使用一個(gè)簡(jiǎn)單的,二維的"hello world"程序來(lái)展示基本的OpenGl API。我們將使用下面這張圖: ![]() 將它畫(huà)到一個(gè)大小合適的窗口中。但是靜態(tài)圖片看起來(lái)很無(wú)趣--我們將它弄得有趣一點(diǎn),讓它和下面這張圖一起進(jìn)行反復地淡入淡出: ![]() 盡管仍然不是一個(gè)很有趣的程序,但是它非常簡(jiǎn)單,更復雜的程序使用的OpenGL特性它幾乎都會(huì )使用到。完整的代碼上傳到了Github這里。僅僅將圖片畫(huà)到屏幕上,這個(gè)程序使用了380行C代碼以及一些的著(zhù)色器代碼,看起來(lái)有點(diǎn)過(guò)。不過(guò),它將是接下來(lái)的一些更有趣的demo的基礎。源文件hello-gl.c中包含了OpenGL渲染的代碼部分,而util.c中包含了很無(wú)聊的公共函數用于讀取TGA格式圖像。我在其中包含了兩個(gè)這種格式的圖像,hello1.tga和hello2.tga,因為這種格式很容易解析而不用依賴(lài)外部庫。我們的著(zhù)色器代碼在兩個(gè)文件中:hello-gl.v.glsl用于頂點(diǎn)著(zhù)色器,hello-gl.f.glsl用于像素著(zhù)色器。 在這一章中,我將解釋hello-gl程序的各個(gè)部分是如何使用OpenGL API將數據放到圖像管線(xiàn)中以及如何讓它運行起來(lái)。當我們討論著(zhù)色器時(shí),我還將給出一個(gè)簡(jiǎn)明的GLSL語(yǔ)言的概述。將這些東西全部放在一篇文章中有點(diǎn)多,所以我將這一章拆成四個(gè)部分。在這第一部分中,我們將通過(guò)GLUT打開(kāi)一個(gè)窗口。在第二部分中,我們將設置我們程序中使用的緩沖區以及紋理對象,它們包含了原始的頂點(diǎn)和圖像數據。之后,我們將寫(xiě)著(zhù)色器代碼來(lái)處理這些數據將我們最終的圖像顯示在屏幕上。既然我們的游戲的計劃已經(jīng)布置好了,下面讓我們演員們登場(chǎng)。我們首先設置好GLUT并在屏幕中創(chuàng )建一個(gè)空的窗口。 OpenGL頭文件 #include #include #ifdef __APPLE__ # include #else # include #endif 不同的平臺將它們的OpenGL頭文件放在不同地方,但是有了GLEW,你不需要擔心這些。不管它們在哪里,包含GL/glew.h將會(huì )為你包含進(jìn)系統的OpenGL頭文件。不幸的是,包含GLUT仍然有些坑,需要你手動(dòng)設置一些跨平臺的東西。它的頭文件一般在GL/glut.h,但是MacOS X的附帶的GLUT框架使用蘋(píng)果自己的頭文件約定,將GLUT頭文件放在GLUT/glut.h。最近版本的Visual Studio的標準C頭文件與glut的交互方式有個(gè)bug,導致包含stdlib.h的順序要在glut.h之前。(譯者注:原文時(shí)間約為2010年4月,我不確定現在版本的VS是否還有這個(gè)問(wèn)題) 用GLUT設置好我們的窗口 int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowSize(400, 300); glutCreateWindow("Hello World"); glutDisplayFunc(&render); glutIdleFunc(&update_fade_factor); GLUT提供了一個(gè)有限制的,但是直觀(guān)并且可移植的窗口系統接口。通過(guò)調用glutInit準備好GLUT之后,我們使用glutInitDisplayMode來(lái)指定我們默認的framebuffer應該使用怎樣的緩沖區。在這里,一個(gè)雙緩沖(GLUTDOUBLE)的顏色緩沖區(GLUTRGB)足夠了。(Double buffering為framebuffer提供了兩個(gè)顏色緩沖區,每一幀中一個(gè)用于顯示在屏幕上,另一個(gè)畫(huà),在兩者中切換,這樣動(dòng)畫(huà)看起來(lái)就是平滑的)。如果我們需要深度或者 stencil 緩沖區,我們可以在這里做。然后我們使用glutIninWindowSize設置初始的圖片的窗口大小為400x300并使用glutCreateWindon創(chuàng )建窗口。最后,我們指定兩個(gè)回調函數接受窗口事件:一個(gè)glutDisplayFunc用于在窗口需要顯示時(shí)渲染我們的圖像,一個(gè)glutIdleFunc持續地更新兩個(gè)圖片之間隨時(shí)間漸變的因子。 glewInit(); if (!GLEW_VERSION_2_0) { fprintf(stderr, "OpenGL 2.0 not available\n"); return 1; } 在GLUT創(chuàng )建我們的窗口之后,它會(huì )準備好OpenGL,這樣我們就能開(kāi)始調用這個(gè)庫。我們首先要做的是初始化GLEW。當函數glewInit被調用時(shí),它會(huì )根據OpenGL的可用版本以及擴展設置一系列的標志。這里在繼續之前我們檢測GLEWVERSION2_0標記以確保OpenGL 2.0是可用的。除了設置版本標記,GLEW幾乎不扮演其它任何角色,并且在它初始化之后我們不需要與它交互。 if (!make_resources()) { fprintf(stderr, "Failed to load resources\n"); return 1; } glutMainLoop(); return 0; } GLEW初始化后,我們調用我們的make_resources函數來(lái)設置我們的OpenGL資源。如果我們的資源加載成功,glutMainLoop會(huì )運行。它顯示窗口,開(kāi)始從窗口系統接收UI事件,并調用我們設置好的回調函數響應這些事件。它還會(huì )在用戶(hù)退出時(shí)幫我們退出程序。return 0僅僅是避免編譯警告,實(shí)際上絕對不會(huì )運行到那里。 編譯并運行我們的程序 現在我們可以先不管GLUT回調函數和make_resources函數,得到一個(gè)可以運行的,盡管沒(méi)什么價(jià)值的程序: static int make_resources(void) { return 1; } static void update_fade_factor(void) { } static void render(void) { glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glutSwapBuffers(); } glClearColor設置一個(gè)RGBA消除顏色(這里是白色),然后glClear使用這個(gè)顏色來(lái)填充framebuffer的顏色緩沖區。glutSwapBuffers然后將我們的用于消除的顏色緩沖區顯示在屏幕上。通過(guò)這幾個(gè)函數,現在我們可以編譯和運行我們的程序。這個(gè)空函數版本在Github倉庫中對應的是hello-gl-dummy.c。編譯程序并鏈接到OpenGL,GLUT和GLEW庫的命令在不同平臺下會(huì )有些區別。在大多數類(lèi)Unix下大概像下面這樣子: gcc -o hello-gl-dummy hello-gl-dummy.c \ -I/usr/X11R6/include -L/usr/X11R6/lib \ -lGL -lGLEW -lglut 在MacOS X中: # Assuming GLEW was installed to /opt/local gcc -o hello-gl-dummy hello-gl-dummy.c \ -I/opt/local/include -L/opt/local/lib \ -framework OpenGL -framework GLUT -lGLEW 在Windows中使用Visual C++: cl /Fohello-gl-dummy.obj /c hello-gl-dummy.c link /out:hello-gl-dummy.exe hello-gl-dummy.obj \ opengl32.lib glut32.lib glew32.lib 在Windows中使用mingw: gcc -o hello-gl-dummy.exe hello-gl-dummy.c \ -lopengl32 -lglut32 -lglew32 在Github倉庫中還包含了各個(gè)平臺下的makefile。你可以使用hello-gl-dummy(或者hello-gl-dummy.exe,在Windows下)編譯這個(gè)版本的程序: make -f Makefile.MacOSX hello-gl-dummy # or Makefile.Unix or Makefile.Mingw nmake /f Nmakefile.Windows hello-gl-dummy.exe 一旦你編譯好程序,你應該能夠運行它并且得到一個(gè)白色的窗口: ![]() 關(guān)閉窗口,或者在MacOS X下退出應該可以關(guān)閉它。 接下來(lái),緩沖以及紋理 我們已經(jīng)準備好了將我們的頂點(diǎn)和圖像放到OpenGL。在下一篇文章中,我們會(huì )介紹OpenGL的緩沖以及紋理對象。 |