天天看點

曲面細分着色器---細分二維四邊形

openGL系列文章目錄

文章目錄

  • ​​openGL系列文章目錄​​
  • ​​前言​​
  • ​​一、曲面細分​​
  • ​​二、細分二維四邊形​​
  • ​​參考​​

前言

術語Tessellation(鑲嵌)是指一大類設計活動,通常是指在平坦的表面上,用各種幾何形狀的瓷磚相鄰排列以形成圖案。它的目的可以是藝術性的或實用性的,很多例子可以追溯到幾千年前在3D 圖形學中,Tessellation 指的是有點不同的東西(曲面細分),但顯然是由它的經典對應物(鑲嵌)啟發而成的。在這裡,曲面細分指的是生成并且操控大量三角形以渲染複雜的形狀和表面,尤其是使用硬體進行渲染。曲面細分是OpenGL 核心近期才增加的新功能,在2010 年的4.0 版本中出現。

一、曲面細分

OpenGL 對硬體曲面細分的支援,通過3 個管線階段提供:

(1)曲面細分控制着色器;

(2)曲面細分器;

(3)曲面細分評估着色器。

第(1)和第(3)階段是可程式設計的;而中間的第(2)階段不是。為了使用曲面細分,

程式員通常會提供控制着色器和評估着色器。

曲面細分器(其全名是曲面細分圖元生成器,或TPG)是硬體支援的引擎,可以生成固

定的三角形網格。②控制着色器允許我們配置曲面細分器要建構什麼樣的三角形網格。然後,

評估着色器允許我們以各種方式操控網格。然後,被操控過的三角形網格,會作為通過管

線前進的頂點的源資料。回想一下圖2.2,在管線上,曲面細分着色器位于頂點着色器和幾

何着色器階段之間。

讓我們從一個簡單的應用程式開始,該應用程式隻使用曲面細分器建立頂點的三角形網

格,然後在不進行任何操作的情況下顯示它。為此,我們需要以下子產品。

(1)C++/OpenGL 應用程式:

建立一個錄影機和相關的MVP 矩陣,視圖(v)和投影(p)矩陣确定錄影機朝向,模

型(m)矩陣可用于修改網格的位置和方向。

(2)頂點着色器:

在這個例子中基本上什麼都不做,頂點将在曲面細分器中生成。

(3)曲面細分控制着色器:

指定曲面細分器要建構的網格。

(4)曲面細分評估着色器:

将MVP 矩陣應用于網格中的頂點。

(5)片段着色器:

隻需為每個像素輸出固定顔色。

程式12.1 顯示了整個應用程式的代碼。即使像這樣的簡單示例也相當複雜,是以許多代

碼元素都需要解釋。請注意,這是我們第一次使用除頂點和片段着色器之外的元件建構

GLSL 渲染程式。是以,我們實作了createShaderProgram()的4 參數重載版本。

二、細分二維四邊形

了解OpenGL的硬體細分操作最好的方法就是細分一個二維四邊形,而後可視化細分的結果。使用線性插值後,産生的三角形和細分坐标(u,v)相關。通過使用不同的輸入和輸出細分級别産生四邊形對于學習很有價值。

曲面細分圖元生成器(TPG)根據6個參數來劃分(u,v)空間。它們是内部細分級别(0和1兩個)和外部細分級别(0-3共6個)。下面是對它們的描述:

外部細分級别0(OL0):沿v方向,u坐标為0的邊進行劃分的個數。

外部細分級别1(OL1):沿u方向,v坐标為0的邊進行劃分的個數。

外部細分級别2(OL2):沿v方向,u坐标為1的邊進行劃分的個數。

外部細分級别3(OL3):沿u方向,v坐标為1的邊進行劃分的個數。

内部細分級别0(IL0):沿u方向進行内部劃分的個數。

内部細分級别1(IL1):沿v方向進行内部劃分的個數。

下圖顯示了劃分級别對應的空間劃分。外部劃分級别定義了沿邊劃分的個數,内部劃分級别定義了

曲面細分着色器---細分二維四邊形

這6個細分級别可以通過數組g_TessLevelOuter和gl_TessLevelInner設定。比如,gl_TessLevelInner[0]對應IL0,gl_TessLevelOuter[2]對應OL2。

我們繪制一個細分四邊形來幫助了解OpenGL的四邊形細分,如下圖所示。

曲面細分着色器---細分二維四邊形

