ポイントスプライトでテクスチャアニメーション

前回ジオメトリシェーダでポイントスプライトを実装しましたが、

このへんを見ると当然、テクスチャ座標を自分で設定したくなりますよね。

gl_TexCoord[0].st = vec2(0,0);
gl_TexCoord[0].st = vec2(0,1);
gl_TexCoord[0].st = vec2(1,0);
gl_TexCoord[0].st = vec2(1,1);

やることは至って単純で、右辺の0と1にあたる数値をCPUから設定してやるだけです。

0がUV位置、1がUV範囲と思えばわかりやすいかと思います。

両方をuniform変数で渡しても良いのですが、汎用性を考えてUV位置は頂点ごとに設定できるようにしました。

  • バーテックスシェーダ

    前回に加えて、glTexCoord2dでCPUから渡されたテクスチャ座標をジオメトリシェーダに渡してます。

    #version 120
    void main()
    {
     gl_Position = gl_Vertex;
     gl_TexCoord[0] = gl_MultiTexCoord0;
    }
    
  • ジオメトリシェーダ

    前回に加えて、テクスチャ座標の計算が入ってます。

    #version 120
    #extension GL_EXT_geometry_shader4 : enable
    uniform vec2 size; // 描画サイズ(CPUからglUniform2fで渡す)
    uniform vec2 size_uv; // UV範囲(CPUからglUniform2fで渡す)
    void main() {
     gl_Position = gl_ModelViewProjectionMatrix * gl_PositionIn[0];
     gl_Position.x -= size.x/2;
     gl_Position.y += size.y/2;
     gl_TexCoord[0] = gl_TexCoordIn[0][0];
     EmitVertex();
     gl_Position.y -= size.y;
     gl_TexCoord[0].t += size_uv.t;
     EmitVertex();
     gl_Position.x += size.x;
     gl_Position.y += size.y;
     gl_TexCoord[0].s += size_uv.s;
     gl_TexCoord[0].t -= size_uv.t;
     EmitVertex();
     gl_Position.y -= size.y;
     gl_TexCoord[0].t += size_uv.t;
     EmitVertex();
    }
    
  • フラグメントシェーダ

    そのまんまです。

    #version 120
    uniform sampler2D tex0;
    void main (void)
    {
     gl_FragColor = texture2D(tex0, gl_TexCoord[0].st);
    }
    

CPU側では、表示したいテクスチャをglBindTextureしてglUniform1iした上でこんな感じで描画しましょう。

glBegin(GL_POINTS)
glTexCoord2d(s,t);
glVertex3d(x,y,z);
glEnd();

これで、頂点に渡すテクスチャ座標を時間変化させるだけでテクスチャアニメーションができますね。

ジオメトリシェーダでポイントスプライト

OpenGLに、ポイントスプライトという機能があります。

点(Vertex)に対してテクスチャを貼り付けて表示するもので、パーティクルの表示等によく使われるみたいです。

もうちょっと自由度ほしいなーというのと、シェーダのお勉強のために、同等の機能をシェーダを使って実装してみました。

  • バーテックスシェーダ

    CPUから渡された座標をそのままジオメトリシェーダに渡します。

    #version 120
    void main()
    {
     gl_Position = gl_Vertex;
    }
    
  • ジオメトリシェーダ

    四角形ポリゴンを作ってテクスチャ座標を指定します。

    ※GL_GEOMETRY_INPUT_TYPE_EXTにはGL_POINTSを、GL_GEOMETRY_OUTPUT_TYPE_EXTにはGL_TRIANGLE_STRIPを指定しておきます。

    #version 120
    #extension GL_EXT_geometry_shader4 : enable
    uniform vec2 size; // 描画サイズ(CPUからglUniform2fで渡す)
    void main() {
     gl_Position = gl_ModelViewProjectionMatrix * gl_PositionIn[0];
     gl_Position.x -= size.x/2;
     gl_Position.y += size.y/2;
     gl_TexCoord[0].st = vec2(0,0);
     EmitVertex();
     gl_Position.y -= size.y;
     gl_TexCoord[0].st = vec2(0,1);
     EmitVertex();
     gl_Position.x += size.x;
     gl_Position.y += size.y;
     gl_TexCoord[0].st = vec2(1,0);
     EmitVertex();
     gl_Position.y -= size.y;
     gl_TexCoord[0].st = vec2(1,1);
     EmitVertex();
    }
    
  • フラグメントシェーダ

    テクスチャを参照して色を設定します。

    #version 120
    uniform sampler2D tex0;
    void main (void)
    {
     gl_FragColor = texture2D(tex0, gl_TexCoord[0].st);
    }
    

