Hatena::ブログ(Diary)

Over&Out その後 このページをアンテナに追加 RSSフィード Twitter

2014-10-17

MoffとWHILLのアプリがリリースされました!その開発裏話など。

iOSアプリ開発者を名乗る者として恥ずかしい話なのであまり自分から積極的に言って来なかったのですが、実はわたくし、2012年末以降、実に2年近く一本もアプリを出せてませんでした


いや、コードはたくさん書いてたんですが、2013年前半はひたすら 書籍執筆とそのサンプルコード作り だったし、後半は SDK をつくってたので、自分の書いたコードが人様のアプリには入ってはいたものの、やはり自分が開発したアプリが出ました!という感はなく。そして2014年になって独立してからも、諸事情でストアに出さないことになったり、プロトタイプやデモまでのお手伝いだったりということが多かったもので。。


で、そんな中、がっつりお手伝いさせていただいたアプリがこの10月に立て続けにリリースとなったのでご報告させていただきます!


裏話、とまでは言えないかもしれませんが、アプリの紹介以外に、開発の経緯とか、働き方とか、技術的なことについても(公開して問題ない範囲で)少し紹介したいと思います。


次世代パーソナルモビリティ『WHILL』

f:id:shu223:20141017084400j:image:w600


昨日ストアに出たばかりの、次世代パーソナルモビリティ WHILL と BLE により連携するアプリです。


f:id:shu223:20140930104709j:image:w500


アプリの機能

f:id:shu223:20141017083349p:image:w600


  • リモートコントロール

ベッドサイドにWHILLを呼び寄せる、介助者が操作する、といったユースケースを想定した機能です。BLEの用途として遠隔操作はベーシックなアイデアですが、WHILLのようにおもちゃサイズではないものがラジコンのように手元のスマホから動かせると、未来感あります。


  • シートのスライドをコントロール

WHILLは乗り降りしやすいようにシートを前後にスライドさせることができるのですが、その操作部はアームの下側にあるので、ベッドなどからWHILLに載る際にはスマホから操作できると便利だそうです。


  • 内部パラメータ設定

パワー、前進速度の最大値、最小値、前進加速度の最大値、最小値、前進減速度の最大値、最小値、後進速度の・・・等々々、19種類におよぶパラメータがあり、これらを自分好みのチューニングにしたいというニーズが非常に強いそうです。100人いれば本当に好みが100人違うそうで、サービスマンが全米を飛び回ってチューニングしてるとコストが莫大になってしまうので、BLE経由で自ら設定変更できるようになっています。


WHILL本体なしで試す

もちろんWHILL本体ありきのアプリなのですが、

  • 最初の "WHILL BLE KEY" の入力ダイアログをキャンセルして、
  • CONNECTボタンじゃなくその下の "START WITHOUT WHILL" を選択

することで一通り試してみることはできます。


https://itunes.apple.com/app/id926042487


開発体制

WHILL の CTO 福岡さんが WHILL 本体側(回路設計&ファーム実装)、アプリ側を堤が担当しました。


アプリのデザインはカヤック時代の同僚、おかず にお願いしました。


BLE112 Development Kit

WHILL は BLE チップとして Bluegiga 社の BLE112 を使っています。で、開発で大活躍したのが下記画像の Development Kit で、


f:id:shu223:20140930104801j:image:w400


これはディスプレイ・USBインターフェース・バッテリーボックス・デバッガ・確認用のセンサ等々、BLEモジュールの開発・検証に必要な諸々がボードにビルトインされているので、部品を集めて回路を組んだりしなくても、買ってすぐに BLE モジュールのファームウェア開発を始められるという代物です。


WHILL は物理的にもコスト的にも開発用に本体を何台も用意したりすることは難しいので、基本的にWHILL本体と繋げて動作させるのは実装完了してからの動作確認時ぐらいになってきます。


