2015年10月02日

テクスチャ名の話

したらばでちょっと話題になってたので、ブログのネタにでもしておこうかと思います。

PMXやPMDのモデルデータではモデル(*.pmx/*.pmd)が、外部のテクスチャファイル(*.pngなど)を参照しているのはご存知かと思います。

このテクスチャファイルですが実は 「ファイル名を日本語で指定するとうまく動作しない」 というケースがたまにあります。

モデルファイルやモデルデータ内の各部分は日本語表記でも特に問題はないのに、何故テクスチャファイルだけが例外なのか?...と、この手の問題に慣れていない方などは不思議に思われるかもしれませんが、

理由としては単純に 「テクスチャファイルの読み込みは DirectXの専用処理を使っている」 からです。

例えば DX9のテクスチャロードでは D3DXCreateTextureFromFile 関数 などを使うのが定番ですが、この処理で指定するファイルパスは(デフォルト設定では)日本語などの2バイト文字に対応していません(使用文字によっては別の記号として認識されてしまう)

※ファイルパスはフルパスで指定する場合がほとんどなので、本来フォルダ名にも注意が必要です。

また 2バイト文字への対応を正しく設定していた場合でも、DirectXの内部処理も同じように対応して(正しく)動作しているかどうかはわかりません。

基本的にベースライブラリを作成している方たちは 「半角英数(7bit)だけで事がすむ」文化圏の方たちですし、昨今ではユニコード対応なども当たり前になりましたが、DX9が作られた頃はまだそうでもない時代でしたので。

※そもそもライブラリではなく呼び出し側に実装ミスがあることもよくあります。

そういった内部の事情から 「テクスチャファイル名の問題」 ということが表面化するわけです。


その他の名称やファイルパス部分で特に問題になることはない理由も同様に、

・PMXエディタやMMMなどの.NETフレームワークベースのアプリケーションはユニコード仕様になりほぼ問題が出なくなった
・MMDなどのネイティブアプリでも作成者が日本人などの多バイト圏の方なら(自身の処理部分では)大体対応済み

ということだからです

※.NETフレームワークから呼び出しているDirectXも結局はネイティブ側の処理に繋がっているので、問題が出ることはよくあります(Xファイルのロードとか)

今でも海外(特に欧米系)のネイティブアプリでは日本語指定でたまに問題が起きたりしますが、このあたりは自分たちで対応していくしかありません(=日本語使わない)

それにしても日本語のファイル名に関する問題とか、こんな風に古いシステムの名残による問題がひょこっと顔を出すと、「ファイル名なんてちょっと前は 8+3 文字(英数のみ)が当たり前だったのになぁ」 みたいにちょっと郷愁的な気分になりますね(笑)


以上


※PMDの各部位やパス指定などの文字列データは特定の容量制限があるので、昨今の PMXから入った方などは特に注意しておきましょう(アトVMDハ今デモ15byte制限アルヨ、キヲツケテ)

posted by - at 12:20| PMX | 更新情報をチェックする

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 | 更新情報をチェックする

2015年08月30日

0232

■更新内容

・状態検証簡易フィルタリング
・任意の状態検証項目の追加(プラグイン実装)

以上


不具合修正がてらのちょっとした機能追加です。

状態検証を ○/△/× で表示分けできるようにしておきました。

合わせて任意の検証項目を追加できるよう機能修正(フィルタがあれば見落としも減るので項目を増やせるようにしても大丈夫かな?と)

といっても検証方法は全てプラグインコードで書く必要があるので「誰でも気軽に」というわけにはいきませんけどね。

※一応、CSスクリプトプラグインでも作成すること自体は可能です(通常プラグインとは異なる仕様なので実行はできません/DLL変換後要再起動)

あと状態検証プラグインは昨今の Cプラグイン仕様ではありませんので、細かくデバッグなどを行いたい場合は、Cプラグインにて検証部分を作成→状態検証プラグインへ移植、といった手順で作成してください(インポート/エクスポートと同様)


以上

posted by - at 21:12| PMX | 更新情報をチェックする