半空洞男女関係

思ったこととかプログラミングしてるときのメモとか色々かいてます。メールはidそのままgmail

openFrameworksでシェーダを扱う

openFrameworksでシェーダ扱える。ofShaderというオブジェクトがあるので、そのオブジェクトにvertexシェーダとfragmentシェーダのファイルを読み込ませて使う。僕の理解ではvertexシェーダが頂点の位置を動かし、fragmentシェーダがある頂点の色を指定する。

class ofApp : public ofBaseApp {

public:
    void setup() {
        shader.load("vert.vs", "frag.fs");
    }

    void draw() {
        shader.begin();
        ofEllipse(mouseX, mouseY, 100, 100);
        shader.end();
    }

    ofShader shader;
}

こんな感じ。こうするとカーソルのいちに書いた円にシェーダが適用される。(言葉遣いあっているか不明。)

僕はGL3を使っているので、ofGLProgrammableRenderer.hをインクルードして、main関数内で ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE);を呼ぶ。

vertexシェーダ

このvertexシェーダはたぶんy座標を累乗して返す。

#version 150 //OpenGL 3.2系はこれ

uniform mat4 modelViewProjectionMatrix //このマトリクスにベクトルかけて返すと良い
in vec4 position //いま取り扱っている座標が入っている

void main() {
  vec4 pos = position;
  pos.y *= pos.y;

  //最終的にgl_PositionにぶちこめばOK
  gl_Position = modelViewProjectionMatrix * pos;
}

ポイントはgl_Positionですかね。

fragmentシェーダ

このfragmentシェーダは赤色でグラデーションをする。

#version 150

out vec4 outputColor; //ここに座標の色を入れればOK

void main() {
   //sin, absなどは使える。gl_FragCoordで現在取り扱っている座標がわかる。
    outputColor = vec4(abs(sin(gl_FragCoord.x / 20)), abs(cos(gl_FragCoord.y / 20)), 0, 1);
}

ポイントはgl_FragCoordout vec4 outputColorですね。

色を渡す

fragmentシェーダに色を渡せる。ofSetColor() で設定した色は、uniform vec4 globalColorとして使える。

追記:modelViewProjectionMatrixについて

とりあえずmodelViewProjectionMatrixに座標をかけるということをしていたが、いったいなんだったのか。それについて。

まず、3Dにおいて座標系がいくつかあるということを知らないといけない。

  • Object Space
    • オブジェクト自身が原点になっている座標系。物体ごとに座標系がある
    • モデリングしてるときの座標系と考えればわかりやすいか。
  • World Space
    • ワールド座標系。どこどこになになにがある、といった感じ。
    • これを仮想空間の座標系と捉えれば良さそう。
  • Eye Space
    • 視点座標系。たとえばカメラの位置とか。視点の位置が原点になる。
  • Clip Space
    • 視点座標系から少しズームしたりして、切り取った座標系。クリップ座標系というらしい。
    • スクリーンみたいな感じだと思う。(それの逆?)
  • Normalized Device Space
    • すべてが絶対値1に収まるようにした座標系。
  • Window Space
    • ウィンドウの座標系。みんながまさに見ている座標系のこと。
    • 原点が左上だったり左下だったり。。。

今回の話において重要なのは最初の4つ。んで、Object Space -> World Space -> Eye Spaceと変換をしていくのに、ModelViewMatrixが必要。さらに、Eye Space -> Clip Spaceに変換していくのにProjectionMatrixが必要なのだ。modelViewProjectionMatrixは、それを一緒にしてしまったものなのかもしれないと考えてみた。

たぶんin vec4 positionで得られるのはワールド座標系。そこでの情報を取り扱って、クリップ座標系にして返す。これがvertexシェーダのしていることなのだろうかと。

詳しい情報はこのpdfから得た。図もわかりやすい。http://www.inftyproject.org/suzuki/lectures/java/ToBegin.pdf

Light Leaksの話は、Window SpaceがProjection Spaceとなり、ミラーボールがmodelViewProjectionMatrixの逆行列となっていて、まさにWorld Spaceに投影しているんだと思う。だとすると、写真などから得られた情報からその行列を求める、みたいなことをしていたってことなのだろうか。逆問題。。。