void AssignSkinWeights(MqoVert vertex) { if (vertex == null) { return; } lvSkinWeights.BeginUpdate(); lvSkinWeights.Items.Clear(); foreach (MqoSkinWeight skin_weight in vertex.skin_weights) { TSONode bone = skin_weight.bone; float weight = skin_weight.weight; if (weight == 0.0f) { continue; } ListViewItem li = new ListViewItem(bone.Name); li.SubItems.Add(weight.ToString("F3")); li.Tag = skin_weight; lvSkinWeights.Items.Add(li); } lvSkinWeights.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); lvSkinWeights.EndUpdate(); }
private void btnPosUpdate_Click(object sender, EventArgs e) { TSONode node = viewer.SelectedNode; if (node == null) { return; } float x1 = float.Parse(edNodePosX.Text); float y1 = float.Parse(edNodePosY.Text); float z1 = float.Parse(edNodePosZ.Text); Vector3 p1 = new Vector3(x1, y1, z1); viewer.BeginNodeCommand(); Matrix m = Matrix.Identity; if (node.parent != null) { m = Matrix.Invert(node.parent.GetWorldCoordinate()); } Vector3 local = Vector3.TransformCoordinate(p1, m); node.Translation = local; viewer.EndNodeCommand(); UpdateSelectedNodeLocalPos(); UpdateSelectedNodeSub(); Invalidate(false); }
private void btnLocalPosUpdate_Click(object sender, EventArgs e) { TSONode node = viewer.SelectedNode; if (node == null) { return; } float x1 = float.Parse(edNodeLocalPosX.Text); float y1 = float.Parse(edNodeLocalPosY.Text); float z1 = float.Parse(edNodeLocalPosZ.Text); Vector3 p1 = new Vector3(x1, y1, z1); viewer.BeginNodeCommand(); node.Translation = p1; viewer.EndNodeCommand(); UpdateSelectedNodePos(); UpdateSelectedNodeSub(); Invalidate(false); }
public void UpdateSelectedNodeLocalPos() { TSONode node = viewer.SelectedNode; Vector3 local = node.Translation; UpdateNodeLocalPos(local); }
public void UpdateSelectedNodePos() { TSONode node = viewer.SelectedNode; Vector3 world = node.GetWorldPosition(); UpdateNodePos(world); }
public void UpdateSelectedNodeSub() { TSONode node = viewer.SelectedNode; Vector3 world = node.GetWorldPosition(); Vector3 local = Vector3.TransformCoordinate(world, node.offset_matrix); UpdateNodeSub(local); }
private Matrix[] ClipBoneMatrices(TSOSubMesh sub_mesh, TMOFile tmo) { Matrix[] clipped_boneMatrices = new Matrix[sub_mesh.maxPalettes]; for (int numPalettes = 0; numPalettes < sub_mesh.maxPalettes; numPalettes++) { TSONode tso_node = sub_mesh.GetBone(numPalettes); TMONode tmo_node = tmo.FindNodeByName(tso_node.Name); clipped_boneMatrices[numPalettes] = tso_node.OffsetMatrix * tmo_node.combined_matrix; } return(clipped_boneMatrices); }
private void lvNodes_SelectedIndexChanged(object sender, EventArgs e) { TSONode node = GetSelectedNode(); if (node == null) { return; } Debug.WriteLine("selected " + node.Name); }
private static string GetReconPath(TSONode node) { if (node.parent != null) { return(GetReconPath(node.parent) + "|" + node.Name); } else { return("|" + node.Name); } }
public TSONode GetSelectedNode() { if (lvNodes.SelectedItems.Count == 0) { return(null); } ListViewItem li = lvNodes.SelectedItems[0]; TSONode node = li.Tag as TSONode; return(node); }
private void cameraSelectedBoneToolStripMenuItem_Click(object sender, EventArgs e) { TSONode node = viewer.SelectedNode; if (node == null) { return; } viewer.Camera.Center = node.GetWorldPosition(); viewer.Camera.ResetTranslation(); Invalidate(false); }
static void Smooth() { int len = use_nodes.Count; TSONode[] nodes = new TSONode[len]; Vector3[] node_world_positions = new Vector3[len]; for (int i = 0; i < len; i++) { node_world_positions[i] = use_nodes[i].GetWorldPosition(); } float[] distances = new float[len]; float[] inv_distances = new float[len]; foreach (UnifiedPositionVertex v in unified_position_vert_heap.ary) { for (int i = 0; i < len; i++) { nodes[i] = use_nodes[i]; } //頂点vに対して距離が近い順に並べたnodesを得る。 for (int i = 0; i < len; i++) { distances[i] = LengthSq(v.position, node_world_positions[i]); } Array.Sort(distances, nodes); for (int i = 0; i < 4; i++) { inv_distances[i] += 1.0f / distances[i]; } //平方距離の逆数の合計 float sum_inv_distances = 0.0f; for (int i = 0; i < 4; i++) { sum_inv_distances += inv_distances[i]; } //平方距離の逆数の割合をweightとする。 for (int i = 0; i < 4; i++) { v.skin_weights[i].bone_index = nodes[i].ID; v.skin_weights[i].weight = inv_distances[i] / sum_inv_distances; } } }
public void UpdateSelectedNodeControls() { TSONode node = viewer.SelectedNode; if (node == null) { ClearNodeControls(); return; } lbNodeName.Text = node.Name; Vector3 local = node.Translation; UpdateNodeLocalPos(local); Vector3 world = node.GetWorldPosition(); UpdateNodePos(world); local = Vector3.TransformCoordinate(world, node.offset_matrix); UpdateNodeSub(local); }
// ----------------------------------------------------- // 頂点を作成 // ----------------------------------------------------- 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 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(); }
static void Main(string[] args) { if (args.Length < 1) { Console.WriteLine("TSOSmooth.exe <tso file>"); return; } string source_file = args[0]; TSOFile tso = new TSOFile(); tso.Load(source_file); Dictionary <string, TSONode> nodemap = new Dictionary <string, TSONode>(); foreach (TSONode node in tso.nodes) { nodemap.Add(node.Name, node); } string[] nodesets = GetSetsNames().ToArray(); Console.WriteLine("nodesets:"); { int i = 0; foreach (string name in nodesets) { Console.WriteLine("{0} {1}", i, name); i++; } } Console.Write("nodesetsを選択 (0-{0}): ", nodesets.Length - 1); int sets_idx = 0; { string line = Console.ReadLine(); if (line.Length != 0) { try { sets_idx = int.Parse(line); } catch (System.FormatException e) { Console.WriteLine(e); return; } } } setsname = nodesets[sets_idx]; char[] delim = { ' ' }; using (StreamReader source = new StreamReader(File.OpenRead(GetSetsPath()))) { string line; while ((line = source.ReadLine()) != null) { string[] tokens = line.Split(delim); string op = tokens[0]; if (op == "node") { Debug.Assert(tokens.Length == 2, "tokens length should be 2: " + line); string cnode_name = tokens[1]; TSONode cnode = nodemap[cnode_name]; use_nodes.Add(cnode); } } } Console.WriteLine("メッシュ:"); { int i = 0; foreach (TSOMesh mesh in tso.meshes) { Console.WriteLine("{0} {1}", i, mesh.Name); i++; } } Console.Write("メッシュを選択 (0-{0}): ", tso.meshes.Length - 1); int mesh_idx = 0; { string line = Console.ReadLine(); if (line.Length != 0) { try { mesh_idx = int.Parse(line); } catch (System.FormatException e) { Console.WriteLine(e); return; } } } TSOMesh selected_mesh = null; try { selected_mesh = tso.meshes[mesh_idx]; } catch (IndexOutOfRangeException e) { Console.WriteLine(e); return; } Console.WriteLine("サブメッシュ:"); Console.WriteLine(" vertices bone_indices"); Console.WriteLine(" -------- ------------"); foreach (TSOSubMesh sub in selected_mesh.sub_meshes) { Console.WriteLine(" {0,8} {1,12}", sub.vertices.Length, sub.bone_indices.Length); } int max_palettes = 16; RebuildMesh(selected_mesh, max_palettes); string dest_path = Path.GetDirectoryName(source_file); string dest_file = Path.GetFileNameWithoutExtension(source_file) + @".new.tso"; dest_path = Path.Combine(dest_path, dest_file); Console.WriteLine("Save File: " + dest_path); tso.Save(dest_path); }