クリエイティブコーディングフレームワークarmosに追加された機能まとめ2017年版

この記事はD言語 Advent Calendar 2017 19日目の記事です.

今年2017年にクリエイティブコーディングフレームワークarmosに追加された機能等を紹介していきます🎉

Mac OS Support

自分がmac book proを使い始めたのでサポートしました. 論理ピクセルと物理ピクセルのサイズが異なるretinaディスプレイへの対応として,interface WindowにframeBufferSize()を追加しました.これは既存のWindow.size()がウィンドウサイズを論理ピクセルで返すのに対し,こちらはウィンドウの物理ピクセルで返します.

頂点座標からの頂点法線情報の生成

armos.graphics.Meshクラスのメンバ関数calcNormal()でスムージングされた頂点法線情報を生成できます.生成された法線情報はMeshのメンバnormalsに保存されます.

シンプルな2Dのグラフィックを表示するexample.

単純な2DのMeshのアニメーションを行うexamples/primitives2dを追加しました.armosに触れる際,一番最初に見ていただくと雰囲気がなんとなく掴めるかと思います.

フォント読み込み機能の実装

https://pbs.twimg.com/media/C8jCzc8VwAAlvFQ.png

Fontクラスでフォントを扱えます.内部でfreetypeを使用しており,フォントのデータをラスタライズしてテクスチャとして描画することができます.

exitApp()の追加

Applicationのinterfaceに追加しました.Applicationの内部でこのメンバ関数を呼ぶことでApplicationを終了させることができます.

リアルタイムの音声入力

音声入力デバイスを扱うクラスarmos.audio.Recorderを実装しました. 実際の使い方はexamples/audiocaptureを参考にしてください.

Colorクラスの仕様変更

従来のColorのRGBAの値はそれぞれ256段階の整数型でしたが,OpenGLとの相性を考え,0から1までのfloat型に変更されました.

generate commandによるテンプレートファイル/フォルダの自動生成機能

armosを使った開発を加速させるCLIツールを追加しました. 以下詳細

glslify support

glslifyを用いてshaderのglslのモジュール化,importができるようになりました. 以下詳細

マルチウィンドウ対応

複数のウィンドウを扱うことができるようになりました.OpenGLのcontextはデフォルトではウィンドウ間で共有されていませんが,アプリケーションの初期化時,Windowを生成する際にコンストラクタへ引数としてcontextを与えることで同じcontextを扱うことができるようになります.

auto config = new armos.app.WindowConfig();
auto window1 = new armos.app.GLFWWindow(config);
auto window2 = new armos.app.GLFWWindow(config);
auto window3 = new armos.app.GLFWWindow(config, window2.context); //share context.

armos.app.mainLoop.register(new MainApp, window1)
                  .register(new SubApp,  window2)
                  .register(new SubApp,  window3)
                  .loop; // call loop function after application and window registations.

実際の使い方はexamples/multiplewindowsを参考にしてください.

MIDI input

armos.communication.MidiStreamを用いることでMIDI信号の入力を扱うことができます.

メンバ関数popMessagesを呼ぶことで受け取ったMIDIメッセージを取り出すことができます. 実際の使い方はexamples/midiinputを参考にしてください.

Reactive Extensions

Rxはじめました.@lempiji氏が開発しているdlang実装のRxを利用させて頂いてます.

現在のarmosのイベントシステムは全てRxに置き換わっており,armos.app.currentObservables()で全てのarmosのイベントのobservableが包含されたCoreObservablesへアクセスすることができます.

マウス入力関係のイベントの追加

Rxの導入によるイベントシステムの刷新に際して,mouse dragとmouse scrollのイベントハンドラをサポートしました.対応するシグネチャは以下の通りです.

void mouseDragged(int currentX, int currentY, int button)
void mouseDragged(int firstX, int firstY, int currentX, int currentY, int button)
void mouseDragged(Vector2f currentPosition, int button)
void mouseDragged(Vector2f firstPosition, Vector2f currentPosition, int button)
void mouseDragged(Vector2i currentPosition, int button)
void mouseDragged(Vector2i firstPosition, Vector2i currentPosition, int button)
void mouseScrolled(float xOffset, float yOffset)
void mouseScrolled(Vector2i position)
void mouseScrolled(Vector2f position)
    

EasyCamのサポート

マウス操作で簡単に視点を操作する機能が組み込まれたcameraの実装です.名前のとおりopenFrameworksのEasyCamと似た挙動になってます.実際の使い方はexamples/easycam/を参考にしてください.

今後の予定

OpenGLのContextを一箇所にまとめる大規模改修

現在,Cinderの設計を参考にしてcontextの管理を局所化する設計変更を行っており,それに伴って既存のRendererのリファクタリングも行っています.影響箇所が多いので開発版のdevブランチに取り込まれるのはもう少し先になりそうです.

映像のサポート

