openFrameworksで軌道の残像を描画しつつ画像保存する方法
Processingでやってきたことを、 さいきんopenFrameworksに移植しています。
きのう、次の問題に出くわしました:
- Processingでは
draw()
関数で、フレームごとに半透明の四角形で覆えば、画面上を移動する描画の軌道を、残像として描写することができる。 - が、openFrameworksでは、同じことをやろうとしても、勝手に前回のフレームで描画したものが消されてしまう。
- この問題は、
ofSetBackgroundAuto()
メソッドがデフォルトではtrue
に設定されているため生じる。 - ゆえに、
ofSetBackgroundAuto(false)
と命令してやれば、解決する。 - ところが、この状態のまま、
ofImage
クラスのメソッドgrabScreen()
を使い、save()
でファイルに保存しようとすると、真っ黒な画像が生成されるだけである。
再現コード:
#include "ofApp.h" ofVec2f pos; ofImage img; void ofApp::setup(){ ofSetFrameRate(60); ofSetBackgroundAuto(false);//←ここでfalse設定 ofBackground(0); pos = ofVec2f(0, 0); } void ofApp::update(){ pos += ofVec2f(1, 1); if (pos.x > ofGetWidth()) { pos.x = 0; } if (pos.y > ofGetHeight()) { pos.y = 0; } } void ofApp::draw(){ ofSetColor(0, 0, 0, 30); ofDrawRectangle(0, 0, ofGetWidth(), ofGetHeight()); ofSetColor(255); ofDrawEllipse(pos, 10, 10); } void ofApp::keyPressed(int key){ if (key == 'x'){ img.grabScreen(0, 0, ofGetWidth(), ofGetHeight()); img.save("captured.jpg"); } }
まあ、見ての通り、左上から右下にひたすらひとつの円が落下していく、というだけのもの。
これを実行すると、画面上は、残像を軌道に残しながら、描画されていく。Windowsのスクショを使って保存した画面:
で、このコードだとx
キーを押すと、その時点の画面をキャプチャして保存してくれるのだけど、こうなる:
こう解決した:
ofApp::update()
メソッドのなかで、ofFbo
クラス(フレームバッファオブジェクト)をbegin()
→end()
させる。- この
begin()
→end()
のなかで、ofSetBackgroundAuto(false)
を命令する。バッファされるフレームのなかでは、残像が描写される。 ofApp::draw()
メソッドの冒頭で、ofSetBackgroundAuto(true)
を命令する。残像は許さない画面の上に、Fboにバッファされたフレームを描くイメージ。ofSetBackgroundAuto(true)
が効いているうちに画像を保存する。
上のコードを修正すると:
#include "ofApp.h" ofVec2f pos; ofImage img; ofFbo fbo; bool bTake; void ofApp::setup(){ ofSetFrameRate(60); ofBackground(0); pos = ofVec2f(0, 0); } void ofApp::update(){ fbo.begin(); ofSetBackgroundAuto(false);//←ここでfalse設定 ofClear(0); pos += ofVec2f(1, 1); if (pos.x > ofGetWidth()) { pos.x = 0; } if (pos.y > ofGetHeight()) { pos.y = 0; } ofSetColor(0, 0, 0, 30); ofDrawRectangle(0, 0, ofGetWidth(), ofGetHeight()); ofSetColor(255); ofDrawEllipse(pos, 10, 10); fbo.end(); } void ofApp::draw(){ ofSetBackgroundAuto(true);//←ここでtrue設定 fbo.draw(0, 0, ofGetWidth(), ofGetHeight()); if (bTake == true) { img.grabScreen(0, 0, ofGetWidth(), ofGetHeight()); img.save("captured.jpg"); bTake = false; } } void ofApp::keyPressed(int key){ if (key == 'x'){ bTake = true; } }
この記事冒頭のものは:
参考書:
↓ofSetBackgroundAuto(false)
で軌道を描く、というのはこれに書いてあった。
田所 淳,齋藤あきこ ビー・エヌ・エヌ新社 2013-06-26
↓冒頭の、パーティクルがドカーンとなるやつは、このProcessing本に書いてあったもの