我們使用線性插值進行細分,圖中的三角形代表了四邊形的劃分。x軸對應u坐标,y軸對應v坐标。三角形的頂點由TPG産生。細分的三角形數量,可以直接從圖中看出。比如,何止外部細分級别為2,内部細分級别為8時,我們可以看到外部的邊被劃分為兩部分,在内部,(u,v)被劃分為8部分。在進行代碼實作之前,我們先讨論以下線性插值。對于下圖的四邊形,它内部的任一點可以通過對四邊形四角的頂點插值得到。

曲面細分着色器---細分二維四邊形

我們通過TPG生成u,v坐标,然後通過上圖的線性插值确定它在四邊形中的位置。

準備

我們通過Uniform變量Inner和Outer在OpenGL程式中設定細分級别。我們使用之前提到的幾何着色器來處理這些三角形。

然後,設定OpenGL程式渲染包含4個頂點的Patch圖元。

實作

我們采取下面的步驟來進行四邊形細分:

  1. 使用下面的代碼作為頂點着色器:
  2. ​#version 400 layout (location = 0 ) in vec2 VertexPosition; void main() { gl_Position = vec4(VertexPosition, 0.0, 1.0); }​

  3. 使用下面的代碼作為曲面細分控制着色器:
  4. ​#version 400 layout( vertices=4 ) out; uniform int Outer; uniform int Inner; void main() { // Pass along the vertex position unmodified gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; gl_TessLevelOuter[0] = float(Outer); gl_TessLevelOuter[1] = float(Outer); gl_TessLevelOuter[2] = float(Outer); gl_TessLevelOuter[3] = float(Outer); gl_TessLevelInner[0] = float(Inner); gl_TessLevelInner[1] = float(Inner); }​

  5. 使用下面代碼作為曲面細分計算着色器:
  6. ​#version 400 layout( quads, equal_spacing, ccw ) in; uniform mat4 MVP; void main() { float u = gl_TessCoord.x; float v = gl_TessCoord.y; vec4 p0 = gl_in[0].gl_Position; vec4 p1 = gl_in[1].gl_Position; vec4 p2 = gl_in[2].gl_Position; vec4 p3 = gl_in[3].gl_Position; // Linear interpolation gl_Position = p0 * (1-u) * (1-v) + p1 * u * (1-v) + p3 * v * (1-u) + p2 * u * v; // Transform to clip coordinates gl_Position = MVP * gl_Position; }​

  7. 使用專欄文章在着色後的網格上繪制線框中的幾何着色器。
  8. 使用下面的代碼作為片段着色器:

#version 400

uniform float LineWidth;

uniform vec4 LineColor;

uniform vec4 QuadColor;

noperspective in vec3 EdgeDistance;

// From geometry shader

layout ( location = 0 ) out vec4 FragColor;

float edgeMix()

{

//insert code here to determine how much of the edge

//color to include (see recipe “Drawing a wireframe on

//top of a shaded mesh”). **

}

void main()

{

float mixVal = edgeMix();

FragColor=mix( QuadColor, LineColor, mixVal);

}

6. 在OpenGL程式中設定Patch圖元頂點個數:

glPatchParameteri(GL_PATCH_VERTICES, 4);

7. 渲染Patch圖元。

原理

我們的頂點着色器在這裡隻用來傳遞參數。

我們在TCS中定義Patch圖元圖元的頂點數目:

layout (vertices=4) out

在main函數,我們沒有對頂點進行修改,隻是進行了細分級别的設定。所有4個外部細分級别被設定為變量Outer的值,所有内部細分級别被設定為變量Inner的值。

在曲面細分計算着色器,我們設定了一些其它的細分參數:

layout ( quads, equal_spacing, ccw ) in;

參數quads表示TPG進行的是四邊形細分。參數equal_spacing表示所有細分大小相同,最後一個參數ccw表示産生的頂點的順序是逆時針的。

在TES的main函數,我們通過數組gl_TessCoord擷取參數坐标。然後讀取數組gl_in中存儲的Patch圖元的4個頂點資訊。最後将這些資訊存儲在臨時變量中進行插值計算。

插值計算的結果指派給變量gl_Position。最後,使用模型視圖投影矩陣轉換頂點坐标到剪切空間。

在片段着色器,我們通過混合函數來渲染三角形的邊和非邊部分。

參閱

參考

繼續閱讀