現在ffmpegを用いたVideoTextureを実装しています.また,ライセンスの都合からarmos本体とは別リポジトリで,armosの拡張という形でのリリースを検討しています.途中で上の大規模改修が始まったため,こちらの作業は一時的に中断しており,改修が終り次第再開しようと考えています

ベクタデータの取扱

未着手です.ベクタデータが扱えるようになると,フォントのアウトラインを変形させるような表現等,幅広く応用できそうです.

東京Node学園祭2017のアフターパーティーでVJをやってきた #nodefest

はじめに

12/25,12/26に開催された,Node.jsコミュニティのカンファレンス,東京Node学園祭のアフターパーティーでVJをやってきた.今回は運営スタッフのamagi(@amagitakayosi)さんに誘って頂いた.amagiさんとは,彼が開発しているVEDAというAtomでライブコーディングを行うプラグインへのContributeを通して知り合いになった.

下ごしらえ

まず,VEDAで映像素材を切り替えるためのサンプラーを外部のアプリケーションとしてarmosを用いて新規に開発した.Ableton liveのセッションビューのような操作体系で,登録したキーを押すことで設定したBPMに同期して映像を切り替えることができる.なお映像の再生速度も同期される.また,タップ入力によるBPMの変更機能付きで,流れている曲に合わせてスペースキーを押すことでいい感じに検出してくれる.入力される音声信号からのリアルタイム検出による自動化もやりたかったが不安要素が多かったのでそのへんは今度やることにした.(昔実装した非リアルタイムBPM検出のアルゴリズムと想定される計算量を比較してみたが,両方で用いられるFFTがΟ(n log n)なので,サンプル数が少ないリアルタイム処理なら速度的に割といけそうな予感がしている)なお,VEDA本体との通信は,Open Sound Control(以下OSC)というプロトコルで行う.VEDAはOSCによる外部からのglslのuniform変数の変更をサポートしているが,映像素材の切り替え機能は今のところ無いので,そのへんの機能をいくつか無理矢理追加する改造を施した.サンプラー側はosc-dというOSCの実装のpackageを用いた.開発の途中でいくつかバグに気がつけたので良かった(修正済み).dogfoodingは最高.

次に,Blender(あと仕上げで少しだけAfterEffects)で普通の4n拍(n∈N)くらいの尺の映像と,2つの映像をミックスするための白黒の映像をいくつか作成した. BlenderはTimeline周りの操作体系も3Dのモデリングと直交性があるので快適にモーションを組むことができる.また,2Dっぽい見た目のモーショングラフィックスを作る際もオブジェクトを三次元的に配置できるので凝ったことができる.

映像素材の制作中は,レンダリング作業の効率化のためlightweightなBlenderレンダリングファームを開発し,計算用のarch linuxのサーバ上で稼働させていた.僕が作業している間,休憩している間に,予め投げておいたキューが逐次処理されていく.ちなみに処理が完了する度にするとtwitterでリプを飛ばしてくれる.

当日

日中は空いた時間に本会場の廊下で,実際の環境を想定して念のためにveda-samplerの全ての操作をmidiコントローラで行えるよう,無限コーヒーを飲みながらバキバキコードを書いていた.楽しかった.

アフターパーティーはfreeeさんのオフィスを借りて行った. 設営からお手伝いさせていただいたが,レイアウト等試行錯誤の末に出来上がったパフォーマンス用のブースが広くて凄みがあり,一体何のイベントのアフターパーティーなんだろう感がにじみ出ていた. freeeさんの社員の方が「会社ってこんなこともできるんだ」的な旨のことを言っていたのを覚えている.

自分のVJ中は記録映像を撮る余裕が無かったので他の方が撮ってくれた様子を以下に引用させて頂きます.(撮影ありがとうございます🙏)

まとめ

  • 実験的な要素を盛り込んだパフォーマンスができて勉強になった.
  • VJ,メディアアート,クリエイティブコーディング系の知り合いが増えた.
  • OSSの活動がきっかけでOSSのイベントに招待して頂いてVJのパフォーマンスをするという素敵な体験ができた.

TipsとしてのVJボツ案供養

本番では使われなかったボツ案です.ご査収ください.

VEDAでsyphonの入力を使いたい

VEDAネイティブでやるのは大変.懇親会でamagiさんと話をしたけどなかなかしんどい(chromiumに手を入れる必要がある).レイテンシを気にしないのであれば,syphoncamTwistを経由してVEDAのcamera入力に渡すという手段がある.

VEDAで透過映像を扱いたい

f:id:ttata:20171129002912p:plain

VEDAが内部で使用しているThree.jsで直接透過映像を扱うのは難しい.そこで,映像のフレームに透過マップをくっつける(この処理はffmpegopenCV等の画像処理ライブラリを使って適当にツールを書いておくと楽).これはgooglechromeの技術デモ『3 Dreams of Black』で用いられていている手法で,以下の動画が参考になる.

