1谦炬、基本圖元連接方式
?
圖元primitive,即圖形元素节沦,是可以編輯的最小圖形單位键思。圖元是圖形軟件用于操作和組織畫面的最基本的素材。一幅畫面由圖元組成甫贯,圖元是一組最簡單的吼鳞、最通用的幾何圖形或字符。
OpenGL的基本圖元有點(Point)叫搁、線段(Line)赔桌、多邊形(Ploygon)供炎、三角形(Triangle)、四邊形(Quadrangle)疾党。
線段又分為獨立線段音诫、不閉合的線(Line Strip)和首尾閉合的線(Line Loop)。
三角形分為獨立三角形雪位、三角形鏈(Triangle Strip)和三角扇形(Triangle Fan)竭钝。
四邊形則分為獨立的四邊形和四邊形鏈(Quadrangle Strip)。
多邊形Polygon可以看成是三角形帶GL_TRIANGLE_TRIPE組成雹洗。
圖元 | 描述 |
---|---|
GL_POINTS | 每個頂點在屏幕上都是單獨點 |
GL_LINES | 每?對頂點定義?個線段 |
GL_LINE_STRIP | 從第?個頂點依次經過各個后續(xù)頂點的線段 |
GL_LINE_LOOP | 和GL_LINE_STRIP相同香罐,但是最后?個頂點和第?個頂點連接起來了 |
GL_POLYGON | 按點的定義順序依次連接 |
GL_TRIANGLES | 每3個頂點定義?個新的三?形,三角形之間是獨立的 |
GL_TRIANGLE_STRIP | 共??個條帶(strip)上的頂點的?組三?形 |
GL_TRIANGLE_FAN | 以?個圓點為中?呈扇形排列,共?相鄰頂點的?組三?形 |
?
三角形帶时肿、三角形扇
相對于GL_TRIANGLES庇茫,當我們會需要繪制?個相連的三角形時,我們可以使用GL_TRIANGLE_STRIP圖元繪制?串相連三?角形嗜侮,從?節(jié)省?量的時間港令。
優(yōu)點:
用前3個頂點指定第1個三角形之后,對于接下來的每?個三角形锈颗,只需要再指定1個頂點顷霹。需要繪制?量的三?形時,采用這種?方法可以節(jié)省?量的程序代碼和數(shù)據(jù)存儲空間击吱。
提供運算性能和節(jié)省帶寬淋淀。更少的頂點意味著數(shù)據(jù)從內存?zhèn)鬏數(shù)綀D形卡的速度更快,并且頂點著?器需要處理的次數(shù)也更少了覆醇。
2朵纷、正背面剔除(Face Culling)
?
在繪制一個3D場景的時候,處于對性能和實際情況的考慮永脓,我們是不是應該決定哪些部分是對觀察者可見的部分袍辞,哪些是觀察者不可見的部分,而不可見的部分常摧,我們是不是不應該渲染搅吁,這樣符合實際情況,也節(jié)省了性能落午。這種情況叫做“隱藏面消除”(Hidden surface elimination).例如下面這張圖片谎懦,有黑色的部分,也有紅色的部分溃斋,顯而易見界拦,黑色的部分不應該讓觀察者看到。
無論使用平面著色器還是默認光源著色器都會出現(xiàn)“隱藏面消除”問題梗劫,只不過使用用平面著色器時沒有黑影效果享甸,看不出來而已截碴。
?
解決辦法:油畫算法
油畫算法:
先繪制場景中的離觀察者較遠的物體,再繪制較近的物體
下圖先繪制紅色的部分,在繪制黃色的問題枪萄,最后繪制灰色的部分隐岛,即可解決隱藏面消除的問題。
油畫法的弊端:
油畫法雖然解決的隱藏面消除的問題瓷翻,我們進一步思考在上面的圖形繪制中聚凹,三個圖形有交匯的地方,我們是不是繪制了三遍齐帚,影響了性能妒牙。還有我們無法繪制圖形相互疊加層次混亂的問題。如下圖:
?
解決方案: 正背面剔除(Face Culling)
我們定義一個多邊形有兩個表面对妄,我們將一個標為正面湘今,一個為背面。通常剪菱,后表面總是不可見的摩瞎,這是因為場景中大多數(shù)物體是密封的。例如盒子孝常、圓柱體旗们、箱子等,并且我們也不能把攝相機放入物體的內部构灸。因此攝相機永不可能看到多邊形的背面上渴。
看不到的面,我們是可以不繪制來提高渲染性能喜颁。OpenGL可以開啟正背面剔除做到檢查所有正面朝向觀察者的面稠氮,并渲染它們,從而丟棄背面朝向的?半开,這樣可以節(jié)約渲染資源隔披,提高渲染效率。
正面背面區(qū)分
傳遞給OpenGL繪制的頂點數(shù)據(jù)是按照一定順序傳遞的寂拆,如果我們規(guī)定逆時針的連接方向為正面锹锰,順時針的連接為背面,那么OpenGL就知道繪制計算規(guī)律漓库,按照正面的原則渲染圖形。正面和背面是有三角形的頂點定義順序和觀察者方向共同決定的园蝠,隨著觀察者的角度?向的改變渺蒿,正面背面也會跟著改變。
默認正面: 按照逆時針頂點連接順序的三角形面
默認背面: 按照順時針頂點連接順序的三?形面
?
正背面剔除使用:
開啟表面剔除(默認背面剔除)
void glEnable(GL_CULL_FACE);
關閉表面剔除(默認背面剔除)
void glDisable(GL_CULL_FACE);
?戶選擇剔除那個面(正面/背面)
void glCullFace(GLenum mode);
mode參數(shù)為: GL_FRONT,GL_BACK,GL_FRONT_AND_BACK ,默GL_BACK
用戶指定那個為正面
void glFrontFace(GLenum mode);
mode參數(shù)為: GL_CW,GL_CCW,默認值:GL_CCW
例如,剔除正面實現(xiàn)(1)
glCullFace(GL_BACK);
glFrontFace(GL_CW);
例例如,剔除正?面實現(xiàn)(2)
glCullFace(GL_FRONT);
?
正背面剔除無法解決的問題
正背面剔除能解決顯示正面彪薛,剔除背面的功能茂装,但是無法解決同時都是正面時怠蹂,那個圖層在前,那個圖層在后少态,無法確定顯示哪個正面城侧,出現(xiàn)圖像顯示問題。
3彼妻、深度測試
?
隱藏?消除嫌佑,除了使?正背?剔除,還可以使?深度測試來解決侨歉。
深度 :
就是在openGL坐標系中屋摇,像素點的Z坐標距離觀察者的距離。當觀察者可以放在坐標系的任意位置幽邓,所以不能簡單的說Z數(shù)值越?或越?炮温,觀察者就越靠近物體。如果觀察者在Z軸的正?向牵舵,Z值越?則靠近觀察者柒啤;如果觀察者在Z軸的負?向,Z值越?則靠近觀察者畸颅。
深度緩沖區(qū)(DepthBuffer) :
深度緩沖區(qū)在顯存中担巩。深度緩存區(qū)原理就是把距離觀察者平?(近裁剪?)的深度值與窗?中每個像素點1對1進?關聯(lián)以及存儲,每個像素都需要存儲一個深度值重斑。
深度緩沖區(qū)(DepthBuffer)和顏?緩存區(qū)(ColorBuffer)是對應的兵睛。顏?緩存區(qū)存儲像素的顏?信息,?深度緩沖區(qū)存儲像素的深度信息窥浪。深度緩存區(qū)的默認值為1.0祖很,表示最?的深度值,深度值的范圍是[0,1]之間漾脂。
- 深度測試 : 在決定是否繪制?個物體表?時假颇,?先要將表?對應的像素的深度值與當前深度緩沖區(qū)中的值進??較,如果?于深度緩沖區(qū)中的值骨稿,則丟棄這部分笨鸡,否則利?這個像素對應的深度值和顏?值,分別更新深度緩沖區(qū)和顏?緩存區(qū)坦冠,這個過程稱為”深度測試”形耗。
// 清空深度緩存區(qū)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 開啟深度測試
glEnable(GL_DEPTH_TEST);
// 關閉深度測試
glDisable(GL_DEPTH_TEST);
我們可以通過 glDepthFunc(GLenum func)來修改深度測試的測試規(guī)則,那么測試的規(guī)則主要在于該函數(shù)中的枚舉值辙浑。
?
深度測試的Z-fighting(Z沖突.閃爍)問題:
開啟深度測試后激涤,OpenGL就不會再去繪制模型被遮擋的部分,這樣實現(xiàn)的顯示更加真實判呕。但是由于深度緩沖區(qū)精度的限制對于深度相差?常?的情況(例如在同?平?上進?2次制)倦踢。OpenGL就可能出現(xiàn)不能正確判斷兩者的深度值送滞,會導致深度測試的結果不可預測,顯示出來的現(xiàn)象是前?幾個畫?交錯出現(xiàn)辱挥。
同?個位置上出現(xiàn)的圖層犁嗅,且深度值出現(xiàn)精確度很低時,就會容易引起 ZFighting現(xiàn)象晤碘。表示幾個物體靠的?常的近褂微,?法確定誰在前,誰在后哼蛆。 ?出現(xiàn)顯示歧義蕊梧。
?
解決ZFighting問題:
既然是因為靠的太近,?法區(qū)分圖層先后. 那么此時,就可以在2個圖層之間加??個微妙的間隔. OpenGL提供了"多邊形偏移"解決?案腮介。
多邊形偏移解決?法:
讓深度值之間產?間隔肥矢,如果2個圖形之間有間隔,是不是意味著就不會產??涉叠洗「矢模可以理解為在執(zhí)?深度測試前將??體的深度值做?些細微的增加,于是就能將重疊的2個圖形深度值之前有所區(qū)分灭抑。
// 啟?多邊形偏移
glEnable(GL_POLYGON_OFFSET_FILL)
GL_POLYGON_OFFSET_POINT 對應模式: GL_POINT
GL_POLYGON_OFFSET_LINE 對應模式: GL_LINE
GL_POLYGON_OFFSET_FILL 對應模式: GL_FILL
// 設置參數(shù)十艾,每個Fragment的深度值都會增加如下所示的偏移量:
// ?般??,只需要將factor和units簡單賦值為-1就基本可以滿?需求。
glPolygonOffset(-1, -1)
// 關閉多邊形偏移
glDisable(GL_POLYGON_OFFSET_FILL)
// glPolygonOffset(Glfloat factor, Glfloat units);
// 每個Fragment的深度值都會增加的偏移量: Offset = ( m * factor ) + ( r * units);
// m:多邊形的深度的斜率的最?值腾节,理解?個多邊形越是與近裁剪?平?, m 就越接近于0忘嫉。
// r:能產?于窗?坐標系的深度值中可分辨的差異最?值。r是由OpenGL平臺指定的?個常量.
// Offset:?個?于0的Offset會把模型推到離你(攝像機)更遠的位置,相應的?個?于0的Offset會把模型拉近案腺。
// ?般??,只需要將factor和units簡單賦值為-1就基本可以滿?需求庆冕。
?
如何預防ZFighting閃爍問題
- 不要將兩個物體靠的太近,避免渲染時三?形疊在?起劈榨。這種?式要求對場景中物體插??個少量的偏移访递,那么就可能避免ZFighting現(xiàn)象。例如上?的??體和平?問題中同辣,將平?下移0.001f就可以解決這個問題拷姿。當然?動去插?這個?的偏移是要付出代價的。
- 盡可能將近裁剪?設置得離觀察者遠?些旱函。上?我們看到响巢,在近裁剪平?附近,深度的精確度是很?的棒妨,因此盡可能讓近裁剪?遠?些的話抵乓,會使整個裁剪范圍內的精確度變??些。但是這種?式會使離觀察者較近的物體被裁減掉,因此需要調試好裁剪?參數(shù)灾炭。
- 使?更?位數(shù)的深度緩沖區(qū),通常使?的深度緩沖區(qū)是24位的颅眶,現(xiàn)在有?些硬件使?使?32/64位的緩 沖區(qū),使精確度得到提?