openFrameworksでGeometry Shader

2017/05/6

glsl, openFrameworks

Geometry Shader test with openFrameworks from rystylee on Vimeo.

openFrameworksでジオメトリシェーダーを使う簡単なサンプルを書いてみました。
ジオメトリシェーダーを使うと、頂点シェーダーとフラグメントシェーダーだけでは実現できなかった様々な表現が可能になります!!

・頂点ごとではなく面ごとの処理
・ジオメトリシェーダーでのポイントスプライト
・頂点数を増減
・ポリゴンを飛ばしてバラバラに
・他にもいろいろ

などなど、色々と表現の幅が広がる香りがします。(こんな表現とか)

というわけでいろいろ弄ってみて冒頭の動画の様な感じになりました。
この記事では自分用のメモも兼ねて軽く解説を書いておきたいと思います。
ソースコードはこちらに置いたので、全文はこちらでご確認ください。
https://github.com/rystylee/geometryShaderSimpleExample

まずはoFでジオメトリシェーダーを使う際の設定をしてあげます。

setupの中に上のコードを記述しています。
シェーダーの読み込みとgeometry shaderの入出力の指定を行います。

ここからシェーダーです。まずはvertex shader。

vertex shaderでは、oFから受け取った頂点の座標のなり法線なりをgeometry shaderに華麗に受け流しています。
ここではgl_Positionに値を書き込んでいないのがポイントです。もちろんgl_Positioinに値を書き込んでも良いのですが、その場合geomery shaderを介さなくても普通にレンダリングが可能になります。(普通にvertex shaderとfragment shaderを使ってレンダリング)
今回のコードでは、geometry shaderの処理を明らかにするために、vertex shaderではgl_Positionに値を書き込まずgeometry shaderに値を流しています。
詳しくは以下のサイトを御覧ください。
OpenGL 3.2 GeometryShader をもう少し使ってみる

次にgeometry Shaderです。

ここでしていることを大雑把に言うと、
①受け取った情報を元にポリゴンを生成
②受け取った情報を元に、座標を法線方向にずらしてポリゴンを生成
となります。
このコードはtrianglesを受け取ってtriangle_stripを出力します。また、その際に3つの頂点を受け取りgeometry shaderの中で頂点を6つに増やして出力します。それは、元のポリゴンを保持しつつ法線方向に動かしたポリゴンも同時に描画するためです。
そして、vertex shaderで行わなかったgl_Positionに値を書き込む処理をgeometry shaderで行っています。

2つのforループがありますが、1つめは元のポリゴン、2つめは法線方向に動かしたポリゴンを生成する処理です。
そしてこの法線方向に動かすという処理ですが、ポリゴンをバラバラに分解するには3つの頂点からなる面の法線を求めなければなりません。vertex shaderから受け取るvNormalは頂点の法線であり、面の法線ではありません。そのため、元のポリゴンの座標にvNormalを足しただけではバラバラに分解することはできず、単に拡大したような結果となってしまいます。(ただし、頂点ごとにスケールの値を変えるとギザギザのハリネズミのような表現をすることができます)
コードの中では、NormalModeの値をGUIで変えることで面法線を適応するか頂点法線を適応するかを変更できるようにしています。

ここではポリゴンをバラバラにしたかったので、main関数の中で頂点座標から面法線を計算しています。
この処理の詳しい説明は以下のサイトを御覧ください。
頂点位置から面法線を算出

そして最後に、fragment Shader。

fragment shaderでは受け取ったテクスチャ座標を元にテクスチャから色情報を取り出し、頂点色と掛け合わせて出力します。

うまくビルドできればこんな感じの絵が出力されると思います。
ジオメトリシェーダー、上手く使いこなせるとどんどん表現の幅が広がっていきそうなので頑張っていきたいです〜
レイトレーシングとかトランスフォーム・フィードバックとか、まだ手を出せていないので隙を見つけて挑みたいです。。