Beispiel #1
0
        public static PatchSkeletalMesh Copy(PatchSkeletalMesh org)
        {
            var m = PatchMesh.Copy(org.mesh);
            var s = PatchSkeleton.Copy(org.skl);
            PatchSkeletalMesh copy = new PatchSkeletalMesh(m, s, org.sections, false);

            return(copy);
        }
Beispiel #2
0
        public static void Fitting(PatchSkeletalMesh smesh, PatchSkeleton skl)
        {
            FTimer.Resume("Fitting:SetCtrl");
            // スケルトンに合わせて制御点を移動
            foreach (var kv in smesh.skeletalControlPointDict)
            {
                PatchSkeletonBone b      = kv.Key;
                List <PointF>     orgPts = kv.Value;
                PatchSkeletonBone br     = CorrespondingBone(skl, b);

                if (br == null)
                {
                    continue;
                }
                if (orgPts.Count <= 1)
                {
                    continue;
                }

                for (int i = 0; i < orgPts.Count; i++)
                {
                    float t = (float)i / (orgPts.Count - 1);

                    // smesh.skeletalControlPointExpandToXXXの値にしたがって、src, dst方向にそれぞれ伸長させる
                    float exSrc = smesh.endJoints.Contains(b.src.name) ? smesh.srcStretchRatio : 0;
                    float exDst = smesh.endJoints.Contains(b.dst.name) ? smesh.dstStretchRatio : 0;
                    float dx    = br.dst.position.X - br.src.position.X;
                    float dy    = br.dst.position.Y - br.src.position.Y;
                    t *= 1 + exSrc + exDst;
                    float lx = dx * t;
                    float ly = dy * t;
                    float ox = -dx * exSrc;
                    float oy = -dy * exSrc;
                    float x  = br.src.position.X + ox + lx;
                    float y  = br.src.position.Y + oy + ly;

//                    float x = br.src.position.X * (1 - t) + br.dst.position.X * t;
//                    float y = br.src.position.Y * (1 - t) + br.dst.position.Y * t;

                    PatchControlPoint c = smesh.mesh.FindControlPoint(orgPts[i]);
                    if (c == null)
                    {
                        continue;
                    }
                    smesh.mesh.TranslateControlPoint(c.position, new PointF(x, y), false);
                }

                // スケルトン(mesh.skl)も動かす
                b.src.position = br.src.position;
                b.dst.position = br.dst.position;
            }
            FTimer.Pause("Fitting:SetCtrl");

            // 制御点の移動を反映してメッシュ変形
            FTimer.Resume("Fitting:FlushDefomation");
            smesh.mesh.FlushDefomation();
            FTimer.Pause("Fitting:FlushDefomation");
        }
Beispiel #3
0
        //-----------------------------------------------------------------------------------
        // FindConnectingSections()
        //-----------------------------------------------------------------------------------

        /// <summary>
        /// skl内の同一のボーンと交差していて、なおかつ向きが逆の切り口を探す
        /// </summary>
        private static bool FindConnectingSections(
            PatchSkeletalMesh smesh1, PatchSkeletalMesh smesh2, PatchSkeleton skl,
            out PatchSection section1, out PatchSection section2, out PatchSkeletonBone crossingBone)
        {
            section1     = new PatchSection(0, -1);
            section2     = new PatchSection(0, -1);
            crossingBone = null;

            if (skl == null)
            {
                return(false);
            }

            if (smesh1 == null || smesh2 == null)
            {
                return(false);
            }

            foreach (var bone in skl.bones)
            {
                List <PatchSection> sections1, sections2;
                List <float>        dir1, dir2;

                // 各切り口がboneと交差しているか
                if (!FindCrossingSection(smesh1, bone, out sections1, out dir1))
                {
                    continue;
                }
                if (!FindCrossingSection(smesh2, bone, out sections2, out dir2))
                {
                    continue;
                }

                for (int i = 0; i < sections1.Count; i++)
                {
                    for (int j = 0; j < sections2.Count; j++)
                    {
                        // 2つの切り口が逆向きか
                        if (dir1[i] * dir2[j] >= 0)
                        {
                            continue;
                        }
                        section1     = sections1[i];
                        section2     = sections2[j];
                        crossingBone = bone;
                        return(true);
                    }
                }
            }

            return(false);
        }
