/// 使うボーン対応表を結合して得ます。 public CorrespondTable GetCorrespondTable() { CorrespondTable cortable = new CorrespondTable(); List <string> names = new List <string>(); switch (BoneKind) { case CorrespondTableListBoneKind.man: names.Add("Man2Miku_Default"); break; case CorrespondTableListBoneKind.woman: names.Add("Girl2Miku_Default"); foreach (string name in Selection.Keys) { if (Selection[name]) { names.Add(name); } } break; } string source_path = GetSourcePath(); foreach (string name in names) { cortable.Load(Path.Combine(source_path, name)); } return(cortable); }
// ----------------------------------------------------- // 頂点を作成 // ----------------------------------------------------- private void MakePMDVertices(CorrespondTable cor_table, int mod_type) { List <PMD_Vertex> vertex_list = new List <PMD_Vertex>(); List <short> indices = new List <short>(); // インデックスリスト inList_indices.Clear(); // ----------------------------------------------------- // Tmoの変形を実行 fig.TPOList.Transform(); morph.Morph(fig.Tmo); fig.UpdateBoneMatricesWithoutTMOFrame(); // ----------------------------------------------------- // 情報をコピー int n_inList = -1; // list中のvertexの番号(処理の前に++するために、初期値は0でなく-1としている) int n_mesh = 0; int prevNumIndices = 0; int prevNumVertices = 0; foreach (TSOSubMesh sub_mesh in mesh_list) { int n_inMesh = -1; // mesh中のvertexの番号(処理の前に++するために、初期値は0でなく-1としている) int a = -1, b = -1, c = -1; // 隣合うインデックス Matrix[] clipped_boneMatrices = ClipBoneMatrices(sub_mesh, fig.Tmo); foreach (Vertex vertex in sub_mesh.vertices) { n_inList++; // list中のvertexの番号を一つ増やす n_inMesh++; // mesh中のvertexの番号を一つ増やす // Tmo中のBoneに従って、Mesh中の頂点位置及び法線ベクトルを置き換えて、書き出す Vector3 pos = Vector3.Empty; Vector3 nor = Vector3.Empty; foreach (SkinWeight sw in vertex.skin_weights) { Matrix m = clipped_boneMatrices[sw.bone_index]; // 頂点位置 pos += Vector3.TransformCoordinate(vertex.position, m) * sw.weight; // 法線ベクトル m.M41 = 0; m.M42 = 0; m.M43 = 0; nor += Vector3.TransformCoordinate(vertex.normal, m) * sw.weight; } // ----------------------------------------------------- // 頂点情報をコピー PMD_Vertex pmd_v = new PMD_Vertex(); pmd_v.vec3Pos = Trans.CopyPos(pos); pmd_v.vec3Normal = Trans.CopyPos(Vector3.Normalize(nor)); pmd_v.uvTex.u = vertex.u; pmd_v.uvTex.v = vertex.v; pmd_v.cbEdge = 0; // ----------------------------------------------------- // スキニング List <string> tmp_b = new List <string>(); List <float> tmp_w = new List <float>(); for (int i = 0; i < 4; i++) { TSONode tso_bone = sub_mesh.bones[(int)vertex.skin_weights[i].bone_index]; string bone_name; if (mod_type == 0 || mod_type == 1) { bone_name = cor_table.skinning[tso_bone.Name]; } else { bone_name = "センター"; } if (tmp_b.IndexOf(bone_name) < 0) { tmp_b.Add(bone_name); tmp_w.Add(vertex.skin_weights[i].weight); } else { tmp_w[tmp_b.IndexOf(bone_name)] += vertex.skin_weights[i].weight; } } float w0 = tmp_w.Max(); pmd_v.unBoneName[0] = tmp_b[tmp_w.IndexOf(w0)]; tmp_b.RemoveAt(tmp_w.IndexOf(w0)); tmp_w.RemoveAt(tmp_w.IndexOf(w0)); float w1; if (tmp_b.Count == 0) { w1 = 0.0f; pmd_v.unBoneName[1] = pmd_v.unBoneName[0]; } else { w1 = tmp_w.Max(); pmd_v.unBoneName[1] = tmp_b[tmp_w.IndexOf(w1)]; } pmd_v.cbWeight = (int)(w0 * 100 / (w0 + w1)); // ----------------------------------------------------- // 頂点リストに頂点を追加 // 重複している頂点がないかをチェックし、 // 存在すれば、そのインデックスを参照 // 存在しなければ、頂点リストに頂点を追加 int idx = -1; for (int i = prevNumVertices; i < vertex_list.Count; i++) { if (vertex_list[i].vec3Pos.x == pmd_v.vec3Pos.x && vertex_list[i].vec3Pos.y == pmd_v.vec3Pos.y && vertex_list[i].vec3Pos.z == pmd_v.vec3Pos.z && vertex_list[i].vec3Normal.x == pmd_v.vec3Normal.x && vertex_list[i].vec3Normal.y == pmd_v.vec3Normal.y && vertex_list[i].vec3Normal.z == pmd_v.vec3Normal.z && vertex_list[i].uvTex.u == pmd_v.uvTex.u && vertex_list[i].uvTex.v == pmd_v.uvTex.v) { idx = i; break; } } if (idx == -1) { vertex_list.Add(pmd_v); idx = vertex_list.Count - 1; inList_indices.Add(idx); } else { inList_indices.Add(-1); } // ----------------------------------------------------- // 頂点インデックス // 過去3つまでのインデックスを記憶しておく a = b; b = c; c = idx; // 隣合うインデックスが参照する頂点位置の重複を判定し、 // 重複している場合はインデックスの追加を省略する if ((n_inMesh >= 2) && !((vertex_list[a].vec3Pos.x == vertex_list[b].vec3Pos.x && vertex_list[a].vec3Pos.y == vertex_list[b].vec3Pos.y && vertex_list[a].vec3Pos.z == vertex_list[b].vec3Pos.z) || (vertex_list[b].vec3Pos.x == vertex_list[c].vec3Pos.x && vertex_list[b].vec3Pos.y == vertex_list[c].vec3Pos.y && vertex_list[b].vec3Pos.z == vertex_list[c].vec3Pos.z) || (vertex_list[c].vec3Pos.x == vertex_list[a].vec3Pos.x && vertex_list[c].vec3Pos.y == vertex_list[a].vec3Pos.y && vertex_list[c].vec3Pos.z == vertex_list[a].vec3Pos.z))) { if (n_inMesh % 2 == 0) { indices.Add((short)(c)); indices.Add((short)(b)); indices.Add((short)(a)); } else { indices.Add((short)(a)); indices.Add((short)(b)); indices.Add((short)(c)); } } } // meshごとのインデックス数を記録 material_list.material_list[n_mesh++].ulNumIndices = indices.Count - prevNumIndices; prevNumIndices = indices.Count; prevNumVertices = vertex_list.Count; } // ----------------------------------------------------- // リストを配列に代入し直す // 頂点情報 pmd.number_of_vertex = vertex_list.Count; pmd.pmd_vertex = (PMD_Vertex[])vertex_list.ToArray(); // 頂点インデックス pmd.number_of_indices = indices.Count; pmd.indices_array = (short[])indices.ToArray(); // マテリアル if (merge_flag == true) { material_list.MergeMaterials(); } pmd.number_of_materials = material_list.material_list.Count; pmd.pmd_material = (PMD_Material[])material_list.material_list.ToArray(); // Toonテクスチャファイル名 pmd.toon_file_name = material_list.GetToonFileNameList(); }
// ----------------------------------------------------- // 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(""); }
// ----------------------------------------------------- // 頂点を作成 // ----------------------------------------------------- private void MakePMDVertices(CorrespondTable cor_table, int mod_type) { List <PMD_Vertex> vertices = new List <PMD_Vertex>(); List <int> indices = new List <int>(); Dictionary <string, short> bone_name_idmap = new Dictionary <string, short>(); { short i = 0; foreach (PMD_Bone node in pmd.nodes) { bone_name_idmap[node.name] = i++; } } inList_indices.Clear(); // ----------------------------------------------------- // Tmoの変形を実行 fig.TPOList.Transform(); morph.Morph(fig.Tmo); fig.UpdateBoneMatricesWithoutTMOFrame(); // ----------------------------------------------------- // 情報をコピー int n_inList = -1; // list中のvertexの番号(処理の前に++するために、初期値は0でなく-1としている) int n_mesh = 0; int prevNumIndices = 0; int prevNumVertices = 0; foreach (TSOSubMesh sub_mesh in meshes) { int n_inMesh = -1; // mesh中のvertexの番号(処理の前に++するために、初期値は0でなく-1としている) int a = -1, b = -1, c = -1; // 隣合うインデックス Matrix[] clipped_boneMatrices = ClipBoneMatrices(sub_mesh, fig.Tmo); foreach (Vertex vertex in sub_mesh.vertices) { n_inList++; // list中のvertexの番号を一つ増やす n_inMesh++; // mesh中のvertexの番号を一つ増やす // Tmo中のBoneに従って、Mesh中の頂点位置及び法線ベクトルを置き換えて、書き出す Vector3 pos = Vector3.Empty; Vector3 nor = Vector3.Empty; foreach (SkinWeight sw in vertex.skin_weights) { Matrix m = clipped_boneMatrices[sw.bone_index]; // 頂点位置 pos += Vector3.TransformCoordinate(vertex.position, m) * sw.weight; // 法線ベクトル m.M41 = 0; m.M42 = 0; m.M43 = 0; nor += Vector3.TransformCoordinate(vertex.normal, m) * sw.weight; } // ----------------------------------------------------- // 頂点情報をコピー PMD_Vertex pmd_v = new PMD_Vertex(); pmd_v.position = Trans.CopyPos(pos); pmd_v.normal = Trans.CopyPos(Vector3.Normalize(nor)); pmd_v.u = vertex.u; pmd_v.v = vertex.v; // ----------------------------------------------------- // スキニング if (cor_table != null) { for (int i = 0; i < 4; i++) { TSONode tso_bone = sub_mesh.bones[vertex.skin_weights[i].bone_index]; string bone_name = cor_table.skinning[tso_bone.Name]; pmd_v.skin_weights[i].bone_index = bone_name_idmap[bone_name]; pmd_v.skin_weights[i].weight = vertex.skin_weights[i].weight; } } else { pmd_v.skin_weights[0].bone_index = 0; pmd_v.skin_weights[0].weight = 1.0f; } // ----------------------------------------------------- // 頂点リストに頂点を追加 // 重複している頂点がないかをチェックし、 // 存在すれば、そのインデックスを参照 // 存在しなければ、頂点リストに頂点を追加 int idx = -1; for (int i = prevNumVertices; i < vertices.Count; i++) { if (vertices[i].position == pmd_v.position && vertices[i].normal == pmd_v.normal && vertices[i].u == pmd_v.u && vertices[i].v == pmd_v.v) { idx = i; break; } } if (idx == -1) { vertices.Add(pmd_v); idx = vertices.Count - 1; inList_indices.Add(idx); } else { inList_indices.Add(-1); } // ----------------------------------------------------- // 頂点インデックス // 過去3つまでのインデックスを記憶しておく a = b; b = c; c = idx; // 隣合うインデックスが参照する頂点位置の重複を判定し、 // 重複している場合はインデックスの追加を省略する if ((n_inMesh >= 2) && !(vertices[a].position == vertices[b].position || vertices[b].position == vertices[c].position || vertices[c].position == vertices[a].position)) { if (n_inMesh % 2 == 0) { indices.Add(c); indices.Add(b); indices.Add(a); } else { indices.Add(a); indices.Add(b); indices.Add(c); } } } // meshごとのインデックス数を記録 material_list.materials[n_mesh++].vindices_count = indices.Count - prevNumIndices; prevNumIndices = indices.Count; prevNumVertices = vertices.Count; } // ----------------------------------------------------- // リストを配列に代入し直す // 頂点情報 pmd.vertices = vertices.ToArray(); // 頂点インデックス pmd.vindices = indices.ToArray(); // マテリアル if (UniqueMaterial) { material_list.UniqueMaterials(); } pmd.texture_file_names = material_list.GetTextureFileNameList(); pmd.materials = material_list.materials.ToArray(); }