【oFセミナーメモ1】 boostライブラリの使い方
『デジタルアートセミナー#3 openFrameworksで学ぶ、クリエイティブ・コーディング』という一泊二日のセミナーに参加しています。
最終的なまとめは最後に書くとして、とりいそぎ本日受けたセッションのメモを載せていきます。
セッション1 : C++テクニック
講師 : 堀口淳史、藤本直明
openFrameworksを本格的に使う上で避けて通れないC++のテクニックを学びます。
今回は、boostライブラリの使い方について学びます。
環境
- MacOS X 10.9.5
- Xcode 6.1 GMAIL.COM seed 2
- oF osx 0.8.4
- boost 1.56.0
boostとは
- C++の高度で便利なライブラリ
- STLを拡張
- oFにpocoってのがもともと入っている
- pocoとは設計思想が違う
- boostはテンプレートを駆使
- STLと違ってC++の開発環境に始めから入っていない
- boostで書かれた過去の資産を利用できるようになる
- ヘッダだけインクルードして使うライトな使い方もある
- 正規表現とかはコンパイルしないと使えない
- 自分でコンパイルしてMac環境で動かすのがなかなかハードルが高い
課題
- oFは32ビットバイナリ、boostは普通にインストールすると64ビットバイナリ
- oFとboostを同時に利用しようとすると、それぞれlibstdc++, libc++を使おうとしててこのあたりがリンクエラーとかの問題になる
→ 「oFで動くMacのboostバイナリ」をどう作るか?
解決策
- oFを64bitバイナリとしてコンパイルするのは簡単ではない
→ boost のコンパイル時に x86 を address-modelに `32_64` を指定する
- oFはlibstdc++利用前提、libc++を利用するとコンパイルできない
- boost はlibstdc++でもlibc++でもコンパイルできる
→ boost のコンパイル時に cxxflags と linflags に `-stdlib=libstdc++` を指定する
libstdc++とlibc++
- libstdc++は GCCと共に開発される古くから使われている標準ライブラリ
GPLライセンス
- libc++は LLVM/Clangと共に開発された新しい標準ライブラリ
- MIT ライセンスと UIUC ライセンス
(2014.10.13追記)libstdc++のライセンスについては、コメント欄より下記のようにご指摘いただきました。
libstdc++のライセンスがGPLというのは少し誤解を招いてしまいかねないです。
というのも、libstdc++は特別な条項(GCC Runtime Library Exception)が追加されているからです。これにより、libstdc++を使用するアプリケーションを作成しても、それを公開する際にGPLを適用する必要がありません。その点で、通常のGPLとは大きく異なります。
oFで手っ取り早く使う
- poco/include/ 配下に boost フォルダのヘッダを丸ごとつっこんじゃえば、パスが通ってるので、ヘッダだけならすぐに使えるようになる(行儀悪い)
- shared pointer とかはそのまま使える
スマートポインタ
普通のポインタ
ofImage * mTestImage;
mTestImage = new ofImage( "test.jpg" );
delete mTestImage;
new したら delete が必要。
スマートポインタの場合(ofPtr は oF のスマートポインタ)
ofPtr < ofImage > mTestImageSP;
mTestImage = ofPtr< ofImage >( new ofImage( "test.jpg" ) );
delete不要。
boostだと、
boost::shared_ptr< ofImage >
って感じでスマートポインタを使える
スマートポインタに NULL 代入はできないので、
mTestImageSP.reset();
で内部でデストラクタが呼ばれて NULL と同じ状態になる。( `if (mTestImageSP)` でfalseになる)
boostインストール
https://github.com/toolbits/boost_1_56_0_xcode610_universal_binary
boost_libstdc++.dmgを解凍
- ヘッダだけを使う場合は、includeのフォルダをパス通ってるとこにコピーする
- libはコンパイル済みのバイナリ
- Xcode6, MacOS X 10.9で動くようにコンパイルしたもの
- 一番よく入れるのが、`/usr/local`
- OS標準以外のあとから追加したライブラリとかを置く場所として(macでは)よく使われる
cd /user/local open .
この配下にコピー
サンプル1: boosted
両端のスペースをカットする文字列処理。ヘッダの機能だけ使用。
boost::algorithm::trim()
void ofApp::setup(){ std::string str; str = " Hello boost "; std::cout << str << std::endl; boost::algorithm::trim(str); std::cout << str << std::endl; }
サンプル2: boost_algorithm
文字列処理のサンプル。これらもヘッダだけで可能。
両端の空白を削除
boost::algorithm::trim(str);
カンマで文字列を分割
boost::algorithm::split(vec, str, boost::is_any_of(",")); for (it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << std::endl; }
分割した各文字列の両端の空白を削除
for (it = vec.begin(); it != vec.end(); ++it) { boost::algorithm::trim(*it); } for (it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << std::endl; }
各文字列を|を区切りにして連結
str = boost::algorithm::join(vec, "|");
文字列の置き換え
boost::algorithm::replace_all(str, "|", " / ");
文字列を置き換えた結果を返す
str = boost::algorithm::replace_first_copy(std::string("C++ source code"), "C++", "boooooooooooooooost");
サンプル3: boost_regex
正規表現のサンプル。これは要バイナリ。このサンプルが動けばboostの全機能が使えるということ。
※プロジェクトに libboost_regex.a が追加されている
boost::regex regex("[^/]+?\\.o$"); boost::match_results<std::string::const_iterator> result;
見つかった項目をすべて表示
std::string::const_iterator bit; std::string::const_iterator eit; bit = str.begin(); eit = str.end(); while (boost::regex_search(bit, eit, result, regex)) { std::cout << "match = " << result.str() << std::endl; bit = result[0].second; }
見つかった項目をすべて置換
str = boost::regex_replace(str, regex, "********.o");
※ofUtilsに同様の文字列処理機能もあるので一度眺めておくと良い
サンプル4: boost_format_lexical_cast
数値を文字列にキャスト。ヘッダだけでOK。
番号で指定された通りに値を文字列化
str = (boost::format("%1% %2% %3%") % 1 % "abc" % 3.14).str();
printf のフォーマット文も利用可能
str = (boost::format("%06X (hex)") % 12648430).str(); str = (boost::format("%d (dec)") % 0xDEADBEEF).str();
lexical_cast を利用した整数から文字列への変換
str = boost::lexical_cast<std::string>(141421356); std::cout << str << " (string)" << std::endl; std::cout << "---- ---- ---- ----" << std::endl;
lexical_cast を利用した文字列から整数への変換
ival = boost::lexical_cast<int>(str);
lexical_cast を利用した文字列から実数への変換
str = "0.12345"; dval = boost::lexical_cast<double>(str);
lexical_cast を利用した不正な文字列から実数への変換
str = "0.12???"; try { dval = boost::lexical_cast<double>(str); } catch (boost::bad_lexical_cast& e) { dval = NAN; }
サンプル5: boost_thread
スレッドをつくる
- libboost_system.a
- libboost_thread.a
サンプル6: boost_mutex
変数へのアクセスを排他にするためのmutex
- libboost_system.a
- libboost_thread.a
boost::mutex _mutex;
// カウント変数を増加
_mutex.lock();
++_count;
_mutex.unlock();
// カウント値を取得
_mutex.lock();
count = _count;
_mutex.unlock();
// lock() / unlock() の替わりに lock_guard を利用しても同じ boost::lock_guard<boost::mutex> guard(_mutex); // カウント変数を減少 --_count;
サンプル7: boost_lock
shared_mutex を使うと、マルチスレッド処理において、read/writeをいい感じにロックしてくれる。
boost::shared_lock<boost::shared_mutex> rlock(_mutex);
書き込みロック(unique_lock)は1つのスレッドからだけ取れる
// カウント変数を増加
{
boost::unique_lock<boost::shared_mutex> wlock(_mutex);
++_count;
}
読みこみロック(shared_lock)は何スレッドからでもとれる
boost::shared_lock<boost::shared_mutex> rlock(_mutex); ofColor color; // カウント値を表示 color.setHsb(abs(_count) % 255, 255, 255); ofBackground(color); ofDrawBitmapString((boost::format("%1%") % _count).str(), 10, 50);
【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
サンプル: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` をオンにした状態