このアプローチをnormal mapやdepth map等の複数種類のソースに拡張することで,deferred shadingをVEDA側で行うことができる.ちなみに,基本的にカラー以外の情報は縮小しても粗さに気が付きにくいため,付加されるマップについては1/2サイズのものにしておくと処理の負荷を抑えることができる.

armos devlog 3f1b057 and 6aab220

github.com

以下の機能がarmosのdev branchに取り込まれた.

  • CLIでのarmos generateコマンドによるコード生成
  • glslifyによるShaderのprecompile

また,今回の変更によりarmosの動作にはnpmを要求するようになった.

(この解説では便宜上,プロジェクトのルートディレクトリを/として表記する)

armos generateコマンド

$ armos generate <target>

いくつかの種類のディレクトリやソースコードを自動生成する.generateの部分はgに省略可能. <target>は以下がサポートされている.

  • project
  • material
  • glslsource(glslsources)

project target

$ armos generate project [<projectpath>] [<options...>]

armosコマンドの<target>projectを指定した場合,新規に指定したパス<projectname>にarmosのプロジェクトを生成する. <projectname>を省略した場合,現在のワーキングディレクトリにプロジェクトが生成される(dub initと同様の挙動と考えて良い).

このコマンドは以下の処理を行う.

  1. dub initの実行によるプロジェクトの生成,
  2. armosのアプリケーションの雛形となるMainApp classとそのエントリーポイントを含んだコードをsource/app.dへ上書き.
  3. glslifyがnpmのglobalに存在しない場合,インストールを行う.

以下のoptionにより,デフォルトで生成されるapp.dに追加するコンポーネントを指定できる.

  • --defaultcamera string

他のコンポーネントについてのoptionは今後追加していく予定.

--defaultcamera string

armos.graphics.camera.DefaultCameraを追加する.このoptionはインスタンスの名前を指定するために文字列の値を設定する必要がある.

material target

$ armos generate material <ClassName> [<path>] [<options...>]

armos.graphics.materialを継承したクラスの定義が書かれたコードを生成する.<ClassName>には生成するクラスの名称を指定する.pathを指定しないこと(e.g. foo/BoxMaterial). 生成されたコードは/source/<projectname>/materials/<classname>.dとして保存される.

以下のoptionが使用可能.

glslsource (glslsources) target

ここでは機能が似ている2つのtargetについて説明する.

$ armos generate glslsource <filepath> [<options...>]

glslsourceは一つのglslファイルを生成する.<filepath>に指定したファイルを/shadersディレクトリ内に生成する. 生成されるファイルがvertex shaderかfragment shaderか,あるいはgeometry shaderかは,<filepath>で指定された文字列の拡張子により判別される. 拡張子は以下を用いること.

  • .vert vertex shader
  • .frag fragment shader
  • .geom geometry shader

optionには以下を使用できる.

$ armos generate glslsources <dirpath> [<options...>]

glslsourcesは vertex shader, fragment shader, geometry shaderの3つのglsl sourceを含んだディレクトリを/shadersディレクトリ内に<dirpath>として生成する. 以下のoptionが使用できる.

  • --no-vert vertex shaderを生成しない
  • --no-geom geometry shaderを生成しない
  • --no-frag fragment shaderを生成しない
  • --path string /ディレクトリからの相対パスで生成先を指定.dirpathより優先される..

今後は--typeoptionにより様々な種類のglsl sourceを生成できるようにしていく予定. .

glslify Shader Precompile

armos.graphics.shaderでglsl sourceをコンパイルする前に行われるソースコードの展開(precompile)にnpmのパッケージであるglslifyを使用するようにした.

この変更により,以下の機能が提供される.

  • glsl sourceのモジュール化と読み込み
  • npmによるglsl-*系パッケージの手軽な利用

詳細は以下の記事を参照.

qiita.com

なお,dlangのソースコードにハードコードされたglsl sourceをarmos.graphics.Shader.loadSourcesに渡した場合, そのコードは/にあると見なされる.glslifyの相対パスによるmodule読み込みの際には注意すること.

引っ越しした

山奥から札幌に引っ越しした.色々と落ち着いてきたのでこの記事を書いている.出自が野蛮な男子寮なので(夜中に人間の鳴き声が聞こえる等.スズメがドン引きするレベル),世間の常識的にどこまで騒いでいいのかよくわからずビクビクしながら静かに生活している.

自炊

f:id:ttata:20170125224143j:plain:w500

