2015年09月18日

状態検証の追加方法

0232で実装した状態検証プラグインの作り方について少々説明しておこうかと思います。

以下、付属の CSスクリプトプラグインを用いた作成方法を紹介します(通常のプラグイン作成の場合は自前で初期化を行う必要がある程度で後は同様です)

■作成手順
1. CS(C#)スクリプトを開き、メニュー[ファイル]-[新規作成-状態検証]を選択(→編集タブが一般形式へ移行/コードが自動的に変更)
2. 検証コードを追記
3. ビルド確認(F6)を行いエラーがなければ、[ファイル]-[プラグインDLL生成]でDLLファイルへ変換し保存
4. PMXエディタを再起動し、追加した状態検証が正常に動作するかチェック

■検証コード
CheckPmx() 処理に渡される PMXデータを適宜調査し、検証結果を PECheckResult データとして返すことで状態検証へ結果が表示されます。

●PECheckResult
Text : 状態検証に表示される結果文字列(string)
Filter : ○/△/×にそれぞれ相当するフィルタ数値(int) ○=0/△=1/×=2

●IEnumerable<PECheckResult>
検証結果は列挙子に包んで返します。よって一つのプラグイン処理で一度に複数の検証を行うことができます。実際のコードでは PECheckResultの配列やリストなどを用いる他、yield return を使って一つずつ結果を返すことも可能です。


■コード例
※参考用なので実用性はありません。

●モデル名が "初音ミク" であるかチェック
public class CheckerClass : IPECheckerPlugin
{
public IEnumerable<PECheckResult> CheckPmx(PEPlugin.Pmx.IPXPmx pmx)
{
if(pmx.ModelInfo.ModelName == "初音ミク") {
yield return new PECheckResult() { Text = @"○ モデル名は ""初音ミク"" です.", Filter = 0 };
}
else {
yield return new PECheckResult() { Text = @"× モデル名が ""初音ミク"" ではありません.", Filter = 2 };
}
}
}


●全ての親ボーンがあるかどうか/全ての親ボーンが先頭であるかどうかを同時にチェック
public class CheckerClass : IPECheckerPlugin
{
public IEnumerable<PECheckResult> CheckPmx(PEPlugin.Pmx.IPXPmx pmx)
{
int bx = -1; // 対象ボーンのIndex
for (int i = 0; i < pmx.Bone.Count; i++) {
if (pmx.Bone[i].Name == "全ての親") {
bx = i;
break;
}
}

var r = new PECheckResult[] {
new PECheckResult(){ Text = "○ 全ての親ボーンが含まれます.", Filter = 0 },
new PECheckResult(){ Text = "○ 先頭ボーンは全ての親ボーンになっています.", Filter = 0 }
};

if (bx < 0) {
r[0].Text = "× 全ての親ボーンが含まれません."; r[0].Filter = 2;
}
if (bx != 0) {
r[1].Text = "× 先頭ボーンが全ての親ボーンではありません."; r[1].Filter = 2;
}

return r;
}
}


●Jointが剛体間に位置しているか簡易チェック
public class CheckerClass : IPECheckerPlugin
{
public IEnumerable<PECheckResult> CheckPmx(PEPlugin.Pmx.IPXPmx pmx)
{
// null指定で検証無効
if (pmx.Joint.Count == 0) { return null; }

var list = new List<int>();
for (int i = 0; i < pmx.Joint.Count; i++) {
var j = pmx.Joint[i];
if (j.BodyA == null || j.BodyB == null) { continue; }

// 剛体位置(xyz)を小〜大で範囲分け
V3 max = V3.Max(j.BodyA.Position, j.BodyB.Position);
V3 min = V3.Min(j.BodyA.Position, j.BodyB.Position);

// Joint位置が両剛体の外側にある場合(X/Yのみ判定)
if (j.Position.X < min.X || max.X < j.Position.X || j.Position.Y < min.Y || max.Y < j.Position.Y) {
// Indexをリストへ追加
list.Add(i);
}
}

// 先頭で通常のreturnを使っているのでyield returnは使えません
var r = new PECheckResult();
if (list.Count == 0) {
r.Text = "○ 全てのJoint位置は関連剛体間に配置されています."; r.Filter = 0;
}
else {
r.Text = "△ 次のJoint位置は関連剛体間に配置されていません(X/Y範囲のみ/Index表示) -> " + string.Join(",", list); r.Filter = 1;
}
return new PECheckResult[] { r };
}
}

※Joint位置は必ずしも剛体A-Bの間にある必要はありませんので、↑の検証自体には大きな意味はありません。


■まとめ
というような感じでエディタのソース内にも状態検証コードがずらずらと並んでいたりします。

単純な検証でも実際のコード作成は色々面倒なことが多いので、誰でも簡単に思った通りのものが作れるわけではありませんが(複雑な検証であれば尚更)、このように必要に応じて拡張自体は一応行うことができるようになっていますよ、というお話でした。

以上

【関連する記事】
posted by - at 22:19| PMX | 更新情報をチェックする