ofxGLSLSandboxファイル監視して更新したら自動で反映

openFrameworksでshaderを使いこなせるように勉強中です。

いろいろ試すのに、yoppa先生製のofxGLSLSandboxってアドオンがとても便利そうです。( https://github.com/tado/ofxGLSLSandbox
GLSL Sandbox( http://glslsandbox.com/ )ってサイトで誰かが描いたシェーダーをコピペでポンで動くみたいです。

 

至極恐縮ですが、ofxGLSLSandboxを少し改造して、自動でファイル監視してcmd+sとかでファイルを更新したら自動で描画に反映されるようにしました。https://github.com/shiyuugohirao/ofxGLSLSandbox

取り急ぎ、OSX oF0.10.0でのみテストしました。

以下シェーダー勉強しながら思ったことをメモしておきます。📝

openFrameworksでshaderを書く際は、bin/dataフォルダにshaderフォルダを作って、そこに.fragや.vertを置いておくことが多いと思います。私の場合は。

雑な紹介ですが、
以下みたいにXcode上でファイルを紐付けると同じプロジェクトファイル内でshaderも編集できるのでいい感じでおすすめです。


srcで右クリックー> Add Files to ~~~


shaderフォルダなどをAdd


oFのプロジェクト内で .frag .vertなど編集できる!

他にもっといいやりかたあるかもだけど。

 


ついでにopennFrameworksでファイル更新の監視プログラムについても。

調べてみたらC++のfilesystemライブラリの中にファイル更新時の取得ができる関数がありました。

string fileName =  ofToDataPath("absolutePath.ooo", true);
long latestUpdate = std::filesystem::last_write_time(fileName);

ポイントは絶対パスを指定するところ。恐らくこうしたほうが確実に更新日時取得できるはず。
ファイルパスをうまく指定できないと、last_write_timeが実行されたときに、ファイルが見つからず落ちてしまうので、パスが正しいかどうかのチェックを入れてから実行するべき。
今回は、ofFile::doesFileExist(fileName)) で一応チェックしてから更新日時取得するようにしてます。

あとは、update()のなかで毎フレームチェックするか、重そうならif(ofGetFramerate()%10==0) みたいにして数フレームごとにチェックするかすればよき。

ちなみに、last_write_time の戻り値は 例えば 1234205545 みたいな整数が返ってくる。
どうやら「1970-01-01 00:00:00からの経過秒数で最終ファイル更新日時」とのこと。(参考)

今回は更新日時に変化があるかどうかだけ見れば良いので、整数のまま比較して〜ごにょり。

詳しくは、改造しましたソースコード を見ていただけると。
ぇぃゃーで公開しているので何かあればコメントいただけると🙏

shaderいっぱい試してがんばります👩‍🎨

http://glslsandbox.com/e#45998.0

展示コンテンツ制作の備忘録

展示コンテンツを制作する際の、注意事項や、組み込んでおくと安心な仕組みを、
仕事などでやったこと、気づいたことを中心にまとめておきます。
長期・短期にかかわらず、手元を離れて展示される・スタッフの方に運用してもらうコンテンツを作る際に役立てば ヨッシャ! です。

整理しつつ、気づいたこと、思い出したことあったら、後日追記していきます。

※ コンテンツはopenFrameworksで作ることが多いので、oFに特化した内容ですが、タスクスケジューラなど標準機能の使用時の注意も覚えている限りで記載するので、参考になれば幸いです🙏
※ ここで紹介している対策は、あくまで私の取った取り急ぎの対策もあるので、もっとスマートに解決できる方法があるかもしれません。
もしこんな対策あるよというものがあればご教示いただければ、とってもとっても幸いです。🙏🙏🙏

 

【Mac】

これから追記します。

【Windows】

・運用において、「シャットダウン→起動」と「再起動」は違う。
デフォルトの設定では、シャットダウンのとき「高速スタートアップ」というものが有効になっており、再起動のときは無効になっているらしい。
「高速スタートアップ」はシャットダウン時にPC周辺機器の情報などをログとして残しておいて、起動時にはそのログを使うことで起動が30%くらい早くなるらしい設定。
シャットダウン→起動の運用を確実に行うときは、この高速スタートアップを無効にする必要がある。

・電源オプションを高パフォーマンスにしておく。
負荷の高いアプリを実行する場合は、消費電力はあがるけど、この設定を変更するとアプリの動作が若干安定する場合がある。

・「次の時間が経過後ハードディスクの電源を切る」を0(OFF)にしておく(?)
一定時間HDDへのアクセスがない場合にHDDが止まり、再び回しだすために負荷がかかる、遅延が生じる場合があるらしい。

上2つは省電力目的の設定なようなので高パフォーマンス・HDDの電源切るオフ にしておいたほうが安定しそう。

・監視アプリを用意する(oF_Win_Watchdogなど)
oFアプリなら何かしらのトラブルでアプリが落ちたとき自動で立ち上がるように、監視用として、oF_Win_Watchdogを入れておくと安心。
https://github.com/Akira-Hayasaka/oF_Win_Watchdog
ポイントとしては、監視するアプリのパスを相対パスで指定すると、環境?立ち上げのタイミング?(原因が明確でないですが、、)によって時々対象のアプリがうまく指定できないことがあった。ので、絶対パスで指定したほうが安心。
oFについては後日別記事で。

・アプリが落ちた際にメールを飛ばす仕組みを用意する
上に加えて自動メール送信をコンボすると、なにかあったときにメールが送られてきて対処が取れる。
Macならmailコマンドがあるので、ofSystem(mail ~~~)などとすれば、比較的簡単に簡単にメールを遅れるが、windowsの場合、認証とかの関係でちょいややこしい。
私の場合は、Windowsを使う案件だったので、vbsスクリプトを書いて、
(vbsの書き方についてはこの辺が参考になるかも→http://serialty.blog117.fc2.com/blog-entry-10.html
監視用のWachdogアプリの中で再起動する際に、ofSystem()からvbsスクリプトを叩いてメールを飛ばす。といった具合で組み込んでいました。
あと日本語を含む場合はshift-jisで保存する必要があった。はず。(チョットワスレマシタ)
参考までに以下vbsスクリプトの例(GmailのSMTPを利用)

'****************************************************************
' mail sender
'****************************************************************

Set Cdo = WScript.CreateObject("CDO.Message")
Cdo.From = "送信元表示名<送信元メールアドレス>"
Cdo.To = "表示名<メールアドレス>;表示名<メールアドレス>;"
Cdo.Subject  = "件名"
Cdo.Textbody = "メッセージ" & vbCrLf & Now
Cdo.BodyPart.Charset = "utf-8"

Cdo.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
Cdo.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "smtp.gmail.com"
Cdo.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 465
Cdo.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 30
Cdo.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = true
Cdo.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = true
Cdo.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusername") = "Googleのユーザー名(
メールアドレス)"
Cdo.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "SMTPパスワード"

Cdo.Configuration.Fields.Update
Cdo.Send

Wscript.Quit(Err.Number)

詳細を後日別記事で書いておきたい。。。

・FreeConsole()
openFrameworksのアプリとかだと、FreeConsole()でコンソールウインドウを非表示にできる。けれど、アプリ終了時にコンソールウィンドウを閉じることができず、バックグラウンドプロセスとして残ってしまう場合がある。(コンテンツの表示されているウインドウは消えているのに、BGMだけがなっていたり、裏でスレッドが走ったままになっていたり)
対策として、oFのExit()関数の中でstd::exit(0)を記載しておけばコンソールウィンドウも一緒に閉じることができました。

・タスクスケジューラ
タスクスケジューラからアプリを起動する場合、通常だとディスクアクセスの優先度が低い状態で起動してしまう。(watchdogも同様に優先度低いのでアプリが立ち上げ直されても優先度は低いまま)
これを変更するには、スケジューラからタスクをエクスポートして、xmlファイル上でpriorityを変更して、再度タスクをインポートして登録する必要がある。
http://ttgcameback.blogspot.com/2015/09/blog-post.html

・ウインドウの最前面化(アクティブ化)
アプリを自動で立ち上げた際、何かしらの影響でアプリ画面がアクティブ状態になっておらず、別のウインドウの下に隠れてしまったりする場合がありました。
またまたvbsスクリプトを書いて、アクティブにするようにしました。
ポイントとなるのは、アクティブ化するためのAppActivateという関数。単純にこれを実行するだけではウインドウが最前面に表れないこともあるそうで、調べてみると同じような現象で悩んでいる方がおられました。
私の場合は、

set WshShell = WScript.CreateObject("WScript.Shell")
Dim result
result = WshShell.Run ("起動するアプリのパス",1)
         WScript.Sleep 10000
         WshShell.AppActivate "ウインドウの名前"
         WScript.Sleep 100
set WshShell = Nothing
set result = Nothing

またoFで作ったアプリはたぶんデフォルトではウインドウの名前が振られていないので、ofSetWindowTitle()で名前を指定する必要がある。

【iOSアプリ】

アプリをインストールする際のアカウントに注意。
特にアプリをアップデートで上書きする際は、一度アプリをiOS端末から削除したほうが無難かも。
途中でアカウントを変更したりすると上書きでは前のライセンスのままインストールされて、期限切れみたいなことになりかねない。というかなった。

本番用にビルドする際は必ずクリーンしてからビルドして実機にインストールする。
画像などのデータがアプリ内部に残ってしまい、予想以上にファイル数が多くなっていたりする。
特にofDirectory使ってまとめて画像を読み込む際には、これによって、順番が変わってしまったりする。

 

【その他】

TeamViewer
・無料アカウントでつなぐと、接続終了時に「この無料セッションは~~提供されました」というウインドウが接続PCと接続先PCに表示される。
が、何度か接続→接続終了を繰り返せば、このウインドウが表示されない時があり、その場合は、接続先PCにもウインドウが表示されないらしい。
ちょっとした小技だけど、仕事などで利用するなら、ちゃんとアカウントを取ったほうが無論良い。

 

 

 

oFでBase64変換する

openFrameworksでBase64というstringに変換する方法

Base64てのは画像ファイルとか音声ファイルとかいろんなデータを64種類の文字列に変換する方式のことで、これすることでデータサイズはちょい増えるけどたいていのファイルを簡単にテキスト化して受け渡しできるというもの。みたい。
https://ja.m.wikipedia.org/wiki/Base64

ターミナルとかなら簡単で、ofSystemなどでコマンド実行して〜みたいなやり方もあると思いますが、oF上でスマートに変換したかったので、いろいろ調べてまとめました。

base64のエンコードとかデコードはC++のネットワーク系ライブラリPocoの中にも実装されていて、今回のやり方ではそれを利用しています。

ofImageにおける変換については探してみたらもろ答えがあった。ありがたみ🙏
https://gist.github.com/kidapu/0b9c2cbe98191a394c80

 




 

あと、変換したstringに改行コードが含まれている場合があって、それが邪魔してデコード失敗するときなどがありました。
というわけで、変換後のstringから改行コードを削除する関数(removeCRLF)も用意しています。
参考にしたのはこちら、そのままだけど。
https://teratail.com/questions/34367

他にも音声ファイルを変換したかったので、やりました。
※音声ファイルはofSoundBufferをwavとしてofBufferに直しています。こちらは後日ついきします。

とりあえず画像や音声データ→Base64に変換(エンコード)がしたかったのでそれのみ。

確認の時に使ったブラウザ上で画像↔Base64の変換確認できるサイト
https://lab.syncer.jp/Tool/Base64-encode/

最近よくoFからAPIを叩くのですが、その時にファイルを送るときは大抵Base64に変換したものを送るので、こうやってまとめておくと便利かも☺︎

使い方としては、ofApp.hなどで #include “ofBase64.h” ってしといて

string imageData = ofBase64::base64_encode(fbo);

という感じで。

classを作る代わりにnamespaceを作って、static関数を定義すれば、グローバルな関数(厳密には違う?)を作れるんですね。地味に結構便利そう。

 

ofColor::red みたいな書き方のwarningを消す

めちゃ些細なこと。openframeworksネタ。

他人の環境でどうなってるのかわからないのですが、ofSetColor(ofColor::red)みたいな書き方をするとXcodeでwarningが出てました。

Instantiation of variable ‘ofColor_<unsigned char>::red’ required here, but no definition is available

別にビルドする分には問題なかったのですが、warning消すことできたのでメモ。

参考にしたのはこちら
https://github.com/openframeworks/openFrameworks/issues/5546

で実際にしたのはこんな感じ

ofGraphics.hで以下を追加。

//### ADD ######################
// reffered from https://github.com/openframeworks/openFrameworks/issues/5546
extern template struct ofColor_<unsigned char>;
//##############################

これでwarning出なくなったので、気兼ねなくofColor::redとか使える!

たまたまつい最近参考にしたフォーラムが更新されてました。githubのoF0.9.8なら解消されているのかも。