glium テッセレーション
David Wolff著「OpenGL 4.0 シェーディング言語 ( OpenGL 4.0 Shading
Language Cookbook )」
第6章「ジオメトリシェーダとテッセレーションシェーダ」
「2D四角形をテッセレートする」
実行結果
tessellation level = 2
tessellation level = 4
tessellation level = 8
(Innerレベルは4に固定し、Outerレベルを変えている)
四角形の内部の点Pは、四角形の4隅(p0, p1, p2, p3)を制御点として、
次の補間式で表せる。u, vはパラメータで、0〜1の値をとる。
P = p0 * (1-u) * (1-v) + p1 * u * (1-v) + p2 * u * v + p3 * v * (1-u) 制御点:p0 = [-0.8, -0.8], p1 = [ 0.8, -0.8], p2 = [ 0.8, 0.8], p3 = [-0.8, 0.8]
この制御点をパッチ プリミティブとして、テッセレーションを使って、
レベルに対応したu, vを生成し描画する。
1 制御点(コントールポイント)の設定
let vertex_buffer = { #[derive(Copy, Clone)] struct Vertex { position: [f32; 2], } implement_vertex!(Vertex, position); glium::VertexBuffer::new(&display, &[ Vertex { position: [-0.8, -0.8] }, Vertex { position: [ 0.8, -0.8] }, Vertex { position: [ 0.8, 0.8] }, Vertex { position: [-0.8, 0.8] }, ] ).unwrap() };
(内容は、前例と同様)
2 パッチ プリミティブとパッチあたりの頂点数を設定
let indices = glium::index::NoIndices( PrimitiveType::Patches { vertices_per_patch: 4 });
(内容は、前例と同様)
3 シェーダプログラムの設定
let program = glium::Program::new(&display, glium::program::SourceCode { vertex_shader: " #version 140 in vec2 position; void main() { gl_Position = vec4(position, 0.0, 1.0); } ", tessellation_control_shader: Some(" #version 400 layout(vertices = 4) out; uniform int Outer = 5; uniform int Inner; void main() { gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; gl_TessLevelOuter[0] = Outer; gl_TessLevelOuter[1] = Outer; gl_TessLevelOuter[2] = Outer; gl_TessLevelOuter[3] = Outer; gl_TessLevelInner[0] = Inner; gl_TessLevelInner[1] = Inner; } "), tessellation_evaluation_shader: Some(" #version 400 layout(quads, equal_spacing, ccw) in; 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; gl_Position = p0 * (1-u) * (1-v) + p1 * u * (1-v) + p2 * u * v + p3 * v * (1-u); } "), geometry_shader: Some(" #version 400 layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; out vec3 color; void main() { gl_Position = gl_in[0].gl_Position; color = vec3(1.0, 0.0, 0.0); EmitVertex(); gl_Position = gl_in[1].gl_Position; color = vec3(1.0, 1.0, 0.0); EmitVertex(); gl_Position = gl_in[2].gl_Position; color = vec3(0.0, 0.0, 1.0); EmitVertex(); EndPrimitive(); } "), fragment_shader: " #version 140 in vec3 color; out vec4 f_color; void main() { f_color = vec4(color, 1.0); } ", }).unwrap();
この例ではジオメトリシェーダを使う。ジオメトリシェーダの設定にはOptionを
使うので、Some()で設定する。
テッセレーション座標u, vは、テッセレーション評価シェーダで、
u = gl_TessCoord.x v = gl_TessCoord.y
の式で生成される。