3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[openFrameworks]pingPongBufferとMRTを手取り早く連携させる

Posted at

pingPongBufferとは

n-1フレームでの計算結果をnフレームでの計算に用いたいことは多くあると思います.しかしshader内では変数を保持することができません.そこでn-1フレーム目の演算結果を入力, nフレーム目での計算結果を出力とするような形でFboを2つ用意する手法をpingPongBufferといいます.

MRT(Multiple Render Targets)

1つのshaderで複数の出力を行うことをMRTと言います.MRTが主に使用される代表的な場面は遅延レンダリングなどでしょう.今回このMRTを使用する理由は、粒子などの座標を物理的な計算を元に計算する場合速度、力(抵抗、圧力)、密度など複数の情報が必要になるためです.

結果

この記事では難しい計算を置いておいてMRT, pingPongBufferにフォーカスを当てて説明するためなるべく簡易的なサンプルとして前フレームでの値を保持して状態変化(色情報)する物を上げておきます.
output.gif
完成コードはここにあげてます.またなかで使用されているpingPongBuffer.hppこちらを使用させていただきました.ちなみに構造としてはoFのexampleの中にあるgpuParticleとほぼ同じかと思います.

流れ

  1. Fboを生成
  2. Fbo内にColorBufferを生成
  3. ColorBufferへ値を登録
  4. MRT用のShaderで値を更新
  5. step4で更新されたBufferと前フレームをswap
  6. step4, step5を繰り返す

ColorBufferへ値の登録

Fboの中に必要な数分のColorBufferが用意できたらColorBufferの中身を初期化していきます.

res = 4;
//internal format
pingPong.allocate(res, res, GL_RGBA32F, 3);
int ch = 3;
    //----ColorTexture1
    float* data1;
    data1 = new float [res * res * ch];
    for(int y=0; y < res; y++){
        for(int x = 0; x < res; x++){
            auto i = (x + y * res) * ch;
            data1[i] = 0.0;
            data1[i+1] = 0.0;
            data1[i+2] = 0.0;
         }
    }
    //pixelFormat
    pingPong.src->getTexture(0).loadData(data1, res, res, GL_RGB);
    delete[] data1;

自分がハマった点なのですが、oFFboでallocateする際に渡すのはinternal formatでloadDataする時に渡すのはpixelFormatという点です.ここで引数をミスるとなかで呼ばれるglPixelStorei で用意したtextureのチャンネル数と配列側のデータ境界がずれてしまいます.

MRT

ここで重要なのはactivateAllDrawBuffers()でこれをコールすることでレンダーターゲットとして全てのColorBufferが登録されます.あとはshaderへ値を送信するだけ.

void ofApp::timeStep(){
    //mrt------
    float t = ofGetElapsedTimef();
    pingPong.dst->begin();
    ofClear(0);
    mrtShader.begin();
    pingPong.src->activateAllDrawBuffers();
    mrtShader.setUniform1f("time", t);
    previewShader.setUniformTexture("tex0", pingPong.dst->getTexture(0), 0);
    previewShader.setUniformTexture("tex1", pingPong.dst->getTexture(1), 1);
    previewShader.setUniformTexture("tex2", pingPong.dst->getTexture(2), 2);
    pingPong.src->draw(0.0, 0.0);
    mrtShader.end();
    pingPong.dst->end();
    pingPong.swap();
    //---------
}

shader側ではlayoutでロケーションを指定してあげないと出力順がおかしくなることがあります.


# version 150
# extension GL_ARB_explicit_attrib_location : enable
precision mediump float;
uniform sampler2DRect tex0;
uniform sampler2DRect tex1;
uniform sampler2DRect tex2;
uniform float time;

in vec2 vTexCoord;

layout (location = 0) out vec4 vFragColor0;
layout (location = 1) out vec4 vFragColor1;
layout (location = 2) out vec4 vFragColor2;


void main(){
  vec4 c0 = texture(tex0, vTexCoord);
  vec4 c1 = texture(tex1, vTexCoord);
  vec4 c2 = texture(tex2, vTexCoord);


  vFragColor0 = vec4(mod(c0.r + 1.0, 2.0), 0.0, 0.0, 1.0);
  vFragColor1 = vec4(0.0, mod(c0.r + 1.0, 2.0), 0.0, 1.0);
  vFragColor2 = vec4(0.0, 0.0, mod(c0.r + 1.0, 2.0), 1.0);
}

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?