2012年5月27日日曜日

BulletSharpの衝突設定3

引き続き物理演算周り

調査中に「物理+ボーン位置合わせ」の剛体が
機能していないことを発見したので修正に掛かる

「物理+ボーン位置合わせ」とは
物理演算による移動回転をボーン座標上に固定する。

普通に物理演算した状態をボーン座標に平行移動した状態です

グローバル変形を求める際に子ボーンに連鎖するので
親ボーンから順に計算する必要があります。

物理変形の計算はGPUでいいかなと思っていたのですが
CPUにごっそりお引越ししました。

スキニングテクスチャで渡している値も必要ないものは削除しないといけませんね

で、この修正を加えた結果
どこかに消えていたリボンとスカーフが戻ってきました。
まだ非数値なので固定状態のままですが。


それにしても
このモデルに限ってこんな状態になるので
正常動作するモデルと数値比較してみたほうがいいかもしれませんね


原因判明

508リンを上手く読み込めない原因
「150左エリ」の親の「149左エリ連D」の付与親の「188左エリ連」で
処理順が149→150→188だから188の値が149に付与されないせいで
150の初期姿勢が不正になって剛体初期値が不正になると

グローバル変形を2周すれば回避できるけど
ボーン処理順の正規化するロジックが欲しいですね

ともあれ、このおかげでいろいろ不備が見つかったのでよかったです



積んでるタスク

1.3Dプログラミング基礎
高速化
物理演算
MMDと比べて重力の影響が大きいのはバージョンの違いなのか実装不具合なのか
ver2.8を入れてみる
並列化の検討 もっといい方法はないか
MMDXのエッジを見る
ボーン処理順の正規化検討

2.ツイッターbot
MMDBotAgentのタイムラインからトレンド抽出
MMDBotSeigaの個人とお題を分けようかな
ごちゃごちゃして見難いし
俺得モデルフェス用のスタンドアロンクローラーマイリスとクリップ

3.3Dプログラミング応用
・ゲームっぽく移動できるもの
・表情をプリクラっぽく出力できるもの
・モデルの首挿げ替えするもの

2012年5月26日土曜日

BulletSharpの衝突設定2

前日書いた件で
Bullet,BulletSharpをリビルドして試してみたものの改善せず

MMMがBulletSharpを使っていたのに気が付き
バージョンを確認してみたところ、特に手を加えている様子はない
表示も正常に行われている

つまり、こちらの剛体設定に何かしらの漏れがあるために
物理演算結果に非数値が返ってくる と

現在設定している内容は

剛体のサイズ
剛体の形状
剛体の重さ
初期姿勢
慣性
移動回転減衰
摩擦力
反発力
非活性化不能設定 ボーン追従時
剛体の動的静的 ボーン追従時
移動回転休止閾値=0,0
衝突グループ番号
非衝突グループリスト
物理空間への剛体追加
剛体活性化(強制)
移動回転速力=0ベクトル

物理空間にジョイント追加


PMXファイルにある情報は設定できている
お約束として普通設定するものが抜けている?

サンプルソースを見て回って手掛かりを見つけよう
また長期化しそうな予感

物理・ボーン位置合わせの考え直し

2012年5月25日金曜日

BulletSharpの衝突設定1

以前、BulletSharpで物理演算を実装したときに、
衝突設定のやり方がわからずに放置していたのを忘れていた。

508リンちゃんのリボン飛びのおかげで思い出せた...

何でやり方がわからないかというと、

物理世界に剛体を追加するメソッドがありまして

public void AddRigidBody(RigidBody body, CollisionFilterGroups group, CollisionFilterGroups mask);

このメソッドの第2,3引数に剛体のグループと非衝突グループの設定を入れるわけですが、
この引数、列挙体なんですよ

[Flags]
public enum CollisionFilterGroups
{
AllFilter = -1,
None = 0,
DefaultFilter = 1,
StaticFilter = 2,
KinematicFilter = 4,
DebrisFilter = 8,
SensorTrigger = 16,
CharacterFilter = 32,
}

PMD,PMXファイルが持っている設定値は0~FFまでの値で
16個のグループに対応するように2進数16桁を10進数にして保持しています。

例えば、
グループ1、非衝突12345とすると

グループ=0000000000000001
非衝突 =1111111111100000

この上下が共に1の場合に衝突が発生する
※と認識しているのですが試せていないので断言できません。

メソッドに戻って、

このようにintを渡す必要があるのに列挙体で0に強制変換されてしまい
どうすればいいんだよって状況に陥ってしまったわけです。

ちなみに呼び出されたメソッド側では
列挙体を(short int)に戻していました。
いったいどういう使い方を想定しているのか...

というわけで今週末はBulletSharpを調べます。

2012年5月20日日曜日

物理演算を別スレッド化

OnRender内でnew Threadしてみたところ
new Thread自体に掛かる時間のため
かえって処理時間が掛かってしまいました。

load時にnew Threadしてwhileで回しておいて
フラグで処理を実行する
この場合はうまくいきましたが、空ループのCPUが無駄になります。

遅延なく呼び出せる方法があるといいのですが...

あと、508リンちゃんのリボンと後ろ髪がとこかに消える
CPUスキニングだとブラックアウトするし
いったい何が悪いのか


積んでるタスク

1.3Dプログラミング基礎
高速化
物理演算
MMDと比べて重力の影響が大きいのはバージョンの違いなのか実装不具合なのか
ver2.8を入れてみる
並列化の検討 もっといい方法はないか
MMDXのエッジを見る
508リンちゃんのリボンどこいったの スカーフの剛体、Jointを削除したら表示された 物理の影響か


2.ツイッターbot
MMDBotAgentのタイムラインからトレンド抽出
MMDBotSeigaの個人とお題を分けようかな
ごちゃごちゃして見難いし
俺得モデルフェス用のスタンドアロンクローラーマイリスとクリップ

3.3Dプログラミング応用
・ゲームっぽく移動できるもの
・表情をプリクラっぽく出力できるもの
・モデルの首挿げ替えするもの

2012年5月19日土曜日

SDEFをHLSLに移植

HLSLのデバッグ環境がないので
目を皿にしてバグ取りをしていました。
改善余地はあるもののとりあえず実装完了

物理後ボーンを考慮に入れていないのでどうしようかなと。

スキニング処理をGPUに移したのでCPU負荷はだいぶ改善されました。
GPU:CPU=4:5くらいです。
CPU側を整理して半々に持ち込めればいいかな。

PMXViewerでまったく手付かずなのがエッジ
エッジ表示が嫌いなのでやる気にならないんですよね
反転ポリだから重くなるし
MMDXでは反転ポリじゃない方法を使ってるそうだから
今度見てみようか

その辺りが終わったら基礎調査終了にして
・ゲームっぽく移動できるもの
・表情をプリクラっぽく出力できるもの
・モデルの首挿げ替えするもの
を作ってみたい

もっとも今のコードからSlimDXのサンプル部を排除する苦行が前提ですが...


積んでるタスク

1.3Dプログラミング基礎
高速化
物理演算
MMDと比べて重力の影響が大きいのはバージョンの違いなのか実装不具合なのか
ver2.8を入れてみる
並列化の検討 .net4が必要か 物理前後の処理があるのでタイミングをどうするか
MMDXのエッジを見る


2.ツイッターbot
MMDBotAgentのタイムラインからトレンド抽出
MMDBotSeigaの個人とお題を分けようかな
ごちゃごちゃして見難いし
俺得モデルフェス用のスタンドアロンクローラーマイリスとクリップ

3.3Dプログラミング応用
・ゲームっぽく移動できるもの
・表情をプリクラっぽく出力できるもの
・モデルの首挿げ替えするもの

2012年5月13日日曜日

SDEFをHLSLに持っていく

HLSLに渡すもののピックアップやコードの整理だけで終わってしまった。
BDEF4のことをすっかり忘れてたよ;
weightTypeの分岐までは書けたので続きは来週に持ち越し

積んでるタスク
1.3Dプログラミング
高速化
SDEFをHLSLに移植
物理演算
MMDと比べて重力の影響が大きいのはバージョンの違いなのか実装不具合なのか
2.ツイッターbot
MMDBotAgentのタイムラインからトレンド抽出
MMDBotSeigaの個人とお題を分けようかな
ごちゃごちゃして見難いし
俺得モデルフェス用のスタンドアロンクローラーマイリスとクリップ

2012年5月12日土曜日

SDEFをHLSLに持っていく準備

HLSLのデバッグ環境ってどうやって作ればいいのか
実行してトライアンドエラーはつらい

#region SDEF
//影響ボーン取得
b0 = this.transVertexList[i].BoneNum1;
b1 = this.transVertexList[i].BoneNum2;

//ボーンマトリックスをブレンド 0.0769%
w1 = this.transVertexList[i].BoneWeight1;
w2 = this.transVertexList[i].BoneWeight2;

if (this.transBoneList[b0].RigidBodyType == 1)
{
skinTransformsb0 = skinTransforms2[b0];
}
else if (this.transBoneList[b0].RigidBodyType == 2)
{
skinTransformsb0 = skinTransforms2[b0];
}
else
{
skinTransformsb0 = skinTransforms1[b0];
}

if (this.transBoneList[b1].RigidBodyType == 1)
{
skinTransformsb1 = skinTransforms2[b1];
}
else if (this.transBoneList[b1].RigidBodyType == 2)
{
skinTransformsb1 = skinTransforms2[b1];
}
else
{
skinTransformsb1 = skinTransforms1[b1];
}

{
//SDEF-C値(x,y,z)
SDEF_C = this.transVertexList[i].SDEF_C;
//SDEF-R0値(x,y,z)
SDEF_R0 = this.transVertexList[i].SDEF_R0;
//SDEF-R1値(x,y,z) ※修正値を要計算
SDEF_R1 = this.transVertexList[i].SDEF_R1;
//R1に対する回転中心の移動割合
SDEF_Weight = this.transVertexList[i].SDEF_Weight;

/*
* ローカル×親×逆BindPose=skinTransform
* skinTransform×BindPose×逆親=ローカル
*
* 1.「b1ボーンの初期Matrix[BindPose]」に「b1ボーンのグローバル変形Matrix[skinTransformsb1]」を掛けて、
*   「b1ボーンの変形後Matrix[globalTransform2]」を求める
* 2a.b1ボーンの親ボーンが物理ボーンの場合、
*   「b1ボーンの変形後Matrix[globalTransform2]」に「b1ボーンの親ボーンの物理変形後Matrixの逆行列」を掛けて、
*   「biボーンのローカル変形Matrix[localTransform2]」を求める
* 2b.b1ボーンの親ボーンが通常ボーンの場合、
*   「b1ボーンの変形後Matrix[globalTransform2]」に「b1ボーンの親ボーンの通常変形後Matrixの逆行列」を掛けて、
*   「b1ボーンのローカル変形Matrix[localTransform2]」を求める
*   localTransform2は初期姿勢を含めた0からの変形量
*   
* ここまでで必要なもの
*  1.this.transBoneList[b1].BindPose
*    InverseBindPoseをすでに渡しているのでどうしたものか
*  2.skinTransformsb1
*    HLSLで算出
*  3.ParentRigidBodyType,ParentRigidBodyIndex
*    親が物理か判定できればいい
*  4.Matrix.Invert(this.transRigidBodyList[this.transBoneList[b1].ParentRigidBodyIndex].RigidBodyTransform)
*  5.Matrix.Invert(this.transBoneList[this.transBoneList[b1].ParentBoneIndex].GlobalTransform)
*    逆行列計算をどちらでやるか matrix.cpp
*/

Matrix globalTransform2 = Matrix.Multiply(this.transBoneList[b1].BindPose, skinTransformsb1);
Matrix localTransform2;
if (this.transBoneList[b1].ParentRigidBodyType > 0 && this.transBoneList[b1].ParentRigidBodyIndex >= 0)
{
localTransform2 = Matrix.Multiply(globalTransform2, Matrix.Invert(this.transRigidBodyList[this.transBoneList[b1].ParentRigidBodyIndex].RigidBodyTransform));
}
else
{
localTransform2 = Matrix.Multiply(globalTransform2, Matrix.Invert(this.transBoneList[this.transBoneList[b1].ParentBoneIndex].GlobalTransform));
}

/*
* 3.「b1ボーンのローカル変形Matrix[localTransform2]」をDecomposeでscale,rotation,translationに分解し
*   「ローカル回転Quaternion[localRotation2]」「ローカル移動Vector3[localTranslation2]」を求める
* 4.「初期回転Quaternionの逆行列?[InverseBindRotation]」に「ローカル回転Quaternion[localRotation2]」を掛けて
*   「ローカル回転変形Quaternion[q2]」を求める
*   「ローカル移動変形Vector3[t2]」を求める
*   
* ここまでで必要なもの
*  6.this.transBoneList[b1].InverseBindTransform
*    Matrix.Decomposeの方法
*
* Decomposeを使用しない
*
* 3.「b1ボーンのローカル変形Matrix[localTransform2]」に「初期変形の逆行列[InverseBindTransform]」を掛けて
*   「ローカル変形Quaternion[m2]」を求める
* 4.「ローカル変形Quaternion[m2]」より「回転成分Vector4[qq]」を取得
* 5.「ローカル変形Quaternion[m2]」より「回転成分Vector4[t2]」を取得
*   
* ここまでで必要なもの
*  6.this.transBoneList[b1].InverseBindTransform
*/

Quaternion q2;
Vector3 t2;

//{
// Vector3 localScale2;
// Quaternion localRotation2;
// Vector3 localTranslation2;
// localTransform2.Decompose(out localScale2, out localRotation2, out localTranslation2);

// q2 = Quaternion.Multiply(this.transBoneList[b1].InverseBindRotation, localRotation2); //※ボーン2から1の回転要素をきれいに抜きたい
// t2 = localTranslation2 - this.transBoneList[b1].BindTranslation; //b2の平行移動
//}

Vector4 qq = Vector4.Zero;
{
Matrix m2 = Matrix.Multiply(localTransform2, this.transBoneList[b1].InverseBindTransform);
//{
// Vector3 localScale;
// Quaternion localRotation;
// Vector3 localTranslation;
// m2.Decompose(out localScale, out localRotation, out localTranslation);

// q2 = localRotation;
// t2 = localTranslation;
//}
{
t2.X = m2.M41;
t2.Y = m2.M42;
t2.Z = m2.M43;

Vector4 q = Vector4.Zero;
q[0] = m2.M11 - m2.M22 - m2.M33 + 1;
q[1] = -m2.M11 + m2.M22 - m2.M33 + 1;
q[2] = -m2.M11 - m2.M22 + m2.M33 + 1;
q[3] = m2.M11 + m2.M22 + m2.M33 + 1;
// 最大成分を検索
int maxIndex = 0;
for (int j = 1; j < 4; j++) { if (q[j] > q[maxIndex])
maxIndex = j;
}
if (q[maxIndex] < 0.0f)
{
// 引数の行列に間違いあり!
}
// 最大要素の値を算出
float v = (float)Math.Sqrt(q[maxIndex]) * 0.5f;

qq[maxIndex] = v;
float mult = 0.25f / v;

switch (maxIndex)
{
case 0: // x
qq[1] = (m2.M12 + m2.M21) * mult;
qq[2] = (m2.M31 + m2.M13) * mult;
qq[3] = (m2.M23 - m2.M32) * mult;
break;
case 1: // y
qq[0] = (m2.M12 + m2.M21) * mult;
qq[2] = (m2.M23 + m2.M32) * mult;
qq[3] = (m2.M31 - m2.M13) * mult;
break;
case 2: // z
qq[0] = (m2.M31 + m2.M13) * mult;
qq[1] = (m2.M23 + m2.M32) * mult;
qq[3] = (m2.M12 - m2.M21) * mult;
break;
case 3: // w
qq[0] = (m2.M23 - m2.M32) * mult;
qq[1] = (m2.M31 - m2.M13) * mult;
qq[2] = (m2.M12 - m2.M21) * mult;
break;
}

float sita = (float)Math.Acos(qq[3]) * 2;
Vector3 axis = new Vector3(qq[0], qq[1], qq[2]);
q2 = Quaternion.RotationAxis(axis, sita);

}
}


/*
* 6.t2にウェイトを掛けてt2wを取得
* 7.「回転成分Vector4[qq]」より回転角度を取得しウェイトを掛けて「回転角度float[sita]」を取得
* 8.「回転成分Vector4[qq]」と「回転角度float[sita]」より移動回転Matrixのベース[skinTransformsb1_2]を生成
*/

Vector3 t2w = t2 * w2;
Matrix skinTransformsb1_2 = Matrix.Identity;

//{
// Quaternion q2w = Quaternion.RotationAxis(q2.Axis, q2.Angle * w2);
// skinTransformsb1_2 = Matrix.RotationQuaternion(q2w);
//}
{
double sita = Math.Acos(qq[3]) * 2 * w2;
Vector3 axis = new Vector3(qq[0], qq[1], qq[2]);
//axis.Normalize();
//axis[0] = axis[0] * (float)Math.Sin(sita / 2);
//axis[1] = axis[1] * (float)Math.Sin(sita / 2);
//axis[2] = axis[2] * (float)Math.Sin(sita / 2);
//float w = (float)Math.Cos(sita / 2);
double d = axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2];

double[] st = new double[16];
st[0] = st[5] = st[10] = st[15] = 1.0;
if (d != 0.0)
{
double u = Math.Sqrt(d);
double l = axis[0] / u, m = axis[1] / u, n = axis[2] / u;
double l2 = l * l, m2 = m * m, n2 = n * n;
double lm = l * m, mn = m * n, nl = n * l;
double s = Math.Sin(sita);
double c = Math.Cos(sita);
double c1 = 1.0 - c;

st[0] = (1.0 - l2) * c + l2;
st[1] = lm * c1 + n * s;
st[2] = nl * c1 - m * s;
st[3] = 0.0;

st[4] = lm * c1 - n * s;
st[5] = (1.0 - m2) * c + m2;
st[6] = mn * c1 + l * s;
st[7] = 0.0;

st[8] = nl * c1 + m * s;
st[9] = mn * c1 - l * s;
st[10] = (1.0 - n2) * c + n2;
st[11] = 0.0;

st[12] = st[13] = st[14] = 0.0;
st[15] = 1.0;
}
skinTransformsb1_2[0, 0] = (float)st[0];
skinTransformsb1_2[0, 1] = (float)st[1];
skinTransformsb1_2[0, 2] = (float)st[2];
skinTransformsb1_2[0, 3] = (float)st[3];
skinTransformsb1_2[1, 0] = (float)st[4];
skinTransformsb1_2[1, 1] = (float)st[5];
skinTransformsb1_2[1, 2] = (float)st[6];
skinTransformsb1_2[1, 3] = (float)st[7];
skinTransformsb1_2[2, 0] = (float)st[8];
skinTransformsb1_2[2, 1] = (float)st[9];
skinTransformsb1_2[2, 2] = (float)st[10];
skinTransformsb1_2[2, 3] = (float)st[11];
skinTransformsb1_2[3, 0] = (float)st[12];
skinTransformsb1_2[3, 1] = (float)st[13];
skinTransformsb1_2[3, 2] = (float)st[14];
skinTransformsb1_2[3, 3] = (float)st[15];
}

