文章出處

Modern OpenGL用Shader拾取VBO內單一圖元的思路和實現(2)

上一篇里介紹了Color-Coded Picking的思路和最基本的實現。在處理GL_POINTS時已經沒有問題,但是處理GL_LINES、GL_TRIANGLES等時會遇到同一圖元的各個頂點顏色不同的問題,這就不能正確拾取了,本篇來解決這個問題。

 

對于GL_LINES,可以用 int objectID = gl_VertexID / 2; 來使得每個線段圖元的兩個頂點顏色分別相同;對于GL_TRIANGLES,則用 int objectID = gl_VertexID / 3; 。但是這個方法無法應用到存在共享頂點的GL_LINE_STRIP、GL_TRIANGLE_STRIP、GL_LINE_LOOP等情況。所以要另辟蹊徑。

 

ShadeMode

首先介紹一下glShadeMode()這個函數。就是靠它才解決了本文的問題。

glShadeMode()

在(https://www.opengl.org/sdk/docs/man2/xhtml/glShadeModel.xml)有它的專業解釋,里面有這樣一張表格。

Primitive Type of Polygon i

Vertex

Single polygon ( i == 1 )

1

Triangle strip

i + 2

Triangle fan

i + 2

Independent triangle

3 × i

Quad strip

2 × i + 2

Independent quad

4 × i

這個表格的意思是:在 glShadeMode(GL_FLAT); 狀態下,在繪制某種圖元時,其顏色由第i個頂點的顏色決定。(其實就是由定義一個圖元的最后一個頂點的顏色決定)

單看表格難以理解,用下面的Demo進行說明。

 

這個Demo繪制了8個頂點,其位置和顏色如下(同上圖左側所示)

 1 gl.Color(0, 0, 0);
 2 gl.Vertex(0, 0);
 3 
 4 gl.Color(1f, 0, 0);
 5 gl.Vertex(0, 1);
 6 
 7 gl.Color(0, 1f, 0);
 8 gl.Vertex(1, 0);
 9 
10 gl.Color(1f, 1f, 0);
11 gl.Vertex(1, 1);
12 
13 gl.Color(0, 0, 1f);
14 gl.Vertex(2, 0);
15 
16 gl.Color(1f, 0, 1f);
17 gl.Vertex(2, 1);
18  
19 gl.Color(0, 1f, 1f);
20 gl.Vertex(3, 0);
21 
22 gl.Color(1f, 1f, 1f);
23 gl.Vertex(3, 1);
Demo 模型

 

下面分別看一下在 glShadeMode(GL_SMOOTH); 和 glShadeMode(GL_FLAT); 模式下,用這個8個頂點繪制各種圖元的情況。

這是GL_SMOOTH 模式下的GL_LINE_STRIP。

 

這是GL_FLAT模式下的GL_LINE_STRIP。

 

這是GL_SMOOTH 模式下的GL_TRIANGLES。

 

這是GL_FLAT 模式下的GL_TRIANGLES。

 

這是GL_SMOOTH 模式下的GL_TRIANGLE_STRIP。

 

這是GL_FLAT模式下的GL_TRIANGLE_STRIP。

 

這是GL_SMOOTH 模式下的GL_QUAD_STRIP。

 

 

這是GL_FLAT 模式下的GL_QUAD_STRIP。

 

您可以點此下載此Demo慢慢對比。

 

GL_FLAT的作用

通過上面一節的觀察可以看到,GL_FLAT模式下,各種類型的圖元的顏色都是由繪制它的最后一個頂點的顏色給出的。

這么絕妙的顏色分配方案簡直就是為了解決本文的問題而設計的。

我們只需在做Picking的繪制時,在GL_FLAT狀態下繪制圖元,就可以用glReadPixel()獲取到應拾取的圖元的最后一個頂點的編號。根據上一節的表格,很容易推算出此編號代表的圖元。

 

'flat' in GLSL

 

 

 

 

 

不過這又帶來一個小問題:glShadeMode();在使用Shader+VBO時是無效的。不過Modern OpenGL必然要有能代替它的功能:GLSL里的flat關鍵字。給in/out變量附加一個flat,就相當于Legacy OpenGL里調用了glShadeMode(GL_FLAT);

flat out vec4 pass_Color; // glShadeMode(GL_FLAT); in legacy opengl.

flat in vec4 pass_Color; // glShadeMode(GL_FLAT); in legacy opengl.

這也是本文與上一篇的程序中唯一的區別。

 

未完待續

拾取一個VBO里的單個圖元的問題已經徹底解決了。那么來看下一個問題:一個場景里可能會有多個VBO,此時每個VBO的gl_VertexID都是從0開始的,那么如何區分不同VBO里的圖元呢?我們下回分解。

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()