朝はシリアルで軽く食べて,昼と夜はスパゲティとかスープ系とかを作って食べている.今日は舞茸とキャベツのペペロンチーノを作った.具が多すぎて野菜炒めみたいになってしまったが,キャベツのやさしい味がして美味しかった.あとシチューとかもこの前作った.ふたり分作ってしまって残りは冷蔵庫に突っ込んでおけるので楽.また,米については炊飯器は買わずに普通の鍋で炊く予定だったが,ここ数日美味しいごはんの食べたみが出てきたので,つい先ほど土鍋と米を買ってしまった.土鍋は頑丈そうで米も炊けそうな銀峯 花三島の8号ってやつを選んだ.ちょっと大きめなので誰かと鍋をつつくのにも使えると思う. これで生活の文明レベルが弥生時代まで急激に発達した.土鍋×ガスの最高のごはん体験楽しみ.とりあえずこの後は,土鍋を調理に使う前に,目止めというならし作業を行うので,実際にごはんを炊くのは明日以降になると思う.

インターネット

さて,引っ越してから1週間が経過して家具や家電は概ね揃ったが,未だに不足しているインフラがある.インターネットだ.今は無線の容量制限付きの回線でなんとかしのいでいるが,半身をwebに置いているような人間なので正直そろそろ息苦しい.予定では2/1には使えるようになるので,それまでに届くよう無線ルーターもポチった.NEC Aterm WG1800HP2ってやつ.回線が整い次第本気出しますよろしくお願いします. 

キリンガラナ500ml缶

この記事は苫小牧高専 Advent Calendar 2016 23日目の記事です。

 冷蔵庫からキリンガラナ500ml缶(以下ガラナ)を取り出した.この記事を書くときに飲もうと取っておいた最後の一缶だ.できるだけ体温で温度が上がらないよう,上面の縁をつまむようにして机へ運ぶ.下面に書かれた製造番号は「NA/1EI59」."NA"が製造工場の識別番号で,スラッシュの後ろがロットになる.この500ml缶は全て,岩内町にある「日本アスパラガス」という工場で生産されていると友人から聞いた.恐らく識別番号は"Nihon Asparagus"の頭文字をとったのだろう.この工場は缶詰の製造ノウハウを清涼飲料水のパッケージングに転用したとかなんとか.さて,ロット違いのものが他にあれば飲み比べもできるが今回はこの一缶だけ.プルタブを引き起こす.炭酸の勢い良く漏れる音と共に鼻の奥を優しく刺激するフルーティーな香りが漂う.最初の一口,喉で味わう.いつもより炭酸は控えめで甘めの味付けだ.冷蔵庫で冷やしただけなので舌触りはサラッとした感触.凍る直前まで冷やすとまろやかになるが,一歩間違えると破裂する恐れがあるので最近はやっていない.高専の寮にいた時は,冬の朝に二重窓の間に置いておいたガラナが破裂し,窓が飴色に染まったのを思い出す――

 僕が寮にいた5年間で一体何本のガラナを飲んだだろうか.一年のうち2/3は寮で生活していたとすると,一日に一本は飲んでいたので,大体1200本は飲んだことになる.いつも買う寮の食堂の前のアホみたいな品揃えの自販機はガラナを100円で販売していたので120000円分ガラナに注ぎ込んだ計算になる.まじか.ドン引きなんだけど.多分計算間違いだと思う.入学したばかりのころはそこまで飲んでいなかったような気がするし.

f:id:ttata:20161223223359j:plain

食堂前,アホみたいな品揃えの自販機(なお周波数の都合で一部点灯してないように見えるがテスト期間につき全て売り切れ)

 授業が終わり,一度寮へ帰る.部活へ行く途中,食堂の前の自販機でガラナを買う.すぐにでも飲みたいが,外の空気に触れると味が変わってしまうので開けずに部室まで縁をつまんで持っていく.未だに不思議なのが,屋内の空気と触れるだけではそこまで味が変わらない点だ.開封したまま外を歩くと,どうしても埃っぽい味になってしまう.まあ,その季節その時間の空気の香りをガラナと一緒に楽しむことができる,という考え方もあるかもしれない.夜は寮の風呂から上がった後に食堂の前の自販機でガラナを買う.そのまま缶を片手に自分の部屋に戻ったり,誰かの部屋に遊びに行ったり.基本的に1日1本だけどテスト期間だと2本目に手を出すことがある.で,そういう時期には寮の自販機のガラナが売り切れたりする.

 卒研室の冷蔵庫には常にガラナが入っていた.というのも,当時の僕を含めた卒研室の5年生はほとんどがガラナ飲みで,いつも机に500ml缶を置きながら研究に励んでいた.あといつの間にか卒研担当の先生もガラナにハマっていた.こうしてそれぞれ買ってきたガラナを冷蔵庫で冷やすようになった.

 ガラナについてのある仮説が提唱されたのもこの場所だった気がする.

ガラナの味が違う」

半分冗談だったけど.甘さや香り,炭酸の強さが,飲む度に微妙に異なることに気がついたのだ.ここでいくつかの仮説が立てられた.

  1. 体調説
  2. ロット説
  3. 経年劣化(熟成)説

