Ejemplo n.º 1
0
        public void AddControlPoint(PointF pt, PointF orgPt)
        {
            if (controlPoints.Any(c => c.position == pt))
            {
                return;
            }

            int part = -1;
            int minIdx;

            // 一番近い頂点を探して、それと同じpartを割り当てる
            FMath.GetMinElement(vertices, v => FMath.SqDistance(v.position, pt), out minIdx);
            if (minIdx >= 0)
            {
                part = vertices[minIdx].part;
            }

            var cp = new PatchControlPoint(orgPt, part);

            cp.position = pt;

            controlPoints.Add(cp);
        }
Ejemplo 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();
        }