Vala プログラミング

Rust & Vala プログラミング

おながのブログ

Rust glium Tessellation (1) Bezier Curve

glium(https://github.com/tomaka/glium)のexamplesにあるtessellation
プログラム(tessellation.rs)を参考にして、David Wolff著「OpenGL 4.0
シェーディング言語 ( OpenGL 4.0 Shading Language Cookbook )」の6章
「ジオメトリシェーダとテッセレーションシェーダ」をgliumで書いてみました。

今回は、「曲線をテッセレートする」の項です。テッセレーションの方法で、
曲線を描きます。

実行結果
f:id:onagat12:20170502124430p:plain tessellation level = 3
f:id:onagat12:20170502124451p:plain tessellation level = 5
f:id:onagat12:20170502124458p:plain tessellation level = 8

この例では、曲線の描画に3次べジェ曲線(ブレンド関数はベルンシュタイン
多項式)を使うので、4個の制御点(コントロールポイント)が必要です。
この4個の制御点がパッチ プリミティブになります。

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.4,  0.8] },
         Vertex { position: [ 0.4, -0.8] },
         Vertex { position: [ 0.8,  0.8] },
      ]
   ).unwrap()
};

VertexBufferを使ってコントロールポイントの頂点座標を設定します。


2 パッチ プリミティブとパッチあたりの頂点数を設定

let indices = glium::index::NoIndices(
    PrimitiveType::Patches { vertices_per_patch: 4 });

IndexBufferのPrimitiveTypeとvertices_per_patchで、パッチ プリミティブの
使用とパッチあたりの頂点数を設定します。


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 tess_level = 5;

         void main() {
            gl_out[gl_InvocationID].gl_Position =
               gl_in[gl_InvocationID].gl_Position;

            gl_TessLevelOuter[0] = 1;
            gl_TessLevelOuter[1] = tess_level;
         }
      "),
      tessellation_evaluation_shader: Some("
         #version 400

         layout(isolines) in;

         void main() {
            float u = gl_TessCoord.x;

            vec3 p0 = gl_in[0].gl_Position.xyz;
            vec3 p1 = gl_in[1].gl_Position.xyz;
            vec3 p2 = gl_in[2].gl_Position.xyz;
            vec3 p3 = gl_in[3].gl_Position.xyz;

            float u1 = (1.0 - u);
            float u2 = u * u;

            float b3 = u2 * u;
            float b2 = 3.0 * u2 * u1;
            float b1 = 3.0 * u * u1 * u1;
            float b0 = u1 * u1 * u1;

            vec3 p = p0 * b0 + p1 * b1 + p2 * b2 + p3 * b3;

            gl_Position = vec4(p, 1.0);
        }
      "),
      geometry_shader: None,
      fragment_shader: "
         #version 140

         out vec4 f_color;

         void main() {
            f_color = vec4(1.0, 1.0, 1.0, 1.0);
         }
      ",
   }).unwrap();

このプログラムでは、バーテックスシェーダ、テッセレーション制御シェーダ、
テッセレーション評価シェーダを使用します。このような場合は、Programの
SourceCodeを使って設定します。
テッセレーションシェーダとジオメトリシェーダはOptionとして設定するので、
None(使用しない)かSome()(使用する場合)で設定します。
曲線の描画では、Innerレベルは使用しません。Outerレベルでは、Outer[0]を1、
Outer[1]にレベルを設定します。GPUによっては、入れ替えが必要な場合が
あります。