Beispiel #4
0
        /// <summary>
        ///
        /// - ざっくり位置合わせ(オーバーラップさせる)
        /// - 接続後の境界を計算
        /// - それにあせてボーンと垂直方向に画像を変形
        /// - リサンプリング
        ///
        /// ・対応する境界線を探す(2D)
        /// ・ざっくり重なるように移動・拡大操作(2D)
        /// ・seam carving method(3D?)
        /// ・graphcut textures(2D)
        /// ・poisson blending(2D) (opencvを使う)
        /// ・resampleしてpatchmeshに戻す(3D)
        /// </summary>
        /// <param name="patches"></param>
        /// <param name="refSkeleton"></param>
        /// <param name="resources"></param>
        /// <returns></returns>
        public static PatchSkeletalMesh Connect(List <PatchSkeletalMesh> patches, PatchSkeleton refSkeleton, PatchMeshRenderResources resources)
        {
            var overlapPairs = OverlapPatchPairs(patches, refSkeleton);

            if (overlapPairs.Count <= 0)
            {
                return(null);
            }

            var newPatch = overlapPairs[0].Item1;
            List <PatchSkeletalMesh> aggregated = new List <PatchSkeletalMesh>();

            aggregated.Add(overlapPairs[0].Item1);

            for (int j = 0; j < overlapPairs.Count; j++)
            {
                // newPatchと接続可能なpatchをひとつ探して繋げる
                // O(N^2)だけど、patchesの総数はせいぜい十数個なので問題ない
                for (int i = 0; i < overlapPairs.Count; i++)
                {
                    var pair = overlapPairs[i];
                    if (aggregated.Contains(pair.Item1) && !aggregated.Contains(pair.Item2))
                    {
                        var connected = Connect(newPatch, pair.Item2, refSkeleton, resources);
                        if (connected != null)
                        {
                            newPatch = connected;
                            aggregated.Add(pair.Item2);
                            overlapPairs.RemoveAt(i);
                            break;
                        }
                    }
                    else if (!aggregated.Contains(pair.Item1) && aggregated.Contains(pair.Item2))
                    {
                        if (newPatch != null)
                        {
                            var connected = Connect(newPatch, pair.Item1, refSkeleton, resources);
                            if (connected != null)
                            {
                                newPatch = connected;
                                aggregated.Add(pair.Item1);
                                overlapPairs.RemoveAt(i);
                                break;
                            }
                        }
                    }
                }
            }

            return(newPatch);
        }
Beispiel #5
0
        static PatchSkeletonBone RefBone(PatchSkeleton refSkeleton, PatchSkeletonBone bone)
        {
            PatchSkeletonBone refBone = null;

            foreach (var b in refSkeleton.bones)
            {
                if (bone == b)
                {
                    refBone = b;
                    break;
                }
            }
            return(refBone);
        }
        static void MoveJoint(PatchSkeleton skl, List <PatchSkeletonJoint> joints, float dx, float dy, HashSet <PatchSkeletonJoint> haschecked)
        {
            if (joints.Count <= 0)
            {
                return;
            }

            foreach (var j in joints)
            {
                j.position = new PointF(j.position.X + dx, j.position.Y + dy);
                haschecked.Add(j);

                MoveJoint(skl, skl.bones.Where(b => b.src == j).Select(b => b.dst).ToList(), dx, dy, haschecked);
            }
        }
Beispiel #7
0
 // スケルトン内のbと同じ(jointの名前が同じ)ボーンを探す
 static PatchSkeletonBone CorrespondingBone(PatchSkeleton skl, PatchSkeletonBone b)
 {
     if (skl == null || b == null || skl.bones == null)
     {
         return(null);
     }
     foreach (var bb in skl.bones)
     {
         // オーバーライドしてるjointの名前が同じならtrue
         if (b == bb)
         {
             return(bb);
         }
     }
     return(null);
 }
Beispiel #8
0
        public void Stretch(float srcRatio, float dstRatio, PatchSkeleton refSkeleton)
        {
            var ends     = EndJointNames(skl);
            var ends_ref = EndJointNames(refSkeleton);

            endJoints.Clear();
            foreach (var j in ends)
            {
                if (!ends_ref.Contains(j))
                {
                    endJoints.Add(j);
                }
            }

            srcStretchRatio = srcRatio;
            dstStretchRatio = dstRatio;
        }
Beispiel #9
0
        //
        // AdjustPosition()
        //

        static void AdjustPosition(
            PatchSkeletalMesh smesh1, PatchSkeletalMesh smesh2, PatchSkeleton skl,
            PatchSection section1, PatchSection section2, PatchSkeletonBone bone)
        {
            PatchSkeletonBone refBone = null;

            foreach (var b in skl.bones)
            {
                if (bone == b)
                {
                    refBone = b;
                    break;
                }
            }

            if (refBone == null)
            {
                return;
            }

            // 切り口の中心とボーンの軸とのずれ(ボーンと垂直な方向について)
            float height1 = SectionHeight(smesh1, section1, refBone);
            float height2 = SectionHeight(smesh2, section2, refBone);

            // ボーンと水平なベクトルと垂直なベクトルをそれぞれx, yとして取得
            PointF x, y;

            CalcBoneCoordinate(refBone, out x, out y);

            // smesh2の切り口の中心がsmesh1の切り口の中心に重なるようにsmesh2をずらす
            if (Math.Abs(height1 - height2) > 1e-4)
            {
                float dx = y.X * (height1 - height2);
                float dy = y.Y * (height1 - height2);

                // mesh2の頂点・制御点を平行移動する
                foreach (var v in smesh2.mesh.vertices)
                {
                    v.position = new PointF(v.position.X + dx, v.position.Y + dy);
                }
                foreach (var c in smesh2.mesh.CopyControlPoints())
                {
                    smesh2.mesh.TranslateControlPoint(c.position, new PointF(c.position.X + dx, c.position.Y + dy), false);
                }
            }
        }