で、それまではiOSアプリ側は、この Development Kit を WHILL の代わりの接続先として使ってました。WHILL側の福岡さんと gatt.xml を共有しつつ。


参考記事: 【改訂版】BLE112 / 113 の開発環境を Mac に構築する - Over&Out その後


参加の経緯

WHILL を手伝い始めたのはけっこう前で、今年の3月に遡ります。CEO 杉江さんから Facebook Message をいただいたのがきっかけでした。


当時から iOS × デバイスの BLE 連携は一番やりたい分野だったし、WHILLは 500startupsにいたころから プロダクトもチームもリスペクトしてたので、ぜひともやりたいですとがっつり食いつかせていただきました。


で、CTO福岡さんと何回かスカイプミーティングをしたあと、町田の工房に行ってWHILLに乗せてもらい、まずは仕様やその後の開発方法について話し合いつつBLE接続なしのUI/UX共有用アプリをつくり、という感じでゆっくりと手伝い始めました。


(当時のブログ記事:独立して最初の3ヵ月間にやったお仕事のまとめ - Over&Out その後


で、その後も基本的に毎週土曜日、でも福岡さんが忙しかったり出張だったりすると中止になるので、だいたい月に3人日ぐらいのペースで開発を進めてきました。


TV出演

アプリだけWBSに出演したこともあります。



ウェアラブルなおもちゃ『Moff』

Moff は、Kickstarter 向け出荷が先月だったので実はそのときにはアプリはもう出ていたのですが、正式に 10/15 に発売になりました!



お子さんのいらっしゃる iOS な方々はぜひお買い求めいただけると嬉しいです。Amazon電子玩具部門で妖怪ウォッチに次ぐ2位の人気だそうです。(僕も甥っ子達へのプレゼント用に2つ買いました)


こういうおもちゃです↓↓↓↓


コンテンツについて

刀でキンキンやりあったりボクシングでボコボコするのも楽しいのですが、なんといっても Drum が楽しいです。



自分の中心軸から左の方に向いて腕を振る(ドラムスティックを振る感じで)とハイハットとスネアが、右に向いて振るとタムが鳴ります。で、上の方で振るとクラッシュシンバルが鳴ると。子供からも(その演奏姿を観る)親御さんからもすごく評判がいいそうです。


ちなみに、最初に入っているコンテンツは13個ですが、いま審査に出しているバージョンから、追加コンテンツの配信機能(一定の条件でダウンロードできるようになる)がつきます!


開発体制

iOSアプリのバージョン1.1.0(審査中)までに関しては、CTO米坂さんと僕とで実装しています。もちろん、ハード、サーバーサイド、デザイン、ジェスチャ認識アルゴリズム開発等々含めるともっと多くの人が関わっています。(が、どの辺りまで書いてよいか要確認なので控えておきます)


参加の経緯

とあるミートアップでCTO米坂さんが声をかけてくれたのがきっかけでした。ちょうどその数日前に「Kickstarterで2日間で目標調達額を達成!」というニュースをFacebookで見かけて興味を持っていたところだったので、こちらも全力で食いつき、GW明けから開発に参加させていただきました。


こちらは最初2週間ぐらい集中して入ってアプリの基本形をつくった後、その後は開発内容やフェーズに応じて週2〜3ペースでお手伝いさせていただいてます。


おわりに

書いてて気付いたのですが、どちらも「CTOとがっつり一緒に開発」というところが共通してるなーと。

  • 開発にまつわる諸々が技術的なことも含め共有できて、
  • プロダクトへの愛と責任があって、
  • その場で即断する裁量がある

方と一緒にやれる場合に自分はいい関係が築けることが多いのかなと。(もちろん今後これ以外にもいろんなパターンがあるとは思いますが)


そんなわけで、WHILL と Moff とそのアプリとフリーランスiOSエンジニアの堤を今後ともよろしくお願いします!


2014-10-14

一泊二日のopenFrameworksセミナーに参加してきました


先週末、『デジタルアートセミナー#3 openFrameworksで学ぶ、クリエイティブ・コーディング』という一泊二日のセミナーに参加してきました。(※参加者のTLでは「oFセミナー」という呼称の方が一般的でした)


自分にとっての openFrameworks (以下 oF)は、 去年真鍋さんと仕事したいがために少しかじってみた ものの、さらっと基礎をなでただけで結局一度も実案件で使うことも自分で何かつくってみることもなかった、という程度の縁しかありません。


それでも参加したのは、講師陣と内容がすごく興味深かったからです。


2014年の今に boost ライブラリについてがっつり2時間半教えてくれるセミナーはなかなかないだろうし、iOS 8 から CIKernel が追加されて GLSL で Core Image のカスタムフィルタをつくれるようになった ので、GLSL についてプロ中のプロから直接学べるなら是非ともという感じだし、プロジェクションマッピングは流行り始めてから数年経つけど自分ではやったことないので要素技術とかポイントは把握しておきたいし、映像制作ソフトの連携や映像解析の話も興味ある分野だったり。


つまるところ oF 抜きにしても今回のセミナー内容は自分にとって学びたい内容ばかりだったので、募集開始直後1分以内ぐらいに全力で応募した次第です。


で、実際に参加してみた結果、期待以上でした。「これが聞けただけでも参加した甲斐があった!」と思った話が何度あったことか。これで宿泊費込みで1.5万円は安すぎるので、次回あったら10万円でも参加したいというレベルです。(実際に講師/TAの方々に正規フィーを払ったらそれでも済まないだろうけど。。)


では以下、それぞれのセッションについて。


セッション1 : C++テクニック(boostライブラリの使い方)

講師 : 堀口淳史、藤本直明

openFrameworksを本格的に使う上で避けて通れないC++のテクニックを学びます。

今回は、boostライブラリの使い方について学びます。


oF も C++ も初心者レベルだったので参加前はついていけるか不安だったのですが、基礎の基礎からじっくり丁寧に解説してくれて、libstdc++ と libc++ の違い とか、「oFで動くMacのboostバイナリ」をコンパイルするためのビルドオプションがどういう理由で決まってくるのかとか、あとboostの使い方自体も、非常に勉強になりました。


詳細な講義メモはこちらにあります。


セッション2: Shaderテクニック(GLSL)

講師 : 藤本直明、神田竜、他

GLSL(Shader)と呼ばれるOpenGLの機能を解説し、それを応用した映像表現を学びます。今回は、3Dを中心としたシェーディング手法を中心に解説していきます。


冒頭に書きましたが、iOS 8 から CIKernel で自前フィルタを GLSL で書けるようになったし、GPUImage とかで自前フィルタ追加したい場合もシェーダを自分で書ける必要があるしで、わりと以前から自分の中でシェーダはちゃんと勉強したい項目のひとつでした。


で、やっぱりこのセッションも超勉強になりました。


自分が興味があったところはフラグメントシェーダ(ピクセルシェーダとも呼ばれる)のあたりで、よく分かってなかった Vertex Shader とかのあたりもすごく腹落ちしたし、ライティングについても ライトの種類から拡散光の求め方まで順序立てて教えてもらえて、これまた勉強したいと思っていた3Dプログラミングの勉強もできた感じです。


f:id:shu223:20141011213048j:image:w600


詳細な講義メモはこちらにあります。


セッション3: 自己紹介&ショートセッション

講師/TA陣が自分の案件とその中で使ってる技術Tipsを紹介してくれるセッション。流れ解散制で、自分は深夜2時に退室したのですが、実に深夜3時半までセッションは続いたそうです。


オフレコな話が多かったので詳細レポートはできませんが、「あの案件の裏側はこうなってたのか!!!」みたいな話が盛りだくさんでこれまた勉強になりすぎる内容でした。


あと、みなさん技術+デザインとか演出のセンス+アイデアがすごくて、iOSしかできない自分はより精進せねば・・・と改めて思ったのでした。


セッション4: プロジェクションマッピング

openFrameworksでのプロジェクションマッピングの基礎を学び、実際に数名ずつのグループで簡単な制作を行います。 また、エッジブレンディングやメッシュワープなど、実践的なプロジェクションマッピングを行う上でのテクニックについても紹介します。


個人的にはあまりプロジェクションマッピングにはそんなに興味がなくて、そしてやったこともなく、でもすごい流行ってるのでちょっと気になる、ちょっと自分で体験してみたりはしたい・・・みたいな存在だったので、まさにうってつけのセッションでした。


f:id:shu223:20141012125651j:image:w600


講義メモ:


このセミナー全体を通して感じたことですが、プロジェクションマッピング(とかAR)は、もはや興味があるとかないとかのレベルじゃなくて、リアルな場での表現手段としてもはや当たり前なものになってるんだなーと。「これはプロジェクションマッピングの作品です」みたいな感じじゃなくて、演劇の背景だったり、TVのスタジオで世界観をつくる使い方だったりで表現のいち手法になってる感じ。


セッション5: openFrameworksと映像制作ソフトの連携

ライゾマ比嘉さんのセッション。


AfterEffectsやCinema4Dなどの映像ソフトとopenFrameworksを連携させる映像制作手法の紹介を行います。 (AfterEffectsやCinema4D、Ableton Live、Adobe Premiereなどをお持ちの方は、持参して頂けると手元で試せるのでよいかもしれません)


受講前は、「AfterEffects持ってないなー」「Cinema4D??」ぐらいの感じだったのですが、動画内のサッカーボールのトラッキングを After Effects でやって、そのキーフレームを取り出すことでいかにも映像解析がすごい的に見せる みたいな方法は目からウロコで感動しました。


f:id:shu223:20141013174310j:image:w600


あと、ofxPDF というアドオンで、PDFベクタ形式のデータを読み取ってアウトラインを順番に取り出してアニメーション表示するやつは、すごくいい感じなので iOS ネイティブにも移植しようかと。Xcode 6 の Asset Catalog でも PDF ベクター形式をサポート したので、PDF 形式自体が iOS 界隈で一般的になってきそうだし。


f:id:shu223:20141013174237j:image:w400


講義メモ:


セッション6: 映像解析によるインタラクション

openFrameworksとOpenCV(ofxOpenCV、ofxCv)を組みあわせることで、映像を用いたインタラクティブな表現の可能性が大きく拡がります。このセッションでは、実例を紹介しながら映像とのリアルタイムなインタラクションの手法を探ります。

田所先生のイントロ、ひつじさんのオプティカルフロー+ドロネー変換、ライゾマ登本さんによるアドバンストな話、の豪華3本立て構成でした。


動画の中から、人間の目ではわからないような微細な変化を検出するアルゴリズム EVM(Eulerian Video Magnification)、トラッキングしながらリアルタイムに学習もしていく TLD(Tracking Learning Detection)アルゴリズム等々、非常に勉強になりました。


f:id:shu223:20141013191301j:image:w600

(EVMの処理フロー)


講義メモ:


あと、講義の後に、登本さんにとあるライゾマ案件のしくみについて直接聞いてみたところ、自分が用意してた答えとは全然違ってて、聞かないとわからなかったであろう方法だったので、それもほんと質問してよかったなと。


おわりに

最高でした!主催のみなさま、講師のみなさま、TAのみなさま、セミナーハウスのみなさまどうもありがとうございました!!


2014-10-13

【oFセミナーメモ5】映像解析

デジタルアートセミナー#3 openFrameworksで学ぶ、クリエイティブ・コーディング』の最終セッション『映像解析によるインタラクション』のメモです。

openFrameworksとOpenCV(ofxOpenCV、ofxCv)を組みあわせることで、映像を用いたインタラクティブな表現の可能性が大きく拡がります。このセッションでは、実例を紹介しながら映像とのリアルタイムなインタラクションの手法を探ります。


田所先生のイントロ、ひつじさんのオプティカルフロー+ドロネー変換、ライゾマ登本さんによるアドバンストな話、の3本立て構成でした。


過去のセッションのレポートはこちら。


田所先生のイントロ

講義資料: Session 6: 映像解析によるインタラクション


オプティカル・フロー

映像内の物体の動きを、ベクトル場で表したもの


f:id:shu223:20141013191045j:image:w500


2種類のアルゴリズム
  • Gunner Farneback

- 密なオプティカルフロー

- ofxCv::FlowFarneback

  • Pyramidal LK

- 疎な特徴集合に対するオプティカルフロー

- ofxCv::FlowPyrLK


ひつじさん

講義資料: オプティカルフローを使ったモーショングラフィックス生成|ひつじ|note



ダンサーさんの踊っている映像を使用して、それをリアルタイムにカットアップしながらオプティカルフローを使ったグラフィックを載せているというプログラムです。


  • YCAMのダンサーの映像にオプティカルフローをかける・・・特徴点を抽出
  • ofxDelaunay ドロネー変換

ドロネー図 - Wikipedia


f:id:shu223:20141013191122p:image


登本さん

Kinectで3Dモデリング

キャリブレーション

  • Kinect3台
  • それぞれのカメラの位置がわかってない
  • そのままだと 2.5d
  • 光る玉を3台のKinectから見える位置で振る
    • kinectのcolorの方で見ると、暗い部屋との対比で、簡単に中心位置を割り出せる
  • カメラ位置の推定に、OpenCV の estimateAffine3D を使用

ofxEvm

Eulerian Video Magnification

動画の中から、人間の目ではわからないような微細な変化を検出する


Eulerian Video Magnification - YouTube


EVMのアルゴリズム

f:id:shu223:20141013191301j:image:w600

(上記動画内の解説図)


論文と MATLAB
  • 論文のコードは MATLAB で公開されてることが多い
  • EVM も MATLAB でコードが公開されてる
  • MATLAB が使われるのは、その世界ではみんな使ってるので、referされやすいから。Pythonも増えてきた。
  • MatLabからのC++エクスポート機能はつかってない。自分でC++で書き直している。

SVGでAR
  • カメラを固定して、映っている対象物の頂点の位置を示したSVGファイル をつくる
  • → その位置に別の映像をオーバーレイするとAR的なことができる
  • CameraCalibrate3D を使用 する
  • 最終的なテクスチャをズームしたり変位させたり回転させたりすることでカメラが動いてるっぽくも見える

TLD Tracker

Tracking Learning Detection



ofxTldTracker

  • ライセンスはLGPL

OpenCV 3.0 にTLDアルゴリズムのとラッカーが追加される

Tracker Algorithms — OpenCV 3.0.0-dev documentation の TrackerTLD


【oFセミナーメモ4】openFrameworksと映像制作ソフトの連携

デジタルアートセミナー#3 openFrameworksで学ぶ、クリエイティブ・コーディング』のライゾマ比嘉さんのセッション『openFrameworksと映像制作ソフトの連携』のメモ。

講師 : 比嘉了

AfterEffectsやCinema4Dなどの映像ソフトとopenFrameworksを連携させる映像制作手法の紹介を行います。


講義資料はこちらで公開されています。markdown形式。


過去のセッションのレポートはこちら。


事例紹介

(ダンスのやつ。動画メモし忘れました)

  • 手と頭につけてるマーカーで軌跡を書く
  • 他の部分は動的生成ではなく、CINEMA 4Dであらかじめ用意していたもの

Illustratorとの連携:ofxPDF

ベクタデータのうち、SVGよりPDFの方がロードが10倍ぐらい速いことがあったので、それからはPDFを使っている。そのPDFをoFで取り扱うアドオン。


普通に描画
ofxPDF pdf;
pdf.loadPDF("tiger.pdf");
pdf.draw();

テキストアニメーション

f:id:shu223:20141013174237j:image:w400

(アニメーションの途中の様子です)


void draw()
{
    float app_time = ofGetElapsedTimef();
    float animation_time = fmodf(app_time, 2) / 2.;
    
    cout << "app_time: = " << app_time << ", animation_time: " << animation_time << endl;
    
    ofSetColor(0);
    
    // PDFのパスを順番に取り出して ofPolyline で描画する
    for (int i = 0; i < pdf.getNumPath(); i++)
    {
        ofPath& path = pdf.getPathAt(i);
        
        vector<ofPolyline>& polys = path.getOutline();
        for (int k = 0; k < polys.size(); k++)
        {
            ofPolyline poly = polys[k];
            
            poly = poly.getResampledByCount(100);
            
            int target_size = poly.size() * animation_time;
            poly.resize(target_size);
            
            poly.draw();
        }
    }
}

順番に見ていくと、


1. パスを取り出す

ofPath& path = pdf.getPathAt(i);

2. パスのアウトラインを取り出す

vector<ofPolyline>& polys = path.getOutline();

ofPolyline がベクタで得られる


3. ofPolylineをリサイズしながら描画する

for (int k = 0; k < polys.size(); k++)
{
    ofPolyline poly = polys[k];

    poly = poly.getResampledByCount(100);

    int target_size = poly.size() * animation_time;
    poly.resize(target_size);

    poly.draw();
}

各アウトラインが、長さ0から元の長さに戻っていく。


After Effects との連携:ofxAfterEffectsKeyframeParser

サッカーのボールの軌跡を追う

AEにはそういう機能が入っている: tracker

-> キーフレームとして入る

-> ofxAfterEffectsKeyframeParser で読む


f:id:shu223:20141013174310j:image:w600


画像解析不要!


Cinema 4Dとの連携:ofxAlembic

https://github.com/perfume-dev/ofxAlembic

  • メッシュアニメーション
  • パーティクル
  • polyline
  • カメラワーク

などが読み書きできる


f:id:shu223:20141013174340j:image:w600

f:id:shu223:20141013174400j:image:w600

(それぞれ ofxAlembic に付属のサンプルを実行したもの。アニメーションします)


2014-10-12

【oFセミナーメモ3】プロジェクションマッピング

デジタルアートセミナー#3 2日目の最初のセッションは、プロジェクションマッピングについて。


講師 : 藤本直明、他

openFrameworksでのプロジェクションマッピングの基礎を学び、実際に数名ずつのグループで簡単な制作を行います。 また、エッジブレンディングやメッシュワープなど、実践的なプロジェクションマッピングを行う上でのテクニックについても紹介します。


過去のセッションのレポートはこちら。


プロジェクションマッピングとは

プロジェクションマッピングじゃないもの・・・マッピングしてなくて、ただプロジェクションしてるだけのものとか

プロジェクションマッピング事例

3D Projection Mapping promoting The Tourist in Dallas - YouTube


マッピングソフト

ofxQuadWarp

シンプルなマッピングのアドオン。4つの頂点を動かすとその矩形に合わせて映像をwarp処理してくれる。


f:id:shu223:20141012125640j:image:w600

(頂点調整前)


f:id:shu223:20141012125651j:image:w600

(頂点調整後)


使い方
// 画像読み込み
img.loadImage("quad_warp_kittens.png");

// 位置とサイズを取得
int x = (ofGetWidth() - img.width) * 0.5;       // center on screen.
int y = (ofGetHeight() - img.height) * 0.5;     // center on screen.
int w = img.width;
int h = img.height;

// FBO確保
fbo.allocate(w, h);

// 画像のrectを ofxQuadWarp にセット
warper.setSourceRect(ofRectangle(0, 0, w, h));              // this is the source rectangle which is the size of the image and located at ( 0, 0 )

// 4つの頂点の初期座標を ofxQuadWarp にセット
warper.setTopLeftCornerPosition(ofPoint(x, y));             // this is position of the quad warp corners, centering the image on the screen.
warper.setTopRightCornerPosition(ofPoint(x + w, y));        // this is position of the quad warp corners, centering the image on the screen.
warper.setBottomLeftCornerPosition(ofPoint(x, y + h));      // this is position of the quad warp corners, centering the image on the screen.
warper.setBottomRightCornerPosition(ofPoint(x + w, y + h)); // this is position of the quad warp corners, centering the image on the screen.

// セットアップ&ロード
warper.setup();
warper.load(); // reload last saved changes.

Quad Warp事例

トラッキングしてプロジェクション

kz - Party in the Car - DRIVING KIDS with TOYOTA スペシャルムービー feat. ULTRA JAPAN 2014 - YouTube


講義資料: プロジェクションマッピング実例と応用|ひつじ|note

車に再帰性反射材のマーカーを付けて、車の位置をトラッキングしながらその周りで映像が展開するという演出です。車のトラッキングには、6台のoptiTrackを15mの高さから吊り下げてセンシングをしています。


optiTrackとは赤外線による光学式モーションキャプチャで、複数台を連携させて高い精度とfpsでマーカーの位置が取得できるデバイスです。


車にマッピングしたくないので、車には白い光をあてて、プロジェクションを逃がしてやる。

再帰性反射材のマーカーを3つ載せて、OptiTrack でトラッキング

  • ラジコンでテスト
  • マーカー付きステッキでテスト

OptiTrackの処理が速く、プロジェクターの処理が追いつかない ので、進行方向にちょっと進ませた場所に投影(講義資料の、『レイテンシ補完』参照)


ジオラマに投影

https://www.youtube.com/watch?v=SRCVKciy-zI


複数のプロジェクタで投影する

エッジブレンディング

プロジェクタ間のキャリブレーション

Mac の [設定] > [ディスプレイ] > [カラー] > [補正]

ディスプレイキャリブレータ・アシスタントが起動する

薄目で林檎マークが溶け込むポイントで、全プロジェクタを調整する


メッシュワープ

Quad Warp みたいに4点だけじゃなくて、もっと多くのポイントでwarpできる・・・曲面への投影


https://www.youtube.com/watch?v=xqrJrqcqFBQ


  • 使用したoFアドオンは非公開
  • OpenGL の命令を直叩きで実装してある

MappaMok

  • カメラで撮影した画像と3Dモデルを合わせる
    • さまざまなパターンをプロジェクタから投影 → カメラで撮影

参考リンク: Kyle McDonaldの「光の演習」ワークショップ@SUPER FLYING TOKYOに参加してきました - Over&Out その後


2014-10-11

【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
};

円にかけてみた例:

f:id:shu223:20141011214001j:image:w500

(左が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がすごく詳しいので、メモは省略)


f:id:shu223:20141011212906j:image:w400

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


サンプル:multiLightExample

examples/gl/multiLightExample


球の解像度

ofSetSphereResolution(128);

f:id:shu223:20141011212822j:image:w500


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


f:id:shu223:20141011213048j:image:w500


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

ofSetSmoothLighting(false);
ofSetSphereResolution(10);

-> フラットシェーディング


法線ベクトルの求め方

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

ofVec3f c = a.crossed(b);

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

拡散光の求め方

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

float c = a.dot(b);

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


グローシェーディング

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


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


【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++の高度で便利なライブラリ
  • 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 .

この配下にコピー


サンプルプロジェクト

サンプルを動かしつつ、boostの機能を紹介。

https://github.com/toolbits/of_plus_boost_2014seminar


サンプル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);

2009 | 08 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |