スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

BVHの仕様について

せっかくボーン姿勢をXYZ座標にできたところでほかのモーションソフトで弄れないと意味がない。
フォーマットを何にするか考えてみたがエルフレイナでモーション作成する予定だったので読み込めるBVHにすることにした。
BlenderはBVHの読み込みも書き込みもあるし、丁度いいかもしれない。

さっそくフォーマット仕様を調べることにした。


~BVHフォーマットの仕様のまとめ~

・テキスト形式である
・右手系座標で軸は任意
・関節ノードに関する情報を記述
・関節回転はオイラー角で記述
・角度の単位はDegree
・HIERARCHY部=キャラクタのスケルトン断層構造を記述
・MOTION部=動きのデータを記述
・#や//や/**/でのコメントの書き込みは不可能



HIERARCHYをちょっと掘り下げる


・JOINT(必ず子を持つ)要素はOFFSETとCHANNELS

・ROOT(始点となる特殊なJOINT)要素はOFFSETとCHANNELS

・END(終点になり子を持たない特殊なJOINT)要素はOFFSET

・OFFSET(親ノードからJOINTへの3次元オフセット成分)XYZの順で記述
ROOTノードの場合は初期位置を指す

・CHANNELS(関節の自由度、位置の自由度、回転の自由度の順で定義)


例) コメントは本来NG

HIERARCHY//今からスケルトン構造を書き出すよ~
ROOT root_name//ROOTノードの名前は「root_name」です
{
//このROOTノードの位置は(0,0,0)です
OFFSET 0 0 0
//XYZ軸に関する位置、X-Y-Z順で合成されるのオイラー角回転の計6つの自由度を持つ
CHANNELS 6 Xposition Yposition Zposition Xrotation Yrotation Zrotation

End Site//子のJOINTはEND1個だけ 名前は「Site」
{
OFFSET 0 10 0//Siteの位置
}
}


予想できると思うがJOINTの親と子の記述は以下
1-2-3
の場合は
ROOT 1
{
     JOINT 2
     {
          END 3
          {
          }
     }
}
となり

  2
1<
  3
の場合は
ROOT1
{
     END 2
     {
     }
     END 3
     {
     }
}
のように記述すればOK

続いてMOTION部分の記述について触れてみる
・Frames: N(記述する総フレーム数)
・Frame Time: SPF(フレームあたりの時間長 FPSの逆数)

例)
MOTION//ここから動作の記述がはじまりますよっと
Frames: 100//モーションは100フレームあります
Frame Time: 0.033//1フレーム0.033second/sec
0 0 0 0 0 0 0 0 0 // フレーム1のスケルトンの姿勢
0 0 0 0 0 0 0 0 0 // フレーム2のスケルトンの姿勢

0 0 0 0 0 0 0 0 0 // フレーム100のスケルトンの姿勢


姿勢情報の見方は次の通りになる
左から順にファイル冒頭からでてくるCHANNELSに割り当てられた要素とリンクする
ROOT root_name
 {
     OFFSET 0 0 0
     CHANNELS 3 ここA ここB ここC
     JOINT joint1
     {
          OFFSET 0 10 0
          CHANNELS 1 ここD
          End Site
          {
               OFFSET 0 10 0
          }
     }
}

だとすると姿勢情報は
A B C Dの順になる

(注意)この後日に書いた記事でこの順に関しての訂正があります
流用を考えている方は必ずその記事をチェックしてください


BVH自体はテキスト形式でOKらしいので仕様が理解できてしまえば扱うのは楽そうなイメージだ。
適当なBVHソースをコピーして自前でC#から作ったものをエルフレイナに読ませたらあっさり読み込めた。
いい感じだ。

角度がオイラー角というもので扱うらしいのだが何のことをいっているのかわからない。
また数学しなきゃいけないかもしれない・・・

ねよっと。
スポンサーサイト

今日は数学

昨日の続き。
とりあえず速度どうでもいいとして作ったので最適化必要な場所多数あるかもです。
例のごとくインデントはFC2に文句言ってください。

a1,a2を端点とする線分とb1,b2を端点とする線分の交差判定(2D)
bool IntersectionFlg(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2)
{
return (cross(a2 - a1, b1 - a1) * cross(a2 - a1, b2 - a1) < 0) && (cross(b2 - b1, a1 - b1) * cross(b2 - b1, a2 - b1) < 0);
}


a1,a2を端点とする線分とb1,b2を端点とする線分の交点計算(2D)
Vector2 Intersection(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2)
{
Vector2 b = b2 - b1;
float d1 = Math.Abs(cross(b, a1 - b1));
float d2 = Math.Abs(cross(b, a2 - b1));
float t = d1 / (d1 + d2);
return a1 + (a2 - a1) * t;
}


ベクトル a と b の内積(2D)
double dot(Vector2 a, Vector2 b)
{
return a.X * b.X + a.Y * b.Y;
}


ベクトル a と b の外積(2D)
double cross(Vector2 a, Vector2 b)
{
return a.X * b.Y - a.Y * b.X;
}


3次元で2つの線が一番近くなる時の距離
引数
ベクトル1上のどこかの1点
ベクトル1
ベクトル2上のどこかの一点
ベクトル2

戻り値
一番近い時の距離
float LineDistance(Vector3 a, Vector3 Va, Vector3 b, Vector3 Vb)
{
Vector3 N = Vector3.Cross(Va, Vb);
//比較した二つのベクトルが平行な場合
if (N==Vector3.Zero) { MessageBox.Show("カメラの視線が平行です 正しい結果が得られません"); }
//NをノーマライズしたときはNanが入るのでこっちで
//if(float.IsNaN(N.X)||float.IsNaN(N.Y)||float.IsNaN(N.Z)){ MessageBox.Show("カメラの視線が平行です 正しい結果が得られません"); }
float d = Math.Abs(Vector3.Dot(N,b - a))/N.Length();
return d;
}

math.jpg
ベクトル2の平面として捕らえ、外積から法線Nを求める。
coθ=d/|V3|になることから。(ってd書き込むの忘れてた。汗。求めたい赤い線の長さがdっす)
内積の公式を意識して展開
d = cosθ|V3| = cosθ|V3||N|/|N| = |V3・N|/|N|

となる。

っと、ここまで来て距離じゃなくて点が欲しいことに気づく。しまった!
疲れてきたので残りはネットで検索~と楽をしようとしてもなかなか例がない・・・

どこかの教授のどこかの説明書きみたいのから持ってきた。

V1上の最近点を「P1にパラメータs*V1を加えたもの」だと考えるとパラメータは次のように表せる。

float s = ((V2.Length() * V2Len.Length() * Vector3.Dot(P2 - P1, V1))- (Vector3.Dot(V1, V2) * Vector3.Dot(P2 - P1, V2)))/ ((V1.Length() * V1.Length() * V2.Length() * V2.Length()) - (Vector3.Dot(V1, V2) * Vector3.Dot(V1, V2)));

わかりやすく一個の式にしたはずがすごいことになっております。
書き直すのめんどいのでこのままで。

無事求まったかどうかデバッグ画面
makeview.jpg

グラフをぐりぐり動かしてどの形でもそれっぽい線を引いていたので数値的な検証が皆無だけどOKとしよう。。(いいのだろうか)

明日注文した安物WEBカメラが届く。昨日トイザラスでアクションフィギュアをまるでクリスマスプレゼントを買うような顔をして購入してきた。ナイスだ!時期!

ねよっと。



へぼソフト完成までの道のり

とりあえず前回の記事を達成させるためにいろいろ部品を作ることにした。
まず静止画を3D座標として受け取る部分の製作。

以前World,View,Projection,Viewportについての記事は散々書いたし、調べごと結構していたので楽そうだ。

まずシェーダを使わずピクチャボックスに3Dを作成してみる

逆関数を作る

2Dからworld座標を得る方法にたどり着く

という流れで進めてみた

何かあっという間に完成

ピクチャボックスは

//ピクチャボックス描写
private void PictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
Vector3 test1 = new Vector3(0,0,0);
Vector3 test2 = new Vector3(0,0,0);
//world
Matrix world1 = Matrix.CreateTranslation(30,0,0);
Matrix world2 = Matrix.CreateTranslation(20,0,10);
//view
Matrix View = Matrix.CreateLookAt(new Vector3(0, 20, 20), new Vector3(20, 0, 0), Vector3.Up);
Vector4 pos1 = Vector4.Transform(test1, world1 * View * Projection);
Vector4 pos2 = Vector4.Transform(test2, world2 * View * Projection);

int x1 = (int)(+(pos1.X / pos1.W * view_size.X / 2.0f) + view_size.X / 2.0f);
int y1 = (int)(-(pos1.Y / pos1.W * view_size.Y / 2.0f) + view_size.Y / 2.0f);
int x2 = (int)(+(pos2.X / pos2.W * view_size.X / 2.0f) + view_size.X / 2.0f);
int y2 = (int)(-(pos2.Y / pos2.W * view_size.Y / 2.0f) + view_size.Y / 2.0f);

pos1 = Vector4.Transform(test1, world1 * View * Projection);

e.Graphics.DrawLine(blackPen, x1, y1, x2, y2);
//モデル移動座標

//変数デバッグ用
e.Graphics.DrawString(i.ToString(),new Font("MS UI Gothic", 20),Brushes.Blue, 0, 0);
}


こんなかんじでDirectXを使わずに3D表現ができる。(といってもこれは一本の線だけども)
ここから逆関数を考えるつもりだったが

ViewportクラスにUnprojectというメソッドが用意されておりこれで楽に逆行列が求まってしまうことを知って拍子抜けである。


モーションキャプチャのほうは二個のカメラから関節に塗った色を判別させる予定だがカメラから得られるベクトル同士がきちんとぶつかるとは思えない。
二つの直線がねじれの位置にあるとして、一番近くなる2点の中間点を取るプログラムを考えなくてはならなくなった。

明日考えよう。

ねよっと

モーションの限界を考える

Blenderとの合わせ技も何とかまとまり、モデリングが楽になった。
順調に進めそうなので同時にモーションを進めることにした。