Beispiel #10
0
        private static PatchSkeleton CombineSkeleton(PatchSkeleton skl1, PatchSkeleton skl2)
        {
            PatchSkeleton skl = new PatchSkeleton();

            // 関節を追加
            foreach (var j in skl1.joints)
            {
                skl.joints.Add(new PatchSkeletonJoint(j.name, j.position));
            }
            foreach (var j in skl2.joints)
            {
                if (!skl.joints.Any(_j => _j.name == j.name))
                {
                    skl.joints.Add(new PatchSkeletonJoint(j.name, j.position));
                }
            }

            // ボーンを追加
            foreach (var b in skl1.bones)
            {
                if (skl.joints.Any(j => j.name == b.src.name) && skl.joints.Any(j => j.name == b.dst.name))
                {
                    var newBone = new PatchSkeletonBone(
                        skl.joints.First(j => j.name == b.src.name),
                        skl.joints.First(j => j.name == b.dst.name));
                    skl.bones.Add(newBone);
                }
            }
            foreach (var b in skl2.bones)
            {
                if (skl.joints.Any(j => j.name == b.src.name) && skl.joints.Any(j => j.name == b.dst.name))
                {
                    var newBone = new PatchSkeletonBone(
                        skl.joints.First(j => j.name == b.src.name),
                        skl.joints.First(j => j.name == b.dst.name));
                    if (!skl.bones.Contains(newBone))
                    {
                        skl.bones.Add(newBone);
                    }
                }
            }

            return(skl);
        }
Beispiel #11
0
        public static PatchSkeletalMesh Connect(List <PatchSkeletalMesh> smeshes, PatchSkeleton refSkeleton, PatchMeshRenderResources resources)
        {
            var overlapPairs = GetOverlappedPairs(smeshes, refSkeleton);

            if (overlapPairs.Count <= 0)
            {
                return(null);
            }

            var newMesh = overlapPairs[0].Item1;
            List <PatchSkeletalMesh> aggregated = new List <PatchSkeletalMesh>();

            aggregated.Add(overlapPairs[0].Item1);

            int _orgCnt = overlapPairs.Count;

            for (int j = 0; j < overlapPairs.Count; j++)
            {
                for (int i = 0; i < overlapPairs.Count; i++)
                {
                    var pair = overlapPairs[i];
                    if (aggregated.Contains(pair.Item1) && !aggregated.Contains(pair.Item2))
                    {
                        newMesh = Connect(newMesh, pair.Item2, refSkeleton, resources);
                        aggregated.Add(pair.Item2);
                        overlapPairs.RemoveAt(i);
                        break;
                    }
                    else if (!aggregated.Contains(pair.Item1) && aggregated.Contains(pair.Item2))
                    {
                        newMesh = Connect(newMesh, pair.Item1, refSkeleton, resources);
                        aggregated.Add(pair.Item1);
                        overlapPairs.RemoveAt(i);
                        break;
                    }
                }
                System.Diagnostics.Debug.Assert(aggregated.Count == j + 2);
                System.Diagnostics.Debug.Assert(overlapPairs.Count == _orgCnt - j - 1);
            }

            return(newMesh);
        }
