Esempio n. 1
0
        // ボーンのdst方向にあるのがpatch2
        static void OverlayPatches(PatchSkeletalMesh patch1, PatchSkeletalMesh patch2, PatchSkeleton refSkeleton, PatchSection section1, PatchSection section2, PatchSkeletonBone bone, float border)
        {
            PatchSkeletonBone refBone = RefBone(refSkeleton, bone);
            float             min1    = float.MaxValue;
            float             max2    = float.MinValue;

            List <PatchVertex> path1 = GetPath(patch1);
            List <PatchVertex> path2 = GetPath(patch2);

            for (int i = section1.First; i < section1.First + section1.Length; i++)
            {
                var   pt    = path1[FMath.Rem(i, path1.Count)].position;
                float param = FMath.ParameterOnLine(pt, refBone.src.position, refBone.dst.position);
                if (float.IsNaN(param))
                {
                    continue;
                }
                min1 = Math.Min(min1, param);
            }
            for (int i = section2.First; i < section2.First + section2.Length; i++)
            {
                var   pt    = path2[FMath.Rem(i, path2.Count)].position;
                float param = FMath.ParameterOnLine(pt, refBone.src.position, refBone.dst.position);
                if (float.IsNaN(param))
                {
                    continue;
                }
                max2 = Math.Max(max2, param);
            }

            PointF x, y;

            BoneCoordinate(refBone, out x, out y);

            float boneLength = FMath.Distance(refBone.src.position, refBone.dst.position);
            float dparam     = border / boneLength;
            float delta      = (min1 - max2 - dparam) * boneLength;
            float dx         = x.X * delta;
            float dy         = x.Y * delta;

            // mesh2の頂点・制御点を平行移動する
            foreach (var v in patch2.mesh.vertices)
            {
                v.position = new PointF(v.position.X + dx, v.position.Y + dy);
            }
            foreach (var c in patch2.mesh.CopyControlPoints())
            {
                patch2.mesh.TranslateControlPoint(c.position, new PointF(c.position.X + dx, c.position.Y + dy), false);
            }
        }
Esempio n. 2
0
        //
        // 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();
        }
Esempio n. 3
0
        private static float OverlapWidth(PatchSkeletalMesh patch1, PatchSkeletalMesh patch2, PatchSkeleton refSkeleton, PatchSection section1, PatchSection section2, PatchSkeletonBone bone, int maxLength, int maxAngle)
        {
            var refBone = RefBone(refSkeleton, bone);

            var path1   = GetPath(patch1);
            var curves1 = section2adjCurves(path1, section1);
            var sorted1 = GetSortedCurves(path1.Select(v => v.position).ToList(), curves1, refBone);

            var path2   = GetPath(patch2);
            var curves2 = section2adjCurves(path2, section2);
            var sorted2 = GetSortedCurves(path2.Select(v => v.position).ToList(), curves2, refBone);

            float[] param        = new float[] { 0, 0, 0, 0 };
            var     sortedCurves = new[] {
                sorted1[0],
                sorted1[1],
                sorted2[0],
                sorted2[1],
            };

            float minCos = (float)Math.Cos(Math.PI / 180 * maxAngle);

            for (int i = 0; i < sortedCurves.Length; i++)
            {
                var           c     = sortedCurves[i];
                var           path  = i < 2 ? path1 : path2;
                List <PointF> pts   = new List <PointF>();
                float         total = 0;
                for (int j = c.Count - 1; j >= 0; j--)
                {
                    var p = c[j];
                    pts.Add(p);
                    if (pts.Count >= 3 && FMath.GetAngleCos(pts) < minCos)
                    {
                        pts.RemoveAt(pts.Count - 1);
                        break;
                    }
                    if (pts.Count >= 2)
                    {
                        total += FMath.Distance(pts[pts.Count - 2], pts[pts.Count - 1]);
                    }
                    if (total >= maxLength)
                    {
                        pts.RemoveAt(pts.Count - 1);
                        break;
                    }
                }
                param[i] = FMath.ParameterOnLine(pts.Last(), refBone.src.position, refBone.dst.position);
            }

            float min1 = Enumerable.Range(section1.First, section1.Length).Min(idx =>
                                                                               FMath.ParameterOnLine(path1[FMath.Rem(idx, path1.Count)].position, refBone.src.position, refBone.dst.position));
            float max1 = Enumerable.Range(section1.First, section1.Length).Max(idx =>
                                                                               FMath.ParameterOnLine(path1[FMath.Rem(idx, path1.Count)].position, refBone.src.position, refBone.dst.position));

            int idx1 = Enumerable.Range(section1.First, section1.Length).First(idx =>
                                                                               max1 == FMath.ParameterOnLine(path1[FMath.Rem(idx, path1.Count)].position, refBone.src.position, refBone.dst.position));

            float min2 = Enumerable.Range(section2.First, section2.Length).Min(idx =>
                                                                               FMath.ParameterOnLine(path2[FMath.Rem(idx, path2.Count)].position, refBone.src.position, refBone.dst.position));
            float max2 = Enumerable.Range(section2.First, section2.Length).Max(idx =>
                                                                               FMath.ParameterOnLine(path2[FMath.Rem(idx, path2.Count)].position, refBone.src.position, refBone.dst.position));

            float idx2 = Enumerable.Range(section2.First, section2.Length).First(idx =>
                                                                                 max2 == FMath.ParameterOnLine(path2[FMath.Rem(idx, path2.Count)].position, refBone.src.position, refBone.dst.position));

            System.Diagnostics.Debug.Assert(param[0] <= max1);
            System.Diagnostics.Debug.Assert(param[1] <= max1);
            System.Diagnostics.Debug.Assert(param[2] >= min2);
            System.Diagnostics.Debug.Assert(param[3] >= min2);

            float[] dParams = new[] {
                Math.Max(0, min1 - param[0]),
                Math.Max(0, min1 - param[1]),
                Math.Max(0, param[2] - max2),
                Math.Max(0, param[3] - max2),
            };

            float minDParam    = dParams.Min();
            float boarderWidth = minDParam * FMath.Distance(refBone.src.position, refBone.dst.position);

            return(boarderWidth);
        }