■PMX仕様

PMDエディタ0.1.0.1以降及び PMXエディタ にて対応されている PMX形式(2.0以降)のデータフォーマット及び動作仕様です。


■使用条件

規約に関しては PMXエディタ等と共通となります。

管理はこちらで一括して行います。勝手な改変についてはNG(こちらでは一切対応しません)
※フォーマット公開についてもこちらで管理します。

各アプリケーションなどでのフォーマットの利用については、非営利であれば自己責任において自由に行ってください。


■バージョン管理と互換性

PMXの互換性はverで厳密に管理します。
非対応verの場合はすみやかに処理を中断してください。

なお、PMX1.0は非公開となります(先頭キーやヘッダ構造も多少異なるので、間違って読み込まないように)

現在の最新verは 2.1 となります。


■データフォーマット

形式 : バイナリのみ
バイト順 : リトルエンディアン
テキストエンコード : ユニコード(UTF16LE) 及び UTF8 の選択方式

○基本データ型とバイトサイズ

[C#/HLSL方式+] : バイトサイズ  | [C方式]

byte	: 1  - 符号なし  | unsigned char
sbyte	: 1  - 符号あり  | char

ushort	: 2  - 符号なし  | unsigned short
short	: 2  - 符号あり  | short

uint	: 4  - 符号なし  | unsigned int
int	: 4  - 符号あり  | int (32bit固定)

float	: 4  - 単精度実数 | float

float2	: 8  (4 * 2)  | Vector2 - X,Y(or U,V) の順
float3	: 12 (4 * 3)  | Vector3 - X,Y,Z(or R,G,B) の順
float4	: 16 (4 * 4)  | Vector4 - X,Y,Z,W(or R,G,B,A) の順

TextBuf	: 可変 | 4 + バッファ長

bitFlag : 1 | 1byte につき 8フラグ bit-0:OFF 1:ON


○TextBuf (テキストバッファ)
int : バイト長
byte * バイト長 : byte列 エンコード形式はPMXヘッダに記載

※バッファサイズは 4 + n [byte]

※エディタ内のエンコード処理は、

→バイト列
byte[] buf = Encoding.Unicode.GetBytes(str);	// UTF16
byte[] buf = Encoding.UTF8.GetBytes(str);	// UTF8

→文字列
string str = Encoding.Unicode.GetString(buf, 0, buf.Length);	// UTF16
string str = Encoding.UTF8.GetString(buf, 0, buf.Length);	// UTF8

これだけです。
変換はすべてライブラリ(.NET Framework)にまかせているので、内部で発生する問題などには対応できないかと思われます。
※サロゲートペアの取り扱いについてなど詳細不明


○Index参照のバイトサイズ
各データのIndex参照値は データの総数に対して 1,2,4バイトで最適化。

対象は、

頂点
テクスチャ(内部テーブル管理)
材質
ボーン
モーフ
剛体

の各項目。参照している側のIndex値が可変サイズになります。

各データサイズについてはPMXヘッダに記載されます。

※データ数の範囲とバイトサイズの関係 - 頂点 8／16bitのみ符号なしとして扱います。

・頂点 - 符号なし
[バイトサイズ] : 頂点数範囲
1 : 0 〜 255
2 : 256 〜 65535
4 : 65536 〜 2147483647  ※符号ありになるので注意


・ボーン／テクスチャ／材質／モーフ／剛体 - 符号あり
[バイトサイズ] : データ数範囲
1 : 0 〜 127
2 : 128 〜 32767
4 : 32768 〜 2147483647

※ボーンや剛体などは -1を非参照値として扱います。材質は材質モーフにより-1:全材質とみなします。
※エディタ内ではIndex参照はすべて int(符号あり32bit) で管理しています。


●PMXのデータ構造概要 - ver2.0用(2.1以降は下記に追記されています)

-先頭-

PMXヘッダ
-
モデル情報
-
頂点数 [int]
頂点 * 頂点数
-
面数 [int]
参照頂点Index * 面数
-
テクスチャ数 [int]
テクスチャパス * テクスチャ数
-
材質数 [int]
材質 * 材質数
-
ボーン数 [int]
ボーン * ボーン数
-
モーフ数 [int]
モーフ * モーフ数
-
表示枠数 [int]
表示枠 * 表示枠数
-
剛体数 [int]
剛体 * 剛体数
-
Joint数 [int]
Joint * Joint数

-終了-


各要素数は int (4バイト) で固定。各データ内部は可変サイズで記録されるので注意。



●PMXヘッダ

4 : byte[4]	| "PMX " | ASCIIで 0x50,0x4d,0x58,0x20  ※末尾空白に注意 (PMX1.0は"Pmx "になっているので間違えないように)
4 : float	| ver (2.0/2.1)

↑ここまでマジックナンバー

1 : byte	| 後続するデータ列のバイトサイズ  PMX2.0は 8 で固定
n : byte[8]	| byte * バイトサイズ

バイト列 - byte
  [0] - エンコード方式  | 0:UTF16 1:UTF8
  [1] - 追加UV数 	| 0〜4 詳細は頂点参照

  [2] - 頂点Indexサイズ | 1,2,4 のいずれか
  [3] - テクスチャIndexサイズ | 1,2,4 のいずれか
  [4] - 材質Indexサイズ | 1,2,4 のいずれか
  [5] - ボーンIndexサイズ | 1,2,4 のいずれか
  [6] - モーフIndexサイズ | 1,2,4 のいずれか
  [7] - 剛体Indexサイズ | 1,2,4 のいずれか


●モデル情報

4 + n : TextBuf	| モデル名
4 + n : TextBuf	| モデル名英
4 + n : TextBuf	| コメント
4 + n : TextBuf	| コメント英


●頂点

○追加UVについて
PMXの頂点には追加UV(中身は4Dベクトル)を最大4つまで格納することが可能。追加数はヘッダで指定される。
尚、追加UV数はファイルサイズに大きく影響するので、不要なら入れない状態が望ましい。

○ウェイトについて
1頂点につき最大4ボーンまでのウェイト情報を格納可能。
格納方法は対応ボーン数及びSDEFに関連し、

BDEF1
BDEF2
BDEF4
SDEF

の 4パターンに分類される(1byteで形式記録)
記録されるデータは、(ボーンIndex参照をintとして仮定)

BDEF1 : int 		| 4   | ボーンのみ
BDEF2 : int,int,float 	| 4*3 | ボーン2つと、ボーン1のウェイト値(PMD方式)
BDEF4 : int*4, float*4	| 4*8 | ボーン4つと、それぞれのウェイト値。ウェイト合計が1.0である保障はしない
SDEF  : int,int,float, float3*3 
			| 4*12 | BDEF2に加え、SDEF用のfloat3(Vector3)が3つ。実際の計算ではさらに補正値の算出が必要(一応そのままBDEF2としても使用可能)

と可変サイズになるので注意。


[頂点データ]

12 : float3  | 位置(x,y,z)
12 : float3  | 法線(x,y,z)
8  : float2  | UV(u,v)

16 * n : float4[n] | 追加UV(x,y,z,w)  PMXヘッダの追加UV数による
  n:追加UV数 0〜4

1 : byte    | ウェイト変形方式 0:BDEF1 1:BDEF2 2:BDEF4 3:SDEF

※変形方式により継続データが異なる／参照Indexは-1:非参照の場合があるので注意

BDEF1 ->
  n : ボーンIndexサイズ  | ウェイト1.0の単一ボーン(参照Index)

BDEF2 ->
  n : ボーンIndexサイズ  | ボーン1の参照Index
  n : ボーンIndexサイズ  | ボーン2の参照Index
  4 : float              | ボーン1のウェイト値(0〜1.0), ボーン2のウェイト値は 1.0-ボーン1ウェイト

BDEF4 ->
  n : ボーンIndexサイズ  | ボーン1の参照Index
  n : ボーンIndexサイズ  | ボーン2の参照Index
  n : ボーンIndexサイズ  | ボーン3の参照Index
  n : ボーンIndexサイズ  | ボーン4の参照Index
  4 : float              | ボーン1のウェイト値
  4 : float              | ボーン2のウェイト値
  4 : float              | ボーン3のウェイト値
  4 : float              | ボーン4のウェイト値 (ウェイト計1.0の保障はない)

SDEF ->
  n : ボーンIndexサイズ  | ボーン1の参照Index
  n : ボーンIndexサイズ  | ボーン2の参照Index
  4 : float              | ボーン1のウェイト値(0〜1.0), ボーン2のウェイト値は 1.0-ボーン1ウェイト
 12 : float3             | SDEF-C値(x,y,z)
 12 : float3             | SDEF-R0値(x,y,z)
 12 : float3             | SDEF-R1値(x,y,z) ※修正値を要計算

↑ウェイトここまで

4 : float    | エッジ倍率  材質のエッジサイズに対しての倍率値


●面

n : 頂点Indexサイズ     | 頂点の参照Index

※3点(3頂点Index)で1面
材質毎の面数は材質内の面(頂点)数で管理 (同PMD方式)


●テクスチャ

材質内で参照されるテクスチャパスのテーブル

4 + n : TextBuf	| テクスチャパス

※材質からはこちらのIndexを参照。テクスチャ／スフィア／個別Toonで一括して利用
※共有Toon -> toon01.bmp〜toon10.bmp はテクスチャテーブルには入れないので注意

※PMDと同様にモデル位置を基準としてサブフォルダ指定が可能
パス区切りについてはシステム側で認識可能な文字('\'or'/'など)とし、PMXとして固定はしない。


●材質

4 + n : TextBuf	| 材質名
4 + n : TextBuf	| 材質名英

16 : float4	| Diffuse (R,G,B,A)
12 : float3	| Specular (R,G,B)
4  : float	| Specular係数
12 : float3	| Ambient (R,G,B)

1  : bitFlag  	| 描画フラグ(8bit) - 各bit 0:OFF 1:ON
                   0x01:両面描画, 0x02:地面影, 0x04:セルフシャドウマップへの描画, 0x08:セルフシャドウの描画, 
                   0x10:エッジ描画

16 : float4	| エッジ色 (R,G,B,A)
4  : float	| エッジサイズ

n  : テクスチャIndexサイズ     | 通常テクスチャ, テクスチャテーブルの参照Index
n  : テクスチャIndexサイズ     | スフィアテクスチャ, テクスチャテーブルの参照Index  ※テクスチャ拡張子の制限なし
1  : byte	| スフィアモード 0:無効 1:乗算(sph) 2:加算(spa) 3:サブテクスチャ(追加UV1のx,yをUV参照して通常テクスチャ描画を行う)

1  : byte	| 共有Toonフラグ 0:継続値は個別Toon 1:継続値は共有Toon
--
共有Toonフラグ:0 の場合
 n : テクスチャIndexサイズ     | Toonテクスチャ, テクスチャテーブルの参照Index

共有Toonフラグ:1 の場合
 1 : byte	| 共有Toonテクスチャ[0〜9] -> それぞれ toon01.bmp〜toon10.bmp に対応
--
↑どちらか一方なので注意


4 + n : TextBuf	| メモ : 自由欄／スクリプト記述／エフェクトへのパラメータ配置など

4  : int	| 材質に対応する面(頂点)数 (必ず3の倍数になる)


●ボーン

4 + n : TextBuf	| ボーン名
4 + n : TextBuf	| ボーン名英

12 : float3	| 位置
n  : ボーンIndexサイズ  | 親ボーンのボーンIndex
4  : int		| 変形階層

2  : bitFlag*2	| ボーンフラグ(16bit) 各bit 0:OFF 1:ON

○ボーンフラグ
 0x0001  : 接続先(PMD子ボーン指定)表示方法 -> 0:座標オフセットで指定 1:ボーンで指定

 0x0002  : 回転可能
 0x0004  : 移動可能
 0x0008  : 表示
 0x0010  : 操作可

 0x0020  : IK

 0x0080  : ローカル付与 | 付与対象 0:ユーザー変形値／IKリンク／多重付与 1:親のローカル変形量
 0x0100  : 回転付与
 0x0200  : 移動付与

 0x0400  : 軸固定
 0x0800  : ローカル軸

 0x1000  : 物理後変形
 0x2000  : 外部親変形

※それぞれの機能詳細は後述の機能概要で行います。

↓フラグによって継続する格納データが変化するので注意

--
接続先:0 の場合
 12 : float3	| 座標オフセット, ボーン位置からの相対分

接続先:1 の場合
 n  : ボーンIndexサイズ  | 接続先ボーンのボーンIndex
--

---
回転付与:1 または 移動付与:1 の場合
 n  : ボーンIndexサイズ  | 付与親ボーンのボーンIndex
 4  : float	| 付与率
---

--
軸固定:1 の場合
 12 : float3	| 軸の方向ベクトル
--

---
ローカル軸:1 の場合
 12 : float3	| X軸の方向ベクトル
 12 : float3	| Z軸の方向ベクトル ※フレーム軸算出方法は後述
---

--
外部親変形:1 の場合
 4  : int  	| Key値
--

---
IK:1 の場合 IKデータを格納

 n  : ボーンIndexサイズ  | IKターゲットボーンのボーンIndex
 4  : int  	| IKループ回数 (PMD及びMMD環境では255回が最大になるようです)
 4  : float	| IKループ計算時の1回あたりの制限角度 -> ラジアン角 | PMDのIK値とは4倍異なるので注意

 4  : int  	| IKリンク数 : 後続の要素数
 <IKリンク>
   n  : ボーンIndexサイズ  | リンクボーンのボーンIndex
   1  : byte	| 角度制限 0:OFF 1:ON
   ----
   角度制限:1の場合
     12 : float3	| 下限 (x,y,z) -> ラジアン角
     12 : float3	| 上限 (x,y,z) -> ラジアン角
   ----
 </IKリンク>
 * IKリンク数
---


●モーフ

○モーフ種類
格納可能なモーフは大別して、

頂点モーフ
UVモーフ
ボーンモーフ
材質モーフ
グループモーフ

の5種類。さらにUVモーフは、UV／追加UV1〜4の計5種類に分類される。
※追加UV数によっては不要なUVモーフが格納されることがあるが、モーフ側は特に削除などは行わないので注意。


それぞれ、

○頂点モーフ
n  : 頂点Indexサイズ  | 頂点Index
12 : float3	| 座標オフセット量(x,y,z)

○UVモーフ
n  : 頂点Indexサイズ  | 頂点Index
16 : float4	| UVオフセット量(x,y,z,w) ※通常UVはz,wが不要項目になるがモーフとしてのデータ値は記録しておく

○ボーンモーフ
n  : ボーンIndexサイズ  | ボーンIndex
12 : float3	| 移動量(x,y,z)
16 : float4	| 回転量-クォータニオン(x,y,z,w)

○材質モーフ
n  : 材質Indexサイズ  | 材質Index -> -1:全材質対象
1  : オフセット演算形式 | 0:乗算, 1:加算 - 詳細は後述
16 : float4	| Diffuse (R,G,B,A) - 乗算:1.0／加算:0.0 が初期値となる(同以下)
12 : float3	| Specular (R,G,B)
4  : float	| Specular係数
12 : float3	| Ambient (R,G,B)
16 : float4	| エッジ色 (R,G,B,A)
4  : float	| エッジサイズ
16 : float4	| テクスチャ係数 (R,G,B,A)
16 : float4	| スフィアテクスチャ係数 (R,G,B,A)
16 : float4	| Toonテクスチャ係数 (R,G,B,A)

○グループモーフ
n  : モーフIndexサイズ  | モーフIndex  ※仕様上グループモーフのグループ化は非対応とする
4  : float	| モーフ率 : グループモーフのモーフ値 * モーフ率 = 対象モーフのモーフ値

を個々のモーフオフセットとする。


[モーフデータ]

4 + n : TextBuf	| モーフ名
4 + n : TextBuf	| モーフ名英

1  : byte	| 操作パネル (PMD:カテゴリ) 1:眉(左下) 2:目(左上) 3:口(右上) 4:その他(右下)  | 0:システム予約

1  : byte	| モーフ種類 - 0:グループ, 1:頂点, 2:ボーン, 3:UV, 4:追加UV1, 5:追加UV2, 6:追加UV3, 7:追加UV4, 8:材質

4  : int  	| モーフのオフセット数 : 後続の要素数
オフセットデータ * n  | モーフ種類に従ってオフセットデータを格納 ※異なる種類の混合は不可


※材質モーフの演算形式について
複数のモーフからの呼び出しを考慮して、乗算用の材質モーフ値と加算用の材質モーフ値は別管理が望ましい。
想定している動作は、モーフ設定の分だけ乗算分を乗算／加算分を加算して保持、描画時に、

材質値 x 乗算値 + 加算値 

でモーフ適用を行う。
乗算／加算仕様があるのは、初期状態で完全透過(A:0)→非透過(A:1) といったモーフ構造を乗算のみでは作成できないため。
また乗算0+加算により、(元の材質値に関わらず)任意の指定値への変換も簡易になる。

テクスチャ(テクスチャ／スフィア／Toon)のモーフA値(非透過度)はテクスチャのRGB透過合成(乗算:白(1,1,1)との比率混合／加算:黒(0,0,0)との比率混合)に使用。
描画に使用するテクスチャA値はモーフ適用後も元のテクスチャの値を使うこと。


●表示枠

ボーン／モーフを共通化して格納可能
PMD/PMXエディタでは Root用とPMD互換の表情枠を特殊枠として初期配置される。

4 + n : TextBuf	| 枠名
4 + n : TextBuf	| 枠名英

1  : byte	| 特殊枠フラグ - 0:通常枠 1:特殊枠

4  : int  	| 枠内要素数 : 後続の要素数
<枠内要素>
  1 : byte	| 要素対象 0:ボーン 1:モーフ
  ----
  要素対象:0の場合
    n  : ボーンIndexサイズ  | ボーンIndex

  要素対象:1の場合
    n  : モーフIndexサイズ  | モーフIndex
  ----
</枠内要素>
* 枠内要素数


※PMXの初期状態では、

表示枠:0(先頭) -> "Root"(特殊枠指定) | 枠内に ボーン:0(先頭ボーン)を追加。対応されれば枠のルート位置への設定用
表示枠:1       -> "表情"(特殊枠指定) | PMD変換時は枠内に 表情枠 と同様の配置 (一部複製処理などで自動的に追加される場合あり)

という特殊枠が配置されます。特殊枠判定は、特殊枠フラグ1及び枠名で判断(編集時に誤って削除しないように注意)


●剛体

※パラメータはPMDの剛体と同様

4 + n : TextBuf	| 剛体名
4 + n : TextBuf	| 剛体名英

n  : ボーンIndexサイズ  | 関連ボーンIndex - 関連なしの場合は-1

1  : byte	| グループ
2  : ushort	| 非衝突グループフラグ

1  : byte	| 形状 - 0:球 1:箱 2:カプセル
12 : float3	| サイズ(x,y,z)

12 : float3	| 位置(x,y,z)
12 : float3	| 回転(x,y,z) -> ラジアン角

4  : float	| 質量
4  : float	| 移動減衰
4  : float	| 回転減衰
4  : float	| 反発力
4  : float	| 摩擦力

1  : byte	| 剛体の物理演算 - 0:ボーン追従(static) 1:物理演算(dynamic) 2:物理演算 + Bone位置合わせ


●Joint

※パラメータはPMDのJointと同様

4 + n : TextBuf	| Joint名
4 + n : TextBuf	| Joint名英

1  : byte	| Joint種類 - 0:スプリング6DOF   | PMX2.0では 0 のみ(拡張用)
--
Joint種類:0 の場合

n  : 剛体Indexサイズ  | 関連剛体AのIndex - 関連なしの場合は-1
n  : 剛体Indexサイズ  | 関連剛体BのIndex - 関連なしの場合は-1

12 : float3	| 位置(x,y,z)
12 : float3	| 回転(x,y,z) -> ラジアン角

12 : float3	| 移動制限-下限(x,y,z)
12 : float3	| 移動制限-上限(x,y,z)
12 : float3	| 回転制限-下限(x,y,z) -> ラジアン角
12 : float3	| 回転制限-上限(x,y,z) -> ラジアン角

12 : float3	| バネ定数-移動(x,y,z)
12 : float3	| バネ定数-回転(x,y,z)
--





■機能概要

●追加UV

PMXの各頂点には4つまで4Dベクトルを追加配置可能。
内部データ的にはPMXヘッダの指定に係わらず常に 4つの4Dベクトルを配置しておくことが望ましい。

・エフェクトから見た頂点バッファ例(セマンティックとの関係)

struct PmxVertex{

float3 Position : POSITION;
float3 Normal : NORMAL;

float2 UV    : TEXCOORD0;

float4 UVA1  : TEXCOORD1;
float4 UVA2  : TEXCOORD2;
float4 UVA3  : TEXCOORD3;
float4 UVA4  : TEXCOORD4;

...
};

※UVモーフの対象になっている追加UVがPMXファイルの頂点に存在しない場合でも、
(0,0,0,0)がデフォルト値として配置されていれば、UVモーフ→エフェクトから任意の処理が可能になります。



●ボーン変形

□変形順序
ボーンの変形順序は

1. 物理前／後
2. 階層順
3. Index順

にて調整(正規化)後、順に変形を行う。1つのボーンにおけるローカル変形処理はIKからのリンク参照を除いて1回のみ。

例：
A, 前,階層2,Index0
B, 後,階層1,Index1
C, 前,階層0,Index2
D, 後,階層0,Index3
E, 前,階層0,Index4
F, 前,階層1,Index5

↓

C, 前,階層0,Index2
E, 前,階層0,Index4
F, 前,階層1,Index5
A, 前,階層2,Index0

<物理演算>

D, 後,階層0,Index3
B, 後,階層1,Index1

という順序で変形処理を行う。


□変形パラメータ
1つのボーンが所持する変形パラメータは以下の通り

・ユーザー操作による 回転／移動量  	| PMD/PMXエディタ内ではスケール値も所持
・ボーンモーフによる 回転／移動量
・付与ありの場合     付与回転／付与移動量  | 保存しておくことで多重付与が可能になる
・IKリンクの場合     IK回転量

・ボーン変形処理によるローカル変形状態
・頂点など形状変形用のグローバル変形状態

※回転はクォータニオン、移動は3Dベクトル、変形状態は同次変換行列を想定


□付与について
(ローカル付与ではない場合)
付与は付与親ボーンの

・ユーザー操作による 回転／移動量
・ボーンモーフによる 回転／移動量
・付与ありの場合     付与回転／付与移動量
・IKリンクの場合     IK回転量

上記変形量を自分自身の変形量にさらに加える変形を行う。
回転／移動は別項目としてそれぞれ追加される(片方だけでもOK)

付与親の親子変形によるボーン変形状態は付与対象ではないので注意。
※ローカル付与の場合はボーン変形状態を特別に付与することが可能(ただし多重付与の場合は無視)

付与変形を行った後、付与した変形量をボーン内に保存し、
別の付与ボーンから付与親参照された場合にその変形量を渡す→多重付与構造

当然ながら付与ボーンでも親子関係による通常のボーン変形は可能となる。


□変形パラメータの適用順序

0. すべてのボーンのローカル／グローバル変形状態を初期化
1. ユーザー操作の回転／移動量をすべてのボーンに設定
2. ボーンモーフによる回転／移動量を対応するボーンに設定

3. 変形順序の正規化
4. 正規化後の順にボーン変形を行う

4.1. ボーンのローカル変形(詳細は後述)
4.2. IKの場合IK変形


以上の手順ですべてのボーンを変形。

物理変形後の適用は、物理変形によるグローバル変形量をローカル変形量に一旦戻し、
それを親参照する変形を継続することで行われる。



□ローカル変形順序

・回転量(クォータニオン)の計算
■ローカル付与ではない場合:
[親付与回転量(or 親回転 * 親回転モーフ) * 付与親のIKリンク]:付与率 * 回転 * 回転モーフ * IKリンク

■ローカル付与の場合:
[付与親のローカル変形量(行列)の回転成分]:付与率 * 回転 * 回転モーフ * IKリンク

--
計算例:
0. 回転量を単位回転量として開始

1. 当該ボーンが付与の場合 : 
 1.1 ローカル付与の場合 : * 付与親のローカル変形量(行列)の回転成分 ※ローカル付与優先
  <> 付与親が付与ボーンの場合 : * 付与親の付与回転量(※後述) 
  <>         付与ボーンではない場合 : * 付与親の回転 * 付与親の回転モーフ

 1.2 付与親がIKリンクの場合(且つローカル付与ではない場合) : * 付与親のIKリンク回転量

 1.3 付与率が1以外の場合 : 回転量を付与率で補正(Quaternion.Slerp()想定)

 1.4 付与親のIKリンク〜回転モーフ(付与率で補正済み)〜回転モーフ を当該ボーンの付与回転量として保存(別の付与ボーンの付与親になった場合の多重付与変形用)
    ※付与回転量 → { [親付与回転量(or 親回転 * 親回転モーフ) * 付与親のIKリンク]:付与率 * 回転 * 回転モーフ } 
             または { [付与親のローカル変形量(行列)の回転成分]:付与率 * 回転 * 回転モーフ }

2. 当該ボーンの回転量追加 : * 回転 * 回転モーフ

3. 当該ボーンがIKリンク回転量を持つ場合 : * IKリンク回転量

※IKリンク回転量は当該ボーンが付与参照される間に別のIKボーンによって変形／更新される可能性があるので、
それを考慮して付与回転量から一旦外す形(付与参照時に再計算)になっています。
付与親のIKリンクは参照時に確定されてしまうなどの問題がありますが、暫定的にこのような計算順序としておきます。


・移動量(3Dベクトル)の計算
■ローカル付与ではない場合:
[親付与移動量(or 親移動 + 親移動モーフ)]*付与率 + 移動 + 移動モーフ

■ローカル付与の場合:
[付与親のローカル移動量]*付与率 + 移動 + 移動モーフ

付与親のローカル移動量:ボーン移動量として計算 ※暫定対応
 = ボーン位置(=ローカル行列の4行1/2/3列要素) - 初期ボーン位置

--
計算例:(基本的に回転と同じ)

0. 移動量を0移動量として開始

1. 当該ボーンが付与の場合 : 
 1.1 ローカル付与の場合 : * 付与親のローカル移動量 ※ローカル付与優先
  <> 付与親が付与ボーンの場合 : + 付与親の付与移動量(※後述)
  <>         付与ボーンではない場合  : + 付与親の移動 + 付与親の移動モーフ

 1.2 付与率が1以外の場合 : 移動量を付与率で補正(付与率乗算でOK)

 1.3 親付与移動量(付与率で補正済み)〜移動モーフ を当該ボーンの付与移動量として保存(別の付与ボーンの付与親になった場合の多重付与変形用)
    ※付与移動量 → { [親付与移動量(or 親移動 + 親移動モーフ)(or 親ローカル移動量)]:付与率 + 移動 + 移動モーフ }

2. 当該ボーンの移動量追加 : + 移動 + 移動モーフ


→
算出された回転／移動の両値から、

ローカル行列 = (スケール行列) * 回転行列 * 移動行列

を計算、親ボーンからのオフセット及び親のローカル行列に合成する。

当該ボーンがIKボーンの場合、(IKボーン／IKターゲットの位置関係より)IKリンクのIK回転量を再計算 → ボーンのIKリンク回転量を更新。
PMXのIK変形はIKボーンの変形順序時にそのまま変形を行う(PMDのように全ボーン変形後などの順序固定ではないので注意)


以上の手順ですべてのボーンのローカル変形を更新。

物理変形後の適用は、物理変形によるグローバル変形量をローカル変形量に戻し、
それを親参照する変形を継続することで行われる。



□変形順序による変形量の参照について

親子変形による伝達が必要な変形は、親→子順にボーン変形を呼び出す必要がある。
子→親の順序では正しく変形しない。

ユーザー操作量を参照する付与伝達の場合は、付与親の変形前にボーン変形が呼び出されても正常に変形する
(ただし1段階のみ／多重付与を行う場合は付与親が先に変形されている必要がある)

ボーンモーフを参照する付与の場合も同様である。


□制限軸

PMDの捩りボーンと同系の仕組み。捩りボーン同様ボーンの内部変形量には関与しない。
操作時の移動及び回転軸を指定した軸方向で固定化する機能を有する。


□ローカル軸

操作上のローカルフレームを任意に定義するための軸方向パラメータ。
X／Zで指定するが、それらが直交関係ではない場合もあるので以下の計算式で補正する。

Y = Vector3.Cross(Z, X);   // Vector3.Cross():ベクトル積
Z' = Vector3.Cross(X, Y);

※PMDでは腕関連のみ子ボーンの方向をX、手前を-Zとする軸でローカルフレームが自動作成される模様。


□外部親変形

指定されたボーンはモデル外部のボーンを親ボーンとして変形することが可能。
その場合の識別用IDとしてKey値(int)が用意されている。

※このフラグ指定に関わらず接続機構を利用可能にしてもよいと思われる。

この構成を利用することで、例えばモデルをアクセサリのように特定のモデルの特定ボーンに関係付ける構造や、
腕IKを使った手同士の接続及び操作モデルによる一括操作を実現することが可能となる。

応用として自分のボーンの親接続の付け替えなども考えられる。


□ボーンの属性(フラグ値)について

 0x0001  : 接続先
 0x0002  : 回転可能
 0x0004  : 移動可能
 0x0008  : 表示
 0x0010  : 操作可
 0x0020  : IK
 0x0080  : ローカル付与
 0x0100  : 回転付与
 0x0200  : 移動付与
 0x0400  : 軸固定
 0x0800  : ローカル軸
 0x1000  : 物理後変形
 0x2000  : 外部親変形

とあるが、この中でボーンの変形特性に係わる属性は

 0x0020  : IK
 0x0080  : ローカル付与
 0x0100  : 回転付与
 0x0200  : 移動付与
 0x1000  : 物理後変形
 0x2000  : 外部親変形

のみで、残りの

 0x0001  : 接続先
 0x0002  : 回転可能
 0x0004  : 移動可能
 0x0008  : 表示
 0x0010  : 操作可
 0x0400  : 軸固定
 0x0800  : ローカル軸

は、表示及び操作時の制限項目になる。
ボーンの変形特性や内部値には関与しないので注意。


□PMDとの互換性

IK／回転影響下 以外のボーン構造は問題なく変換可能。
上記2種類は、親子系列での変形後、特定タイミングでさらに特定の変形を行うので、
基本的に1ボーン1度のみの変形が基準であるPMXのボーン構造ではうまく変換できない場合がある。

PMD→PMX 変換では、

IKボーン及びそのIKを親としている系列の変形階層を 0→1
回転影響下以下の変形階層を 0→2

にすべて変換して対応しているが(系列状態からさらの階層を調整)、
ボーン構造によってはこの変換では異なる変形様式になる可能性があるので注意。

対応方法としては、PMDの複数回変形の構造に対して、PMX側も複数のボーン構造(分割したボーンは親子結合or付与結合)を
用いることが考えられる。









======================================================================================================================

■PMX2.1拡張／変更項目

●データ構造

-先頭-

(省略)
-
Joint数 [int]
Joint * Joint数
-
SoftBodyt数 [int]
SoftBody * SoftBody数		| 2.0の後方へ後付けで配置

-終了-


●PMXヘッダ
ver 2.1

他は2.0と同一です。


●頂点

○ウェイトについて
QDEF : int*4, float*4	| 4*8 | ボーン4つと、それぞれのウェイト値。ウェイト合計が1.0である保障はしない

を追加。

QDEF は DualQuaternion(デュアルクォータニオン) 方式のウェイト変形です。
変形方法については多くの公開情報があるので省略します。


[頂点データ]

(省略)
1 : byte    | ウェイト変形方式 0:BDEF1 1:BDEF2 2:BDEF4 3:SDEF 4:QDEF(※2.1拡張)

QDEF ->
  n : ボーンIndexサイズ  | ボーン1の参照Index
  n : ボーンIndexサイズ  | ボーン2の参照Index
  n : ボーンIndexサイズ  | ボーン3の参照Index
  n : ボーンIndexサイズ  | ボーン4の参照Index
  4 : float              | ボーン1のウェイト値
  4 : float              | ボーン2のウェイト値
  4 : float              | ボーン3のウェイト値
  4 : float              | ボーン4のウェイト値 (ウェイト計1.0の保障はない)

※データ形式は BDEF4 と共通



●面

n : 頂点Indexサイズ     | 頂点の参照Index

----

形式は PMX2.0 と同様ですが、材質のPoint／Line描画への対応のため、

A-B-C という△面パターン以外にも、A-A-A(1-Point) や A-B-A(1-Line) などの頂点参照パターンに対応する必要があります。

重複状態での不要項目の描画については特に指定はしません。
※PMXエディタ上では重複分もそのまま複数回描画しています。

PMXエディタでの A-B-C パターンは、

Point : 3頂点を全て Point描画
Line  : A-B, B-C, C-A で作られる 3辺をLine描画

という描画を行っています。それぞれ Indexバッファの取り方が通常の△面とは異なるのでご注意ください。



●材質

(省略)
1  : bitFlag  	| 描画フラグ(8bit) - 各bit 0:OFF 1:ON
                   0x01:両面描画, 0x02:地面影, 0x04:セルフシャドウマップへの描画, 0x08:セルフシャドウの描画, 
                   0x10:エッジ描画, 0x20:頂点カラー(※2.1拡張), 0x40:Point描画(※2.1拡張), 0x80:Line描画(※2.1拡張)
(省略)
4  : float	| エッジサイズ, Point描画時はPointサイズ(※2.1拡張)

----

頂点カラー  : 頂点の "追加UV1" の値(float4)を "照明計算後の色値" として描画に利用するモード
Point描画   : 描画プリミティブを PointList で描画
Line描画    : 描画プリミティブを LineList で描画

※Point／Line 双方とも ON の場合は Point 優先

PMXエディタでは、

Point描画時 -> セルフシャドウ／シャドウマップ／地面影／エッジ無効(Pointサイズ用にエッジサイズを転用します)
Line描画時  -> エッジ無効 (セルフシャドウや地面影は材質設定のまま)

としています。

頂点カラーの色値については、材質、照明色からの色計算後の値とし、
その色値にテクスチャ／Toon／スフィア／セルフシャドウなどの加工をシェーダ内で行っています。

仕様上 追加UV1 を参照しているので、スフィアのサブテクスチャモードとは共存できません。

色計算は実装により異なる結果になりますが、PMXの仕様として固定はしません。自由に実装してください。

※例えば 追加UV1 だけでなく、追加UV1〜3(4) までを使い Diffuse/Specular/Ambient として、
頂点色を照明計算に利用するなどの発展も考えられます。



●モーフ

○モーフ種類

フリップモーフ
インパルスモーフ

を追加


○フリップモーフ
n  : モーフIndexサイズ  | モーフIndex
4  : float	| モーフ値

※データ形式は グループモーフ と共通

○インパルスモーフ
n  : 剛体Indexサイズ  | 剛体Index
1  : ローカルフラグ   | 0:OFF 1:ON
12 : float3	| 移動速度 (x,y,z)
12 : float3	| 回転トルク (x,y,z)   ※ 移動速度／回転トルク すべて 0 の場合は"停止制御"として特殊化


[モーフデータ]
(省略)
1  : byte	| モーフ種類 - 0:グループ, 1:頂点, 2:ボーン, 3:UV, 4:追加UV1, 5:追加UV2, 6:追加UV3, 7:追加UV4, 8:材質, 
                               9:フリップ(※2.1拡張) 10:インパルス(※2.1拡張)

----

■フリップモーフの実装方法

フリップモーフは複数登録されたモーフを、フリップモーフのモーフ値から一つだけ選択するモーフです。
対象モーフの切り替え点は登録モーフ数により変化します。

※登録可能な対応モーフはフリップモーフを含んで全てのモーフに対応します。

初期状態(0)はどのモーフも選択されない状態なので、実質的に (登録数 + 1) が選択対象数となります。

モーフ値から対応するモーフへの変換は、

count : 登録モーフ数
value : フリップモーフのモーフ値
として、

   index = (int)((count + 1) * value) - 1;

となります。モーフ値が端値(0-,1)の場合index範囲を超えるので制限補正を行ってください(0-1の外側も同様)

例: 9個登録でモーフ値0.3の場合
   index = (9+1)*0.3 - 1 = 3-1 = 2   -> 3番目の登録モーフ [0,1,2,3,.....]

モーフ値の適用方法は単純に、

  選択対象のモーフ値を "現在の状態に関わらず" フリップモーフで指定されたモーフ値に入れ替え

を行うだけです。

変形の初期状態では各モーフ値は初期化されているので、
フリップモーフは ユーザーやモーションから設定された値を強制的に上書きするだけで実装可能です。


■グループモーフや他のフリップモーフとの共存

グループモーフと異なりフリップモーフは登録に対して制限はありません。仕様上は自身を登録することも可能です。
共存させるために以下の手順でモーフ全体の変形を行います。

[モーフ変形]

1. 初期化及びユーザー／モーションから各モーフ値の設定 (変形準備) ※全体のモーフ値を格納する場所を予め用意しておきます。

2. モーフをIndex順に順次変形
 2.1 フリップモーフの場合 : フリップ変形 -> 対象のモーフ値を指定値で書き換え
 2.2 グループモーフの場合 : グループ要素内のフリップモーフをフリップ変形 -> 対象のモーフ値を指定値で書き換え
 2.3 それ以外の場合       : 変形は行わない

3. 再度モーフをIndex順に(先頭から)順次変形
 3.1 フリップモーフの場合 : 変形は行わない
 3.2 グループモーフの場合 : グループ要素内のフリップモーフを除いてグループ変形
 3.3 それ以外の場合       : モーフ変形

それぞれのモーフは変形時に自身のモーフ値を参照することで、フリップ／グループモーフを組み合わせた変形が可能となります。

基本的にIndex順として先の方が優先されるのはボーン変形と同じですが、
フリップモーフによるモーフ値の書き換えなどは上書き側に支配されるのでご注意ください(応用すればモーフ変形中に同じモーフを異なるモーフ値で使いまわすことも可能)



■インパルスモーフの実装方法

1. 剛体毎の 速度インパルス／回転トルクをローカル／グローバルで分けて保持できる場所を確保及び初期化。

2. インパルスモーフ変形  : モーフ値が 0 の対象はインパルス変形を行わない。
 ※ インパルス設定が[全て0]＝停止制御の場合
 2.1a 対象の剛体に初期化フラグON (どれか一つでもフラグONなら初期化対象)

 ※ インパルス制御の場合
 2.1b インパルスモーフの設定量 * モーフ値[0-1(※)] を対象剛体の保持値に加算(回転トルクもXYZとして加算)

3. 全てのモーフ変形確定後 (以下は物理演算直前に物理エンジンに設定を行うのが望ましい)
 3.1 初期化フラグON対象の剛体へ初期化設定(下記参照)
 3.2 インパルス制御対象の剛体へ設定(下記参照)

4. 物理演算シミュレート

※モーフ値は環境により[0-1]である必要はありません。グループモーフなどから参照された場合は[0-1]環境であっても、負設定[-1]などが普通にありえます。


○ 初期化設定(停止制御)
setLinearVelocity()
setAngularVelocity()
setInterpolationLinearVelocity()
setInterpolationAngularVelocity()
setInterpolationWorldTransform()
clearForces()

により運動状態を初期化します(パラメータは0値)

※完全停止などの方が扱いやすい場合は変更になるかもしれません。

○ インパルス設定
applyCentralImpulse()
applyTorqueImpulse()

により速度インパルス、トルクを直接付加します(グローバル設定の場合、値の加工は特に必要ありません)

ローカルの場合は、剛体のフレーム軸で軸補正 (エディタの実装では、回転トルクも速度インパルスと同様の計算で軸補正を行っています)

ローカル／グローバルの総計インパルス値は、両者を加算せずに 2回に分けて別々に物理側へ送信しています。

※ボーン追従剛体(Static 及び Kinematic) の場合はインパルス設定などの必要はありません(エディタ上では関係なく送信されていますが)







●Joint

(省略)
1  : byte	| Joint種類 - 0:ﾊﾞﾈ付6DOF, 1:6DOF, 2:P2P, 3:ConeTwist, 4:Slider, 5:Hinge

※Joint種類に関わらず以下のデータは ﾊﾞﾈ付6DOF(0) と同じ形式

----

■Joint種類と物理演算側の対応

□ ﾊﾞﾈ付6DOF   | 0
PMX2.0及びPMDと同様

対応: btGeneric6DofSpringConstraint()


□ 6DOF        | 1
ﾊﾞﾈ付6DOF に対して バネ定数-移動/回転 が無効

対応: btGeneric6DofConstraint()


□ P2P         | 2
PointToPoint - 各制限／バネ定数が無効

対応: btPoint2PointConstraint()   ※Joint向きや剛体からの回転姿勢の差は意味がないので注意


□ ConeTwist    | 3
円錐範囲指定での回転用Joint

対応: btConeTwistConstraint()

setLimit()
  _swingSpan1  : 回転制限-下限 - Z
  _swingSpan2  : 回転制限-下限 - Y
  _twistSpan   : 回転制限-下限 - X
  _softness    : バネ定数-移動 - X
  _biasFactor  : バネ定数-移動 - Y
  _relaxationFactor :バネ定数-移動 - Z

setDamping()
  damping      : 移動制限-下限 - X

setFixThresh()
  fixThresh    : 移動制限-上限 - X

enableMotor()  : 移動制限-下限 - Z  | モーター有効 - 0:OFF 1:ON

<モーター有効の場合>
  setMaxMotorImpulse()
    maxMotorImpulse : 移動制限-上限 - Z

  setMotorTargetInConstraintSpace() : バネ定数-回転(xyz) ※3軸回転のrad値として記録 -> 回転量へ変換して設定
<>
※ Jointのパラメータ説明にも書いてありますが、モーター関係の動作が不明なので暫定的な対応となります。

※ 回転制限は 初期状態での視覚的な軸角度を元にXYZを定めていますが、
仕様的には X軸向き を初期状態とし

 X(_twistSpan)  : 捻り方向
 Y(_swingSpan2) : 回転範囲の拡がり-横(縦)
 Z(_swingSpan1) : 回転範囲の拡がり-縦(横)

という表現が正確かと思われます。


□ Slider        | 5
軸移動Joint

対応: btSliderConstraint()

setLowerLinLimit() : 移動制限-下限 - X
setUpperLinLimit() : 移動制限-上限 - X
setLowerAngLimit() : 回転制限-下限 - X
setUpperAngLimit() : 回転制限-上限 - X

setPoweredLinMotor() : バネ定数-移動 - X  | モーター有効 - 0:OFF 1:ON
<移動モーター有効の場合>
  setTargetLinMotorVelocity() : バネ定数-移動 - Y
  setMaxLinMotorForce()       : バネ定数-移動 - Z
<>

setPoweredAngMotor() : バネ定数-回転 - X  | モーター有効 - 0:OFF 1:ON
<回転モーター有効の場合>
  setTargetAngMotorVelocity() : バネ定数-回転 - Y
  setMaxAngMotorForce()       : バネ定数-回転 - Z
<>


□ Hinge         | 6
軸回転Joint

対応: btHingeConstraint()

setLimit()
  low          : 回転制限-下限 - X
  high         : 回転制限-上限 - X
  _softness    : バネ定数-移動 - X
  _biasFactor  : バネ定数-移動 - Y
  _relaxationFactor :バネ定数-移動 - Z

enableMotor() : バネ定数-回転 - X  | モーター有効 - 0:OFF 1:ON
<回転モーター有効の場合>
  enableAngularMotor()
    enableMotor     : バネ定数-回転 - X
    targetVelocity  : バネ定数-回転 - Y
    maxMotorImpulse : バネ定数-回転 - Z
<>


※各Jointにおいても、軸ズレや剛体との位置ズレなどは通常Jointと変わらず発生するので、適宜補正処理を行うこと。




●SoftBody  ※PMX2.1の新規追加項目

4 + n : TextBuf	| SoftBody名
4 + n : TextBuf	| SoftBody名英

1  : byte	| 形状 - 0:TriMesh 1:Rope

n  : 材質Indexサイズ  | 関連材質Index

1  : byte	| グループ
2  : ushort	| 非衝突グループフラグ

1  : bitFlag  	| フラグ(8bit) - 各bit 0:OFF 1:ON
○フラグ
 0x01   : B-Link 作成 
 0x02   : クラスタ作成
 0x04   : リンク交雑      ※これらの詳細は下記の実装説明を参照

4  : int	| B-Link 作成距離
4  : int	| クラスタ数

4  : float	| 総質量
4  : float	| 衝突マージン

4  : int	| AeroModel - 0:V_Point, 1:V_TwoSided, 2:V_OneSided, 3:F_TwoSided, 4:F_OneSided

<config>
4  : float	| VCF
4  : float	| DP 
4  : float	| DG 
4  : float	| LF 
4  : float	| PR 
4  : float	| VC 
4  : float	| DF 
4  : float	| MT 
4  : float	| CHR
4  : float	| KHR
4  : float	| SHR
4  : float	| AHR

<cluster>
4  : float	| SRHR_CL
4  : float	| SKHR_CL
4  : float	| SSHR_CL
4  : float	| SR_SPLT_CL
4  : float	| SK_SPLT_CL
4  : float	| SS_SPLT_CL

<iteration>
4  : int	| V_IT
4  : int	| P_IT
4  : int	| D_IT
4  : int	| C_IT

<material>
4  : float	| LST
4  : float	| AST
4  : float	| VST

4  : int	| アンカー剛体数
<アンカー剛体>
  n  : 剛体Indexサイズ  | 関連剛体Index
  n  : 頂点Indexサイズ  | 関連頂点Index
  1  : byte	| Near モード  0:OFF 1:ON
</アンカー剛体>
* アンカー剛体数

4  : int	| Pin頂点数
<Pin頂点>
  n  : 頂点Indexサイズ  | 関連頂点Index
</Pin頂点>
* Pin頂点数



■SoftBodyの実装方法

まず bullet の SofyBodyデモ(appSoftBodyDemo) にしっかり目を通してください。

※PMX(2.1)の物理演算は MMD との互換性のため bullet 2.75 を基準にしています。


● ワールド設定
btSoftRigidDynamicsWorld() が動作するよう初期化部分を変更してください(デモのままで十分だと思います)

※PMXエディタでは air_density = 1.2f で初期化。地面は従来通り無限平面を配置しています(SofyBodyは突き抜けてしまうようですが)

重力設定はワールドとSoftBody側で別管理なのでご注意を。


● SoftBodyの作成／登録

1. SoftBodyインスタンス作成
形状 :
 TriMesh -> btSoftBodyHelpers::CreateFromTriMesh() で作成。材質に関連した面-頂点(位置列) を物理側に合うように整形して渡してください。

 Rope    -> btSoftBodyHelpers::CreateRope() を"改変"し作成 (直列の頂点(位置)列と頂点間をリンク接続する処理だけで必要十分)

※念のため SoftBody の位置は初期化。 btSoftBody::transform()
※モデル側の法線は使えませんが、物理変形後の法線はフィードバックして描画に使用します。


2. パラメータ設定
 btSoftBody::setTotalMass()     : 総質量
 btCollisionShape::setMargin()  : マージン  ※ btSoftBody::getCollisionShape()

 btSoftBody::collisions |= btSoftBody::fCollision::VF_SS;  : 衝突フラグ(SofyBodyと衝突するよう変更)


3. Config 設定   | btSoftBody::Config
 aeromodel   : AeroModel       ※ PMX側の数値(暫定値)をそのまま使わないこと

 kVCF        : VCF
...
 kSS_SPLT_CL : SS_SPLT_CL      ※ k*** は同名のパラメータをそのまま設定。全ての表記は省略。

 viterations : V_IT
 piterations : P_IT
 diterations : D_IT
 citerations : C_IT


4. Material 更新
 btSoftBody::appendMaterial()


5. BendingConstraints 生成
※ B-Link ON の場合
 btSoftBody::generateBendingConstraints()   : B-Link距離と 4. の Material で作成


6. Material 設定
 kLST : LST          ※ Config と同様
 kAST : AST
 kVST : VST


7. クラスタ生成
※ クラスタ生成 ON の場合
 btSoftBody::generateClusters()    : クラスタ数で初期化
 btSoftBody::collisions = btSoftBody::fCollision::CL_SS | btSoftBody::fCollision::CL_RS;     : クラスタ判定へ変更


8. リンク交雑
※ リンク交雑 ON の場合
 btSoftBody::randomizeConstraints()


9. アンカー剛体の設定
 btSoftBody::appendAnchor()      : 頂点Indexや登録剛体は物理ワールド側の値なので注意(要補正)


10. ピン頂点の設定
 SoftBody内の対象ノード(頂点) -> m_im = 0;    : ノード(頂点)Indexは物理ワールド側の値

※ btSoftBody::Node::m_im


11. グループ設定及びワールドへ登録
 通常の剛体と同様です。



● SoftBodyの変形手順

物理演算前 : 
 Pin頂点の座標を変更
  - ボーン変形から頂点位置を変形 → 物理側のSoftBody内のノード頂点位置を直接設定  ※ btSoftBody::Node::m_x

↓
物理演算
↓

物理演算後
 アンカー剛体のNear処理
  - 剛体がボーン追従の場合 : 対応のノード頂点の速度を剛体方向へ加算。
                             btSoftBody::Node::m_x と剛体位置の差を m_v へ加算  ※効果はほとんどありません。
  - 剛体が物理剛体の場合 : 剛体位置をノード頂点位置へ強制移動  ※ 参考：ロックJoint用の剛体引き戻し処理

 SoftBody 頂点(Node::m_x)／法線(Node::m_n)の取得 → 描画へ使用 (ボーン変形は全て無視)

※ SoftBody対象材質ではない材質描画時も、頂点が SoftBody から変形されている場合は SoftBody 側の値に従うこと。



● 非対応項目と問題点など

ボリューム系の設定はできません。ノード(頂点)毎の質量設定は対応していません。

機能的には破断の表現なども ノードのリンクを外す などで簡単に表現できますが、
外部からの設定方法を定義できないのでモデルフォーマットとしては対応しません。

クラスタを使用している場合、物理シミュレートでエラー終了が発生します(ほぼ確定)
※bullet側が物理シミュレート内で問題を起こしているようです。クラスタはPin頂点による直接位置設定と相性が悪い様子？

ロープ形状なのにメッシュで生成した場合や、その逆は物理シミュレートがエラー終了する場合があります。
パラメータ値によっても同様にエラー終了する場合があります。

SoftBody の各パラメータについては

/*---------------------------------------------------------------------------
<config>
eAeroModel::_	aeromodel;	// Aerodynamic model (default: V_Point)
btScalar	kVCF;		// Velocities correction factor (Baumgarte)
btScalar	kDP;		// Damping coefficient [0,1]
btScalar	kDG;		// Drag coefficient [0,+inf]
btScalar	kLF;		// Lift coefficient [0,+inf]
btScalar	kPR;		// Pressure coefficient [-inf,+inf]
btScalar	kVC;		// Volume conversation coefficient [0,+inf]
btScalar	kDF;		// Dynamic friction coefficient [0,1]
btScalar	kMT;		// Pose matching coefficient [0,1]		
btScalar	kCHR;		// Rigid contacts hardness [0,1]
btScalar	kKHR;		// Kinetic contacts hardness [0,1]
btScalar	kSHR;		// Soft contacts hardness [0,1]
btScalar	kAHR;		// Anchors hardness [0,1]

<cluster>
btScalar	kSRHR_CL;	// Soft vs rigid hardness [0,1] (cluster only)
btScalar	kSKHR_CL;	// Soft vs kinetic hardness [0,1] (cluster only)
btScalar	kSSHR_CL;	// Soft vs soft hardness [0,1] (cluster only)
btScalar	kSR_SPLT_CL;	// Soft vs rigid impulse split [0,1] (cluster only)
btScalar	kSK_SPLT_CL;	// Soft vs rigid impulse split [0,1] (cluster only)
btScalar	kSS_SPLT_CL;	// Soft vs rigid impulse split [0,1] (cluster only)

<iteration>
int		viterations;	// Velocities solver iterations
int		piterations;	// Positions solver iterations
int		diterations;	// Drift solver iterations
int		citerations;	// Cluster solver iterations

<material>
btScalar	m_kLST;		// Linear stiffness coefficient [0,1]
btScalar	m_kAST;		// Area/Angular stiffness coefficient [0,1]
btScalar	m_kVST;		// Volume stiffness coefficient [0,1]

---------------------------------------------------------------------------*/

となっていますが、(デモを見る限りでは)効果範囲が極端に小さな値(0.001以下)のものから 1000単位で使うものまであるようなので、
取り扱いが非常に難しいです。

※おそらく効果のないパラメータもいくつかあると思いますが、一応一通り全部入れておきました。

なお、極端なパラメータ値にすると簡単に物理シミュレートが壊れるのも、bulletのSoftBodyの特徴のようです。


SoftBodyの実装自体はそれほど難しいものではありませんが、運用においては残念ながら精度や速度など問題点も多いので、
場合によっては対応しないことなども、選択肢に入れて頂ければよろしいかと思います。







以上

極北P (PMX仕様 ver2.1)


