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のタイムラインからトレンド抽出

2012年4月30日月曜日

以前の日記 2012年04月30日

SDEFの実装にえらい時間が掛かったので
参考にしたページのリンクを( ..)φメモメモ

Mikoto作者のゆーり氏
http://www.ipa.go.jp/SPC/report/02fy-pro/report/1220/paper.pdf

実験的観測
http://mattaku.sa-ra-sa.com/techbbs/su1_guestbook.cgi?action=showlast&cat=&txtnumber=log&next_page=30&t_type=

mqdlさんの概念解説
http://d.hatena.ne.jp/mqdl/20080525

dual quaternion skinning
http://isg.cs.tcd.ie/projects/DualQuaternions/

Spherical Blend Skinning
http://www.tmps.org/index.php?%A5%AF%A5%A9%A1%BC%A5%BF%A5%CB%A5%AA%A5%F3%A5%B9%A5%AD%A5%CB%A5%F3%A5%B0

以下、感想

最初に概念解説を見て
Spherical Blend Skinningの派生なのかなと思って
とりあえずSBSを実装してみようとしたのですが、

まったく理解できなかった上
そこに登場しなかったR0,R1を重要要素ではないと勘違いしてしまい
しばらくの間袋小路入り

実験的観測を見つけることができたのは幸いでした
図解のおかげでR0は0%ウェイト、R1は100%ウェイト座標と理解し、
計算式を模索

ここまででローカル変化量で綺麗に曲がるのを確認

さらにグローバル、物理演算の影響を考慮
この辺りよく理解していなかったのでよい機会でした

先人はこんなのよくホイホイ作れるなと感心しますね