まず,体調説の検証は難しそうなのでパス.でも体調で味覚が左右される話はよく聞くので,可能性としては大いにあると思う.また,ロット説については,研究室のメンバーが異なる複数のロットのものを仕入れるため,それぞれ別のルート,寮の食堂前の自販機,学生会館の購買等からガラナを入手し飲み比べをした.確か味が異なっていた記憶がある.要追実験.最後に,経年劣化(熟成)説は,事前に僕が,食堂前の自販機のガラナが売り切れた際の戦略備蓄として,自分の部屋の机の引き出しに保存しておいた,購入から1年が経過したガラナをサンプルとして利用し,検証する予定だった.でも結局,なかなか開封するタイミングがつかめずに卒業してしまった.あの熟成ガラナは当時の卒研室のメンバーだった僕の友人に譲渡した気がする.今もまだあるのだろうか.

 ガラナのアレンジは,他のジュースと混ぜるあたりでやめておいたほうが良いのかもしれない.ガラナを少し飲んだ後にレッドブルを混ぜたガラナブルはテスト期間等切羽詰っている時にお世話になった.あとレモンを絞ると美味しいらしい.これは友人から聞いただけで実はまだ一度も試せてない.ポッカレモンよりも生のレモンが良いとか.

 問題はここからで,ある時ふと魔が差して固形物のガラナを食べたくなってしまって,フライパンでガラナを煮詰めてガラナ飴を作った.いい感じに箸に巻きつけて,それっぽい見た目にすることには成功した.ただ,どうにも若干火加減が強かったらしく,焦げてしまったらしい.ほろ苦い大人向けの仕上がりになってしまった.もともとの液体の色がキャラメル色なので,判断が難しいんだと思う.誰かこの失敗を活かして美味しいガラナ飴を作って欲しい.

f:id:ttata:20161223224247j:plain

ガラナ飴 苦い

 で,最悪だったのがホットガラナ.元のガラナが美味しいだけに,これは本当に驚いた.コニカルビーカーに入れて湯煎したので見た目に凄みがあったのも大きいかもしれない.僕と,共犯の1人は口に含んだ直後に吐き出した.なお別の共犯者は普通に飲んでたので個人差があるのかもしれない.まあ,あれは本当に最悪のエクスペリエンスだった.簡単にできるのでこの記事を読んだ人はぜひ実践していただきたい.

f:id:ttata:20161223224345j:plain

吐き気を催す邪悪

 大事な話をするのを忘れていたんだけど,キリンガラナって,容器によって味が微妙に異なる.これは僕のまわりのガラナ飲みからコンセンサスが得られてるんだけど,500ml缶が至高.ペットボトルだと味に雑味が入る.アルミのボトルタイプのものも同様.どちらもフタ付きで飲みきりではないので何らかの保存料が追加で含まれているのかもしれない.ただこれだと190ml,350ml缶の味が500ml缶に劣る理由が説明できない.なんでだろう.誰か調べてみてほしい.(あとキリンガラナの他にもコアップとか色々な種類のガラナがあるけどキリンガラナが一番美味しいと思います)

 そろそろ開けたガラナも無くなりそうなのでこの記事もこのへんでまとめていこうと思う.昔からガラナについて何か記事を書いておこうと考えてはいたけどタイミングが見つけられなかった.そこで今回,苫高専AdventCalendar23日目という機会を頂いたので,ポエムを献上させて頂いた次第.しかしこうして昔のことを思い返すと僕も友人たちも本当に脳にガラナが回ってたんじゃないかと不安になる.まあ,在校していた当時から,卒業して今に至るまで,ガラナを本当に沢山の人と飲みながら,下らないことから大事なことまで色々な話をしたし,きっとこれからも,昔の友人と会うときはガラナで乾杯するのだろう.

ガラナはいいぞ.

f:id:ttata:20161223232431j:plain:w340

明日,24日の記事はhanaken_nさんの「クリスマスイブデートを断って後輩たちに捧げるポエムです。それでは聴いてください。『あえて言おう、mkは休学すると』」です.僕もmkくんは無傷で専攻科を卒業できるとは思っていないのでとても楽しみにしてます.

D言語でクリエイティブコーディングのためのフレームワークarmosを開発している話

はじめに

 この記事はD言語 Advent Calendar 2016クリエイティブコーディング Advent Calendar 2016の記事です.

 1年ほど前からopenFrameworksprocessingのようなフレームワークD言語で開発しています.この記事では,ざっくりですがその紹介をしていきたいを思います.なお現在のarmosの仕様は暫定的なもので,これから大きく変更される可能性があります.

armos

f:id:ttata:20161206230838p:plain

