void ReadBoneStructure(string path) { using (StreamReader sr = new StreamReader(path, encoding)) { string line = null; while ((line = sr.ReadLine()) != null) { string[] row = line.Split(','); string bone_name = row[0].Trim(); string bone_kind = row[1].Trim(); string parent_name = row[2].Trim(); string tail_name = row[3].Trim(); string target_name = row[4].Trim(); string disp_name = row[5].Trim(); PMD_Bone pmd_b = new PMD_Bone(); pmd_b.name = bone_name; pmd_b.Kind = int.Parse(bone_kind); pmd_b.ParentName = (parent_name != "") ? parent_name : null; pmd_b.TailName = (tail_name != "") ? tail_name : null; pmd_b.TargetName = (target_name != "") ? target_name : null; // すでにpmd_b.nameが存在するなら上書き boneStructure[pmd_b.name] = pmd_b; if (disp_name != "") { AddBoneNameInDisp(bone_name, disp_name); } } } }
// ボーン名をIDに置き換える public void SetBoneIDFromName(PmxFile pmd) { parent_node_id = pmd.GetBoneIDByName(ParentName); tail_node_id = pmd.GetBoneIDByName(TailName); target_node_id = pmd.GetBoneIDByName(TargetName); if (parent_node_id != -1) { // 親が捩りボーンなら軸固定を設定する PMD_Bone parent = pmd.nodes[parent_node_id]; if (parent.flags_hi == 0x04) { parent.axis = Vector3.Normalize(position - parent.position); } } }
/// 親子関係を元に並び替える static void SortNodes(List <PMD_Bone> nodes) { for (int i = 0; i < nodes.Count; i++) { PMD_Bone node = nodes[i]; //親より前に居る子を見つける for (int j = 0; j < i; j++) { if (nodes[j].ParentName == node.name) { //親を削除 nodes.RemoveAt(i); //親を子の直前に挿入 nodes.Insert(j, node); break; } } } }
// ----------------------------------------------------- // FigureデータよりPmdFileデータを作成 // ----------------------------------------------------- public string Figure2PmdFileDataWithHumanBone() { CorrespondTable cor_table = null; int mod_type = 0; if (fig.Tmo.nodes.Length == 227) { corTable_list.SetManFlag = false; cor_table = corTable_list.GetCorrespondTable(); mod_type = 0; } else if (fig.Tmo.nodes.Length == 75) { corTable_list.SetManFlag = true; cor_table = corTable_list.GetCorrespondTable(); mod_type = 1; } else { return("未対応のボーン構造です。\n人型以外を変換する場合は、\n出力ボーンに”1ボーン”を指定してください。"); } // ----------------------------------------------------- // 予め、情報をコピーするmeshを選定し、並び替えておく // ----------------------------------------------------- SelectMeshes(); // ----------------------------------------------------- // 頂点 // ----------------------------------------------------- MakePMDVertices(cor_table, mod_type); // 頂点数が上限を超えてないかチェックし、超えていたらエラーを出して終了 if (pmd.number_of_vertex > 65535) { return("頂点数(" + pmd.number_of_vertex.ToString() + ")が上限(65535)を超えています。"); } // ----------------------------------------------------- // 表情 // ----------------------------------------------------- if (mod_type == 0) { InitializePMDFaces(); MakePMDBaseFace(); MakePMDFaces(); } else if (mod_type == 1) { InitializePMDFaces(); MakePMDBaseFace(); pmd.number_of_face = 0; } // ----------------------------------------------------- // 表情枠 // ----------------------------------------------------- if (mod_type == 0) { pmd.skin_disp_count = pmd.number_of_face - 1; // 表情枠に表示する表情数 pmd.skin_index = new int[pmd.skin_disp_count]; for (int i = 0; i < pmd.skin_disp_count; i++) { pmd.skin_index[i] = i + 1; // 表情番号 } } else if (mod_type == 1) { pmd.skin_disp_count = 0; // 表情枠に表示する表情数 } // ----------------------------------------------------- // ボーン情報 // ----------------------------------------------------- List <PMD_Bone> bone_list = new List <PMD_Bone>(); foreach (KeyValuePair <string, PMD_Bone> bone_kvp in cor_table.boneStructure) { PMD_Bone pmd_b = new PMD_Bone(); PMD_Bone bone = bone_kvp.Value; pmd_b.szName = bone.szName; pmd_b.cbKind = bone.cbKind; // ボーンの種類 0:回転 1:回転と移動 2:IK 3:不明 4:IK影響下 5:回転影響下 6:IK接続先 7:非表示 8:捻り 9:回転運動 pmd_b.ParentName = bone.ParentName; pmd_b.ChildName = bone.ChildName; pmd_b.IKTargetName = bone.IKTargetName; string bone_name = null; cor_table.bonePosition.TryGetValue(pmd_b.szName, out bone_name); if (bone_name != null) { pmd_b.vec3Position = Trans.CopyMat2Pos(fig.Tmo.FindNodeByName(bone_name).combined_matrix); // モデル原点からの位置 } bone_list.Add(pmd_b); } // ----------------------------------------------------- // 親と子の前後関係を並び替える for (int i = 0; i < bone_list.Count; i++) { for (int j = 0; j < bone_list.Count; j++) { if (bone_list[i].szName == bone_list[j].ParentName) { if (i > j) { bone_list.Insert(j, bone_list[i]); bone_list.RemoveAt(i + 1); } } } } // ----------------------------------------------------- // リストを配列に代入し直す pmd.number_of_bone = bone_list.Count; pmd.pmd_bone = (PMD_Bone[])bone_list.ToArray(); // ----------------------------------------------------- // センターボーンの位置調整 pmd.getBoneByName("センター").vec3Position = new MmdVector3( 0.0f, pmd.getBoneByName("下半身").vec3Position.y * 0.65f, 0.0f); pmd.getBoneByName("センター先").vec3Position = new MmdVector3( 0.0f, 0.0f, 0.0f); // ----------------------------------------------------- // 両目ボーンの位置調整 if (mod_type == 0) { pmd.getBoneByName("両目").vec3Position = new MmdVector3( 0.0f, pmd.getBoneByName("左目").vec3Position.y + pmd.getBoneByName("左目").vec3Position.x * 4.0f, pmd.getBoneByName("左目").vec3Position.z - pmd.getBoneByName("左目").vec3Position.x * 2.0f); pmd.getBoneByName("両目先").vec3Position = new MmdVector3( pmd.getBoneByName("両目").vec3Position.x, pmd.getBoneByName("両目").vec3Position.y, pmd.getBoneByName("両目").vec3Position.z - 1.0f); } // ----------------------------------------------------- // IK先ボーンの位置調整 pmd.getBoneByName("左足IK先").vec3Position = new MmdVector3( pmd.getBoneByName("左足IK").vec3Position.x, pmd.getBoneByName("左足IK").vec3Position.y, pmd.getBoneByName("左足IK").vec3Position.z + 1.7f); pmd.getBoneByName("右足IK先").vec3Position = new MmdVector3( pmd.getBoneByName("右足IK").vec3Position.x, pmd.getBoneByName("右足IK").vec3Position.y, pmd.getBoneByName("右足IK").vec3Position.z + 1.7f); pmd.getBoneByName("左つま先").vec3Position.y = 0.0f; pmd.getBoneByName("左つま先IK").vec3Position.y = 0.0f; pmd.getBoneByName("左つま先IK先").vec3Position = new MmdVector3( pmd.getBoneByName("左つま先IK").vec3Position.x, pmd.getBoneByName("左つま先IK").vec3Position.y - 1.0f, pmd.getBoneByName("左つま先IK").vec3Position.z); pmd.getBoneByName("右つま先").vec3Position.y = 0.0f; pmd.getBoneByName("右つま先IK").vec3Position.y = 0.0f; pmd.getBoneByName("右つま先IK先").vec3Position = new MmdVector3( pmd.getBoneByName("右つま先IK").vec3Position.x, pmd.getBoneByName("右つま先IK").vec3Position.y - 1.0f, pmd.getBoneByName("右つま先IK").vec3Position.z); // ----------------------------------------------------- // IK配列 // ----------------------------------------------------- pmd.number_of_ik = cor_table.IKBone.Count; pmd.pmd_ik = (PMD_IK[])cor_table.IKBone.ToArray(); // ----------------------------------------------------- // ボーン枠用枠名リスト // ----------------------------------------------------- pmd.bone_disp_name_count = cor_table.dispBoneGroup.Count; // ボーン枠用の枠名数 pmd.disp_name = new string[pmd.bone_disp_name_count]; // 枠名(50Bytes/枠) for (int i = 0; i < cor_table.dispBoneGroup.Count; i++) { pmd.disp_name[i] = cor_table.dispBoneGroup[i].group_name + Convert.ToChar(Convert.ToInt16("0A", 16)); } //PMDEditorを使う場合は、枠名を0x0A00で終わらせる必要があります(0x00のみだと表示されません)。 // ----------------------------------------------------- // ボーン枠用表示リスト // ----------------------------------------------------- // 枠に表示するボーン数 pmd.bone_disp_count = 0; for (int i = 0; i < cor_table.dispBoneGroup.Count; i++) { pmd.bone_disp_count += cor_table.dispBoneGroup[i].bone_name_list.Count; } // 枠用ボーンデータ (3Bytes/bone) pmd.bone_disp = new PMD_BoneDisp[pmd.bone_disp_count]; int n = 0; // 通し番号 int n_disp = 1; foreach (DispBoneGroup dbg in cor_table.dispBoneGroup) { foreach (string name in dbg.bone_name_list) { pmd.bone_disp[n] = new PMD_BoneDisp(); pmd.bone_disp[n].bone_name = name; // 枠用ボーン名 pmd.bone_disp[n++].bone_disp_frame_index = n_disp; // 表示枠番号 } n_disp++; } // ----------------------------------------------------- // 英名対応(0:英名対応なし, 1:英名対応あり) // ----------------------------------------------------- pmd.english_name_compatibility = 0; // ----------------------------------------------------- // 剛体&ジョイント // ----------------------------------------------------- // ----------------------------------------------------- // 物理オブジェクトを生成 physOb_list = new T2PPhysObjectList(bone_list); // ----------------------------------------------------- // テンプレートを適用 template_list.PhysObExecute(ref physOb_list); // ----------------------------------------------------- // 剛体&ジョイントを配列に代入し直す pmd.rigidbody_count = physOb_list.body_list.Count; pmd.rigidbody = (PMD_RigidBody[])physOb_list.body_list.ToArray(); pmd.joint_count = physOb_list.joint_list.Count; pmd.joint = (PMD_Joint[])physOb_list.joint_list.ToArray(); // ----------------------------------------------------- // 終了 return(""); }
/// Figureを元にPmdFileを更新します。 /// ボーンは人型です。 public void UpdatePmdFromFigureWithHumanBone() { int mod_type = 0; if (fig.Tmo.nodes.Length == 227) { mod_type = 0; } else if (fig.Tmo.nodes.Length == 75) { mod_type = 1; } else { throw new FormatException("未対応のボーン構造です。\n人型以外を変換する場合は、\n出力ボーンに\"1ボーン\"を指定してください。"); } CorrespondTable cortable; if (mod_type == 0) { cortable = cortable_list.GetCorrespondTable(); } else { cortable_list.BoneKind = CorrespondTableListBoneKind.man; cortable = cortable_list.GetCorrespondTable(); } // ----------------------------------------------------- // ボーン情報 // ----------------------------------------------------- List <PMD_Bone> nodes = new List <PMD_Bone>(); foreach (KeyValuePair <string, PMD_Bone> bone_kvp in cortable.boneStructure) { PMD_Bone bone = bone_kvp.Value; PMD_Bone pmd_b = new PMD_Bone(); pmd_b.name = bone.name; pmd_b.name_en = bone.name_en; pmd_b.Kind = bone.Kind; pmd_b.ParentName = bone.ParentName; pmd_b.TailName = bone.TailName; pmd_b.TargetName = bone.TargetName; string bone_name = null; cortable.bonePositions.TryGetValue(pmd_b.name, out bone_name); if (bone_name != null) { pmd_b.position = Trans.CopyMat2Pos(fig.Tmo.FindNodeByName(bone_name).combined_matrix); // モデル原点からの位置 } nodes.Add(pmd_b); } SortNodes(nodes); // ----------------------------------------------------- // リストを配列に代入し直す pmd.nodes = nodes.ToArray(); UpdateRootBonePosition(); if (mod_type == 0) { UpdateEyesBonePosition(); } UpdateIKTailBonePosition(); // ----------------------------------------------------- // 予め、情報をコピーするmeshを選定し、並び替えておく // ----------------------------------------------------- SelectMeshes(); // ----------------------------------------------------- // 頂点 // ----------------------------------------------------- MakePMDVertices(cortable, mod_type); // ----------------------------------------------------- // 表情 // ----------------------------------------------------- if (mod_type == 0) { InitializePMDFaces(); MakePMDFaces(); } else { InitializePMDFaces(); pmd.skins = new PMD_Skin[0]; } // ----------------------------------------------------- // IK配列 // ----------------------------------------------------- pmd.iks = cortable.iks.ToArray(); // ----------------------------------------------------- // 表示枠 // ----------------------------------------------------- pmd.disp_groups = cortable.boneDispGroups; if (mod_type == 0) { PMD_DispGroup disp_group = pmd.disp_groups[1];//表情枠 for (int i = 0; i < pmd.skins.Length; i++) { PMD_SkinDisp skin_disp = new PMD_SkinDisp(); skin_disp.skin_id = (sbyte)i; disp_group.disps.Add(skin_disp); } } if (mod_type == 0) { T2PPhysObjectList physOb_list = new T2PPhysObjectList(nodes); template_list.PhysObExecute(ref physOb_list); pmd.bodies = physOb_list.bodies.ToArray(); pmd.joints = physOb_list.joints.ToArray(); } else { pmd.bodies = new PMD_RBody[0]; pmd.joints = new PMD_Joint[0]; } }