dskjal
広告
広告

GPU Shader Module(gpu)の翻訳

カテゴリ:blender

これはGPU Shader Module (gpu) の翻訳だ。

このモジュールは Python から GPU を扱うためのラッパーを提供する。より抽象度の高い機能は gpu_extras モジュールにある。

以下のサブモジュールがある。

ジオメトリバッチ

ジオメトリはバッチ処理される。バッチには描画に必要なデータを格納する必要がある。頂点バッファは常に必要となるが、インデックスバッファはなくてもよい。それらは今後のセクションで解説する。バッチは描画タイプも指定する。典型的な描画タイプは点(POINTS)、線(LINES)、三角形(TRIS)だ。描画タイプはデータの解釈方法と描画方法とを決めるのに使われる。

頂点バッファ

頂点バッファオブジェクト(VBO)(gpu.types.GPUVertBuf)はシェーダの描画に必要な情報を格納する。位置・法線・色・UV 等がよく使われる。頂点バッファはそれぞれ頂点フォーマット(gpu.types.GPUVertFormat)と、バッファ内の頂点数を指定する長さパラメータを持つ。頂点フォーマットは頂点ひとつあたりのデータの解釈方法を記述する。

以下のコードは6つの頂点を含む頂点バッファの作成方法を示している。頂点それぞれに位置と法線との情報を格納している。

import gpu
vertex_positions = [(0, 0, 0), ...]
vertex_normals = [(0, 0, 1), ...]

fmt = gpu.types.GPUVertFormat()
fmt.attr_add(id="pos", comp_type='F32', len=3, fetch_mode='FLOAT')
fmt.attr_add(id="normal", comp_type='F32', len=3, fetch_mode='FLOAT')

vbo = gpu.types.GPUVertBuf(len=6, format=fmt)
vbo.attr_fill(id="pos", data=vertex_positions)
vbo.attr_fill(id="normal", data=vertex_normals)

この頂点バッファは6つの点、3つの独立した線、5つの連続した線、2つの独立した三角形等のどれかを描画できる。頂点バッファがどのようなポリゴンとしてレンダリングされるかはバッチ作成時に指定する。

インデックスバッファ

三角形や線がひとつ以上の頂点を共有することはよくある。頂点バッファのみでこれをレンダリングする場合、同じ頂点属性を複数回複製する必要がある。これは効率が悪い。なぜなら閉じた三角形メッシュは、平均して6回同じ頂点が使われるからだ。このような場合はインデックスバッファ(IBO)(gpu.types.GPUIndexBuf)(エレメントバッファ)を使うと効率的だ。インデックスバッファは頂点バッファ内の頂点を指すインデックスを格納する配列だ。

例えば、ふたつの三角形からなる四角形を描画するとき、以下のようにしてインデックスバッファを利用できる。

positions = (
    (-1, 1), (1, 1),
    (-1, -1), (1, -1))

indices = ((0, 1, 2), (2, 1, 3))
ibo = gpu.types.GPUIndexBuf(type='TRIS', seq=indices)

indices の最初のタプルは最初の三角形がどの頂点を使っているかを示している。対角線の頂点1と2とがふたつの三角形で共有されていることに注目してほしい。

シェーダ

シェーダは GPU で実行されるプログラムだ。Blender では GLSL を使って書く。シェーダにはいくつかの種類がある。最も重要なものは頂点シェーダとフラグメントシェーダだ。普通、複数のシェーダはプログラム(Program)にまとめられる。しかし、Blender Python API ではシェーダは OpenGL プログラムを指す。すべての gpu.types.GPUShader は頂点シェーダ・フラグメントシェーダ・オプションのジオメトリシェーダからなる。よく使う描画タスクは gpu.shader.from_builtin にあるシェーダが使える。それには 2D_UNIFORM_COLOR や 3D_FLAT_COLOR のような識別子がついている。

すべてのシェーダは、シェーダ内で使用できる属性(attributes)や uniforms を定義できる。属性は頂点バッファから設定され、個別の頂点とは異なっている。uniforms はドローコール(draw call)ごとに設定できる定数だ。uniforms はシェーダがバインドされた後で、shader.uniform_* 関数を使って設定できる。

バッチの作成

バッチの作成には頂点バッファとインデックスバッファとが必要になる。しかし gpu_extras.batch.batch_for_shader 関数の使用を推奨する。それはシェーダが要求する頂点の属性が存在することを自動で検証してくれる。batch_for_shader が引数にシェーダを要求するのはそれが理由だ。

バッチは可能ならばキャッシュしておいて再利用すべきだ。

オフスクリーンレンダリング

レンダリング後にスクリーンに表示されるバッファをフロントバッファと呼ぶ。ドローコールが発行されると、バッチはバックバッファに描画し、それが完了するとバックバッファとフロントバッファとを入れ替える。

レンダリング結果を画像として保存したり、テクスチャとして利用するために別のバッファに描画することがある。これをオフスクリーンレンダリングと呼ぶ。Blender ではオフスクリーンレンダリングには gpu.types.GPUOffScreen を使う。

警告

GPUOffScreen オブジェクトは 作成された OpenGL コンテキストにバインドされている。Blender がこのコンテキストを破棄する(つまりウインドウが閉じられる)と、そのオフスクリーンインスタンスは解放される。

サンプルコードは Blender にコピーペーストして実行するだけで動作するようにしてある。ただし登録した描画関数を削除できないので、他のコードを試す場合は Blender を再起動する必要がある。

単色の3Dライン

三角形をカスタムシェーダでシェーディング

インデックスバッファを使ったワイヤーフレームのキューブ

ランダムな頂点色を持つメッシュ

2D矩形

2D画像

このサンプルコードを実行するには画像を Blender にロードしておく必要がある。

オフスクリーンレンダリングでテクスチャの作成

  1. gpu.types.GPUOffScreen オブジェクトの作成
  2. それに円を描画
  3. 3D空間にそれを表示するシェーダを作成
  4. 作成したシェーダを使ってオフスクリーンレンダリングしたテクスチャを表示

オフスクリーンレンダリングの結果を画像に変換

このサンプルコードは IMAGE_NAME で指定された名前で新しい画像を作成する。既に存在する場合は置き換えられる。

現状では実行時間のほとんどが最後の行の実行に使われている。将来的には、bgl.Buffer と bpy.types.Image.pixels(bpy_prop_array)の Python バッファプロトコルの実装により解決される見込みだ。

ビューポートをテクスチャにレンダリング

このサンプルコードはカメラが必要になる。本来は特定のカメラに依存せずに実装できるが、Blender にはカメラを使わずにビュー行列とプロジェクション行列とを作成する関数がまだない。

点線の3Dラインを描画するカスタムシェーダ

このサンプルコードは弧の長さは頂点ごとに計算されている。頂点シェーダからフラグメントシェーダへデータを渡す際に、スクリーン上で可視である頂点は自動的にその値が補間される。フラグメントシェーダで弧の長さの sin が計算される。その結果をもとにそのフラグメントが描画されるかどうかが決定される。

関連記事

Blender 記事の目次


広告
広告

カテゴリ