我的opengl編程學習(一)(簡介、繪製圖像、三維觀察、光照)
這是我第二次學習OPENGL,第一次學習是在大二的計算機圖形學課堂上,那是對opengl隻是走馬觀花,現在過了兩年,我打算把opengl進行新一編完整而係統的學習,有三個目的:1.熟練掌握opengl編程,2從opegl的體係中加深對計算機圖形渲染管線的整個體係的了解,作為深入學習GPU編程的進階,3.製作好看的CG作品。
這裏是我在學習《opengl programming guide fifth edition》過程的從頭到尾的整個的學習筆記,放在這裏,給自己做個以後的參考,也想與大家交流。有很多錯別字,請原諒~~
最前麵:OpenGL是一個開放的2D/3D圖形繪製的工業標準,正因為隻是一個標準,所以OPENGL的管理者並沒有一個所謂的SDK,所有開發者可以使用的SDK都是Khronos Group(OpenGl標準的管理者)的成員應用這個標準自己編寫的(它的成員可以得到這個標準),例如常見在Microsoft的Visual Studio下的opengl是由微軟根據OpenGl1.1而自己編寫的。
Opengl的更高版本的更多特性都叫做,OPENGL擴展,不同的顯卡支持這些擴展中的不同擴展函數,所以使用更高級的特性時你必須擁有這些擴展庫,並且你的顯卡支持你用的特性。
GLEW就是一個非常好的擴展庫,它包括了最近的OPENGL核心庫,和大量的擴展庫,並且可以根據硬件自動識別哪些擴展可用。並且NVIDIA會有最新的OPENGL_SDK_Guide,這個guide其實就是以各種DEMO的形式來向開發者展示他們的顯卡都支持到的最新的核心庫和哪些擴展庫,他們的DEMO基本上也是用GLEW來寫的。
NVIDIA為了支持OPENGL的更高版本和新的擴展也會經常發布新的硬件驅動,來支持OPENGL的發展,可隨時關注NVIDIA的開發者網站。
0. 配置開發環境:
在VS2005下一般選用WIN32控製台程序,然後還要加入<window.h>
1. glut程序的一般組成:
glutInit
glutInitDisplayMode
glutInitWindowPosition
glutInitWindowSize
glutCreateWindow
直到調用glutMainLoop()窗口才真的會顯現
每當窗口內容需要重繪時都會調用glutDisplayFunc(void (*func)(void)),當你再改變某些內容想強製重繪時可調用glutPostRedisplay(void)發送一個信號
2 glut的四個時間響應回掉函數
glutReshapeFunc(void (*func)(int w, int h))
glutKeyboardFunc(void (*func)(unsigned char key, int x, int y))
glutMouseFunc(void (*func)(int button, int state, int x, int y))
glutMotionFunc(void (*func)(int x, int y))
3.雙緩存,一個顯示,另一個準備下一幀的繪製,當下一幀繪製好來,切換到另一個緩存,如此交替,可以時人看不到繪製當過程,隻有繪製好當結果才會被看到,就不會出現黑的屏幕(閃)。
在寫運動的程序中,除來初始化時用glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB)外,在繪製函數的最後一般要加上glutSwapBuffers(),因為打開雙緩存後,程序不會自動交換要顯示的那個緩存,而是一直顯示一個緩存的內容,這樣當一幀結束後這一緩存會清屏並進行重繪,而這以過程也被顯示出來,通常回看到程序像卡調,因為大部分時間這一個緩存在進行繪製運算,真正顯現出當繪製的結果隻是一瞬,所以要調用glutSwapBuffers()馬上顯示另一個緩存已完成的結果。
4.opengl繪製的三個最基本操作:clearing the window, drawing a geometric object, drawing a raster object(指一些二維對象)
clearing the window:為什麼要先CLEAR,因為緩存中的數據通常是上次保留的,要清掉
圖形硬件有好多個緩存,glClear後麵括號中指的是要清理的是那個緩存,有Color buffer Depth buffer Accumulation buffer Stencil buffer四種。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
比
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT)要快
繪製的基本原語:點 線 三角形 四邊形 多邊形 ,此外還有一個特殊點glRect函數繪製矩形 (在先進點GPU上,用一個向量做參數來製定一個點比用四個位置做參數性能會更好)
畫虛線: 先glLineStipple(1, 0x3F07)設置類型,再glEnable(GL_LINE_STIPPLE)打開虛線開關,這樣以後調用等畫線語句都畫虛線.
多邊形;
glPolygonMode(GLenum face, GLenum mode)用設置多邊形的外麵和裏麵的填充樣式和線性
多邊行的內外,默認時按頂點逆時針方向的那個麵為外麵(可見的),另外一個為裏,可以用glFrontFace(GLenum mode)來定義哪種時針方向的為外麵,通常多邊形組成空間體時,裏麵的裏.
glCullFace可以用來刪除外麵或側麵,比如永遠不可能看到側麵的情況,此處需要打開刪除開關.
Stippling Polygons,可以用一個位圖數據填充的方式來繪製多邊形,隻要先glEnable (GL_POLYGON_STIPPLE)打開開關,再glPolygonStipple ()載入這個位圖數據,然後繪製出的多邊形就都是用該位圖填充的.
Add:
Glflush()保證前麵所有的繪製命令強製被執行,並且是在優先時間內,因為有事由於一些優化等原因,繪製代碼並不會馬上就執行繪製,調用此函數保證馬上進行繪製
Glfinish ()也是強行繪製,但是與glflush不同是它被調用後進程被暫時阻塞直到繪製完成,比如一些用戶交互,當繪製完成後,你的鍵盤鼠標輸入才會正常響應.
繪製多邊形;隻能繪製簡單的凸包多邊形
1glEdgeFlag(GLboolean flag);來指定後麵的點的一個性質,如果為假,則這個點不會引導繪製出一條線,默認為真,這個函數為了繪製一些不需要內部線條的形狀或不是凸包的多邊形
2設置一個點的發向量的方法:glNormal3fv(n0); glVertex3fv(v0);
glEnable(GL_NORMALIZE)為打開自動歸一化發向量的開關(使成為單位向量)通常用在一些不常用的幾何操作(如乘以某個矩陣)時.因為默認OPENGL在計算時上是不會自動單位化這個法向量的.
4.數組數據,
glArrayElemernt
當繪製圖形時使用大量的頂點\發向量\顏色等時,可定義數組數據減少代碼,
static GLint vertices[] = {25, 25,
100, 325,
175, 25,
175, 325,
250, 25,
325, 325};
glEnableClientState (GL_VERTEX_ARRAY);打開頂點數組開關
glVertexPointer (2, GL_INT, 4*sizeof(GLint), vertices);//指定結構,表2個元素為一組,並選用其前4個;
glInterleavedArrays (GL_C3F_V3F, 0, intertwined);可以同時存儲多種數據的數組(如頂點和發向,要在數組中先定義頂點再定義發向)
然後用
glBegin(GL_TRIANGLES);
glArrayElement (2)來訪問其中的第三個元素
glend()
而且可以同時定義發向量等其他數組,可以在調用上句時同時調用
glDrawElements
用來進行一組繪製
static GLubyte allIndices = {4, 5, 6, 7, 1, 2, 6, 5,
0, 1, 5, 4, 0, 3, 2, 1,
0, 4, 7, 3, 2, 3, 7, 6};
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, allIndices);用24個點繪製正方形(也就是繪製6個)
這個函數不能用在glbegin和glend之間
glDrawArrays(GLenum mode, GLint first, GLsizei count);
用first到first+count-1之間的數做為值來繪製MODE(一個幾何體)
5.狀態管理和查詢,大多數狀態默認下是關閉的,以便達到根高的渲染速度,通過void glEnable(GLenum cap)和void glDisable(GLenum cap)來開或閉,
查詢當前狀態可以用glIsEnabled(GLenum capability)詢問某個狀態的關閉,或者更強大的void glGetBooleanv(GLenum pname, GLboolean *params);
void glGetIntegerv(GLenum pname, GLint *params);
void glGetFloatv(GLenum pname, GLfloat *params);
void glGetDoublev(GLenum pname, GLdouble *params);
void glGetPointerv(GLenum pname, GLvoid **params);這些可以查詢基本所有的數據(如當前的顏色等);
6.變換矩陣
viewing and modeling transformations-從物體坐標係轉換到視域坐標係(比如物體的一個頂點p在它的自身坐標係下坐標為(1,1,1),經過平移的MODEL矩陣後變為(1,2,1),而人是在原點向斜前方四五度觀察度,所以再乘以view矩陣變換到人的視域坐標係後,改點再以人眼為原點,觀察方向為z負方向的坐標係中就又不是(1,2,1)了,而變掉了,
projection matrix-從你的視域坐標係中,根據已定義的視錐體剪除調再視錐體外的部分,並且,將XYZ除以W以歸一化,還要確定投影的形式,是透視變換還是正交變換
viewport transformation-將三維的位置信息變換到二維屏幕的位置
glLoadIdentity()再OPENGL中,所有的轉換都是將轉換矩陣乘以當前矩陣,然後吧結果再作偽當前矩陣,所以再做一些變換前可能要調用此函數來清空當前矩陣
可以與他相乘的有gllookat glscale(rotate..)<modelview matrix>
glFrustum<projection matrix>等
glLoadMatrix*()將load一個你指定的矩陣作偽當前矩陣
opengl中矩陣的存儲形式為 ,可以定義一個16元素的叔祖來代表這個矩陣;
透視投影用來生成真是世界,正交投影用來生成需要嚴格考慮真是尺寸等情形
Opengl中同時存在一個MODELVIEW矩陣和一個PROJECTION矩陣,當你希望改變的是PROJECTION矩陣時,要用glMatrixMode (GL_PROJECTION)來切換,繁殖亦然,這樣切換後,當你再調用glFrustum等就是再PROJECTION矩陣上相乘,而不改變MODELVIEW矩陣.
一般MODELVIEW等變換都寫在繪製函數中,VIEW變換語句永遠要寫在MODEL變換前麵,而PROJECTION和VIEWPORT變換寫在RESHAPE函數中(因為投影和viewport要隨著窗口尺寸而變)
變換矩陣的相乘順序,矩陣的出現順序於實際變換順序時相反的,如先ROTATION再TRANSLATION的代碼應該是
glLoadIdentity();
glMultMatrixf(T); /* translation */
glMultMatrixf(R); /* rotation */
draw_the_object()
glscale的參數如果是負值,則表示朝向相反方向,如果想做關於Xz平麵的鏡像,隻要GLSCALE(1.-1.1),GLSCALE會降低性能
兩個透視投影函數gluPerspective glfrustum
Viewport的寬高比要和projection的寬高閉相同圖像才不會歪曲
Glpushmatrix() glpopmatrix(),把轉換的代碼寫在中間可以在結束後將矩陣再重置為push之前,但是OPENGL的矩陣堆棧是又限製的,可以用glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, GLint *params).查詢當前還可以放多少矩陣
7自定義剪裁平麵,除了用GLPERSPECTIVE剪裁四個邊界外,還可已自定義任意平麵對可見視錐體進行剪裁,可以定義多大6個平麵,用glClipPlane定義剪裁麵並進行剪裁,定以後要用glEnable打開開關才行
8.反轉矩陣變換,即從屏幕對二維信息轉換到物體對建模時對三維空間,等於將整個渲染管線反轉,用gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *objx, GLdouble *objy, GLdouble *objz)函數
其中WINZ是指深度緩存,默認為0-1,從0-1的深度緩存將對應出物體建模空間的一條線出來,其中還要製定渲染管線過程中的各個矩陣
gluProject()則是它的相反,模仿正常的幾何渲染管線得到三維對應二維的數據
9.顏色緩存由比特平麵構成,每個比特平麵為像素提供以為存儲,由幾個平麵就有幾位存儲
dithering(遞色),用合理的棋盤格疊加創造更多硬件不支持的顏色,通常在比特麵少的情況下,另外在使用雙緩存時,由於比特平麵減少了一半,有時也可能會使用,用glEnable(GL_DITHER)開啟
指定顏色時用glcolor3ub即可使用uchar類型(0-255)
用顏色索引表模式時設置清屏顏色用glClearIndex(),設置顏色用glIndex()。用glutSetColor()設置顏色表
用glShadeModel設置顏色的渲染模型,隻有GL_SMOOTH和GL_FLAT. smooth為默認
10.opengl中使用光照的步驟:
為每一個定點定義其法向量(其中glutSolidSphere()等這樣等函數已經定義好了默認的法向量)
i創建光源(用glLight()來設定光源的各種屬性,位置/屬性/參與打各種類型光的顏色,默認下環境光為0.0.0即不為環境的光做貢獻,第一個光源的反射光都為1.1.1,白光,其他的都無光)
ii創建光照模型(默認情況下認為人和物體無限遠,這樣就不用考慮人和物體的連線和光刀物體的聯線的夾角,默認還認為隻計算物體外麵的光照)
定義關照模型的函數為glLightModel,它有三種參數,為
GL_LIGHT_MODEL_AMBIENT,它用來定義一個基本的環境光,這個環境光時不是由任何實際光源所貢獻的環境光
GL_LIGHT_MODEL_LOCAL_VIEWER(GL_TURE OR FALE),用來定義視點時否離物體無限遠,也就是說如果為真,那麼光源在每個頂點處不用考慮角度的因素,各個點是一樣的,如果為錯則更真實一點,默認為無限遠
GL_LIGHT_MODEL_TWO_SIDE定義是否雙麵光照
iii定義物體的表麵光照材質(用glMaterialfv()來定義各種反射的屬性)
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission)可以定義一個模擬的光源
注意,設置glMaterialfv後這個屬性回一直影響到後麵所有繪製物體的狀態
一種簡化設置光照材質屬性的方法,用glColorMaterial()和GLCOLOR聯合,當定義了
glColorMaterial()後,並打開glEnable(GL_COLOR_MATERIAL)開關,則以後每改變GLCOLOR,則改變glColorMaterial()中所定義當那種材質屬性的顏色
還要用glEnable(GL_LIGHTING)打開關照功能,用glEnable(GL_LIGHT0)打開相應的光源
光源的名稱為GL_LIGHT0, GL_LIGHT1, GL_LIGHT2, GL_LIGHT3。。。
11.光源類型,OPENGL由方向光源(太陽,隻有方向無位置)和位置光源(隻有位置),當製定參數GL_POSITION時,如果矩陣當W為0,則為方向光源,XYZ代表方向,如果W非零,則為位置光源,XYZ為其次的位置坐標
其中位置光源可以設置光強衰減(模仿自然光),可以設置其衰減的參數用glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5);
因為實際光強= ×光強,默認KC=1,其餘為0;
所有位置光源可以攝製成聚光燈,用glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0);定義夾角,用glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);定義方向
光源的位置也會受到MODELVIEW矩陣的影響,所以有時要用POP PUSH堆棧
最後更新:2017-04-02 00:06:43
上一篇:
secrets of the javascript Ninja( with(){} 的用法)(javascript忍者的秘密)
下一篇:
偷Microsoft師學MFC藝:且看C++如何支持反射
PostgreSQL 邏輯訂閱 - 給業務架構帶來了什麼希望?
物聯網帶動醫療服務升級:六大原則守護網路安全
Android開發3——查看和輸出日誌信息
windows下ruby中顯示中文的3種方法
JavaMail學習筆記(一)、理解郵件傳輸協議(SMTP、POP3、IMAP、MIME)
測試文檔下載
Object reference not set to an instance of an object.
windows中修改catalina.sh上傳到linux執行報錯This file is needed to run this program
Arale 背後的一些設計理念
ASP.NET使用數據庫實現網站統計器