github.com

 armosはクロスプラットフォームのクリエイティブコーディングフレームワークを目指して開発されました.言語は,ネイティブコンパイル言語の処理速度と,軽量言語の書きやすさを兼ね備えたD言語を採用しており,シンプルなプロトタイピングから,複雑でスピードを要求されるようなアプリケーションまで柔軟な記述が可能です.画像や音声等の複数のライブラリを統一的なIFでラップしており,開発者はD言語のコードからそれぞれの機能を簡単に扱うことができます.

 現在のarmosについては,動作環境については,Linuxと一部のWindowsで確認しており,Macについては未確認となっています.一部グラボによっては描画が正しく行われない,等の環境依存があるようです.機能については,openGLによる描画処理,Assimpによる3Dモデルの読み込み,openALによる3次元音声処理,GLFWによるウィンドウ管理と各種入力デバイスのサポート等が実装されています.これらは工数の兼ね合いから,ライブラリの全機能のラッピングよりも主要な部分の実装が優先されており,あまり重要ではない機能やユーテリティは後回しとなっています.また,今後は動画やフォント,パスの描画等の機能を実装していく予定です.

機能の追加やバグフィックス等がありましたら是非気軽にContributionお願いします:)

サンプルコード

 moduleの数がそれなりに多く網羅的な説明をこの記事で行うのは困難なので,armosの基本的なアプリケーションの記述方法を紹介していきたいと思います.

// armosの機能を使うためのimport文.
// コード中のどの部分がarmosの機能なのかを明示するためにstaticをつけている.
static import ar = armos;

// oFと同様にBaseAppを継承してアプリケーションのclassを記述していく.
// 基本的なメンバ関数は以下の3つがある.
// setup  実行時の最初に一度だけ呼ばれる
// update 毎フレーム呼び出される.メンバの更新処理を記述する
// draw   毎フレームupdateの直後に呼び出され,描画処理を記述する

class TestApp : ar.app.BaseApp{
    override void setup(){
        // アルファブレンディングを有効にするため,BlendModeを指定する.
        ar.graphics.blendMode = ar.graphics.BlendMode.Alpha;
        
        // Lenaの画像を扱うImage classのインスタンスを生成し,画像ファイルを読み込む.
        // 読み込みの処理はFreeImageを使用.
        _imageLena = (new ar.graphics.Image).load("lena_std.tif");
        
        // 同様にD-man(D言語くん)の画像を読み込む.
        // また,ここでは拡大した際にぼけないよう,テクスチャのフィルタの設定も行っている.
        // このように,armosで実装されているほとんどのclassやstructはメソッドチェーンで処理を書いていくことができる.
        _imageDman = (new ar.graphics.Image).load("d-man.png")
                                            .minMagFilter(ar.graphics.TextureMinFilter.Nearest, ar.graphics.TextureMagFilter.Nearest);
    }
    
    override void draw(){
        // Lenaの画像の一部分を表示.
        // 第一引数と第二引数は表示位置,それ以降の引数で切り抜く範囲のピクセル座標を指定する.
        _imageLena.drawCropped(512, 512, 256, 256, 512, 512);
        // Lenaの画像を0,0の位置に表示.
        _imageLena.draw(0, 0);
        
        // oFやp5にある同名の関数と同様,Model行列を保存(stackにpush)する.
        ar.graphics.pushMatrix;
            // Model行列のx, y座標を10倍に拡大する.
            ar.graphics.scale(10, 10, 1);
            // 今のModel行列が適応されるので10倍のサイズのD言語くんが表示される.
            _imageDman.draw(14, 5);
        // 保存しておいたModel行列を再び読み出す(stackからpop).
        ar.graphics.popMatrix;
    }
    
    private{
        // 画像を読み込み,表示するためのImage.
        ar.graphics.Image _imageLena;
        ar.graphics.Image _imageDman;
    }
}

// D言語の標準のエントリーポイント.
void main(){
    // 上で実装したアプリケーションを実行する.
    ar.app.run(new TestApp);
}

このコードを実行することで,以下のような表示を行うアプリケーションが動作します.

f:id:ttata:20161206231226p:plain

 armosには各機能の動作を紹介するサンプルプロジェクトが同梱されているので,詳細はそちらを参照してください.

armos/examples at dev · tanitta/armos · GitHub

特徴

 いくつか紹介したいと思います.

oFライクなイベント

 armosを用いたアプリケーションを開発する際に継承するクラスarmos.app.BaseAppは,openFrameworksのofBaseAppと同様なメソッドを用意しています.キーボード入力は,現在のキーの状態をすぐに確認できるhasPressedKey, hasHeldKey, hasReleasedKeyが実装されています.   https://github.com/tanitta/armos/blob/dev/source/armos/app/baseapp.d

Vector

 ベクトルを表すstructです.要素の型と次元をtemplate引数として指定します.各種オペレータのオーバーロードが実装されており簡単にベクトルの計算ができます.

auto v = Vector!(float, 3);

また,Vector Swizzleが実装されており,GLSLのvector.xzのような記法でのプロパティへのアクセスが可能です.