CPU側では、表示したいテクスチャをglBindTextureしてglUniform1iした上でこんな感じで描画しましょう。

glBegin(GL_POINTS)
glVertex3d(x,y,z);
glEnd();

ofxGuiの拡張addonをつくったよ(ofxParamEdit)

—————————————————————————
(追記 – 20121224)

アップデートによってGithubのバージョンとこの記事の内容とに差異があります。
Githubの方のREADMEを参照ください。
—————————————————————————

ofxGuiという、超便利なaddonがあります。

この動画の画面左のやつです。

Eden 1.2 + ofxComposer + ofxGui from Patricio Gonzalez Vivo on Vimeo.

スライダーやトグルボタンでグラフィカルに変数をコントロールできて、そのために書くコードの量もさほど多くないというスグレモノなんですが

  • int,float,bool としてしか使えない(charとかucharとか使いたいことあるじゃん)
  • 利用する変数の型が気持ち悪い(intが使いたいだけなのにofxIntSliderを持っとかなきゃいけないなんて!)
  • そのせいで利用時に処理が深い(ポインタ参照やら関数呼び出しが3回くらい?)
  • アプリの規模がでかくなった時にまとめて管理しづらい(お手軽に使える故なんですが。。。)

あたりがもうちょっと解消されればなあと思って作りました。こちらです。

ofxParamEdit on Github

良い特徴としては

  • char, uchar, short, ushort, int, uint, float, double, bool が使える(内部的にはint,float,boolなので値域のはみだすバグがあるかも)
  • intとかfloatとかの普通の変数を持ってれば使える(すでに作ったアプリに組み込むのも簡単!)
  • 利用時の処理コストなし(普通に変数を参照するのと同じ)
  • コントロール群をグループとして管理するので、複数箇所で使う際に分離がよい

悪い特徴としては

  • 値を編集したときの処理が増えてる
    →たかだか1フレームに1回のことなので問題にはならないでしょう
  • Guiを作るのにofxParamEditのインスタンスが必要
    →ofxParamEditを複数作れることに利点もあるのでまあ一長一短ってことで。。。
    アプリ側でシングルトンにする運用も可だと思います。

あと、プログラムのコメントにも書いてますが、ofEventのremoveの動作が怪しい(たぶん)ので、ofxGuiの一部ソースをコメントアウトして利用してください。

ofxSlider.cppとofxButton.cppとofxToggle.cppのofRegisterMouseEventsの行です。

Pull Request歓迎なんでプログラマの方よろしくお願いしまーす!

これ、ofxGuiの本家に組み込んでもらいたいなー。

グループ化の処理は置いといたとしても、Guiの機能を持ったクラスを利用側が保持しとく必要があるのはあんまり良くないと思うんだ。

フォーラムのどこで提案すればいいんだろう。

pull requestできるところまで作るには規模のでかい変更になるのでまずはお伺いをたてたいのだが。。。

ofxBox2dとofxOpenCvを同時に使用する際に発生する(かも知れない)コンパイルエラーについて(vc10)

ofxBox2dを使っていたプログラムでofxOpenCvを使用しようとしたらいきなり身に覚えがないところで見に覚えのないコンパイルエラーが発生してしばらくはまっていたのでメモ。

コンパイル時に出るエラーログは下記で始まるやつでした。

1>c:program files (x86)microsoft visual studio 10.0vcincludexcomplex(441): error C2143: 構文エラー : ')' が 'const' の前にありません。
1>c:program files (x86)microsoft visual studio 10.0vcincludexcomplex(441): error C3861: 'dot': 識別子が見つかりませんでした
1>c:program files (x86)microsoft visual studio 10.0vcincludexcomplex(441): error C2059: 構文エラー : ')'
1>c:program files (x86)microsoft visual studio 10.0vcincludexcomplex(448): error C2065: '_Ty' : 定義されていない識別子です。
1>c:program files (x86)microsoft visual studio 10.0vcincludexcomplex(449): error C2143: 構文エラー : ';' が '{' の前にありません。
1>c:program files (x86)microsoft visual studio 10.0vcincludexcomplex(449): error C2447: '{' : 対応する関数ヘッダーがありません (旧形式の仮引数リスト?)

で、問題(っぽい)xcomplexの441行目付近は下記。

		// TEMPLATE FUNCTION norm
_TMPLT(_Ty) inline
	_Ty norm(const _CMPLX(_Ty)& _Left)
	{	// return squared magnitude
	return (real(_Left) * real(_Left) + imag(_Left) * imag(_Left));
	}

