// ----------------------------------------------------- // 頂点を作成 // ----------------------------------------------------- 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(); }
// 表情モーフを設定 private void MakePMDFaces() { int n_vertex = 0; // 表情の頂点の番号(通し番号) int n_inList = -1; // list中のvertexの番号(処理の前に++するために、初期値は0でなく-1としている) // ----------------------------------------------------- // 表情情報(base以外) // ----------------------------------------------------- List <Vector3[]> verPos_face = new List <Vector3[]>(); foreach (TSOSubMesh sub_mesh in mesh_list) { int n_inMesh = -1; // mesh中のvertexの番号(処理の前に++するために、初期値は0でなく-1としている) verPos_face.Clear(); // 前回の分を消去 foreach (MorphGroup mg in morph.Groups) { foreach (Morph mi in mg.Items) { // 現在のモーフを有効にする mi.Ratio = 1.0f; // モーフ変形を実行 fig.TPOList.Transform(); morph.Morph(fig.Tmo); fig.UpdateBoneMatricesWithoutTMOFrame(); // 現在のモーフを無効にする mi.Ratio = 0.0f; Matrix[] clipped_boneMatrices_for_morphing = ClipBoneMatrices(sub_mesh, fig.Tmo); // Tmo(各表情に対応する)中のBoneに従って、Mesh中の頂点位置を置き換える Vector3[] output_v = new Vector3[sub_mesh.vertices.Length]; int n = 0; foreach (Vertex vertex in sub_mesh.vertices) { Vector3 pos = Vector3.Empty; Vector3 nor = Vector3.Empty; foreach (SkinWeight sw in vertex.skin_weights) { // 頂点位置 Matrix m = clipped_boneMatrices_for_morphing[sw.bone_index]; pos += Vector3.TransformCoordinate(vertex.position, m) * sw.weight; } output_v[n++] = pos; } verPos_face.Add(output_v); } // モーフ変形を初期化する fig.TPOList.Transform(); morph.Morph(fig.Tmo); fig.UpdateBoneMatricesWithoutTMOFrame(); } foreach (Vertex vertex in sub_mesh.vertices) { n_inList++; // list中のvertexの番号を一つ増やす n_inMesh++; // mesh中のvertexの番号を一つ増やす int idx = inList_indices[n_inList]; if (idx == -1) { continue; } PMD_Vertex pmd_v = pmd.pmd_vertex[idx]; // 表情に関連するboneに影響を受ける頂点であれば、情報を記憶する foreach (SkinWeight skin_w in vertex.skin_weights) { // 表情に関連するboneに影響を受ける頂点であれば、表情用の頂点とする if (FACE_BONE_MIN <= sub_mesh.bone_indices[skin_w.bone_index] && sub_mesh.bone_indices[skin_w.bone_index] <= FACE_BONE_MAX) { // 表情の頂点情報(base以外) for (int i = 1; i < pmd.number_of_face; i++) { // 表情用の頂点の番号(baseの番号。skin_vert_index) pmd.pmd_face[i].pVertices[n_vertex].ulIndex = n_vertex; // bace以外は相対位置で指定 MmdVector3 pmd_face_pos = Trans.CopyPos(verPos_face[i - 1][n_inMesh]); pmd.pmd_face[i].pVertices[n_vertex].vec3Pos.x = pmd_face_pos.x - pmd_v.vec3Pos.x; pmd.pmd_face[i].pVertices[n_vertex].vec3Pos.y = pmd_face_pos.y - pmd_v.vec3Pos.y; pmd.pmd_face[i].pVertices[n_vertex].vec3Pos.z = pmd_face_pos.z - pmd_v.vec3Pos.z; } n_vertex++; break; } } } } }
// ----------------------------------------------------- // 頂点を作成 // ----------------------------------------------------- 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(); }