// // Expand() // /// <summary> /// smesh1, smesh2の輪郭をずらして重ねる。輪郭に制御点をおいてARAPする /// curveOffset, curveLengthは切り口付近の補間に使う部分曲線 /// </summary> static void Expand( PatchSkeletalMesh patch1, PatchSkeletalMesh patch2, PatchSkeleton refSkeleton, PatchSection section1, PatchSection section2, PatchSkeletonBone bone, float curveLength, float curveBuffer) { // メッシュを固定 patch1.mesh.FreezeMesh(true); patch2.mesh.FreezeMesh(true); List <PatchVertex> rawPath1 = GetPath(patch1); List <PatchVertex> rawPath2 = GetPath(patch2); List <PointF> path1 = rawPath1.Select(v => v.position).ToList(); List <PointF> path2 = rawPath2.Select(v => v.position).ToList(); // 切り口に隣接する2曲線をそれぞれ取得 var rawCurves1 = section2adjCurves(rawPath1, section1); var rawCurves2 = section2adjCurves(rawPath2, section2); if (rawCurves1 == null || rawCurves2 == null) { return; } var trimCurves1 = TrimCurves(rawPath1, rawCurves1, 0, curveLength); var trimCurves2 = TrimCurves(rawPath2, rawCurves2, 0, curveLength); PatchSkeletonBone refBone = RefBone(refSkeleton, bone); var sorted1 = GetSortedCurves(path1, trimCurves1, refBone); var sorted2 = GetSortedCurves(path2, trimCurves2, refBone); if (sorted1.Count != 2 || sorted2.Count != 2) { return; } // patch1の制御点 patch1.mesh.ClearControlPoints(); for (int i = 0; i < 2; i++) { foreach (var p in sorted1[i]) { patch1.mesh.AddControlPoint(p, p); } } patch1.mesh.BeginDeformation(); // patch2の制御点 patch2.mesh.ClearControlPoints(); for (int i = 0; i < 2; i++) { foreach (var p in sorted2[i]) { patch2.mesh.AddControlPoint(p, p); } } patch2.mesh.BeginDeformation(); // 第一要素、第二要素がそれぞれボーンにとって同じ側の切り口となるように並び替える // 切り口に近づく向きに点が並んでいる float h10 = CurveHeight(sorted1[0], refBone); float h11 = CurveHeight(sorted1[1], refBone); float h20 = CurveHeight(sorted2[0], refBone); float h21 = CurveHeight(sorted2[1], refBone); var curve10 = sorted1[0].ToList(); var curve11 = sorted1[1].ToList(); var curve20 = sorted2[0].ToList(); var curve21 = sorted2[1].ToList(); // curveの重心を揃える PointF x, y; BoneCoordinate(refBone, out x, out y); float c0 = (h10 + h20) * 0.5f; float dy10 = c0 - h10; for (int i = 0; i < curve10.Count; i++) { curve10[i] = new PointF(curve10[i].X + dy10 * y.X, curve10[i].Y + dy10 * y.Y); } float dy11 = c0 - h20; for (int i = 0; i < curve20.Count; i++) { curve20[i] = new PointF(curve20[i].X + dy11 * y.X, curve20[i].Y + dy11 * y.Y); } float c1 = (h11 + h21) * 0.5f; float dy20 = c1 - h11; for (int i = 0; i < curve11.Count; i++) { curve11[i] = new PointF(curve11[i].X + dy20 * y.X, curve11[i].Y + dy20 * y.Y); } float dy21 = c1 - h21; for (int i = 0; i < curve21.Count; i++) { curve21[i] = new PointF(curve21[i].X + dy21 * y.X, curve21[i].Y + dy21 * y.Y); } // curveをエルミート保管して繋げる var ends0 = new[] { curve10[0], curve10.Last(), curve20[0], curve20.Last() }; int min0, max0; FMath.GetMinElement(ends0, p => FMath.ParameterOnLine(p, refBone.src.position, refBone.dst.position), out min0); FMath.GetMinElement(ends0, p => - FMath.ParameterOnLine(p, refBone.src.position, refBone.dst.position), out max0); var ends1 = new[] { curve11[0], curve11.Last(), curve21[0], curve21.Last() }; int min1, max1; FMath.GetMinElement(ends1, p => FMath.ParameterOnLine(p, refBone.src.position, refBone.dst.position), out min1); FMath.GetMinElement(ends1, p => - FMath.ParameterOnLine(p, refBone.src.position, refBone.dst.position), out max1); PointF[] es = new[] { ends0[min0], ends1[min1], ends0[max0], ends1[max1], }; PointF[] vs = new[] { new PointF(curve10[0].X - curve10[curve10.Count - 1].X, curve10[0].Y - curve10[curve10.Count - 1].Y), new PointF(curve11[0].X - curve11[curve11.Count - 1].X, curve11[0].Y - curve11[curve11.Count - 1].Y), new PointF(-(curve20[0].X - curve20[curve20.Count - 1].X), -(curve20[0].Y - curve20[curve20.Count - 1].Y)), new PointF(-(curve21[0].X - curve21[curve21.Count - 1].X), -(curve21[0].Y - curve21[curve21.Count - 1].Y)), }; float[] ps = new[] { FMath.ParameterOnLine(es[0], refBone.src.position, refBone.dst.position), FMath.ParameterOnLine(es[1], refBone.src.position, refBone.dst.position), FMath.ParameterOnLine(es[2], refBone.src.position, refBone.dst.position), FMath.ParameterOnLine(es[3], refBone.src.position, refBone.dst.position), }; for (int i = 0; i < 2; i++) { var e1 = es[i]; var v1 = vs[i]; float param1 = ps[i]; var e2 = es[i + 2]; var v2 = vs[i + 2]; float param2 = ps[i + 2]; if (Math.Abs(param2 - param1) <= 1e-4) { continue; } float paramRatio = 1 / (param2 - param1); for (int j = 0; j < sorted1[i].Count; j++) { float param = FMath.ParameterOnLine(sorted1[i][j], refBone.src.position, refBone.dst.position); float t = (param - param1) * paramRatio; PointF to = FMath.HelmitteInterporate(e1, v1, e2, v2, t); patch1.mesh.TranslateControlPoint(sorted1[i][j], to, false); } for (int j = 0; j < sorted2[i].Count; j++) { float param = FMath.ParameterOnLine(sorted2[i][j], refBone.src.position, refBone.dst.position); float t = (param - param1) * paramRatio; PointF to = FMath.HelmitteInterporate(e1, v1, e2, v2, t); patch2.mesh.TranslateControlPoint(sorted2[i][j], to, false); } } // 変形 patch1.mesh.FlushDefomation(); patch2.mesh.FlushDefomation(); // 変形終了 patch1.mesh.EndDeformation(); patch2.mesh.EndDeformation(); }
// // Expand() // /// <summary> /// smesh1, smesh2の輪郭をずらして重ねる。輪郭に制御点をおいてARAPする /// </summary> static void Expand(PatchSkeletalMesh smesh1, PatchSkeletalMesh smesh2, PatchSkeleton skl, PatchSection section1, PatchSection section2, PatchSkeletonBone bone) { List <PatchVertex> rawPath1 = GetPath(smesh1); List <PatchVertex> rawPath2 = GetPath(smesh2); List <PointF> path1 = rawPath1.Select(v => v.position).ToList(); List <PointF> path2 = rawPath2.Select(v => v.position).ToList(); // // 輪郭を変形できるように制御点を作り直す // // smesh1 smesh1.mesh.ClearControlPoints(); foreach (var v in rawPath1) { smesh1.mesh.AddControlPoint(v.position, v.orgPosition); } smesh1.mesh.BeginDeformation(); // smesh2 smesh2.mesh.ClearControlPoints(); foreach (var v in rawPath2) { smesh2.mesh.AddControlPoint(v.position, v.orgPosition); } smesh2.mesh.BeginDeformation(); // // 切り口に隣接する2曲線を各切り口について取得し、これらが重なるように輪郭をずらす // // 切り口に隣接する2曲線をそれぞれ取得 var rawCurves1 = SectionToAdjuscentCurves(path1, section1, 5, 30); var rawCurves2 = SectionToAdjuscentCurves(path2, section2, 5, 30); if (rawCurves1 == null || rawCurves2 == null) { return; } PatchSkeletonBone refBone = null; foreach (var b in skl.bones) { if (bone == b) { refBone = b; break; } } // curves1, curves2の第一要素、第二要素がそれぞれ向かい合う(ボーンにとって同じ側の)切り口となるように並び替える var curves1 = GetSortedCurves(path1, rawCurves1, refBone); var curves2 = GetSortedCurves(path2, rawCurves2, refBone); if (curves1.Count != 2 || curves2.Count != 2) { return; } // curves1, curves2の移動履歴を記録 List <Tuple <PointF, PointF> > move1 = new List <Tuple <PointF, PointF> >(); List <Tuple <PointF, PointF> > move2 = new List <Tuple <PointF, PointF> >(); // 対応する曲線間で2点がかぶる(同じ座標になる)ように変形。 for (int i = 0; i < 2; i++) { var p1 = curves1[i].First(); var v1 = new PointF(p1.X - curves1[i].Last().X, p1.Y - curves1[i].Last().Y); var p2 = curves2[i].First(); var v2 = new PointF(curves2[i].Last().X - p2.X, curves2[i].Last().Y - p2.Y); // 2点かぶらせる int cnt = curves1[i].Count + curves2[i].Count - 2; if (cnt <= 1) { continue; } for (int j = 0; j < curves1[i].Count; j++) { PointF to = FMath.HelmitteInterporate(p1, v1, p2, v2, (float)j / (cnt - 1)); if (j == curves1[i].Count - 1) { move1.Add(new Tuple <PointF, PointF>(curves1[i][j], to)); } smesh1.mesh.TranslateControlPoint(curves1[i][j], to, false); } for (int j = 0; j < curves2[i].Count; j++) { PointF to = FMath.HelmitteInterporate(p1, v1, p2, v2, (float)(-j + cnt - 1) / (cnt - 1)); if (j == curves2[i].Count - 1) { move2.Add(new Tuple <PointF, PointF>(curves2[i][j], to)); } smesh2.mesh.TranslateControlPoint(curves2[i][j], to, false); } } // // 各曲線の動きに合わせて切り口を動かす // List <PointF> sections1 = new List <PointF>(); for (int i = section1.First + 1; i < section1.First + section1.Length - 1; i++) { sections1.Add(path1[FMath.Rem(i, path1.Count)]); } List <PointF> newSection1 = ARAPDeformation.ARAPDeformation.Deform(sections1, move1); if (newSection1.Count == sections1.Count) { for (int i = 0; i < newSection1.Count; i++) { smesh1.mesh.TranslateControlPoint(sections1[i], newSection1[i], false); } } List <PointF> sections2 = new List <PointF>(); for (int i = section2.First + 1; i < section2.First + section2.Length - 1; i++) { sections2.Add(path2[FMath.Rem(i, path2.Count)]); } List <PointF> newSection2 = ARAPDeformation.ARAPDeformation.Deform(sections2, move2); if (newSection2.Count == sections2.Count) { for (int i = 0; i < newSection2.Count; i++) { smesh2.mesh.TranslateControlPoint(sections2[i], newSection2[i], false); } } // // 変形 // smesh1.mesh.FlushDefomation(); smesh2.mesh.FlushDefomation(); // // 変形終了 // smesh1.mesh.EndDeformation(); smesh2.mesh.EndDeformation(); }
private static void ExpandSegments(List <SegmentMeshInfo> meshes, SkeletonAnnotation an, List <ConnectPair> pairs) { int _cnt = 0; foreach (var m in meshes) { if (m.arap == null) { continue; } m.arap.controlPoints.Clear(); SegmentMeshInfo.SetPathControlPoints(m.arap); m.arap.BeginDeformation(); m.arap.ToBitmap().Save("../../../Test2/" + (_cnt++) + ".png"); } foreach (var b in an.bones) { foreach (var p in pairs) { if (p.bone != b) { continue; } var m1 = p.meshInfo1; var m2 = p.meshInfo2; if (m1.arap == null || m2.arap == null) { continue; } var path1 = m1.arap.GetPath(); var path2 = m2.arap.GetPath(); var ranges1 = SectionToCurves(path1, p.sectionRange1, 5, 30); var ranges2 = SectionToCurves(path2, p.sectionRange2, 5, 30); if (ranges1 == null || ranges2 == null) { continue; } var curves1 = GetSortedCurves(path1, ranges1, b); var curves2 = GetSortedCurves(path2, ranges2, b); if (curves1.Count != 2 || curves2.Count != 2) { continue; } List <Tuple <PointF, PointF> > move1 = new List <Tuple <PointF, PointF> >(); List <Tuple <PointF, PointF> > move2 = new List <Tuple <PointF, PointF> >(); for (int i = 0; i < 2; i++) { var p1 = curves1[i].First(); var v1 = new PointF(p1.X - curves1[i].Last().X, p1.Y - curves1[i].Last().Y); var p2 = curves2[i].First(); var v2 = new PointF(curves2[i].Last().X - p2.X, curves2[i].Last().Y - p2.Y); // 2点かぶらせる int cnt = curves1[i].Count + curves2[i].Count - 2; if (cnt <= 1) { continue; } for (int j = 0; j < curves1[i].Count; j++) { PointF to = FMath.HelmitteInterporate(p1, v1, p2, v2, (float)j / (cnt - 1)); if (j == curves1[i].Count - 1) { move1.Add(new Tuple <PointF, PointF>(curves1[i][j], to)); } m1.arap.TranslateControlPoint(curves1[i][j], to, false); } for (int j = 0; j < curves2[i].Count; j++) { PointF to = FMath.HelmitteInterporate(p1, v1, p2, v2, (float)(-j + cnt - 1) / (cnt - 1)); if (j == curves2[i].Count - 1) { move2.Add(new Tuple <PointF, PointF>(curves2[i][j], to)); } m2.arap.TranslateControlPoint(curves2[i][j], to, false); } } List <PointF> sections1 = new List <PointF>(); List <PointF> sections2 = new List <PointF>(); for (int i = p.sectionRange1.First + 1; i < p.sectionRange1.First + p.sectionRange1.Length - 1; i++) { sections1.Add(path1[Rem(i, path1.Count)]); } for (int i = p.sectionRange2.First + 1; i < p.sectionRange2.First + p.sectionRange2.Length - 1; i++) { sections2.Add(path2[Rem(i, path2.Count)]); } List <PointF> newSection1 = ARAPDeformation.Deform(sections1, move1); List <PointF> newSection2 = ARAPDeformation.Deform(sections2, move2); if (newSection1.Count == sections1.Count) { for (int i = 0; i < newSection1.Count; i++) { m1.arap.TranslateControlPoint(sections1[i], newSection1[i], false); } } if (newSection2.Count == sections2.Count) { for (int i = 0; i < newSection2.Count; i++) { m2.arap.TranslateControlPoint(sections2[i], newSection2[i], false); } } m1.arap.FlushDefomation(); m2.arap.FlushDefomation(); } } foreach (var m in meshes) { if (m.arap == null) { continue; } m.arap.EndDeformation(); } }