internal void CreateVertices() { Heap <MqoVert> mh = new Heap <MqoVert>(); foreach (TSOSubMesh sub_mesh in mesh.sub_meshes) { int cnt = 0; ushort a, b = 0, c = 0; MqoVert ma, mb = new MqoVert(), mc = new MqoVert(); foreach (Vertex v in sub_mesh.vertices) { MqoVert m = new MqoVert(v.position, v.normal, null); ushort i; if (mh.map.TryGetValue(m, out i)) { //集約先はidx=i m = mh.ary[i]; } else { m.skin_weights = new MqoSkinWeight[4]; for (int w = 0; w < 4; w++) { m.skin_weights[w] = new MqoSkinWeight(sub_mesh.GetBone(v.skin_weights[w].bone_index), v.skin_weights[w].weight); } //mはidx=iになる i = (ushort)mh.Count; mh.Add(m); } //集約する m.rel.Add(new TSOPair(v, sub_mesh)); cnt++; a = b; b = c; c = i; ma = mb; mb = mc; mc = m; m.Index = i; graph.AddNode(m); if (cnt < 3) { continue; } if (a != b && b != c && c != a) { graph.AddEdge(new MqoEdge(a, b, GetCost(ma, mb))); graph.AddEdge(new MqoEdge(b, c, GetCost(mb, mc))); graph.AddEdge(new MqoEdge(c, a, GetCost(mc, ma))); } } } vertices = mh.ary.ToArray(); }
/// 頂点操作を生成します。 public VertexCommand(TSOFile tso, TSONode selected_node, MqoVert vertex, float weight, WeightOperation weight_op) { this.tso = tso; this.selected_node = selected_node; this.vertex = vertex; this.weight = weight; this.weight_op = weight_op; }
internal static float GetCost(MqoVert ma, MqoVert mb) { float dx = mb.position.X - ma.position.X; float dy = mb.position.Y - ma.position.Y; float dz = mb.position.Z - ma.position.Z; return(dx * dx + dy * dy + dz * dz); }
public bool Equals(MqoVert o) { if ((object)o == null) { return(false); } return(position.Equals(o.position) && normal.Equals(o.normal)); }
public override bool Equals(object obj) { if (obj is MqoVert) { MqoVert o = (MqoVert)obj; return(position.Equals(o.position) && normal.Equals(o.normal)); } return(false); }
//選択ボーンに対応するウェイトを検索して保持する。 public void FindWeight(MqoVert v) { foreach (MqoSkinWeight skin_weight in v.skin_weights) { if (skin_weight.bone == selected_node) { weits[v.Index] = skin_weight.weight; break; } } }
//選択ボーンに対応するウェイトを補間して保持する。 public void SmoothWeight(MqoVert v) { float total_weit = 0; float total = 0; foreach (MqoEdge edge in mqo_mesh.graph.edges[v.Index]) { float weit = weits[edge.To]; float factor = 1.0f / edge.Cost; total_weit += weit * factor; total += factor; } float new_weit = total_weit / total; float cur_weit = weits[v.Index]; new_weits[v.Index] = (new_weit + cur_weit) * 0.5f; }
Rectangle GetRectOnDotWeit(MqoVert v) { int x = 0; int y = 0; if (v.selected) { if (v.factor == 1.0f) { x = 4; y = 3; } else { int n = (int)(v.factor * 20.0f) % 20; x = n % 5; y = n / 5; } } return(new Rectangle(x * 8, y * 8, 7, 7)); }
/// 頂点を描画する。 void DrawVertices(MqoMesh mqo_mesh) { CalcSkindeform(); Rectangle rect = new Rectangle(0, 0, 7, 7);//red Vector3 rect_center = new Vector3(3, 3, 0); switch (vertex_selection_mode) { case VertexSelectionMode.AllVertices: { if (selected_vertex != null) { sprite.Begin(SpriteFlags.None); foreach (MqoVert v in mqo_mesh.vertices) { if (HiddenVert(v)) { continue; } rect = GetRectOnDotWeit(v); Vector3 p2 = GetVertPositionOnScreen(v); p2.Z = 0.0f; sprite.Draw(dotweit_texture, rect, rect_center, p2, Color.White); } sprite.End(); } else { sprite.Begin(SpriteFlags.None); foreach (MqoVert v in mqo_mesh.vertices) { if (HiddenVert(v)) { continue; } Vector3 p2 = GetVertPositionOnScreen(v); p2.Z = 0.0f; sprite.Draw(dotweit_texture, rect, rect_center, p2, Color.White); } sprite.End(); } } break; case VertexSelectionMode.CcwVertices: { bool[] ccws = CreateCcws(mqo_mesh); if (selected_vertex != null) { sprite.Begin(SpriteFlags.None); for (int i = 0; i < mqo_mesh.vertices.Length; i++) { if (!ccws[i]) { continue; } MqoVert v = mqo_mesh.vertices[i]; if (HiddenVert(v)) { continue; } rect = GetRectOnDotWeit(v); Vector3 p2 = GetVertPositionOnScreen(v); p2.Z = 0.0f; sprite.Draw(dotweit_texture, rect, rect_center, p2, Color.White); } sprite.End(); } else { sprite.Begin(SpriteFlags.None); for (int i = 0; i < mqo_mesh.vertices.Length; i++) { if (!ccws[i]) { continue; } MqoVert v = mqo_mesh.vertices[i]; if (HiddenVert(v)) { continue; } Vector3 p2 = GetVertPositionOnScreen(v); p2.Z = 0.0f; sprite.Draw(dotweit_texture, rect, rect_center, p2, Color.White); } sprite.End(); } } break; case VertexSelectionMode.None: break; } }
Vector3 GetVertPositionOnScreen(MqoVert v) { return(WorldToScreen(v.deformed_position)); }
bool HiddenVert(MqoVert v) { Vector3 view_position = Vector3.TransformCoordinate(v.deformed_position, Transform_View); return(view_position.Z > 0.0f); }
/// 頂点を選択します。 /// returns: 頂点を見つけたかどうか public bool SelectVertex() { bool found = false; if (SelectedMesh != null) { //スクリーン座標から頂点を見つけます。 //衝突する頂点の中で最も近い位置にある頂点を返します。 float x = lastScreenPoint.X; float y = lastScreenPoint.Y; int width = 3;//頂点ハンドルの幅 float min_z = 1e12f; MqoVert found_vertex = null; MqoMesh mqo_mesh = MqoMesh.FromTSOMesh(SelectedMesh); CalcSkindeform(); switch (vertex_selection_mode) { case VertexSelectionMode.AllVertices: { for (int i = 0; i < mqo_mesh.vertices.Length; i++) { MqoVert v = mqo_mesh.vertices[i]; Vector3 p2 = GetVertPositionOnScreen(v); if (p2.X - width <= x && x <= p2.X + width && p2.Y - width <= y && y <= p2.Y + width) { if (p2.Z < min_z) { min_z = p2.Z; found = true; found_vertex = v; } } } } break; case VertexSelectionMode.CcwVertices: { bool[] ccws = CreateCcws(mqo_mesh); for (int i = 0; i < mqo_mesh.vertices.Length; i++) { if (!ccws[i]) { continue; } MqoVert v = mqo_mesh.vertices[i]; Vector3 p2 = GetVertPositionOnScreen(v); if (p2.X - width <= x && x <= p2.X + width && p2.Y - width <= y && y <= p2.Y + width) { if (p2.Z < min_z) { min_z = p2.Z; found = true; found_vertex = v; } } } } break; case VertexSelectionMode.None: break; } // if (found) { selected_vertex = found_vertex; SelectVertices(); if (SelectedVertexChanged != null) { SelectedVertexChanged(this, EventArgs.Empty); } } } return(found); }