auto vec = Vector3f(2.0,4.0,6.0);
vec.yx = Vector2f(0.0,1.0);
assert (vec == Vector3f(1.0,0.0,6.0));

他にもVectorを元にしたMatrixやQuaternion等が実装されています.

Shader

 openGLのShaderを扱うclassです.基本的なインターフェースはoFと似たものとなっていますが,Shaderのプログラムのattributeやuniformにデータを渡す関数は,D言語の強力なコンパイルメタプログラミング機能により,データの要素の型や要素数を意識することなく扱うことが可能です.

int d = 1;
shader.uniform("distance", d);
shader.uniform("position", ar.math.Vector2f(1.0,2.0));

Material

 ポリゴンの材質を表す,Shaderとプロパティをまとめたinterfaceで,複数の材質の切り替えやパラメータの管理等を容易に行えます.また,このinterfaceを元にオリジナルのMaterialを作成することができます.

AutoLoadMaterial

 上のMaterial interfaceを元にしたMaterialで,読み込んでいるShaderのソースファイルが更新された際に自動的に変更を検知し,再読み込み,コンパイルを行います.これにより,GLSLを用いたライブコーディングが可能となっております.

2Dデータ

 2DのデータはImage, Bitmap, Textureの3種類があります.簡単に画像を扱うためのImage classは,ファイルの読み込みから画面への描画をサポートします.画像の読み込みはFreeImageにより行うため,様々な形式の画像ファイルに対応しています.Bitmap structは画像を表す単純なデータ構造で,サイズ分のピクセル情報を持ちます.拡張機能として,ndsliceへの変換が可能なため,複雑な画像処理でも高速で行うことができます.Texture classは,openGL側で画像を扱うためのもので,Bitmapからの変換が可能です.

3Dデータ

 armosでの3Dのデータは階層構造になっています.

  • 形状を表すMesh class
  • Meshと材質を表すMaterialを束ねたEntity class
  • 複数のEntityを束ねたModel class

なおModelはファイル名を指定することで外部ファイルからデータを読み込む機能も実装されています(Assimpを使用).また,MeshとEntityはGPU側で高速に扱うためのBufferMesh,BufferEntityが存在します.これらは,openGLのVBOを用いてデータを管理しており,元のMeshやEntityから簡単に変換することができます(CinderのBatchのような感じ).

Filter機能

 Fbo classのメンバ関数FilteredByを使うことで,表示結果にフィルタをかけていくことができます.引数にはMaterialを指定します.

fbo.filteredBy(invert)
   .filteredBy(offRegistrationFilter);

D言語でクリエイティブコーディングをするときの便利なパッケージ

 D言語で色々やっていくために書きました.

easing

github.com

 よくあるeasing関数がまとめられたパッケージです.関数を直接扱う際は定義域,値域共に(0,1)ですが,付属のmap関数を用いることで,それらを自由に変更することができます.実装されているeasing関数はパッケージのREADME.mdを参照してください.

import easing;
auto output = input.linear;
//                  |
// easing function -+

auto output = input.map!linear(0.0, 10.0, 0.0, 1.0);
//                      |      |    |     |    |
// easing function -----+      |    |     |    |
// min of input ---------------+    |     |    |
// max of input --------------------+     |    |
// min of output -------------------------+    |
// max of output ------------------------------+

osc-d

github.com

 おなじみOpen Sound Control(OSC)プロトコルD言語実装です.外部のシーケンサ等からarmosのアプリケーションを操作することができるようになります.

実際のところD言語でクリエイティブコーディングってどうなの

 D言語の仕様については問題なく快適にコードが書けます.ビルド速度も高速で,試行錯誤のサイクルをガンガン回すことができ,テンプレートをゴリゴリ使ってもそれほど遅くなりません.hppとcppでコードを分ける必要も無く,module機能が実装されているのでincludeの依存関係で悩む必要も無いため,ソースコードの取り回しが非常に楽です,また,昔のD言語はアップデートが派手だったらしいのですが,最近のD言語はそのような破壊的な変更も無く安定しています.言語仕様が洗練されているため学習コストも低く,特にC++erなら非常に楽に学べると思います.

 エコシステムに関しては,モダンな言語でよくあるパッケージマネージャとしてdubがあり,プロジェクトと要求パッケージのバージョン依存を管理をしてくれます.ライブラリ周りについては,品揃えはそこそこ充実してきたのですが,どうしてもクリエイティブコーディングのような用途で要求されるような特殊なものは不足してしまうところがあります.また,D言語はCで書かれたコードについては互換性がありますが,一方でC++はそのへんが難しいらしく,そのため,openCVKinectのようなライブラリがC++で記述されたものについては,一度Cでラッパを書いてそこから呼び出す,等の方法をとる必要があるようです.(なお,openCVについては,同様の画像処理ライブラリとして現在dcvが開発されており,今後が非常に楽しみです)

 このように,ライブラリついては若干不安がありますが,言語自体は非常に優秀です.足りないライブラリはガンガン実装してコミュニティに貢献していきましょう!