Beispiel #12
0
        public static bool CanConnect(List <PatchSkeletalMesh> smeshes, PatchSkeleton refSkeleton)
        {
            if (smeshes == null || refSkeleton == null || smeshes.Count <= 1)
            {
                return(false);
            }

            // 1) ボーンの重なりが最大2
            // 2) 重なっているボーンで全てのメッシュが連結される
            // -FindConnectingSections() == true

            var overlapPairs = GetOverlappedPairs(smeshes, refSkeleton);

            HashSet <PatchSkeletalMesh> overlapSMeshes = new HashSet <PatchSkeletalMesh>();

            foreach (var pair in overlapPairs)
            {
                overlapSMeshes.Add(pair.Item1);
                overlapSMeshes.Add(pair.Item2);
            }

            if (overlapSMeshes.Count != smeshes.Count)
            {
                return(false);
            }

            foreach (var pair in overlapPairs)
            {
                PatchSection      section1;
                PatchSection      section2;
                PatchSkeletonBone crossingBone;
                bool found = FindConnectingSections(pair.Item1, pair.Item2, refSkeleton, out section1, out section2, out crossingBone);

                if (!found)
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #13
0
        PatchSkeleton(PatchSkeleton skl)
        {
            if (skl == null)
            {
                return;
            }

            this.joints = new List <PatchSkeletonJoint>();
            foreach (var j in skl.joints)
            {
                this.joints.Add(new PatchSkeletonJoint(j.name, j.position));
            }

            this.bones = new List <PatchSkeletonBone>();
            foreach (var b in skl.bones)
            {
                this.bones.Add(new PatchSkeletonBone(
                                   this.joints.First(j => j.name == b.src.name),
                                   this.joints.First(j => j.name == b.dst.name)));
            }
        }
        // 超簡易的なFK
        // 子ノードを親ノードと同じだけ平行移動させる
        public static void MoveJoint(PatchSkeleton skl, PatchSkeletonJoint joint, PointF to)
        {
            if (skl == null)
            {
                return;
            }
            if (joint == null)
            {
                return;
            }
            float dx = to.X - joint.position.X;
            float dy = to.Y - joint.position.Y;

            joint.position = to;

            HashSet <PatchSkeletonJoint> haschecked = new HashSet <PatchSkeletonJoint>();

            haschecked.Add(joint);

            MoveJoint(skl, skl.bones.Where(b => b.src == joint).Select(b => b.dst).ToList(), dx, dy, haschecked);
        }
Beispiel #15
0
        HashSet <string> EndJointNames(PatchSkeleton skl)
        {
            var ends    = new HashSet <string>();
            var cntDict = new Dictionary <string, int>();

            foreach (var j in skl.joints)
            {
                cntDict[j.name] = 0;
            }
            foreach (var b in skl.bones)
            {
                cntDict[b.src.name]++;
                cntDict[b.dst.name]++;
            }
            foreach (var kv in cntDict)
            {
                if (kv.Value == 1)
                {
                    ends.Add(kv.Key);
                }
            }
            return(ends);
        }
Beispiel #16
0
        // コピーせずに参照をそのまま格納する
        public PatchSkeletalMesh(PatchMesh mesh, PatchSkeleton skl, List <PatchSection> sections, bool setSkeletalControlPoints = true)
        {
            this.mesh     = mesh;
            this.skl      = skl;
            this.sections = new List <PatchSection>(sections);
            this.skeletalControlPointDict = CreateSkeletalControlPoints(skl, 20, 3);

            // 既存の制御点を消して、スケルトン周りの制御点を追加
            if (setSkeletalControlPoints)
            {
                this.mesh.ClearControlPoints();
                foreach (var ls in this.skeletalControlPointDict.Values)
                {
                    foreach (var pt in ls)
                    {
                        this.mesh.AddControlPoint(pt, pt);
                    }
                }
            }

            srcStretchRatio = 0;
            endJoints       = new HashSet <string>();
        }
Beispiel #17
0
        //--------------------------------------------------------------------------
        // Combine()
        //--------------------------------------------------------------------------

        /// <summary>
        /// 2つのメッシュを統合して1つのARAP可能なメッシュを作成する
        /// TODO: さすがに関数にわけるべき
        /// </summary>
        static PatchSkeletalMesh Combine(PatchSkeletalMesh smesh1, PatchSkeletalMesh smesh2, PatchSection section1, PatchSection section2)
        {
            //
            // Meshを作成
            //

            List <PatchVertex> vertices = CombineVertices(smesh1.mesh.vertices, smesh2.mesh.vertices);

            // 頂点から各種インデックスへの辞書を作っておく
            Dictionary <PointF, int> p2i = new Dictionary <PointF, int>();

            for (int i = 0; i < vertices.Count; i++)
            {
                p2i[vertices[i].position] = i;
            }
            Dictionary <PointF, int> pt2part = vertices.ToDictionary(v => v.position, v => v.part);

            Dictionary <int, int> part2part_1 = new Dictionary <int, int>(); // smesh1の各パートが新しいメッシュのどのパートになるか

            foreach (var v in smesh1.mesh.vertices)
            {
                part2part_1[v.part] = pt2part[v.position];
            }

            Dictionary <int, int> part2part_2 = new Dictionary <int, int>(); // smesh2の各パートが新しいメッシュのどのパートになるか

            foreach (var v in smesh2.mesh.vertices)
            {
                part2part_2[v.part] = pt2part[v.position];
            }

            List <PatchControlPoint> controlPoints = CombineControlPoints(smesh1.mesh.CopyControlPoints(), smesh2.mesh.CopyControlPoints(), part2part_1, part2part_2);
            List <PatchTriangle>     triangles     = CombineTriangles(smesh1.mesh.triangles, smesh2.mesh.triangles, smesh1.mesh.vertices, smesh2.mesh.vertices, p2i);
            List <int> path = CombinePath(smesh1.mesh.pathIndices, smesh2.mesh.pathIndices, smesh1.mesh.vertices, smesh2.mesh.vertices, section1, section2, p2i);

            PatchMesh rawMesh = new PatchMesh(vertices, controlPoints, triangles, path);

            //
            // 骨格を統合
            //

            PatchSkeleton skl = CombineSkeleton(smesh1.skl, smesh2.skl);


            //
            // 切り口を統合.
            //
            List <PatchSection> sections = CombineSections(
                smesh1.sections, smesh2.sections,
                section1, section2,
                smesh1.mesh.vertices, smesh2.mesh.vertices,
                smesh1.Mesh.pathIndices, smesh2.Mesh.pathIndices,
                path, p2i);

            //
            // SkeletalMeshを作成.
            //
            PatchSkeletalMesh newMesh = new PatchSkeletalMesh(rawMesh, skl, sections);

            return(newMesh);
        }
Beispiel #18
0
        /// <summary>
        /// 2つの骨格つきメッシュをスケルトン情報を元に結合する
        /// 1. スケルトンに合わせて各メッシュをざっくり移動・ボーン方向にARAP
        /// 2. メッシュ同士が自然に繋がるように位置・角度・スケールを調整(fitting(), adjustposition())
        /// 3. 繋ぎ目が重なるようにARAP(expand())
        /// 4. 新しいARAP可能なひとつのメッシュを生成(combine)                                                                                                                                                                                                                                                                                          /// </summary>
        /// (5. リソースの更新。これはここでやるべきなのだろうか?)
        /// </summary>
        public static PatchSkeletalMesh Connect(PatchSkeletalMesh smesh1, PatchSkeletalMesh smesh2, PatchSkeleton refSkeleton, PatchMeshRenderResources resources)
        {
            if (refSkeleton == null)
            {
                return(null);
            }

            // メッシュ・骨格データはConnect()内で変更されうるのでコピーしたものを使う
            PatchSkeletalMesh smesh1_t = PatchSkeletalMesh.Copy(smesh1);
            PatchSkeletalMesh smesh2_t = PatchSkeletalMesh.Copy(smesh2);

#if DEBUG
            PatchSkeletalMeshRenderer.ToBitmap(smesh1_t, smesh1_t.sections, alignment: true).Save("smesh1_t.png");
            PatchSkeletalMeshRenderer.ToBitmap(smesh2_t, smesh2_t.sections, alignment: true).Save("smesh2_t.png");
#endif
            var refSkeleton_t = PatchSkeleton.Copy(refSkeleton);

            // smesh1, smesh2で同じボーンを共有している(結合すべき)切り口を探す
            // これらの切り口の付近を変形することでメッシュを繋げる
            PatchSection      section1;
            PatchSection      section2;
            PatchSkeletonBone crossingBone;

            bool canConnect = CanConnect(new List <PatchSkeletalMesh>()
            {
                smesh1, smesh2
            }, refSkeleton);
            bool canConnect_t = CanConnect(new List <PatchSkeletalMesh>()
            {
                smesh1_t, smesh2_t
            }, refSkeleton_t);

            bool found = FindConnectingSections(smesh1_t, smesh2_t, refSkeleton_t, out section1, out section2, out crossingBone);
            if (!found)
            {
                return(null);
            }
#if _DEBUG
            PatchSkeletalMeshRenderer.ToBitmap(smesh1_t, new List <CharacterRange>()
            {
                section1
            }).Save("output/3_mesh1_t_seciton1.png");
            PatchSkeletalMeshRenderer.ToBitmap(smesh2_t, new List <CharacterRange>()
            {
                section2
            }).Save("output/4_mesh2_t_section2.png");
#endif

            // 2つのsmeshが重なるように位置調整およびARAP変形をする
            smesh1_t.mesh.BeginDeformation();
            smesh2_t.mesh.BeginDeformation();
            Deform(smesh1_t, smesh2_t, refSkeleton_t, section1, section2, crossingBone);
            smesh2_t.mesh.EndDeformation();
            smesh1_t.mesh.EndDeformation();
#if _DEBUG
            PatchSkeletalMeshRenderer.ToBitmap(smesh1_t).Save("output/6_mesh1_t_deformed.png");
            PatchSkeletalMeshRenderer.ToBitmap(smesh2_t).Save("output/7_mesh2_t_deformed.png");
#endif

            // 2つの変形済みのsmeshを1つのsmeshに結合して、ARAPできるようにする
            var combinedSMesh = Combine(smesh1_t, smesh2_t, section1, section2);
#if _DEBUG
            PatchSkeletalMeshRenderer.ToBitmap(combinedSMesh, combinedSMesh.sections).Save("output/8_conbinedMesh.png");
#endif

            if (resources != null)
            {
                List <string> textureKeys = resources.GetResourceKeyByPatchMesh(smesh1.mesh);
                textureKeys.AddRange(resources.GetResourceKeyByPatchMesh(smesh2.mesh));

                foreach (var key in textureKeys)
                {
                    string patchKey = key.Split(':').Last();
                    string newKey   = PatchMeshRenderResources.GenerateResourceKey(combinedSMesh.mesh, patchKey);
                    // TODO: テクスチャはコピーしたほうが良い?
                    resources.Add(newKey, resources.GetTexture(key));
                }
            }

            return(combinedSMesh);
        }
Beispiel #19
0
        //
        // 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();
        }
Beispiel #20
0
        public static PatchSkeleton Load(string filepath, Bitmap refSkeletonBmp)
        {
            if (!File.Exists(filepath))
            {
                return(null);
            }

            filepath = Path.GetFullPath(filepath);

            var an = new PatchSkeleton();

            an.joints = File.ReadAllLines(filepath)
                        .Where(line => !string.IsNullOrWhiteSpace(line) && line.Contains(':'))
                        .Select(line =>
            {
                var tokens = line.Split(':');
                if (tokens.Length != 2)
                {
                    return(null);
                }
                var xys = tokens[1].Split(',');
                if (xys.Length != 2)
                {
                    return(null);
                }
                float x, y;
                if (!float.TryParse(xys[0], out x) || !float.TryParse(xys[1], out y))
                {
                    return(null);
                }
                return(new PatchSkeletonJoint(tokens[0], new PointF(x, y)));
            })
                        .Where(j => j != null)
                        .ToList();

            an.bones = File.ReadAllLines(filepath)
                       .Where(line => !string.IsNullOrWhiteSpace(line) && line.Contains('>'))
                       .Select(line =>
            {
                var tokens = line.Split('>');
                if (tokens.Length != 2)
                {
                    return(null);
                }
                PatchSkeletonJoint src = null, dst = null;
                foreach (var j in an.joints)
                {
                    if (j.name == tokens[0])
                    {
                        src = j;
                    }
                    if (j.name == tokens[1])
                    {
                        dst = j;
                    }
                }
                if (src == null || dst == null)
                {
                    return(null);
                }

                return(new PatchSkeletonBone(src, dst));
            })
                       .Where(b => b != null)
                       .ToList();

            return(an);
        }
Beispiel #21
0
        //-----------------------------------------------------------------------------------
        // Deform()
        //-----------------------------------------------------------------------------------

        /// <summary>
        /// 切り口付近で2つのsmeshが重なるように変形する
        /// </summary>
        private static void Deform(PatchSkeletalMesh smesh1, PatchSkeletalMesh smesh2, PatchSkeleton skl, PatchSection section1, PatchSection section2, PatchSkeletonBone crossingBone)
        {
            if (smesh1 == null || smesh2 == null)
            {
                return;
            }

            // 各メッシュを大雑把にスケルトンに合わせる
            PatchSkeletonFitting.Fitting(smesh1, skl);
            PatchSkeletonFitting.Fitting(smesh2, skl);
#if _DEBUG
            PatchSkeletalMeshRenderer.ToBitmap(smesh1, new List <PatchSection>()
            {
                section1
            }).Save("output/5_1_mesh1_fitting.png");
            PatchSkeletalMeshRenderer.ToBitmap(smesh2, new List <PatchSection>()
            {
                section2
            }).Save("output/5_2_mesh2_fitting.png");
#endif

            // サイズの修正は手動でやる
            // 回転はFitting()でやってるから必要ない

            // 位置の調整
            AdjustPosition(smesh1, smesh2, skl, section1, section2, crossingBone);
#if _DEBUG
            PatchSkeletalMeshRenderer.ToBitmap(smesh1, new List <PatchSection>()
            {
                section1
            }).Save("output/5_3_mesh1_AdjustPosition.png");
            PatchSkeletalMeshRenderer.ToBitmap(smesh2, new List <PatchSection>()
            {
                section2
            }).Save("output/5_4_mesh2_AdjustPosition.png");
#endif

            // メッシュを伸ばして繋げる
            Expand(smesh1, smesh2, skl, section1, section2, crossingBone);
#if _DEBUG
            PatchSkeletalMeshRenderer.ToBitmap(smesh1, new List <PatchSection>()
            {
                section1
            }).Save("output/5_5_mesh1_ExpandPatches.png");
            PatchSkeletalMeshRenderer.ToBitmap(smesh2, new List <PatchSection>()
            {
                section2
            }).Save("output/5_6_mesh2_ExpandPatches.png");
#endif
        }
Beispiel #22
0
        static Dictionary <PatchSkeletonBone, List <PointF> > CreateSkeletalControlPoints(PatchSkeleton skl, int linearSpan, int minPtNum)
        {
            Dictionary <PatchSkeletonBone, List <PointF> > dict = new Dictionary <PatchSkeletonBone, List <PointF> >();

            // ボーン沿いに制御点を追加
            if (skl != null && linearSpan >= 1)
            {
                foreach (var b in skl.bones)
                {
                    dict[b] = new List <PointF>();
                    float dist  = FLib.FMath.Distance(b.src.position, b.dst.position);
                    int   ptNum = Math.Max(2, (int)(dist / linearSpan) + 1);
                    if (ptNum < minPtNum)
                    {
                        ptNum = minPtNum;
                    }
                    for (int i = 0; i < ptNum; i++)
                    {
                        float t = (float)i / (ptNum - 1);
                        // 誤差の問題があるので i == 0, ptNum - 1のときは明示的に端点を代入する
                        PointF p;
                        if (i == 0)
                        {
                            p = b.src.position;
                        }
                        else if (i == ptNum - 1)
                        {
                            p = b.dst.position;
                        }
                        else
                        {
                            p = FLib.FMath.Interpolate(b.src.position, b.dst.position, t);
                        }
                        dict[b].Add(p);
                    }
                }
            }
            return(dict);
        }
Beispiel #23
0
 public PatchSkeleton CopySkeleton()
 {
     return(PatchSkeleton.Copy(skl));
 }
Beispiel #24
0
        static List <Tuple <PatchSkeletalMesh, PatchSkeletalMesh> > GetOverlappedPairs(List <PatchSkeletalMesh> smeshes, PatchSkeleton refSkeleton)
        {
            Dictionary <PatchSkeletonBone, List <PatchSkeletalMesh> > overlaps = new Dictionary <PatchSkeletonBone, List <PatchSkeletalMesh> >();

            foreach (var b in refSkeleton.bones)
            {
                overlaps[b] = new List <PatchSkeletalMesh>();
            }

            foreach (var sm in smeshes)
            {
                foreach (var b in sm.skl.bones)
                {
                    if (overlaps.ContainsKey(b))
                    {
                        overlaps[b].Add(sm);
                        if (overlaps[b].Count >= 3)
                        {
                            //                       System.Diagnostics.Debug.Assert(false);
                            return(new List <Tuple <PatchSkeletalMesh, PatchSkeletalMesh> >());
                        }
                    }
                }
            }

            var pairs = new List <Tuple <PatchSkeletalMesh, PatchSkeletalMesh> >();

            foreach (var kv in overlaps)
            {
                if (kv.Value.Count != 2)
                {
                    continue;
                }
                pairs.Add(new Tuple <PatchSkeletalMesh, PatchSkeletalMesh>(kv.Value[0], kv.Value[1]));
            }

            return(pairs);
        }
Beispiel #25
0
        public static PatchSkeletalMesh Connect(PatchSkeletalMesh patch1, PatchSkeletalMesh patch2, PatchSkeleton refSkeleton, PatchMeshRenderResources resources)
        {
            if (refSkeleton == null)
            {
                return(null);
            }

            if (!System.IO.Directory.Exists("output_Connector2"))
            {
                System.IO.Directory.CreateDirectory("output_Connector2");
            }

            FLib.FileManager.OpenExplorer("output_Connector2");

#if _DEBUG
            PatchSkeletalMeshRenderer.ToBitmap(patch1).Save("output_Connector2/1_patch1.png");
            PatchSkeletalMeshRenderer.ToBitmap(patch2).Save("output_Connector2/1_patch2.png");
#endif
            // 1. パッチをコピー
            PatchSkeletalMesh patch1_t = PatchSkeletalMesh.Copy(patch1);
            PatchSkeletalMesh patch2_t = PatchSkeletalMesh.Copy(patch2);
            var refSkeleton_t          = PatchSkeleton.Copy(refSkeleton);

            // 2. patch1, patch2の接続面および対応するボーンを探す
            PatchSection      section1;
            PatchSection      section2;
            PatchSkeletonBone crossingBone;
            bool swap;
            bool found = ConnectableSections(patch1_t, patch2_t, refSkeleton_t, out section1, out section2, out crossingBone, out swap);
            if (!found)
            {
                return(null);
            }

            if (swap)
            {
                FMath.Swap(ref patch1_t, ref patch2_t);
                FMath.Swap(ref section1, ref section2);
            }

#if _DEBUG
            PatchSkeletalMeshRenderer.ToBitmap(patch1_t, new List <CharacterRange>()
            {
                section1
            }).Save("output_Connector2/2_patch1.png");
            PatchSkeletalMeshRenderer.ToBitmap(patch2_t, new List <CharacterRange>()
            {
                section2
            }).Save("output_Connector2/2_patch2.png");
#endif

            // 3. 2つのパッチが重なるように位置調整およびARAP変形
            patch1_t.mesh.BeginDeformation();
            patch2_t.mesh.BeginDeformation();
            Deform(patch1_t, patch2_t, refSkeleton_t, section1, section2, crossingBone);
            patch2_t.mesh.EndDeformation();
            patch1_t.mesh.EndDeformation();

#if _DEBUG
            PatchSkeletalMeshRenderer.ToBitmap(patch1_t, new List <CharacterRange>()
            {
                section1
            }).Save("output_Connector2/3_patch1.png");
            PatchSkeletalMeshRenderer.ToBitmap(patch2_t, new List <CharacterRange>()
            {
                section2
            }).Save("output_Connector2/3_patch2.png");
#endif

            // 4. 2つのパッチのテクスチャを合成して、新しいパッチを生成

//            TODO:メッシュをビットマップ画像として書き出してリサンプリング

            // todo
            var combinedSMesh = Combine(patch1_t, patch2_t, section1, section2);


            // 5. 新しいパッチに使うテクスチャをリソースに登録

            // todo
            if (resources != null)
            {
                List <string> textureKeys = resources.GetResourceKeyByPatchMesh(patch1.mesh);
                textureKeys.AddRange(resources.GetResourceKeyByPatchMesh(patch2.mesh));

                foreach (var key in textureKeys)
                {
                    string patchKey = key.Split(':').Last();
                    string newKey   = PatchMeshRenderResources.GenerateResourceKey(combinedSMesh.mesh, patchKey);
                    resources.Add(newKey, resources.GetTexture(key));
                }
            }
            return(combinedSMesh);
        }
Beispiel #26
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();
        }
