一、說明
??OpenGL 中的術語“基元”用于指代兩個相似但獨立的概念。 “原語”的第一個含義是指 OpenGL 使用的解釋方案來確定渲染時頂點流所代表的內容,例如“GL_POINTS”。這樣的頂點序列可以是任意長的。
??“原語”的另一個含義,也稱為“基本原語”,指的是頂點流的解釋結果,作為原語組裝的一部分。因此,通過這些基元解釋之一處理頂點流會產生基元的有序序列。各個基元有時被稱為“基本基元”。
二、頂點流
??頂點流是頂點的有序列表。該流的來源取決于 Primitive Assembly 發生的時間以及涉及渲染管道的哪些階段。頂點流可以來自:
- 頂點渲染命令,通過頂點規范定義并由頂點著色器處理。原始類型是渲染命令指定的類型。
- 曲面細分,執行曲面細分評估著色器后。原始類型由 TES 中指定的抽象補丁類型定義。
- 幾何著色器基元輸出。原始類型由 GS 指定。
與流關聯的圖元定義了如何將該流分解為基本圖元的有序序列:點、線或三角形。
三、點基元
??只有一種點原語:GL_POINTS。這將導致 OpenGL 將流中的每個單獨的頂點解釋為一個點。映射了紋理的點通常稱為“點精靈”。
??點被光柵化為給定窗口空間大小的屏幕對齊正方形。大小可以通過兩種方法給出:通過最后一個活動頂點處理著色器階段或通過上下文的狀態。要從著色器設置點大小,請啟用帶參數 (GL_PROGRAM_POINT_SIZE) 的 glEnable 以從程序設置點大小。如果啟用 GL_PROGRAM_POINT_SIZE,則點大小來自輸出變量 float gl_PointSize。如果禁用,則圖元中所有點的點大小都是恒定的,并由 glPointSize 函數設置。
??大小定義了點正方形每條邊占用的窗口像素數。該點的位置定義了該正方形的中心。
??無論點大小如何定義,它都必須大于 0,否則會導致未定義的行為。點大小有一個實現定義的范圍,并且任一方法給出的大小都被限制在該范圍內。您可以使用 GL_POINT_SIZE_RANGE 查詢范圍(返回 2 個浮點數)。還有一個點粒度,可以用 GL_POINT_SIZE_GRANULARITY 查詢;該實現會將大小限制為最接近的粒度倍數。
3.1 點片段輸入
??點僅由單個頂點定義。因此,通過光柵化該點生成的每個片段都會被賦予相同的用戶定義輸入值。然而,準確地知道特定片段著色器調用在點內的位置是有用的。雖然片段的具體位置 gl_FragCoord 會發生變化,但根據片段的位置,了解片段相對于點基元本身的位置會更有用。
??為了幫助實現這一點,片段著色器可以使用內置輸入 vec2 gl_PointCoord。這給出了 [0, 1] 范圍內的坐標。 (0, 0) 的位置取決于 GL_POINT_SPRITE_COORD_ORIGIN 的點參數設置:如果設置為 GL_LOWER_LEFT,則 (0, 0) 是左下坐標。而如果是GL_UPPER_LEFT,那么(0, 0)就是左上角坐標。默認值為 GL_UPPER_LEFT,適合 OpenGL 常用的右手坐標系。
3.2 多重采樣和衰落
??TODO:此部分需要填寫。
??當使用多重采樣渲染和繪制點時,片段著色器輸出變量可以調整其 alpha 以表示點“淡出”。
四、線基元
??根據頂點流的不同解釋,有 3 種線基元。
- GL_LINES:頂點 0 和 1 被視為一條線。頂點 2 和 3 被視為一條線。等等。如果用戶指定非偶數個頂點,則多余的頂點將被忽略。
- GL_LINE_STRIP:相鄰頂點被視為線。因此,如果通過 n 個頂點,您將得到 n-1 條線。如果用戶僅指定 1 個頂點,則繪圖命令將被忽略。
- GL_LINE_LOOP:作為線帶,只不過第一個和最后一個頂點也用作線。因此,您將獲得 n 個輸入頂點的 n 條線。如果用戶僅指定 1 個頂點,則繪圖命令將被忽略。第一個和最后一個頂點之間的線出現在序列中所有先前線之后。
4.1 線寬
??TODO:此部分需要填寫。
??線條被光柵化為寬度均勻的屏幕對齊四邊形。
五、基本三角形
??三角形是由 3 個頂點形成的圖元。它是頂點數量最少的 2D 形狀,因此渲染器通常旨在渲染它們。由于它僅由 3 個頂點創建,因此也保證是平面的。
??根據對頂點流的不同解釋,有 3 種三角形基元:
- GL_TRIANGLES:頂點 0、1 和 2 形成一個三角形。頂點 3、4 和 5 形成一個三角形。等等。
- GL_TRIANGLE_STRIP:每組 3 個相鄰頂點形成一個三角形。條帶的面方向由第一個三角形的纏繞確定。每個連續的三角形的有效面順序都會顛倒,因此系統通過以相反的方式測試它來補償這一點。長度為 n 的頂點流將生成 n-2 個三角形。
- GL_TRIANGLE_FAN:第一個頂點始終保持固定。從那時起,每組 2 個相鄰頂點與第一個頂點形成一個三角形。因此,使用頂點流,您會得到一個三角形列表,如下所示: (0, 1, 2) (0, 2, 3), (0, 3, 4) 等。長度為 n 的頂點流將生成 n- 2個三角形。
任何不完整的原語都將被忽略。例如,將 GL_TRIANGLES 與多個不能被 3 整除的頂點一起使用將忽略最后的不完整圖元。少于 3 個頂點的渲染將導致無渲染。
??以下是一些更具說明性的示例:
??GL_TRIANGLES:
Indices: 0 1 2 3 4 5 ...
Triangles: {0 1 2}{3 4 5}
GL_TRIANGLE_STRIP:Indices: 0 1 2 3 4 5 ...
Triangles: {0 1 2}{1 2 3} drawing order is (2 1 3) to maintain proper winding{2 3 4}{3 4 5} drawing order is (4 3 5) to maintain proper winding
GL_TRIANGLE_FAN:Indices: 0 1 2 3 4 5 ...
Triangles: {0 1 2}{0} {2 3}{0} {3 4}{0} {4 5}
5.1 三角面
??纏繞順序決定三角形的面。三角形的面可用于根據正面還是背面來剔除面。即使不使用面剔除,三角形的面也可以在模板測試中使用,并且片段數據的一部分是一個布爾值,表示片段是從三角形的正面還是背面生成。這允許片段著色器根據三角形的面進行不同的處理。
??面僅對三角形原始光柵化很重要。所有非三角形基元類型都被視為對正面進行光柵化,并且面剔除僅適用于三角形。
六、四邊形
??警告:本節介紹已從核心 OpenGL 3.1 及更高版本中刪除的舊版 OpenGL API(僅在 OpenGL 3.0 中棄用)。建議您不要在程序中使用此功能。
四邊形是 4 個頂點的四邊形基元。四個頂點預計共面;如果不這樣做可能會導致不確定的結果。
??四邊形通常被光柵化為一對三角形。 GL 規范沒有定義這一點,但它是允許的。由于頂點/幾何著色器輸出如何在 2 個生成的三角形上進行插值,這可能會導致一些偽影。
??GL_QUADS:頂點 0-3 形成一個四邊形,頂點 4-7 形成另一個四邊形,依此類推。頂點流必須是可被 4 整除的頂點數才能工作。
??GL_QUAD_STRIP:與三角形帶類似,四邊形帶使用相鄰邊形成下一個四邊形。對于四邊形,一個四邊形的第三個和第四個頂點用作下一個四邊形的邊。所以頂點 0-3 是一個四邊形,2-5 是一個四邊形,依此類推。長度為 n 的頂點流將生成 (n - 2) / 2 個四邊形。與三角形條帶一樣,每隔一個四邊形的四邊形的纏繞順序都會發生變化。
七、鄰接原語
??TODO:此部分需要填寫。
??這些是特殊的基元,預計專門與幾何著色器 (GS) 一起使用。這些圖元為幾何著色器提供了更多頂點來處理每個輸入圖元。通常,當使用上述任何原語時,GS 僅獲得基本類型之一。如果您將 GS 與 GL_TRIANGLE_STRIP 一起使用,則 GS 的每次執行只會看到一個特定三角形的 3 個頂點。這些特殊的基元模式允許 GS 訪問相鄰三角形的頂點數據。
八、補丁
??主條目:曲面細分#補丁
??GL_PATCHES 原始類型只能在 Tessellation 處于活動狀態時使用。它是一個具有用戶定義數量的頂點的圖元,然后根據控制和評估著色器將其細分為規則的點、線或三角形,具體取決于 TES 的設置。
??每個補丁的頂點數是通過使用 GL_PATCH_VERTICES 和一定數量的頂點調用 glPatchParameteri 來定義的,該數量必須小于 GL_MAX_PATCH_VERTICES。如果補丁中的頂點數量為 v?,則系統會將每個 v?頂點解釋為單獨的補丁,就像 GL_LINES 和 GL_TRIANGLES 一樣。因此,如果您想要類似條帶的行為,則需要使用索引。
??與從流中獲取多個值的其他基元類型一樣,不完整的補丁將被忽略。因此,如果您渲染的頂點數量不能被 v 整除,那么最后的頂點將被忽略。
九、激發頂點
??輸出基元中的頂點之一被指定為“激發頂點”。該頂點對于圖元具有特殊含義。例如,當對輸出變量使用平面著色時,僅使用來自激發頂點的輸出;該基元生成的每個片段都從引發頂點的輸出獲取輸入。
??每個基元類型定義頂點流中的哪個索引定義特定輸出基元的激發頂點。有一種方法可以更改激發頂點約定(主要是為了 D3D 兼容性):
void glProvokingVertex(GLenum provokeMode?);
??provokeMode?可以是下表列出的兩個枚舉器之一;默認為 GL_LAST_VERTEX_CONVENTION。該表定義了哪個頂點索引(使用基于一的索引)是特定基元類型的引發頂點。 i? 表示正在繪制的圖元的從一開始的索引。例如,如果您繪制具有 5 個頂點的 GL_TRIANGLE_FANS,則會產生 3 個圖元,因此 i?的范圍將超過 [1, 3]。因此,當使用最后一個頂點約定時,基元索引 2 的引發頂點將是頂點索引 4(該頂點的從零開始的索引是 3)。
??同樣,該表使用基于 1 的索引。
Primitive type | GL_FIRST_VERTEX_CONVENTION | GL_LAST_VERTEX_CONVENTION |
---|---|---|
GL_POINTS | i? | i? |
GL_LINES | 2i? - 1 | 2i? |
GL_LINE_LOOP | i? | i? + 1, if i? < the number of vertices.1 if i? is equal to the number of vertices. |
GL_LINE_STRIP | i? | i? + 1 |
GL_TRIANGLES | 3i? - 2 | 3i? |
GL_TRIANGLE_STRIP | i? | i? + 2 |
GL_TRIANGLE_FAN | i? + 1 | i? + 2 |
GL_LINES_ADJACENCY | 4i? - 2 | 4i? - 1 |
GL_LINE_STRIP_ADJACENCY | i? + 1 | i? + 2 |
GL_TRIANGLES_ADJACENCY | 6i? - 5 | 6i? - 1 |
GL_TRIANGLE_STRIP_ADJACENCY | 2i? - 1 | 2i? + 3 |
??補丁沒有引發頂點,因為 GL_PATCHES 只能與曲面細分一起使用。此過程將路徑圖元轉換為其他類型的圖元,因此當光柵化器看到它時,它不再是補丁。 TES 的輸出基元確實具有激發頂點,但對于特定線/三角形來說哪個頂點是激發頂點是實現定義的,因此不能依賴。因此,如果不同的基元需要不同的值,則使用平面插值的曲面細分是一個可疑的前景。
十、原始重啟
??主條目:頂點渲染#Primitive Restart
??設置基元重新啟動索引將導致在頂點流中達到該索引時重置基元的解釋。該索引處的頂點數據將不會被處理,也不會將頂點插入到該索引值的頂點流中。