My First Game Jam: Summer Editionに参加した

 久しぶりにゲームジャムやりたいなと思ってIndie Game Jamsを眺めていたら,My First Game Jamっていう初心者向けのゆるそうなイベントを見つけたので参加してきた.

itch.io

 自分は以前にGlobal Game Jamに参加したこと(参照)があるので"My First Game Jam"ってわけじゃないんだけど,今回使ったprocessingでゲームを作るのは始めてだったのでまあ初心者ってことで.

My First Game Jamとは

  • 初心者向けのゲームジャム
  • ルールはかなりゆるい
  • 期間は2週間
  • 一人で開発してもよし,チームを組んでもよし
  • 普通のゲームジャムと同様,開催直後に発表されるテーマに沿って開発する.

開催までの色々

 一人で作るのも寂しかったので,普段から素晴らしい楽曲を書いているOtObOx先生をサウンド回り担当として誘った.「やる?」「やる」的な二つ返事でコトが進んだ記憶がある.フットワークが軽くて素敵だと思う.というわけで,自分がプログラミングとグラフィック担当,OtObOx先生がサウンド担当って感じでチームが決まった.

開催後前半

 どんなゲームを作っていくか,SlackとTeamSpeak3で作戦を練った.今回発表されたテーマは"a spin on a popular story/myth".スピンオンってなんだ.ググりまくった記憶がある.とりあえず日本の昔話系をリストアップした.自分はゲーム作りやすそうだったので因幡の白うさぎをゴリ押しした気がする.サメから落ちたらゲームオーバーみたいな.最終的に竹取物語ベースのシューティングを作ることになった.この時はまだ,月からの使者を迎撃する普通のインベーダ的なゲームを想定していたのであった...

開催後後半

 1週間が経過した.「そろそろつくろっか.まあ1週間もあれば余裕っしょ.ハンデハンデ笑」という気持ちで開発が始まった.とりあえず2日間ぽちぽちドットを打ち,もくもくコードを書いて叩き台が完成.設計や実装の美しさを無視した,とりあえず動けばいいコードを乱暴に書き上げていく作業は,背徳感とスピード感があってとても気持ちが良かった.あとは楽曲や効果音を組み込みつつ,難易度を下げる方向に調整していった.

 最終日は,時間ギリギリまでテストプレイのフィードバックでクオリティを上げていく作業をした.朝ごはんとして温めた角煮肉まんを電子レンジから取り出す暇が無いほどエクストリームだった.(テスターのみなさんありがとうございました!)13時の提出直前は,バージョンを一つ戻すかどうかで決断を迫られる体験ができた.git rebaseのコマンドをド忘れして激焦った.提出も,イベントのページと別でアカウントが管理されている都合,無事にアップロードできてるのか分からなくて激ヤバだった.

 最後は,すっかり冷えきった角煮肉まんをもう一度レンチンしなおして笑顔でおいしく頂けたのでよかった.

できあがったもの

f:id:ttata:20160817153702p:plain

tanitta.itch.io

github.com

 月から地球にやってくる使者のウサギから,かぐや姫を守るシューティングゲーム.前半1週間でOtObOx先生が「弓飛ばそう弓」と言ってた気がするが,実際に実装されたのは,タケヤリにロケットブースタをポン付けした星間ミサイルと,それに作用する重力場であった.射出後に加速するタケヤリミサイルを地球の軌道に上手く乗せて,飛来するウサギを迎撃していく.真上に打ち上げるだけだと,重力が作用してすぐに落下してしまうため慣れが必要.また,タケヤリの残弾数は地上のタケを刈り取ることで回復できる.WindowsLinux対応.(Macは適当にprocessingでビルドして動かして下さい.)なお,開発途中で名前が"taketori war"から"taketori wars"に変わったため,表記ゆれが非常に激しい.あとdision氏のスコアがオーバーフローしたプレイ動画乗せておきます.

www.youtube.com

得られた知見

  • 相手の作業風景を直接見れないのでリモート難しい.くだらない内容でも良いので連絡をこまめにとると,お互いの開発状況がなんとなくわかって安心.
  • 少ないメンバーで迅速な意思決定ができたのでよかった.多くても3人とかがよさ気?
  • 実際に作業する人手が不足している.自分がプログラミングとグラフィック両方やるのはちょっと厳しい.どちらかできる人がもう一人いれば....
  • ゲームの難易度は,開発者自身が実装の過程で慣れてしまうため,調整が難しい.自分が思っている以上に下げる,あるいはコアメンバ以外の人にテストプレイをしてもらう必要がある.
  • 爆発エフェクトは白黒の点滅を入れると視覚的に威力が上がる.
  • 適当なバネモデルで画面を揺らすと激しい肌触りになる.
  • 早めの提出