Beispiel #27
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);
            }
        }
Beispiel #28
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);
        }
Beispiel #29
0
        //----------------------------------------------------------------

        #region Connectability

        static List <Tuple <PatchSkeletalMesh, PatchSkeletalMesh> > OverlapPatchPairs(List <PatchSkeletalMesh> smeshes, PatchSkeleton refSkeleton)
        {
            var overlaps = new Dictionary <PatchSkeletonBone, List <PatchSkeletalMesh> >();

            foreach (var b in refSkeleton.bones)
            {
                overlaps[b] = new List <PatchSkeletalMesh>();
            }

            foreach (var sm in smeshes)
            {
                foreach (var b in sm.skl.bones)
                {
                    if (overlaps.ContainsKey(b))
                    {
                        overlaps[b].Add(sm);
                        if (overlaps[b].Count >= 3)
                        {
                            return(new List <Tuple <PatchSkeletalMesh, PatchSkeletalMesh> >());
                        }
                    }
                }
            }

            var pairs = new List <Tuple <PatchSkeletalMesh, PatchSkeletalMesh> >();

            foreach (var kv in overlaps)
            {
                if (kv.Value.Count != 2)
                {
                    continue;
                }
                pairs.Add(new Tuple <PatchSkeletalMesh, PatchSkeletalMesh>(kv.Value[0], kv.Value[1]));
            }

            return(pairs);
        }
