public static int FindUsingBone(IPXBone b, IPXVertex v) { if (v.Bone1.Equals(b)) { return(0); } if (v.Bone2 == null) { return(-1); } if (v.Bone2.Equals(b)) { return(1); } if (v.Bone3 == null) { return(-1); } if (v.Bone3.Equals(b)) { return(2); } if (v.Bone4 == null) { return(-1); } if (v.Bone4.Equals(b)) { return(3); } return(-1); }
private static void writeBoneNode( Node node, NodeInfo info, StreamWriter writer) { IPXBone bone = (IPXBone)node.pmxElement; string shape = NodeConfig.determineShape(info); string color = NodeConfig.determineColor(info); string style = NodeConfig.determineStyle(info); int index = boneIndexDict[bone]; string nodeLabel = string.Format("{0:D}: {1}", index, bone.Name); string bodyLabel = null; if (info.hasAttr("物理演算")) { bodyLabel = info.getAttr("物理演算"); } else if (info.hasAttr("ボーン追従")) { bodyLabel = info.getAttr("ボーン追従"); } string label = null == bodyLabel ? "\"" + nodeLabel + "\"": "\"" + nodeLabel + "\\n(" + bodyLabel + ")\""; writer.WriteLine(string.Format( "{0} [shape={1}, label={2}, style =\"{3}\"," + "fillcolor=\"{4}\"];", node.id, shape, label, style, color)); }
private static Node makeBoneNode(IPXBone bone) { int index = boneIndexDict[bone]; string boneID = "BONE_" + index.ToString(); return(new Node(boneID, bone)); }
// ボーン(ノード)の属性を設定する private static void updateNodeAttrs(BoneGraph g) { foreach (Node node in g.nodes) { NodeInfo info = g.directedEdges[node].Item1; IPXBone bone = (IPXBone)node.pmxElement; if (bone.IsIK) { info.setAttr("IKボーン", ""); } if (bone.Controllable) { info.setAttr("操作可能", ""); } else { info.setAttr("操作不可能", ""); } if (bone.Visible) { info.setAttr("表示", ""); } else { info.setAttr("非表示", ""); } if (bone2bodies.ContainsKey(bone)) { string bodytext = ""; bool first = true; bool dyn = false; foreach (IPXBody body in bone2bodies[bone]) { int bodyIndex = bodyIndexDict[body]; if (!first) { bodytext += ", "; } bodytext += String.Format("{0:D}: {1}", bodyIndex, body.Name); if (BodyMode.Dynamic == body.Mode || BodyMode.DynamicWithBone == body.Mode) { dyn = true; } first = false; } if (dyn) { info.setAttr("物理演算", bodytext); } else { info.setAttr("ボーン追従", bodytext); } } } }
private float DistortedDist(IPXBone bone, IPXVertex vertex) { var dist = BoneLocalVerticePosition(bone, vertex); dist.X *= space.X; dist.Y *= space.Y; dist.Z *= space.Z; return(dist.Length()); }
private void TestMoveVertice(IPXBone selBone) { for (int v = 0; v < Pmx.Vertex.Count; v++) { var item = Pmx.Vertex[v]; Vector3 vector3 = BoneLocalVerticePosition(selBone, item); item.Position = vector3; } }
private static BoneGraph makeBoneGraph(IPXPmx pmx) { BoneGraph boneGraph = new BoneGraph(); foreach (IPXBone bone in pmx.Bone) { Node boneNode = makeBoneNode(bone); /////////// // 4 種類のエッジを作成する // (1) 親 -> 子 (type=親子) // (2) 付与親 -> 子 (type=付与親) // (2) IKボーン -> IKターゲットボーン (type=IKターゲット) // (3) IKボーン -> IKリンクボーン (type=IKリンク) boneGraph.addNode(boneNode); // 4種に当てはまらないボーン用 // (1) IPXBone parentBone = bone.Parent; if (null != parentBone) { Node parentNode = makeBoneNode(parentBone); EdgeInfo info = new EdgeInfo(boneNode, "親子"); boneGraph.addEdge(parentNode, info); } // (2) if (null != bone.AppendParent && (bone.IsAppendRotation || bone.IsAppendTranslation)) { Node appendNode = makeBoneNode(bone.AppendParent); EdgeInfo info = new EdgeInfo(boneNode, "付与親"); info.setAttr( "weight", string.Format("{0:F3}", bone.AppendRatio)); boneGraph.addEdge(appendNode, info); } // (3), (4) if (bone.IsIK && null != bone.IK) { if (null != bone.IK.Target) { Node targetNode = makeBoneNode(bone.IK.Target); EdgeInfo targetInfo = new EdgeInfo( targetNode, "IKターゲット"); boneGraph.addEdge(boneNode, targetInfo); } foreach (IPXIKLink ikLink in bone.IK.Links) { Node linkNode = makeBoneNode(ikLink.Bone); EdgeInfo linkInfo = new EdgeInfo( linkNode, "IKリンク"); boneGraph.addEdge(boneNode, linkInfo); } } } return(boneGraph); }
public static void SetTargetPosition(IPXBone bone, V3 pos) { if (bone.ToBone != null) { bone.ToBone.Position = pos; } else { bone.ToOffset = pos - bone.Position; } }
private IEnumerable <int> VertexIndiceInRange(IPXBone selBone, float range) { for (int v = 0; v < Pmx.Vertex.Count; v++) { var item = Pmx.Vertex[v]; Vector3 vector3 = BoneLocalVerticePosition(selBone, item); vector3.Z *= 0.2f; if (vector3.Length() < range) { yield return(v); } } }
//public static V3 public static V3 TargetPosition(IPXBone bone) { var worldBoneTarget = new V3(); if (bone.ToBone != null) { worldBoneTarget = bone.ToBone.Position; } else { worldBoneTarget = bone.Position + bone.ToOffset; } return(worldBoneTarget); }
private Vector3 BoneLocalVerticePosition(IPXBone selBone, IPXVertex item) { var pos = PmxUtil.BoneAttitude(selBone); pos.Decompose(out Vector3 scale, out Quaternion rot, out Vector3 loc); rot = Quaternion.Invert(rot); //foreach (var item in Pmx.Vertex) { // なんかpositionなくなる //item.Position -= selBone.Position; //Vector4 vector4 = Vector3.Transform(item.Position, Matrix.RotationAxis(rot.Axis, rot.Angle)); //item.Position = new V3(vector4.X, vector4.Y, vector4.Z); var tmp = item.Position - selBone.Position; Vector4 vector4 = Vector3.Transform(tmp, Matrix.RotationAxis(rot.Axis, rot.Angle)); return(new V3(vector4.X, vector4.Y, vector4.Z)); } }
public void Do() { foreach (var bone in Bones) { IPXBone createdBone = bone.Clone() as IPXBone; bone.Name += "R"; bone.NameE += "R"; bone.AppendParent = createdBone; bone.AppendRatio = 1; bone.IsAppendLocal = false; bone.IsAppendRotation = true; bone.IsAppendTranslation = true; Pmx.Bone.Insert(Pmx.Bone.IndexOf(bone), createdBone); } }
public static Matrix BoneAttitude(IPXBone bone) { V3 worldBoneTarget = TargetPosition(bone); var toward = worldBoneTarget - bone.Position; toward.Normalize(); var up = Vector3.UnitY; if (Vector3.Dot(up, toward) > 0.8) { up = Vector3.UnitX; } //Matrix right = Matrix.LookAtRH(bone.Position, worldBoneTarget, up); Matrix right = LookAt(bone.Position, worldBoneTarget, up); right.Decompose(out Vector3 scale, out Quaternion rot, out Vector3 loc); return(Matrix.Translation(bone.Position) * right); }
// Generate straight bone chain public static IPXBone[] GenerateChain(IPXPmxBuilder builder, int count, Vector3 distance, Vector3 center, string name, string nameE) { IPXBone[] bones = new IPXBone[count]; for (int i = 0; i < count; ++i) { IPXBone bone = builder.Bone(); bone.Name = name.Replace("#", i.ToString()).Replace("&", (i + 1).ToString()); bone.NameE = nameE.Replace("#", i.ToString()).Replace("&", (i + 1).ToString()); bone.Position = center + (distance * i); if (i > 0) { bone.Parent = bones[i - 1]; bone.Parent.ToBone = bone; } bones[i] = bone; } return(bones); }
public float getDistanceBoneToVertex(IPXBone bone, IPXVertex vertex) { if (bone.ToBone != null) { V3 from = (V3)bone.Position; V3 to = (V3)bone.ToBone.Position; V3 v = (V3)vertex.Position; float d1, d2, d3; d1 = (v - from).Length(); d2 = (v - to).Length(); V3 line = to - from; V3 dif = v - from; if (line.Length() > 0.00001f) { d3 = (Cross(line, dif)).Length() / line.Length(); } else { d3 = 100000f; } if (line.Length() > 0) { float difDot = Dot(line, dif) / line.Length(); //垂線の足がボーン上 if (difDot > 0 && difDot < line.Length()) { return(Math.Min(d1, Math.Min(d2, d3))); } } return(Math.Min(d1, d2)); } else { V3 dif = (V3)((V3)vertex.Position - (V3)bone.Position); return(dif.Length()); } }
public float getDistanceBoneToVertex(IPXBone bone, IPXVertex vertex) { if (bone.ToBone != null) { V3 from = (V3)bone.Position; V3 to = (V3)bone.ToBone.Position; V3 v = (V3)vertex.Position; float d1, d2, d3; d1 = (v - from).Length(); d2 = (v - to).Length(); V3 line = to - from; V3 dif = v - from; if (line.Length() > 0.00001f) { d3 = (Cross(line, dif)).Length() / line.Length(); } else { d3 = 100000f; } if (line.Length() > 0) { float difDot = Dot(line, dif) / line.Length(); //垂線の足がボーン上 if (difDot > 0 && difDot < line.Length()) { return Math.Min(d1, Math.Min(d2, d3)); } } return Math.Min(d1, d2); } else { V3 dif = (V3)((V3)vertex.Position - (V3)bone.Position); return dif.Length(); } }
public static float BoneWeight(IPXBone b, IPXVertex v) { int usingBone = FindUsingBone(b, v); if (usingBone == 0) { return(v.Weight1); } if (usingBone == 1) { return(v.Weight2); } if (usingBone == 2) { return(v.Weight3); } if (usingBone == 3) { return(v.Weight4); } return(0); }
// Create segmented bone chain public static IPXBone[] GenerateSegmentedChain(IPXPmxBuilder builder, int count, Vector3[] points, string name, string nameE) { IPXBone[] bones = new IPXBone[count]; int segmentCount = points.Length - 1; float totalLength = 0; float[] segmentLengths = new float[segmentCount]; // Determine the lengths of segments for (int i = 0; i < segmentCount; ++i) { float length = points[i].Distance(points[i + 1]); segmentLengths[i] = length; totalLength += length; } // Determine the number of links that can fit into each segment float avgDist = totalLength / count; int[] bonesPerSegment = new int[segmentCount]; int remaining = count; for (int i = 0; i < segmentCount - 1; ++i) { bonesPerSegment[i] = Mathf.RoundToInt(segmentLengths[i] / avgDist); remaining -= bonesPerSegment[i]; } // Put any remaining bones into the last segment bonesPerSegment[segmentCount - 1] = remaining; // Create the bones for (int i = 0; i < segmentCount; ++i) { System.Windows.Forms.MessageBox.Show($"{i}\t{segmentLengths[i]}"); } return(bones); }
private void buttonRun_Click(object sender, EventArgs e) { var selectedMaterialID = listBoxMaterial.SelectedIndex - 1; if (selectedMaterialID < 0) { MessageBox.Show("ウェイト転写対象の材質を選択してください。"); return; } if (comboBoxBone.SelectedIndex < 0) { MessageBox.Show("ウェイト対象のボーンを選択してください。"); return; } pmx = args.Host.Connector.Pmx.GetCurrentState(); IPXMaterial targetMaterial = pmx.Material[selectedMaterialID]; IPXBone targetBone = pmx.Bone[comboBoxBone.SelectedIndex]; var mesh = new PXMesh(targetMaterial); for (int i = 0; i < mesh.Vertices.Count; i++) { IPXVertex v = mesh.Vertices[i]; (IPXBone bone, float weight)bw = (targetBone, GetPointColor(v).R / 255f); var vertexWB = Utility.GetWeights(v); //頂点のウェイトを編集 vertexWB.RemoveAll(w => w.bone == bw.bone); Utility.NormalizeWeights(vertexWB, 1 - bw.weight); vertexWB.Add(bw); Utility.SetVertexWeights(vertexWB, ref v); } Utility.Update(args.Host.Connector, pmx, PmxUpdateObject.Vertex); MessageBox.Show("完了"); }
// Create uneven bone chain along spline public static IPXBone[] GenerateSplineChain(IPXPmxBuilder builder, int count, Vector3[] points, string name, string nameE) { IPXBone[] bones = new IPXBone[count]; // Construct a cubic Bézier curve from the points // Place a link at every t = (1 / count) point float dt = 1.0f / count; for (int i = 0; i < count; ++i) { IPXBone bone = builder.Bone(); bone.Name = name.Replace("#", i.ToString()).Replace("&", (i + 1).ToString()); bone.NameE = nameE.Replace("#", i.ToString()).Replace("&", (i + 1).ToString()); bone.Position = Mathf.Curve.BezierPoint(dt * i, points); if (i > 0) { bone.Parent = bones[i - 1]; bone.Parent.ToBone = bone; } bones[i] = bone; } return(bones); }
//--------------------------------------------------------------------- // IK関連 //--------------------------------------------------------------------- // targetBone(制限角low~high)のIKLinkを作成 public IPXIKLink MakeIKLink(IPXBone targetBone, V3 low, V3 high) { return targetBone == null ? null : bdx.IKLink(targetBone, low, high); }
private void generateButton_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(namingText.Text)) { MessageBox.Show("The name cannot be empty!"); return; } switch (positionSelect.SelectedIndex) { case 0: if (lastPointVector.Value.Magnitude <= 0) { MessageBox.Show("The target vector cannot be zero!"); return; } break; case 1: if (linkNumber.Value < pointCount.Value) { MessageBox.Show("The number of links must not be less than the number of control points."); return; } break; default: break; } if (editPoints.Checked) { editPoints.Checked = false; } IPXPmx pmx = _args.Host.Connector.Pmx.GetCurrentState(); IPXBone parent = null; if (parentBoneSelect.SelectedIndex > 0) { parent = pmx.Bone[parentBoneSelect.SelectedIndex - 1]; } IPXBone[] chain = null; int count; Vector3 start; Vector3 delta; switch (positionSelect.SelectedIndex) { case 0: // From start through target start = firstPointVector.Value; delta = lastPointVector.Value.Normalized * (float)distanceNumber.Value; count = (int)Math.Round(linkNumber.Value); chain = Builder.GenerateChain(_args.Host.Builder.Pmx, Math.Max(count, 1), delta, start, namingText.Text, namingEnText.Text); break; case 1: // Segmented path count = (int)Math.Round(linkNumber.Value); chain = Builder.GenerateSegmentedChain(_args.Host.Builder.Pmx, count, _curvePoints, namingText.Text, namingEnText.Text); break; case 2: // Along a spline count = (int)Math.Round(linkNumber.Value); chain = Builder.GenerateSplineChain(_args.Host.Builder.Pmx, count, _curvePoints, namingText.Text, namingEnText.Text); break; case 3: // Along a spline with even distribution count = (int)Math.Round(linkNumber.Value); chain = Builder.GenerateSplineChainEvenSpaced(_args.Host.Builder.Pmx, count, _curvePoints, namingText.Text, namingEnText.Text); break; default: break; } if (chainTypeIK.Checked) { IPXBone handle = _args.Host.Builder.Pmx.Bone(); handle.Parent = parent; handle.Name = namingText.Text.Replace("#", "IK").Replace("&", "IK"); handle.NameE = namingEnText.Text.Replace("#", "IK").Replace("&", "IK"); handle.IsTranslation = true; handle.IsIK = true; IPXIK ik = handle.IK; for (int i = chain.Length - 2; i >= 0; --i) { ik.Links.Add(_args.Host.Builder.Pmx.IKLink(chain[i])); } ik.Target = chain[chain.Length - 1]; ik.Angle = (float)((20.0 / 180.0) * Math.PI); ik.LoopCount = 10; handle.Position = ik.Target.Position; pmx.Bone.Add(handle); } if (createPhysics.Checked) { IPXJoint pj = null; if (_physicsSettings.AttachToParent) { IPXBody pb = pmx.Body.Where(b => b.Bone == parent).FirstOrDefault(); if (pb == null) { MessageBox.Show("Could not attach physics chain to the parent bone because it doesn't have a rigidbody.", "Warning"); } else { pj = _args.Host.Builder.Pmx.Joint(); pj.Name = namingText.Text.Replace("#", "P").Replace("&", "P"); pj.NameE = namingEnText.Text.Replace("#", "P").Replace("&", "P"); pj.Position = pb.Bone.Position; pj.BodyA = pb; pmx.Joint.Add(pj); } } Builder.GeneratePhysics(_args.Host.Builder.Pmx, chain, _physicsSettings, out IPXBody[] rigidbodies, out IPXJoint[] joints);
// 選択されたボーン配列を取得 public IPXBone[] SelectedBones() { var bi = connect.View.PmxView.GetSelectedBoneIndices(); if (bi.Length == 0) return null; var ret = new IPXBone[bi.Length]; for (var i = 0; i < bi.Length; i++) ret[i] = bone[bi[i]]; return ret; }
// 新しい名前でボーンを複製 public IPXBone CloneBone(IPXBone origBone, string newName) { var bx = (IPXBone)origBone.Clone(); bx.Name = newName; return bx; }
// ボーンを表示枠に追加 public void AddBoneToNode(IPXNode targetNode, IPXBone targetBone) { targetNode.Items.Add(bdx.BoneNodeItem(targetBone)); }
// targetBoneの直前にnewBoneを挿入 // 返り値は挿入できたかどうか public bool InsertBoneBefore(IPXBone targetBone, IPXBone newBone) { for (var i = 0; i < bone.Count; i++) { if (bone[i] != targetBone) continue; bone.Insert(i, newBone); return true; } return false; }
public bool InsertBoneBefore(string targetBoneName, IPXBone newBone) { var targetBone = FindBone(targetBoneName); if (targetBone == null) return false; return InsertBoneBefore(targetBone, newBone); }
// ボーンを表示枠から削除 public void RemoveBoneFromNode(IPXNode targetNode, IPXBone targetBone) { var b = targetNode.Items.FirstOrDefault(ni => ni.IsBone && ni.BoneItem.Bone == targetBone); if (b == null) return; targetNode.Items.Remove(b); }
// targetBoneにlinkBoneを回転付与親として設定 public bool AppendRotation(IPXBone targetBone, IPXBone linkBone, float ratio) { if (targetBone == null || linkBone == null) return false; targetBone.IsAppendRotation = true; targetBone.AppendParent = linkBone; targetBone.AppendRatio = ratio; return true; }
public IPXIKLink IKLink(IPXBone bone, V3 low, V3 high) { throw new NotImplementedException(); }
public IPXBoneNodeItem BoneNodeItem(IPXBone bone) { throw new NotImplementedException(); }
// targetBoneのIKLinkを作成 public IPXIKLink MakeIKLink(IPXBone targetBone) { return targetBone == null ? null : bdx.IKLink(targetBone); }
private void ButtonExecute_Click(object sender, EventArgs e) { IPXPmx pmx = args.Host.Builder.Pmx.Pmx(); pmx.ModelInfo.ModelName = textBoxModelName.Text; pmx.ModelInfo.Comment = textBoxModelText.Text; // 作成したpmxにマテリアルをコピー foreach (int i in listBoxMaterial.SelectedIndices) { pmx.Material.Add(currentPmx.Material[i]); } // マテリアルに含まれる頂点のリストを作成 List <IPXVertex> vertices = new List <IPXVertex>(); foreach (var m in pmx.Material) { foreach (var f in m.Faces) { vertices.Add(f.Vertex1); vertices.Add(f.Vertex2); vertices.Add(f.Vertex3); } } // 重複を除去 vertices = vertices.Distinct().ToList(); foreach (var v in vertices) { pmx.Vertex.Add(v); } // 頂点のウェイトに基づいてボーンをコピー if (checkBoxBone.Checked) { if (radioAllBone.Checked) { foreach (var b in currentPmx.Bone) { pmx.Bone.Add(b); } if (checkBoxPhysics.Checked) { foreach (var b in currentPmx.Body) { pmx.Body.Add(b); } foreach (var j in currentPmx.Joint) { pmx.Joint.Add(j); } } } else { // 元のボーン順を保存 Dictionary <IPXBone, int> boneIndex = new Dictionary <IPXBone, int>(); for (int i = 0; i < currentPmx.Bone.Count; i++) { boneIndex.Add(currentPmx.Bone[i], i); } // 関連ボーン List <IPXBone> bones = new List <IPXBone>(); foreach (var v in vertices) { if (v.Bone1 != null) { bones.Add(v.Bone1); } if (v.Bone2 != null) { bones.Add(v.Bone2); } if (v.Bone3 != null) { bones.Add(v.Bone3); } if (v.Bone4 != null) { bones.Add(v.Bone4); } } bones = bones.Distinct().ToList(); if (checkBoxPhysics.Checked) { // 関連ボーンの関連剛体 List <IPXBody> bodies = new List <IPXBody>(); foreach (var b in bones) { bodies.AddRange(currentPmx.Body.Where(x => x.Bone == b)); } bodies = bodies.Distinct().ToList(); // 関連剛体の関連ジョイント List <IPXJoint> joints = new List <IPXJoint>(); foreach (var b in bodies) { joints.AddRange(currentPmx.Joint.Where(x => x.BodyA == b || x.BodyB == b)); } joints = joints.Distinct().ToList(); // ジョイントに必要な剛体がbodiesに不足していた場合追加 foreach (var j in joints) { if (!bodies.Any(b => b == j.BodyA)) { bodies.Add(j.BodyA); } if (!bodies.Any(b => b == j.BodyB)) { bodies.Add(j.BodyB); } } // 剛体に必要なボーンがbonesに不足していた場合追加 foreach (var b in bodies) { if (!bones.Any(x => x == b.Bone)) { bones.Add(b.Bone); } } // 剛体・ジョイントの並び順を戻す Dictionary <IPXBody, int> bodyIndex = new Dictionary <IPXBody, int>(); for (int i = 0; i < currentPmx.Body.Count; i++) { bodyIndex.Add(currentPmx.Body[i], i); } Dictionary <IPXJoint, int> jointIndex = new Dictionary <IPXJoint, int>(); for (int i = 0; i < currentPmx.Joint.Count; i++) { jointIndex.Add(currentPmx.Joint[i], i); } bodies.Sort((a, b) => bodyIndex[a] - bodyIndex[b]); joints.Sort((a, b) => jointIndex[a] - jointIndex[b]); foreach (var b in bodies) { pmx.Body.Add(b); } foreach (var j in joints) { pmx.Joint.Add(j); } } bones.Sort((a, b) => boneIndex[a] - boneIndex[b]); if (radioRelationBone.Checked) { foreach (var b in bones) { pmx.Bone.Add(b); } } if (radioRelationBoneAndParent.Checked) { List <IPXBone> bonesWithParent = new List <IPXBone>(); //関連ボーンの親を遡って保持 for (int i = 0; i < bones.Count; i++) { IPXBone b = bones[i]; IPXBone forcus = b; while (forcus != null) { if (bonesWithParent.Exists(x => x == forcus)) { break; } bonesWithParent.Add(forcus); if (forcus.AppendParent != null && !bones.Exists(x => x == forcus.AppendParent)) { bones.Add(forcus.AppendParent); } forcus = forcus.Parent; } } bonesWithParent.Sort((a, b) => boneIndex[a] - boneIndex[b]); foreach (var b in bonesWithParent) { pmx.Bone.Add(b); } } } } // モーフをコピー if (checkBoxMorph.Checked) { foreach (var m in currentPmx.Morph) { IPXMorph morph = m; bool morphExists = true; switch (m.Kind) { case MorphKind.Vertex: List <IPXVertexMorphOffset> vmo = m.Offsets.ToList().ConvertAll(o => (IPXVertexMorphOffset)o); foreach (var o in vmo) { if (!vertices.Exists(v => v == o.Vertex)) { morph.Offsets.Remove(o); } } break; case MorphKind.UV: case MorphKind.UVA1: case MorphKind.UVA2: case MorphKind.UVA3: case MorphKind.UVA4: List <IPXUVMorphOffset> umo = m.Offsets.ToList().ConvertAll(o => (IPXUVMorphOffset)o); foreach (var o in umo) { if (!vertices.Exists(v => v == o.Vertex)) { morph.Offsets.Remove(o); } } break; case MorphKind.Material: List <IPXMaterialMorphOffset> mmo = m.Offsets.ToList().ConvertAll(o => (IPXMaterialMorphOffset)o); foreach (var o in mmo) { if (!pmx.Material.Contains(o.Material)) { morph.Offsets.Remove(o); } } break; default: morphExists = false; break; } if (morphExists && morph.Offsets.Count != 0) { pmx.Morph.Add(morph); } } } Update(args.Host.Connector, pmx, PmxUpdateObject.All); MessageBox.Show("完了"); Reload(); }
/// <summary> /// Parses the Wavefront Object file at the provided path and returns the operation's result. /// </summary> public static ImportResult Import(string path, IPXPmxBuilder builder, ImportSettings settings, IOProgress progress) { // Cancel the process if needed if (progress.CancellationToken.IsCancellationRequested) { progress.CancellationToken.ThrowIfCancellationRequested(); } IPXPmx pmx = builder.Pmx(); pmx.Clear(); pmx.ModelInfo.ModelName = pmx.ModelInfo.ModelNameE = Path.GetFileNameWithoutExtension(path); pmx.ModelInfo.Comment = pmx.ModelInfo.CommentE = "(Imported from OBJ by WPlugins.ObjIO)"; StreamReader reader = null; System.Globalization.NumberFormatInfo fi = System.Globalization.NumberFormatInfo.InvariantInfo; System.Globalization.NumberStyles ns = System.Globalization.NumberStyles.Float; // Model elements List <V3> vList = new List <V3>(); List <V2> vtList = new List <V2>(); List <V3> vnList = new List <V3>(); Dictionary <Tuple <int, int, int>, int> vertexDictionary = new Dictionary <Tuple <int, int, int>, int>(); Dictionary <string, IPXMaterial> materials = new Dictionary <string, IPXMaterial>(); IPXMaterial currentMaterial = null; // Values derived from settings V3 positionScale = new V3(settings.ScaleX, settings.ScaleY, settings.ScaleZ) * (settings.UseMetricUnits ? 0.254f : 0.1f); // Statistics int lineNumber = 0; try { reader = new StreamReader(path); char[] separator = { ' ' }; while (!reader.EndOfStream) { System.Threading.Thread.Sleep(2); // Cancel the process if needed if (progress.CancellationToken.IsCancellationRequested) { progress.CancellationToken.ThrowIfCancellationRequested(); } string line = reader.ReadLine().Trim(); ++lineNumber; ++progress.LineNumber; progress.Report(IOProgress.Percent(reader.BaseStream.Position, reader.BaseStream.Length)); // Skip empty lines and comments if (string.IsNullOrWhiteSpace(line) || line[0] == '#') { continue; } string[] split = line.Split(separator, StringSplitOptions.RemoveEmptyEntries); switch (split[0]) { // Vertex position case "v": try { float x = float.Parse(split[1], ns, fi); float y = float.Parse(split[2], ns, fi); float z = float.Parse(split[3], ns, fi); vList.Add(new V3(x, y, -z)); } catch (FormatException ex) { if (progress.ReportError(string.Format("A format exception has occured: {0}", line))) { return(ImportResult.Fail(ex, progress.WarningCount, progress.ErrorCount)); } vList.Add(new V3()); } break; // Vertex texture coordinates case "vt": try { // Technically this can be a V3 or any vector, but PMX only uses the first two elements for the main UV channel. float x = float.Parse(split[1], ns, fi); float y = float.Parse(split[2], ns, fi); vtList.Add(new V2(x, -y)); } catch (FormatException ex) { if (progress.ReportError(string.Format("A format exception has occured: {0}", line))) { return(ImportResult.Fail(ex, progress.WarningCount, progress.ErrorCount)); } vtList.Add(new V2()); } break; // Vertex normal case "vn": try { float x = float.Parse(split[1], ns, fi); float y = float.Parse(split[2], ns, fi); float z = float.Parse(split[3], ns, fi); vnList.Add(new V3(x, y, -z)); } catch (FormatException ex) { if (progress.ReportError(string.Format("A format exception has occured: {0}", line))) { return(ImportResult.Fail(ex, progress.WarningCount, progress.ErrorCount)); } vnList.Add(new V3()); } break; // Face definition case "f": if (currentMaterial == null) { progress.ReportWarning(string.Format("Encountered a face record when no active group was set.", lineNumber)); currentMaterial = builder.Material(); } // Triangle if (split.Length == 4) { int v = 0; int vt = 0; int vn = 0; bool newVertex; try { // Split each vertex assignment triple into its respective v/vt/vn indices. GetVertexElements(split[1], out v, out vt, out vn); // Based on the indices, determine if the vertex assignment is unique or already exists. A vertex is considered unique if one or more index is different, regardless of the vectors they represent. newVertex = GetUniqueVertex(v, vt, vn, vertexDictionary, pmx.Vertex.Count, out int index1); if (newVertex) { IPXVertex vert = builder.Vertex(); pmx.Vertex.Add(vert); // The new vertex is added to the end of the list, making its index equal to the list's count before the addition. if (v >= 0) { vert.Position = vList[v] * positionScale; } if (vt >= 0) { vert.UV = vtList[vt]; } if (vn >= 0) { vert.Normal = vnList[vn]; } } IPXVertex vertex1 = pmx.Vertex[index1]; // Repeat the same process for the rest of the vertex triples. GetVertexElements(split[2], out v, out vt, out vn); newVertex = GetUniqueVertex(v, vt, vn, vertexDictionary, pmx.Vertex.Count, out int index2); if (newVertex) { IPXVertex vert = builder.Vertex(); pmx.Vertex.Add(vert); if (v >= 0) { vert.Position = vList[v] * positionScale; } if (vt >= 0) { vert.UV = vtList[vt]; } if (vn >= 0) { vert.Normal = vnList[vn]; } } IPXVertex vertex2 = pmx.Vertex[index2]; GetVertexElements(split[3], out v, out vt, out vn); newVertex = GetUniqueVertex(v, vt, vn, vertexDictionary, pmx.Vertex.Count, out int index3); if (newVertex) { IPXVertex vert = builder.Vertex(); pmx.Vertex.Add(vert); if (v >= 0) { vert.Position = vList[v] * positionScale; } if (vt >= 0) { vert.UV = vtList[vt]; } if (vn >= 0) { vert.Normal = vnList[vn]; } } IPXVertex vertex3 = pmx.Vertex[index3]; // Build the triangle and assign the vertices; use reverse order and negative normal vectors if the triangles are reversed. IPXFace face = builder.Face(); if (settings.FlipFaces) { vertex1.Normal *= -1; vertex2.Normal *= -1; vertex3.Normal *= -1; face.Vertex1 = vertex1; face.Vertex2 = vertex2; face.Vertex3 = vertex3; } else { face.Vertex1 = vertex3; face.Vertex2 = vertex2; face.Vertex3 = vertex1; } currentMaterial.Faces.Add(face); } catch (Exception ex) { if (progress.ReportError(ex.ToString())) { return(ImportResult.Fail(ex, progress.WarningCount, progress.ErrorCount)); } } } // Quad else if (split.Length == 5) { int v = 0; int vt = 0; int vn = 0; bool newVertex; try { GetVertexElements(split[1], out v, out vt, out vn); newVertex = GetUniqueVertex(v, vt, vn, vertexDictionary, pmx.Vertex.Count, out int index1); if (newVertex) { IPXVertex vert = builder.Vertex(); pmx.Vertex.Add(vert); if (v >= 0) { vert.Position = vList[v] * positionScale; } if (vt >= 0) { vert.UV = vtList[vt]; } if (vn >= 0) { vert.Normal = vnList[vn]; } } IPXVertex vertex1 = pmx.Vertex[index1]; GetVertexElements(split[2], out v, out vt, out vn); newVertex = GetUniqueVertex(v, vt, vn, vertexDictionary, pmx.Vertex.Count, out int index2); if (newVertex) { IPXVertex vert = builder.Vertex(); pmx.Vertex.Add(vert); if (v >= 0) { vert.Position = vList[v] * positionScale; } if (vt >= 0) { vert.UV = vtList[vt]; } if (vn >= 0) { vert.Normal = vnList[vn]; } } IPXVertex vertex2 = pmx.Vertex[index2]; GetVertexElements(split[3], out v, out vt, out vn); newVertex = GetUniqueVertex(v, vt, vn, vertexDictionary, pmx.Vertex.Count, out int index3); if (newVertex) { IPXVertex vert = builder.Vertex(); pmx.Vertex.Add(vert); if (v >= 0) { vert.Position = vList[v] * positionScale; } if (vt >= 0) { vert.UV = vtList[vt]; } if (vn >= 0) { vert.Normal = vnList[vn]; } } IPXVertex vertex3 = pmx.Vertex[index3]; GetVertexElements(split[4], out v, out vt, out vn); newVertex = GetUniqueVertex(v, vt, vn, vertexDictionary, pmx.Vertex.Count, out int index4); if (newVertex) { IPXVertex vert = builder.Vertex(); pmx.Vertex.Add(vert); if (v >= 0) { vert.Position = vList[v] * positionScale; } if (vt >= 0) { vert.UV = vtList[vt]; } if (vn >= 0) { vert.Normal = vnList[vn]; } } IPXVertex vertex4 = pmx.Vertex[index4]; int faceIndex1 = 0, faceIndex2 = 0; IPXFace face = builder.Face(); if (settings.FlipFaces) { face.Vertex3 = settings.TurnQuads ? vertex3 : vertex4; face.Vertex2 = vertex2; face.Vertex1 = vertex1; currentMaterial.Faces.Add(face); faceIndex1 = currentMaterial.Faces.Count - 1; face = builder.Face(); face.Vertex1 = settings.TurnQuads ? vertex1 : vertex2; face.Vertex2 = vertex3; face.Vertex3 = vertex4; currentMaterial.Faces.Add(face); faceIndex2 = currentMaterial.Faces.Count - 1; } else { face.Vertex1 = settings.TurnQuads ? vertex3 : vertex4; face.Vertex2 = vertex2; face.Vertex3 = vertex1; currentMaterial.Faces.Add(face); faceIndex1 = currentMaterial.Faces.Count - 1; face = builder.Face(); face.Vertex3 = settings.TurnQuads ? vertex1 : vertex2; face.Vertex2 = vertex3; face.Vertex1 = vertex4; currentMaterial.Faces.Add(face); faceIndex2 = currentMaterial.Faces.Count - 1; } if (settings.SaveTrianglePairs) { currentMaterial.Memo += string.Format("({0},{1})", faceIndex1, faceIndex2); } } catch (Exception ex) { if (progress.ReportError(ex.ToString())) { return(ImportResult.Fail(ex, progress.WarningCount, progress.ErrorCount)); } } } else { if (progress.ReportError(string.Format("The OBJ file contains a polygon with an invalid number of vertices. Currently only triangles and quads are supported. Line content: {0}", line))) { return(ImportResult.Fail(new InvalidOperationException("Invalid polygon"), progress.WarningCount, progress.ErrorCount)); } } break; // Group assignment defines which PMX object (IPXMaterial instance) the subsequent faces belong to. case "g": currentMaterial = builder.Material(); currentMaterial.Name = currentMaterial.NameE = line.Trim().Substring(2); progress.Report("New object: " + currentMaterial.Name); pmx.Material.Add(currentMaterial); // Set default properties currentMaterial.Diffuse = new V4(1, 1, 1, 1); currentMaterial.Ambient = new V3(0.5f, 0.5f, 0.5f); break; // Material assignment defines which material template should be applied to the currently active PMX object. Any number of PMX objects can refer to a single material template. case "usemtl": if (currentMaterial == null) { progress.ReportWarning(string.Format("Encountered a material template reference when no active group was set.", lineNumber)); currentMaterial = builder.Material(); } { string name = line.Trim().Substring(7); IPXMaterial m = currentMaterial; // Active material IPXMaterial t = materials[name]; // Template material m.Diffuse = t.Diffuse; m.Specular = t.Specular; m.Power = t.Power; m.Ambient = t.Ambient; m.Diffuse = t.Diffuse; m.SelfShadow = t.SelfShadow; m.SelfShadowMap = t.SelfShadowMap; m.Shadow = t.Shadow; m.Tex = t.Tex; m.EdgeSize = t.EdgeSize; m.EdgeColor = t.EdgeColor; m.Edge = t.Edge; } break; // Material library, may occur multiple times in a model. case "mtllib": string materialLibraryName = line.Substring(7); progress.Report("Importing materials from " + materialLibraryName); // Try relative path string materialLibraryPath = Path.Combine(Path.GetDirectoryName(path), materialLibraryName); if (!File.Exists(materialLibraryPath)) { // Try absolute path materialLibraryPath = materialLibraryName; if (!File.Exists(materialLibraryPath)) { progress.ReportError(string.Format("Material library not found ({0}).", materialLibraryName)); break; } } Dictionary <string, IPXMaterial> tempDict = ImportMaterials(materialLibraryPath, builder, settings, progress); foreach (KeyValuePair <string, IPXMaterial> kvp in tempDict) { if (materials.ContainsKey(kvp.Key)) { progress.ReportWarning(string.Format("Duplicate material {0} imported from {1} has been discarded.", kvp.Key, materialLibraryName)); } else { materials.Add(kvp.Key, kvp.Value); } } progress.Report(string.Format("Imported {0} materials from {1}.", tempDict.Count, materialLibraryName)); break; // Smoothing group assignment (unused) case "s": break; default: break; } } // Second pass for bone weights and transformations because I'm lazy IPXBone bone = null; if (settings.CreateBone != ImportSettings.CreateBoneMode.None) { bone = builder.Bone(); bone.Name = bone.NameE = pmx.ModelInfo.ModelName.Replace(' ', '_'); } foreach (IPXVertex vertex in pmx.Vertex) { // Bone if (settings.CreateBone == ImportSettings.CreateBoneMode.Average) { bone.Position += vertex.Position; } vertex.Bone1 = settings.CreateBone != ImportSettings.CreateBoneMode.None ? bone : null; vertex.Weight1 = 1.0f; vertex.Bone2 = vertex.Bone3 = vertex.Bone4 = null; vertex.Weight2 = vertex.Weight3 = vertex.Weight4 = 0; // Axis swap if (settings.SwapYZ) { float temp = vertex.Position.Y; vertex.Position.Y = vertex.Position.Z; vertex.Position.Z = temp; temp = vertex.Normal.Y; vertex.Normal.Y = vertex.Normal.Z; vertex.Normal.Z = temp; } } if (settings.CreateBone == ImportSettings.CreateBoneMode.Average) { bone.Position /= pmx.Vertex.Count; } } catch (OperationCanceledException) { throw; } catch (Exception ex) { if (progress.ReportError(ex.ToString())) { return(ImportResult.Fail(ex, progress.WarningCount, progress.ErrorCount)); } } finally { if (reader != null) { reader.Close(); reader = null; } } return(ImportResult.Success(pmx, progress.WarningCount, progress.ErrorCount)); }
public IPXBoneMorphOffset BoneMorphOffset(IPXBone bone, V3 translation, Q rotation) { throw new NotImplementedException(); }
// エントリポイント public override void Run(IPERunArgs args) { try { //PMD/PMXファイルを操作するためにおまじない。 this.host = args.Host; this.builder = this.host.Builder; this.bd = this.host.Builder.SC; this.connect = this.host.Connector; this.pex = this.connect.Pmd.GetCurrentStateEx(); this.PMD = this.connect.Pmd.GetCurrentState(); this.PMX = this.connect.Pmx.GetCurrentState(); this.Form = this.connect.Form; this.PMDView = this.connect.View.PMDView; //-----------------------------------------------------------ここから----------------------------------------------------------- //ここから処理開始 //-----------------------------------------------------------ここから----------------------------------------------------------- if (this.connect.Form.PmxFormActivate) { for (int i = 0; i < this.PMX.Vertex.Count; i++) { IPXVertex vertex = this.PMX.Vertex[i]; V3 vp = (V3)vertex.Position; int ind1, ind2; ind1 = ind2 = -1; float dis1, dis2; dis1 = dis2 = 10000000; for (int j = 0; j < this.PMX.Bone.Count; j++) { IPXBone bone = this.PMX.Bone[j]; V3 bp = (V3)bone.Position; float dis; if (bone.ToBone == null) { continue; } else { dis = getDistanceBoneToVertex(bone, vertex); } if (dis < dis1) { dis2 = dis1; ind2 = ind1; ind1 = j; dis1 = dis; } else if (dis < dis2) { dis2 = dis; ind2 = j; } } if (ind1 >= 0) { vertex.Bone1 = this.PMX.Bone[ind1]; vertex.Weight1 = 1.0f; } if (ind2 >= 0) { vertex.Bone2 = this.PMX.Bone[ind2]; #if MODE_EXCLUSIVE vertex.Weight2 = 0f; #else vertex.Weight2 = (1f * dis1 / (dis1 + dis2)); vertex.Weight1 = 1.0f - vertex.Weight2; #endif } } } else { for (int i = 0; i < this.PMD.Vertex.Count; i++) { IPEVertex vertex = this.PMD.Vertex[i]; V3 vp = (V3)vertex.Position; int ind1, ind2; ind1 = ind2 = -1; float dis1, dis2; dis1 = dis2 = 10000000; for (int j = 0; j < this.PMD.Bone.Count; j++) { IPEBone bone = this.PMD.Bone[j]; V3 bp = (V3)bone.Position; float dis; if (bone.To == -1 || bone.To == 0) { continue; } else { dis = getDistanceBoneToVertex(bone, vertex); } // float dis = (bp - vp).Length(); if (dis < dis1) { dis2 = dis1; ind2 = ind1; ind1 = j; dis1 = dis; } else if (dis < dis2) { dis2 = dis; ind2 = j; } } if (ind1 >= 0) { vertex.Bone1 = ind1; } if (ind2 >= 0) { vertex.Bone2 = ind2; #if MODE_EXCLUSIVE vertex.Weight = 100; #else vertex.Weight = (int)(100f * dis2 / (dis1 + dis2)); #endif } } } //-----------------------------------------------------------ここまで----------------------------------------------------------- //処理ここまで //-----------------------------------------------------------ここまで----------------------------------------------------------- //モデル・画面を更新します。 this.Update(); #if MODE_EXCLUSIVE MessageBox.Show(this.PMD.Vertex.Count.ToString() + "個の頂点のウェイトを最短排他形式で設定しました。", "ウェイト自動設定(排他的)", MessageBoxButtons.OK, MessageBoxIcon.Information); #else MessageBox.Show(this.PMX.Vertex.Count.ToString() + "個の頂点のウェイトを中間補完形式で設定しました。", "ウェイト自動設定(補完的)", MessageBoxButtons.OK, MessageBoxIcon.Information); #endif } catch (Exception ex) { MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } }
public IPXIKLink IKLink(IPXBone bone) { throw new NotImplementedException(); }
private float NormalDist(IPXBone bone, IPXVertex vertex) { return((vertex.Position - bone.Position).Length()); }
public static IEnumerable <IPXVertex> FromBoneWeight(IPXBone bone, IPXPmx pmx) => pmx.Vertex.Where(v => v.Bone1 == bone || v.Bone2 == bone || v.Bone3 == bone || v.Bone4 == bone);
// ボーンを表示枠に挿入 public void InsertBoneToNode(IPXNode targetNode, IPXBone targetBone, int idx) { targetNode.Items.Insert(idx, bdx.BoneNodeItem(targetBone)); }
/// <summary> /// Executes the provided XmlDocument on the PMX object. /// </summary> public static RunnerResult Execute(XmlDocument doc, IPXPmx pmx, IPXPmxBuilder builder, RunnerProgress progress) { XmlElement root = doc.DocumentElement; progress.Report(0, "> Execution started."); // Begin processing // Only the first level of elements are interpreted as commands. XmlElement[] commands = root.ChildNodes.OfType <XmlElement>().ToArray(); for (int i = 0; i < commands.Length; ++i) { try { XmlElement node = commands[i]; // The meaningful content of each case constitutes a separate block to avoid mixing variables. Might be unnecessary, but right now I'm not feeling too hot and my output WILL be sloppy. // Should review this code later. switch (node.Name.ToLowerInvariant()) { // Creates a new bone with the provided properties. case "bone": { string name = Math.Abs(Guid.NewGuid().GetHashCode()).ToString(); IPXBone bone = null; // Get name and check for collision if (node["name"] != null) { name = node["name"].InnerText; IPXBone existing = pmx.Bone.Where(b => b.Name == name).FirstOrDefault(); if (existing != null) { // If there is a collision, refer to the collision attribute switch (node["name"].GetAttribute("collision")) { // If the attribute is "update" or "replace", refer to the existing bone for the rest of the command. case "replace": case "update": bone = existing; break; // If the attribute is "skip", don't do anything with the bone and skip the command. case "skip": continue; // If the attribute is not valid, create a new bone and ignore the old one. default: bone = builder.Bone(); bone.Name = bone.NameE = name; break; } } else { bone = builder.Bone(); bone.Name = bone.NameE = name; } } else { bone = builder.Bone(); bone.Name = bone.NameE = name; } if (node["position"] != null) { bone.Position = node["position"].GetV3(); } if (node["translation"] != null) { bone.IsTranslation = bool.TryParse(node["translation"].InnerText, out bool translation) ? translation : false; } if (node["parent"] != null) { bone.Parent = Selector.Bone.Selector(node["parent"], pmx).FirstOrDefault(); } if (node["axis"] != null) { V3 v = node["axis"].GetV3(); v.Normalize(); bone.IsFixAxis = true; bone.FixAxis = v; } if (node["weight"] != null) { //IEnumerable<IPXVertex> vertices = Selector.Vertex.SelectorList(node["weight"].ChildNodes, pmx); IEnumerable <IPXVertex> vertices = Selector.Vertex.SelectorNode(node["weight"], pmx); foreach (IPXVertex v in vertices) { v.Bone1 = bone; v.Weight1 = 1; v.Bone2 = v.Bone3 = v.Bone4 = null; v.Weight2 = v.Weight3 = v.Weight4 = 0; } } pmx.Bone.Add(bone); progress.Report(Percent(i + 1, commands.Length), string.Format("[bone] Added new bone {0}.", bone.Name)); } break; // Assigns the selected vertices to the selected bone using BDEF1. case "weight": { IPXBone bone = null; if (node["target"] != null) { bone = Selector.Bone.Selector(node["target"], pmx).FirstOrDefault(); if (bone == null) { progress.Report(Percent(i + 1, commands.Length), string.Format("[weight] Bone was not found.", node["target"].InnerText)); break; } } else { progress.Report(Percent(i + 1, commands.Length), "[weight] Bone selector was not specified."); break; } // Set vertex weights if (node["select"] == null) { progress.Report(Percent(i + 1, commands.Length), "[weight] No vertices were selected."); break; } IEnumerable <IPXVertex> vertices = Selector.Vertex.SelectorNode(node["select"], pmx); foreach (IPXVertex v in vertices) { v.Bone1 = bone; v.Weight1 = 1; v.Bone2 = v.Bone3 = v.Bone4 = null; v.Weight2 = v.Weight3 = v.Weight4 = 0; } progress.Report(Percent(i + 1, commands.Length), string.Format("[weight] Weighted {0} vertices to {1} ({2}).", vertices.Count(), bone.Name, bone.NameE)); } break; // Creates a new UV morph. case "uvmorph": { // The morph's properties are defined in attributes. IPXMorph morph = builder.Morph(); morph.Kind = MorphKind.UV; // Set the UV channel if (int.TryParse(node.GetAttribute("channel"), out int ch)) { switch (ch) { case 1: morph.Kind = MorphKind.UVA1; break; case 2: morph.Kind = MorphKind.UVA2; break; case 3: morph.Kind = MorphKind.UVA3; break; case 4: morph.Kind = MorphKind.UVA4; break; default: morph.Kind = MorphKind.UV; break; } } // Set the group panel if (int.TryParse(node.GetAttribute("group"), out int group) && group <= 4 && group >= 0) { morph.Panel = group; } else { switch (node.GetAttribute("group").ToLowerInvariant()) { case "hidden": case "hide": case "none": case "0": morph.Panel = 0; break; case "eyebrow": case "eyebrows": case "1": morph.Panel = 1; break; case "eye": case "eyes": case "2": morph.Panel = 2; break; case "mouth": case "3": morph.Panel = 3; break; default: morph.Panel = 4; break; } } // Set the name, ignore collisions if (node.HasAttribute("name")) { morph.Name = morph.NameE = node.GetAttribute("name"); } else { morph.Name = morph.NameE = morph.GetHashCode().ToString(); } // Each morph contains one or more steps. Each step has its own selectors and transforms, which are applied independently. foreach (XmlElement step in node.ChildNodes.OfType <XmlElement>().Where(el => el.Name.ToLowerInvariant() == "step")) { // Skip steps that have no selectors if (step["select"] == null) { continue; } // Select vertices IEnumerable <IPXVertex> vertices = Selector.Vertex.SelectorNode(step["select"], pmx); foreach (XmlElement e in step) { switch (e.Name.ToLowerInvariant()) { case "pan": case "translate": { V2 v = e.GetV2(); foreach (IPXVertex vertex in vertices) { IPXUVMorphOffset offset = builder.UVMorphOffset(); offset.Vertex = vertex; offset.Offset = new V4(v.X, v.Y, 0, 0); morph.Offsets.Add(offset); } } break; case "rotate": // TODO: UV morph rotation case "scale": // TODO: UV morph scaling default: break; } } } pmx.Morph.Add(morph); progress.Report(Percent(i + 1, commands.Length), string.Format("[uvmorph] Created UV morph {0} with {1} offsets.", morph.Name, morph.Offsets.Count)); } break; // No particular functionality, testing only. case "test": { //foreach (IPXMorph morph in pmx.Morph.Where(m => m.Kind == MorphKind.UV)) //{ // foreach (IPXUVMorphOffset o in morph.Offsets) // { // _report(string.Format("{0:f2}, {1:f2}, {2:f2}, {3:f2}", o.Offset.X, o.Offset.Y, o.Offset.Z, o.Offset.W), -1); // } //} } break; // Sets up the selected vertices for use with AutoLuminous. case "autoluminous": { if (node["select"] == null) { progress.Report(Percent(i + 1, commands.Length), "[weight] No vertices were selected."); break; } IEnumerable <IPXVertex> vertices = Selector.Vertex.SelectorNode(node["select"], pmx); // Set required values. pmx.Header.UVACount = Math.Max(pmx.Header.UVACount, 3); // UV1 int texture = 0; int hsv = 0; float flashFrequency = 0; // UV2 V4 baseColor = new V4(0, 0, 0, 0); // UV3 float texSubtract = 0; float flashBias = 0; float push = 0; // Base emissive color if (node["color"] != null) { baseColor = node["color"].GetV4(); } // Base emissive power if (node["power"] != null) { baseColor.W = node["power"].GetSingle(); } if (node["texture"] != null) { int.TryParse(node["texture"].InnerText, System.Globalization.NumberStyles.Integer, System.Globalization.NumberFormatInfo.InvariantInfo, out texture); } if (node["colormode"] != null) { switch (node["colormode"].InnerText.ToLowerInvariant()) { case "hsv": hsv = 10; break; default: hsv = 0; break; } } if (node["flash"] != null) { float.TryParse(node["flash"].GetAttribute("bias"), System.Globalization.NumberStyles.Float, System.Globalization.NumberFormatInfo.InvariantInfo, out flashBias); flashFrequency = node["flash"].GetSingle(); } if (node["subtract"] != null) { texSubtract = node["subtract"].GetSingle(); } if (node["push"] != null) { push = node["push"].GetSingle(); } foreach (IPXVertex v in vertices) { v.UVA1.X = 0.2f; // Required value v.UVA1.Y = 0.7f; // Required value v.UVA1.Z = flashFrequency; v.UVA1.W = texture + hsv; v.UVA2 = baseColor; v.UVA3.X = texSubtract; v.UVA3.Y = flashBias; v.UVA3.Z = push; } } break; // Creates a vertex morph for AutoLuminous properties. case "almorph": { if (node["select"] == null) { progress.Report(Percent(i + 1, commands.Length), "[weight] No vertices were selected."); break; } HashSet <IPXVertex> vertices = new HashSet <IPXVertex>(Selector.Vertex.SelectorNode(node["select"], pmx)); V4 color = new V4(); if (node["color"] != null) { color = node["color"].GetV4(); } // TODO: Implement the rest of the AL properties in ALMorph IPXMorph morph = builder.Morph(); morph.Kind = MorphKind.UVA2; if (node.HasAttribute("name")) { morph.Name = morph.NameE = node.GetAttribute("name"); } else { morph.Name = morph.NameE = morph.GetHashCode().ToString(); } foreach (IPXVertex v in vertices) { // Set required values in case the vertex isn't already AL-enabled v.UVA1.X = 0.2f; v.UVA1.Y = 0.7f; // Create the offset morph.Offsets.Add(builder.UVMorphOffset(v, color)); } } break; // Sets environment variables. case "settings": { foreach (XmlElement child in node.ChildNodes.OfType <XmlElement>()) { switch (child.Name.ToLowerInvariant()) { case "exception": break; case "regex": bool regexCI = GlobalSettings.RegexCaseInsensitive; bool.TryParse(child.GetAttributeCI("caseinsensitive"), out regexCI); break; case "colortype": GlobalSettings.ColorIsFloat = child.InnerText.ToLowerInvariant() == "float"; break; default: break; } } } break; // Displays a MessageBox with the provided content. Optionally perform certain actions based on user input. case "mbox": case "messagebox": case "prompt": { if (int.TryParse(node.GetAttributeCI("skip"), out int skipNumber) && skipNumber > 0) { StringBuilder sb = new StringBuilder(string.Format("Would you like to skip the following {0} command(s)?\n", skipNumber)); for (int j = 1; j <= skipNumber; ++j) { sb.Append(commands[i + j].Name); } MessageBox.Show(sb.ToString(), "Prompt: skip", MessageBoxButtons.YesNo, MessageBoxIcon.Question); } else { MessageBox.Show(node.InnerText, "Message", MessageBoxButtons.OK, MessageBoxIcon.Information); } } break; // Prints a line in the console. case "echo": case "print": progress.Report(Percent(i + 1, commands.Length), node.InnerText); break; default: progress.Report(Percent(i + 1, commands.Length), "Skipping unknown command " + node.Name); break; } } catch (Exception ex) { if (GlobalSettings.Exception == GlobalSettings.ErrorHandling.Ask) { if (MessageBox.Show(string.Format("The following exception has occured:\n\n{0}\n\nWould you like to continue execution?", ex.ToString()), "Exception", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Error) == System.Windows.Forms.DialogResult.No) { return(RunnerResult.Fail); } } else if (GlobalSettings.Exception == GlobalSettings.ErrorHandling.Abort) { return(RunnerResult.Fail); } } } // If control has reached this point, the execution is considered successful. return(RunnerResult.Success); }
// targetBoneの直前にmovingBoneを移動 // 返り値は移動できたかどうか public bool MoveBoneBefore(IPXBone targetBone, IPXBone movingBone) { bone.Remove(movingBone); return InsertBoneBefore(targetBone, movingBone); }