‘const’の前に’)'がないって言われてるってことは’norm(‘がおかしいんだろうなーと思ったんだけど、ちゃんと関数宣言してるからおかしいところないし・・・と思って次のエラーを見てみると

‘dot’ってなんやねん。

ってことで’#define norm dot’的なやつを探してみると、ありました。(VisualStudio使用なのでF12押しただけですけど)

ofxBox2dPolygonUtils.h(38)

// dot product (3D) which allows vector operations in arguments
//#define dot(u,v)   ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z)
#define norm2(v)   dot(v,v)        // norm2 = squared length of vector
#define norm(v)    sqrt(norm2(v))  // norm = length of vector
#define d2(u,v)    norm2(u-v)      // distance squared = norm2 of difference
#define d(u,v)     norm(u-v)       // distance = norm of difference

で、ここからはもう別に調べる必要ないんですけど一応。問題の行は

_Ty sqrt(dot(const complex<_Ty>& _Left, const complex<_Ty>& _Left))

こんな風に展開されてて、コンパイラさんに「引数あるなら書いて欲しいんですけど’dot(‘とか知らんしwwwww’const’とか書く前に括弧閉じろしwwwwwww」

って言われてたわけですね。すっきり!でも腹立たしい!

で、とりあえずの解決策としてはofxBox2dPolygonUtils.hよりも前にxcomplexを#includeしてほしいので

ofxOpenCv.hをofxBox2d.hの前に#includeしてやれば通るようになりました。

(ちなみに#include <complex>はopencv2/core/core.hppにあります)

とりあえずはこれでいいけど、根本的にはofxBox2dでこんなに一般的な名前を#defineしてるほうが腹立たしくてしょうがないんですけどね!!!せめて#undefしろ!

(追記)

ofxBox2dPolygonUtils.hの#defineあたりのコードはどうやらofPolyline.cppを元にしているようでした。

僕はlibにビルドして使用してるからcppに書いてある分には問題ないけど、

プロジェクトにoFのソースまで含めて作ってる人(少なからずいると思うんだ)の間で問題になってないんだろうか・・・?

となりの要素の表示状態を切り替える(+localStorageへ保存する)

開閉式メニューを実現するのに下記のようなコードをよく見かけるのですが

<a onclick="ChangeVisibleById('childId');">parent</a>
<div id="childId">child</div>

これだとchildIdが2箇所にあって嫌な感じです。

そこで、Visibilityを切り替える対象を隣の要素に限定して下記のようにしてみました。

<a onclick="ChangeVisibleNext(this);">parent</a>
<div>child</div>

こうすれば、どこへでもコピペ可能だしchildにidを書かなくて良いので可搬性バツグンです。

ちなみにChangeVisible~の実装はこんな感じです。

ついでにchild要素にidが指定されていたらVisibilityの値をlocalStorageに保存するようにしてみました。

var PREFIX = "visibility_";// 重複を防ぐためプレフィックスをつけとく(きやすめ)
var STORAGE_NAME="storage_name";// localStorageが使えない環境のためにLSTJSON(※)を使う場合
function ChangeVisible(obj)
{
	obj.style.display = (obj.style.display=="none")?"block":"none";
	if(obj.id) {
		localStorage[PREFIX+obj.id] = obj.style.display;
		LSTJSON.save(STORAGE_NAME);
	}
}
function ChangeVisibleById(id)
{
	var obj = document.getElementById(id);
	ChangeVisible(obj);
}
function ChangeVisibleNext(obj)
{
	do {
		obj = obj.nextSibling;
	} while(obj && obj.nodeType != 1);
	ChangeVisible(obj);
}
// localStorageからVisibilityを拾ってくる処理
function Load()
{
	LSTJSON.load(STORAGE_NAME);
	for(id in localStorage) {
		if(id.indexOf(PREFIX) == 0) {
			var obj = document.getElementById(id.substring(PREFIX.length));
			if(obj) {
				obj.style.display = localStorage[id];
			}
		}
	}
}

なお、htmlとhtaでnextSiblingの返すオブジェクトが違ったようなので、ChangeVisibleNextの実装にはこちらのサイトを参考にしました。
Finding HTML elements using Javascript nextSibling and previousSibling

(※)LSTJSONについてはこちら
htaでlocalStorageっぽいものを使えるようにしてみる

htaでlocalStorageっぽいものを使えるようにしてみる

localStorage超便利るんるんーって言ってたところで、htaではlocalStorageが使用できないことが判明(使えないよね?)

まぁhtaならファイル読み書き余裕ですしどっかローカルに保存しときゃ問題ないんですが

htaとhtmlとで違うコードを書かなきゃいけないのはいやだったので作りました。

localStorageが使えない環境だと自前で生成したlocalStorageを、localStorageが使える環境だと普通にlocalStorageを使用します。

■使用法

  1. localStorageを使用するより前(onloadあたり?)にLSTJSON.load(filename)を一度だけ呼んでおく
  2. 普通にlocalStorageにホイホイ代入
  3. 保存したいタイミング(onunloadあたり?)でLSTJSON.save(filename)を呼ぶ

※filenameはloadとsaveで対応がとれていれば適当で構いませんが、重複すると上書きされるので一意なものにすることをおすすめします。

※ファイルは環境変数%TMP%のフォルダに作られます。

■通常のlocalStorageと比べて良い点

・保存したファイルをhtaと一緒にパッケージとして配布できる(保存場所は工夫する必要あり?)

・ファイル単位で管理されるため、オリジン(プロトコル、ドメイン、ポート)をまたいで共有できる

■悪い点

・わざわざloadとsaveをする必要がある

・StorageクラスにあってArrayクラスにない機能が使えない

var LSTJSON = {};

// localStorageが使えない時のみ有効にする
if(!localStorage) {
	// json2を使うので読み込んどく。パスは適当に書き換えてください。
	// json2を持っていない方はこちらからDL→https://github.com/douglascrockford/JSON-js
	document.write('<script type="text/javascript" src="./js/json2.js"></sciprt>');

	var localStorage = new Array();

	LSTJSON.load = function(filename) {
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		// 作成済みなら%TMP%下にある
		var filepath = fso.BuildPath(fso.GetSpecialFolder(2).Path, filename+".json");
		// 空っぽだと困るので初期値を入れておく
		var str = "{}";
		if(fso.FileExists(filepath)) {
			var stream = fso.OpenTextFile(filepath);
			str = stream.ReadAll();
			stream.Close();
		}
		localStorage = JSON.parse(str);
	};

	LSTJSON.save = function(filename) {
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		// %TMP%下に作成
		var filepath = fso.BuildPath(fso.GetSpecialFolder(2).Path, filename+".json");
		var stream = fso.CreateTextFile(filepath);
		stream.Write(JSON.stringify(localStorage));
		stream.Close();
	};
}
// localStorageが使える時はloadとsaveを無視する
else {
	LSTJSON.load = function(){};
	LSTJSON.save = function(){};
}

GitHubに上げました。不便ところは多々あると思うのでご協力お願いします。

GitHub – WebStorageOnHTA

localStorageいいね!

Google Chromeはローカル環境でクッキーを作らないことに数時間気づけず打ちひしがれた心にオアシス。

localStorage。

個人的にはクッキーよりも簡潔に書けるので好きです。

LocalStorageがおもいのほか便利すぎたのでまとめ

ブラウザでストレージ? Web Storageを使いこなそう

が、現状では文字列しか保持できないらしいのでそこだけ注意ですね。

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

localStorage.value = true;
obj.checked = localStorage.value;
alert(obj.checked);

結果:なんの冗談かとおもいますよね。

Perfume Global Site Project #001

Perfume Global Site Project #001 でPerfumeのダンスモーションデータと曲データが公開されているので

一緒に公開されているサンプルコードを改造して動画を作ってみました。

Processingを使用してます。

気持ちいいディレイになると確信して作り始めたものの、まあやっぱ難しい。

こだわりだしたらきりがないので途中経過ということにしてアップ。

今後、曲の展開に合わせてパラメータを制御したりカメラをいじったり新しい処理を追加したり…

妄想はつきませんが、手の空いた時にゆっくりやろうかなといったところ。

BVHファイルのフレームレートを変更するperlスクリプト

どうやら巷ではここで配布されているBVHファイルを読み込むのが流行っているようです。

ただ、中には(ファイルに書いてあるはずの)フレームレートが無視されてしまうソフトに苦戦している方もいらっしゃるようですので

(把握してる限りだとCinema4Dがそうっぽい?)

BVHファイルのフレームレートを変更するコンバータを作成しました。

ご利用、再配布等々ご自由にどうぞ。

なお、何か悪いことが起きても責任は取りません。あしからず。

※要perl

conv_bvh_frame_rate.zip

フォルダ内にあるファイルのリストを作成するバッチ処理

ご無沙汰してます。

ちょろっと作ってみました。

make_file_list.bat

使い方:コマンドプロンプトで make_file_list.bat ルートフォルダ 出力ファイル名(フルパス) を実行してください。

フォルダ階層をカンマで区切ったファイル(csv形式)が生成されます。

※フルパスで指定しないと大変なことになります。

※ユーザビリティのことはあんまり考えてません…

※普通に dir /s /b すれば良いことには作ってから気付きました…