Beispiel #30
0
        //-----------------------------------------------------------------------------------
        // Deform()
        //-----------------------------------------------------------------------------------

        /// <summary>
        /// 切り口付近で2つのsmeshが重なるように変形する
        /// patch2がdst方向
        /// </summary>
        private static void Deform(PatchSkeletalMesh patch1, PatchSkeletalMesh patch2, PatchSkeleton refSkeleton, PatchSection section1, PatchSection section2, PatchSkeletonBone crossingBone)
        {
            if (patch1 == null || patch2 == null)
            {
                return;
            }

            // 各メッシュを大雑把にスケルトンに合わせる
            PatchSkeletonFitting.Fitting(patch1, refSkeleton);
            PatchSkeletonFitting.Fitting(patch2, refSkeleton);

            // TODO: サイズの修正

            // 回転はFitting()でやってるから必要ない

            // 位置の調整

            float overlap = OverlapWidth(patch1, patch2, refSkeleton, section1, section2, crossingBone, 100, 45);

            AdjustHeight(patch1, patch2, refSkeleton, section1, section2, crossingBone);
            OverlayPatches(patch1, patch2, refSkeleton, section1, section2, crossingBone, overlap);

#if _DEBUG
            PatchSkeletalMeshRenderer.ToBitmap(patch1).Save("output_Connector2/4_patch1.png");
            PatchSkeletalMeshRenderer.ToBitmap(patch2).Save("output_Connector2/4_patch2.png");
#endif
            // メッシュを伸ばして繋げる
            Expand(patch1, patch2, refSkeleton, section1, section2, crossingBone, overlap, overlap);
        }