/*
* 9.SDEF_R1をウェイト100%と想定
*   BoneHeadPosを中心としてSDEF_R1を100%回転位置に持っていくために中心座標pos2を求める
*   pos2 = SDEF_R1 - this.transBoneList[b1].BoneHeadPos;
* 10.pos2を「ローカル回転変形Quaternion[q2]」で回転し、座標posR1を求める
* 11.SDEF_R1の移動量を取得
*   diffR1 = posR1 - pos2
* 12.SDEFウェイトを掛けて基準回転中心SDEF_Cの移動量を求める
*   diffR1_w = diffR1 * SDEF_Weight
* 13.「移動回転Matrixのベース[skinTransformsb1_2]」にSDEF_C、diffR1_w、t2wを加算し回転中心を設定
* 14.頂点の回転用座標を求める
*   skinPos = this.transVertexList[i].SkinPosition - SDEF_C
* 15.skinPosを「移動回転Matrixの[skinTransformsb1_2]」で回転し、座標outPos、法線outNorを求める
* 16.親移動回転skinTransformsb0を掛けて完了
*/

//子ボーン
Vector4 outPos;
Vector3 outNor;
{
//(1)回転+元位置への戻し+移動+(0)回転+移動
{
//他ウェイト頂点の線形移動量
Vector3 diffR1_w = Vector3.Zero;
{
//R1'の移動量
Vector3 diffR1;
{
//R1移動後座標:R1'
//Vector4 posR1;
//{
// Vector3 pos2 = SDEF_R1 - this.transBoneList[b1].BoneHeadPos;
// Vector3.Transform(ref pos2, ref q2, out posR1);
// posR1.X = posR1.X + this.transBoneList[b1].BoneHeadPos.X;
// posR1.Y = posR1.Y + this.transBoneList[b1].BoneHeadPos.Y;
// posR1.Z = posR1.Z + this.transBoneList[b1].BoneHeadPos.Z;
//}
//diffR1.X = posR1.X - SDEF_R1.X;
//diffR1.Y = posR1.Y - SDEF_R1.Y;
//diffR1.Z = posR1.Z - SDEF_R1.Z;

Vector3 pos2 = SDEF_R1 - this.transBoneList[b1].BoneHeadPos;
Vector4 posR1;
Vector3.Transform(ref pos2, ref q2, out posR1);
diffR1.X = posR1.X - pos2.X;
diffR1.Y = posR1.Y - pos2.Y;
diffR1.Z = posR1.Z - pos2.Z;
}
//
diffR1_w.X = diffR1.X * SDEF_Weight;
diffR1_w.Y = diffR1.Y * SDEF_Weight;
diffR1_w.Z = diffR1.Z * SDEF_Weight;
}
skinTransformsb1_2.M41 = SDEF_C.X + diffR1_w.X + t2w.X;
skinTransformsb1_2.M42 = SDEF_C.Y + diffR1_w.Y + t2w.Y;
skinTransformsb1_2.M43 = SDEF_C.Z + diffR1_w.Z + t2w.Z;
}
//頂点を回転用座標へ移動
Vector3 skinPos = this.transVertexList[i].SkinPosition - SDEF_C;
Vector3.Transform(ref skinPos, ref skinTransformsb1_2, out outPos);
Vector3.TransformNormal(ref this.transVertexList[i].Normal, ref skinTransformsb1_2, out outNor);
}
//親ボーン
{
Vector3 inPosition;
inPosition.X = outPos.X;
inPosition.Y = outPos.Y;
inPosition.Z = outPos.Z;
Vector3 inNormal;
inNormal.X = outNor.X;
inNormal.Y = outNor.Y;
inNormal.Z = outNor.Z;
Vector3.Transform(ref inPosition, ref skinTransformsb0, out outPosition);
Vector3.TransformNormal(ref inNormal, ref skinTransformsb0, out outNormal);
}
}

#endregion

2012年5月9日水曜日

俺得モデルフェス2

MMDBotSeigaのDBから俺得モデルフェス2の情報を抽出

コメントのURLをばらしてみたけれど使い道があるだろうか
http://bowlroll.net/up/dl5059

2012年5月6日日曜日

徒然なるままに

徒然なるままに、blogなど始めてみる。

日曜プログラマーなので週1ペースで
備忘録代わりに進捗と予定など書いていこうかな

積んでるタスク
1.3Dプログラミング
高速化
SDEFをHLSLに移植
Matrix.Decompose、Quaternion.RotationAxisの数式が課題
物理演算
MMDと比べて重力の影響が大きいのはバージョンの違いなのか実装不具合なのか
2.ツイッターbot
MMDBotAgentのタイムラインからトレンド抽出