はい、いつもの問題発生!

BVHをもってこれるならもう安心などと高をくくっていたわけだが、事実そんなに甘くなさそうなのである。
2時間も必死にサイトを探せば明確でしょう。↓

どこいっても大体同じサイトに行かされる!(10箇所くらい)
しかも有料モーションサイトのサンプルみたいなのが多い。


うーん。困った。
以前BVHの記事を書いたことがあるけれどそれを使うにしてもやはり限度がありそう。

ゲーム関係なんてまったく触れた事もないわけでよいモーションの作成の方法もわからない。
実際手付けと言われる方法で数時間かけて作ったモーションも素人臭くて使い物にならない。
ニコニコ動画で関連の動画を見てみると「慣性」や「重心」を意識したモーション作りが明暗をわけそうだ。

理屈でわかっていてもこういうものは回数が勝負みたいところもあるでしょう。
しかーし、個人製作ってこともあり人生をモーションに捧げるわけにもいきません。


困った困った。
そんなときモーションキャプチャの存在を知る。
手とか足に機械をつけて動くとモーションを読み取ってくれるらしい。
しかし問題が二点。

めちゃ高い。
誰が動くの??


またまた困った困った。


っは!ピキーン(閃く音)
自作モーションキャプチャっぽいのを作っちまえばいいんでね?!!!!
いつにも増して無謀な挑戦っぽいけれど挑戦するだけしてみようと思う。
目指すのはこんな感じ。

・稼動が多い人形を用意してその人形のボーンの形をカメラから認識させる。
・動的生成機能はいらないと思うけど自分好みなので一応挑戦する。
・製作時間は1週間くらいで無理かどうかの見切りをつける。



・これなら自分が動く必要が全くない。
・リギング(間接に制限を加えてモーション作成を手助けする)の必要もないし、全体のバランスを取るのが比較的楽そう。素人の自分に優しい。
・安上がり。


早速インターネットでWEBカメラの注文でもしてくるかなぁ。
いつも思うけどゲーム製作から遠ざかってる・・・気がする・・・・


ねよっと。

メタセコプラグイン(一応公開)

昨日の記事の続きです。

えっと。Metaseqoia用Plugin完成です。
ぽちっとな

・UV点をすべて分離して、もとのUV位置から移動します。
・移動の際、UV座標の各々の面の中心に任意の距離だけ縮めます。
・NormalMap作成者にはありがたい(かなり疑問)「すべてのオブジェクトのスムージングを切る」という機能まで搭載しました。

機能的に使う人は限られるプラグインかも。
ちなみにプログラムを使用して生じたいかなる損害も作者は責任を負いません。(注)むしろ逆切れします。
付属txtにCopyright (C)-- 2008. All rights reserved.とか偉そうに書いてあるけど、書いてみたかっただけなので自分が作ったような顔してどこでも配布してもらって結構です。




さて奮闘記録です。

ちなみに、私は
C++初めて見る。学ぶ。触る。
DLL開発初めて。怖い。逃げろ。
です。


C++ダウンロード開始

->とか見たこと無い形で戸惑う

C++とC#、二文字違うだけじゃないか!と自分を励ます

ビルドが上手くいかない 環境変数とかリンカってなに?そもそもビルドとかコンパイルもデバッグもイメージでしか分かっていない

グーグル先生に頼りまくる←45分経過

そのままじゃDLL作成ができないって・・道理でビルドできないわけだ ←1時間半経過

ようやくビルド成功

Metasequoia作者のサンプル、コメント、プラグイン用のリファレンスどれもすばらしい~ 整頓の上手い人だね絶対! 本当にありがとうございます

DLL触りだしてものの30分でプラグインは完成 いぁ~これは便利 C++も味があっていいねコレ

公開したいといういらない欲がでてくる(これが無ければ・・)

インターフェイスが欲しくなる え?リソースって何(泣)

無料版じゃリソースエディタ使えないって・・C++2008とフリーソフトの例しか載ってない

2008C++をDL開始 ExpressEditionは永遠の親友になれそうです

リソースとはユーザーインターフェイスとプログラムを繋ぐものだろうと勝手にイメージ

イベントハンドラってなんじゃ~←この辺で5時間経過

どうせならスムージングを一気に切る機能もつけちまええええ

完成

【観想】
C++は巷で言われるほどとっつきにくくは無かった。いいやつだ。
スペルミスが人の30倍くらいある自分には文字を打ってる最中に何が無いとか使われて無いとかウダウダ言ってくれるC#がやっぱり好き。
そして正直、差を語れるほど触っていない


メタセコ作者の親切なリファレンスのおかげでC++も触れたし、モデル関係で究極に困ったときはプラグインで解決できそうで嬉しい。

ふぅ。ゲーム製作は奥が深い。


ねよっと。
プロフィール

あしゅ

Author:あしゅ
ぷぃぷぃ日常。
いつのまにか雑記ブログに。

カテゴリ
最新記事
検索フォーム
最新コメント
リンク
このブログをリンクに追加する
ブロとも申請フォーム

この人とブロともになる

カウンター
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。