その後のその後

iOSエンジニア 堤 修一のブログ github.com/shu223

【oFセミナーメモ2】 GLSL(Shader)テクニック

セッション1「C++テクニック」(boostライブラリの使い方)のメモ に続いて、セッション2 のメモです。

セッション2 : Shaderテクニック
講師 : 藤本直明、神田竜、他
GLSL(Shader)と呼ばれるOpenGLの機能を解説し、それを応用した映像表現を学びます。今回は、3Dを中心としたシェーディング手法を中心に解説していきます。

GLSLとは

  • OpenGLと一緒につかうシェーディング言語
  • シェーディング: 3DCGの見た目を決める
    • 光源の計算
    • 陰影の計算
    • ピクセルの計算
  • C言語っぽい見た目
  • グラボで並列処理
    • CPUで処理するよりも高速

ofShader

  • oFではofShaderを使う
  • 適用部分をbeginとendで挟む
  • oFからパラメータも渡せる
mShader.load("test.vert", "test.frag", "test.geom");
mShader.begin();

mShader.setUniform1f("rad", 10);

mVbo.draw(GL_POINTS, 0 , NUM);
mShader.end();

GLSLの種類

処理順に、

  • Vertex shader
  • Geometry shader
  • Fragment shader

Vertex Shader

頂点座標の変換

  • 頂点をうねうねさせる
  • ライティングのための準備

Geometry Shader

頂点の数の増減

  • 法線の方向にヒゲを生やす
  • ポリゴンを分割する
    • LOD (Level of Detail)・・・カメラの近くは繊細に、遠くは荒くても良い、みたいな動的に頂点数を増減する、みたいな使い方


省略可能

Fragment Shader

最終的な色を決める

  • ライティング
  • いらない部分を破棄する
  • ポストエフェクト

"tea pot discard glsl" で画像検索すると、ティーポットをFragment Shaderで処理した例が見れる


ピクセルシェーダとも呼ばれる

フラグメントシェーダを使ったポストエフェクト

講義資料:
ピクセルシェーダ on ofxPostGlitch|ひつじ|note


ofxPostGlitch

使用手順
  • addons フォルダに入れる
  • shader が入ってるフォルダ(shaders_pg)を、プロジェクトフォルダ配下の bin/data 直下に入れる
    • shaderは実行時に読み込まれるため、バイナリのデータフォルダに入れる必要がある


ofApp.h

#include "ofxPostGlitch.h"
ofxPostGlitch postGlitch;
ofFbo buffer;


ofApp.cpp

void ofApp::setup(){

    buffer.allocate(1024, 768);     // バッファ確保
    
    postGlitch.setup(&buffer);      // fboのポインタを渡す
}
void ofApp::draw(){
    
    // FBOに円を描画
    buffer.begin();
    ofClear(0, 0, 0);
    ofSetColor(255, 0, 0);
    ofCircle(100, 100, 100);
    buffer.end();

    // エフェクト選択
    postGlitch.setFx(OFXPOSTGLITCH_INVERT, ofGetKeyPressed());

    // エフェクトをかける
    postGlitch.generateFx();

    // FBOの内容を画面に描画
    buffer.draw(0,0);
}


setFxの引数を変えればエフェクトが変わる

postGlitch.setFx(OFXPOSTGLITCH_GLOW, ofGetKeyPressed());


ofxPostGlitchType一覧(ヘッダより)

enum ofxPostGlitchType{
	OFXPOSTGLITCH_CONVERGENCE,
	OFXPOSTGLITCH_GLOW,
	OFXPOSTGLITCH_SHAKER,
	OFXPOSTGLITCH_CUTSLIDER,
	OFXPOSTGLITCH_TWIST,
	OFXPOSTGLITCH_OUTLINE,
	OFXPOSTGLITCH_NOISE,
	OFXPOSTGLITCH_SLITSCAN,
	OFXPOSTGLITCH_SWELL,
	OFXPOSTGLITCH_INVERT,
	OFXPOSTGLITCH_CR_HIGHCONTRAST,
	OFXPOSTGLITCH_CR_BLUERAISE,
	OFXPOSTGLITCH_CR_REDRAISE,
	OFXPOSTGLITCH_CR_GREENRAISE,
	OFXPOSTGLITCH_CR_REDINVERT,
	OFXPOSTGLITCH_CR_BLUEINVERT,
	OFXPOSTGLITCH_CR_GREENINVERT
};


円にかけてみた例:

(左がOFXPOSTGLITCH_TWIST、右がOFXPOSTGLITCH_SWELL)

フラグメントシェーダ

// 1ピクセルごとにこの処理が行なわれる
void main (void)
{
    // 自分の座標を取得
	vec2 texCoord = vec2(pos.x , pos.y);
    
    // 画像内のその座標における色を取得
	vec4 col = texture2DRect(image,texCoord);;
    
    // 反転させる
	col.r = 1.0 - col.r;
	col.g = 1.0 - col.g;
	col.b = 1.0 - col.b;
    
    // 反転後の色を適用
	gl_FragColor = col;
}

`gl_FragColor` に突っ込んだ色( vec4 構造体)が最終的な色になる。

GLSLのバージョンについて

  • oF上でさくっと動かせるバージョンは120と150
  • oFのサンプル、vboMeshDrawInstancedExample のシェーダを見ると、バージョン120と150の違いがわかる
#version 120
#version 150
  • 言語の仕様が全然違う
    • 最後 `gl_FragColor` につっこむのは120の仕様
    • ofxPostGlitch は120ベース


oFで150を使う場合は、

#define USE_PROGRAMMABLE_GL 1

をヘッダで定義する

(あとで追記)パーティクルにテクスチャを貼る

聞くだけで精一杯だったのであとで追記します。

oFでのシェーディング

固定機能シェーダ
  • OpenGLに元々入っている
  • フラットシェーディング
  • グローシェーディング
  • ライティング

- ofLightとofMaterial

プログラマブルシェーダ
  • 自分でプログラムでシェーディングを記述できる
  • 固定機能シェーダの内容をすべて実現できる(が、全部自分で書かなければならない。大変。)
  • vertex shader

ライトの種類

(配布pdfがすごく詳しいので、メモは省略)


(この画像はoFのサイトにあったもの)

サンプル:multiLightExample

examples/gl/multiLightExample


球の解像度

ofSetSphereResolution(128);



128だからツルツル、10とかにすると荒くなる



解像度落として、smoothlightingをオフにすると、

ofSetSmoothLighting(false);
ofSetSphereResolution(10);
  • > フラットシェーディング

法線ベクトルの求め方

ポリゴンの2つの辺の外積を計算する

ofVec3f c = a.crossed(b);

// 単位ベクトルにする
c.normalize();

拡散光の求め方

物体の法線とライト方向の内積から、拡散光が計算できる

float c = a.dot(b);


※固定機能シェーダを使う場合にはOpenGLが計算してくれるので、自分で計算する必要はない

グローシェーディング

球のシェーディングとかのときに、 滑らかな曲面を表現するために、隣り合う平面の法線を平均したものをそれぞれの面の法線とする 方法


oF の `ofSetSmoothLighting` をオンにした状態