Beispiel #1
0
        /// <summary>
        /// カット面を埋める?
        /// </summary>
        /// <param name="vertices">ポリゴンを形成する頂点リスト</param>
        /// <param name="boneWeights">ポリゴンを形成する頂点に紐付いたボーンウェイト</param>
        /// <param name="blade">カット平面</param>
        private void FillCap(MeshCutData data)
        {
            #region ### Center of vertices ###
            // カット平面の中心点を計算する
            Vector3 center = Vector3.zero;

            // 引数で渡された頂点位置をすべて合計する
            foreach (Vector3 point in data.CapVertpolygon)
            {
                center += point;
            }

            // それを頂点数の合計で割り、中心とする
            center = center / data.CapVertpolygon.Count;
            #endregion ### Center of vertices ###

            #region ### Center of bone weights ###
            BoneWeight centerWeight         = new BoneWeight();
            Dictionary <int, float> weights = new Dictionary <int, float>();
            for (int i = 0; i < data.CapBoneWeightpolygon.Count; i++)
            {
                BoneWeight weight = data.CapBoneWeightpolygon[i];
                for (int j = 0; j < 4; j++)
                {
                    switch (j)
                    {
                    case 0:
                        if (weights.ContainsKey(weight.boneIndex0))
                        {
                            weights[weight.boneIndex0] += weight.weight0;
                        }
                        else
                        {
                            weights[weight.boneIndex0] = weight.weight0;
                        }
                        break;

                    case 1:
                        if (weights.ContainsKey(weight.boneIndex1))
                        {
                            weights[weight.boneIndex1] += weight.weight1;
                        }
                        else
                        {
                            weights[weight.boneIndex1] = weight.weight1;
                        }
                        break;

                    case 2:
                        if (weights.ContainsKey(weight.boneIndex2))
                        {
                            weights[weight.boneIndex2] += weight.weight2;
                        }
                        else
                        {
                            weights[weight.boneIndex2] = weight.weight2;
                        }
                        break;

                    case 3:
                        if (weights.ContainsKey(weight.boneIndex3))
                        {
                            weights[weight.boneIndex3] += weight.weight3;
                        }
                        else
                        {
                            weights[weight.boneIndex3] = weight.weight3;
                        }
                        break;
                    }
                }
            }

            var list = weights.OrderByDescending(w => w.Value).ToArray();
            int len  = 4;
            if (list.Length < 4)
            {
                len = list.Length;
            }

            float total = 0;
            for (int i = 0; i < len; i++)
            {
                total += list[i].Value;
            }
            for (int i = 0; i < len; i++)
            {
                switch (i)
                {
                case 0:
                    centerWeight.boneIndex0 = list[i].Key;
                    centerWeight.weight0    = list[i].Value / total;
                    break;

                case 1:
                    centerWeight.boneIndex1 = list[i].Key;
                    centerWeight.weight1    = list[i].Value / total;
                    break;

                case 2:
                    centerWeight.boneIndex2 = list[i].Key;
                    centerWeight.weight2    = list[i].Value / total;
                    break;

                case 3:
                    centerWeight.boneIndex3 = list[i].Key;
                    centerWeight.weight3    = list[i].Value / total;
                    break;
                }
            }
            #endregion ### Center of bone weights ###

            // you need an axis based on the cap
            // カット平面をベースにしたupward
            Vector3 upward = Vector3.zero;

            // 90 degree turn
            // カット平面の法線を利用して、「上」方向を求める
            // 具体的には、平面の左側を上として利用する
            upward.x = data.Blade.Normal.y;
            upward.y = -data.Blade.Normal.x;
            upward.z = data.Blade.Normal.z;

            // 法線と「上方向」から、横軸を算出
            Vector3 left = Vector3.Cross(data.Blade.Normal, upward);

            Vector3 displacement = Vector3.zero;
            Vector3 newUV1       = Vector3.zero;
            Vector3 newUV2       = Vector3.zero;

            // 引数で与えられた頂点分ループを回す
            for (int i = 0; i < data.CapVertpolygon.Count; i++)
            {
                // 計算で求めた中心点から、各頂点への方向ベクトル
                displacement = data.CapVertpolygon[i] - center;

                // 新規生成するポリゴンのUV座標を求める。
                // displacementが中心からのベクトルのため、UV的な中心である0.5をベースに、内積を使ってUVの最終的な位置を得る
                newUV1   = Vector3.zero;
                newUV1.x = 0.5f + Vector3.Dot(displacement, left);
                newUV1.y = 0.5f + Vector3.Dot(displacement, upward);
                newUV1.z = 0.5f + Vector3.Dot(displacement, data.Blade.Normal);

                // 次の頂点。ただし、最後の頂点の次は最初の頂点を利用するため、若干トリッキーな指定方法をしている(% vertices.Count)
                displacement = data.CapVertpolygon[(i + 1) % data.CapVertpolygon.Count] - center;

                newUV2   = Vector3.zero;
                newUV2.x = 0.5f + Vector3.Dot(displacement, left);
                newUV2.y = 0.5f + Vector3.Dot(displacement, upward);
                newUV2.z = 0.5f + Vector3.Dot(displacement, data.Blade.Normal);

                // 左側のポリゴンとして、求めたUVを利用してトライアングルを追加
                data.LeftSide.AddTriangle(
                    new Vector3[] {
                    data.CapVertpolygon[i],
                    data.CapVertpolygon[(i + 1) % data.CapVertpolygon.Count],
                    center
                },
                    new Vector3[] {
                    -data.Blade.Normal,
                    -data.Blade.Normal,
                    -data.Blade.Normal
                },
                    new Vector2[] {
                    newUV1,
                    newUV2,
                    new Vector2(0.5f, 0.5f)
                },
                    new BoneWeight[]
                {
                    data.VictimMesh.HasBoneWeight?data.CapBoneWeightpolygon[i] : new BoneWeight(),
                    data.VictimMesh.HasBoneWeight ? data.CapBoneWeightpolygon[(i + 1) % data.CapVertpolygon.Count] : new BoneWeight(),
                    data.VictimMesh.HasBoneWeight ? centerWeight : new BoneWeight(),
                },
                    -data.Blade.Normal,
                    data.LeftSide.SubIndices.Count - 1 // カット面。最後のサブメッシュとしてトライアングルを追加
                    );

                // 右側のトライアングル。基本は左側と同じだが、法線だけ逆向き。
                data.RightSide.AddTriangle(
                    new Vector3[] {
                    data.CapVertpolygon[i],
                    data.CapVertpolygon[(i + 1) % data.CapVertpolygon.Count],
                    center
                },
                    new Vector3[] {
                    data.Blade.Normal,
                    data.Blade.Normal,
                    data.Blade.Normal
                },
                    new Vector2[] {
                    newUV1,
                    newUV2,
                    new Vector2(0.5f, 0.5f)
                },
                    new BoneWeight[]
                {
                    data.VictimMesh.HasBoneWeight?data.CapBoneWeightpolygon[i] : new BoneWeight(),
                    data.VictimMesh.HasBoneWeight ? data.CapBoneWeightpolygon[(i + 1) % data.CapVertpolygon.Count] : new BoneWeight(),
                    data.VictimMesh.HasBoneWeight ? centerWeight : new BoneWeight(),
                },
                    data.Blade.Normal,
                    data.RightSide.SubIndices.Count - 1 // カット面。最後のサブメッシュとしてトライアングルを追加
                    );
            }
        }
Beispiel #2
0
        /// <summary>
        /// カットを実行
        /// </summary>
        private void Capping(MeshCutData data)
        {
            // カット用頂点追跡リスト
            // 具体的には新頂点全部に対する調査を行う。その過程で調査済みをマークする目的で利用する。
            data.CapVertTracker.Clear();

            // 新しく生成した頂点分だけループする=全新頂点に対してポリゴンを形成するため調査を行う
            // 具体的には、カット面を構成するポリゴンを形成するため、カット時に重複した頂点を網羅して「面」を形成する頂点を調査する
            for (int i = 0; i < data.NewVertices.Count; i++)
            {
                // 対象頂点がすでに調査済みのマークされて(追跡配列に含まれて)いたらスキップ
                if (data.CapVertTracker.Contains(data.NewVertices[i]))
                {
                    continue;
                }

                // カット用ポリゴン配列をクリア
                data.CapVertpolygon.Clear();
                data.CapBoneWeightpolygon.Clear();

                // 調査頂点と次の頂点をポリゴン配列に保持する
                data.CapVertpolygon.Add(data.NewVertices[i + 0]);
                data.CapVertpolygon.Add(data.NewVertices[i + 1]);

                // 頂点に紐づくボーンウェイトを配列に保持する

                if (data.VictimMesh.HasBoneWeight)
                {
                    data.CapBoneWeightpolygon.Add(data.NewBoneWeights[i + 0]);
                    data.CapBoneWeightpolygon.Add(data.NewBoneWeights[i + 1]);
                }

                // 追跡配列に自身と次の頂点を追加する(調査済みのマークをつける)
                data.CapVertTracker.Add(data.NewVertices[i + 0]);
                data.CapVertTracker.Add(data.NewVertices[i + 1]);

                // 重複頂点がなくなるまでループし調査する
                bool isDone = false;
                while (!isDone)
                {
                    isDone = true;

                    // 新頂点郡をループし、「面」を構成する要因となる頂点をすべて抽出する。抽出が終わるまでループを繰り返す
                    // 2頂点ごとに調査を行うため、ループは2単位ですすめる
                    for (int k = 0; k < data.NewVertices.Count; k += 2)
                    { // go through the pairs
                      // ペアとなる頂点を探す
                      // ここでのペアとは、いちトライアングルから生成される新頂点のペア。
                      // トライアングルからは必ず2頂点が生成されるため、それを探す。
                      // また、全ポリゴンに対して分割点を生成しているため、ほぼ必ず、まったく同じ位置に存在する、別トライアングルの分割頂点が存在するはずである。
                        if (data.NewVertices[k] == data.CapVertpolygon[data.CapVertpolygon.Count - 1] && !data.CapVertTracker.Contains(data.NewVertices[k + 1]))
                        {   // if so add the other
                            // ペアの頂点が見つかったらそれをポリゴン配列に追加し、
                            // 調査済マークをつけて、次のループ処理に回す
                            isDone = false;
                            data.CapVertTracker.Add(data.NewVertices[k + 1]);
                            data.CapVertpolygon.Add(data.NewVertices[k + 1]);

                            if (data.VictimMesh.HasBoneWeight)
                            {
                                data.CapBoneWeightpolygon.Add(data.NewBoneWeights[k + 1]);
                            }
                        }
                        else if (data.NewVertices[k + 1] == data.CapVertpolygon[data.CapVertpolygon.Count - 1] && !data.CapVertTracker.Contains(data.NewVertices[k]))
                        {   // if so add the other
                            isDone = false;
                            data.CapVertTracker.Add(data.NewVertices[k]);
                            data.CapVertpolygon.Add(data.NewVertices[k]);

                            if (data.VictimMesh.HasBoneWeight)
                            {
                                data.CapBoneWeightpolygon.Add(data.NewBoneWeights[k]);
                            }
                        }
                    }
                }

                // 見つかった頂点郡を元に、ポリゴンを形成する
                FillCap(data);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Cut the specified victim, blade_plane and capMaterial.
        /// (指定された「victim」をカットする。ブレード(平面)とマテリアルから切断を実行する)
        /// </summary>
        /// <param name="victim">Victim.</param>
        /// <param name="blade_plane">Blade plane.</param>
        public CutterMesh[] Cut(CutterObject victim, CutterPlane blade)
        {
            // 対象のメッシュを取得
            MeshCutData data = new MeshCutData(victim.CutterMesh, blade);

            // ここでの「3」はトライアングル
            bool[] sides = new bool[3];
            int[]  indices;
            int    p1, p2, p3;

            // go throught the submeshes
            // サブメッシュの数だけループ
            for (int sub = 0; sub < victim.SubMeshCount; sub++)
            {
                // サブメッシュのインデックス数を取得
                indices = victim.CutterMesh.GetIndices(sub);

                // List<List<int>>型のリスト。サブメッシュ一つ分のインデックスリスト
                data.LeftSide.SubIndices.Add(new List <int>());  // 左
                data.RightSide.SubIndices.Add(new List <int>()); // 右

                // サブメッシュのインデックス数分ループ
                for (int i = 0; i < indices.Length; i += 3)
                {
                    // p1 - p3のインデックスを取得。つまりトライアングル
                    p1 = indices[i + 0];
                    p2 = indices[i + 1];
                    p3 = indices[i + 2];

                    // それぞれ評価中のメッシュの頂点が、冒頭で定義された平面の左右どちらにあるかを評価。
                    // `GetSide` メソッドによりboolを得る。
                    sides[0] = blade.GetSide(data.VictimMesh.Vertices[p1]);
                    sides[1] = blade.GetSide(data.VictimMesh.Vertices[p2]);
                    sides[2] = blade.GetSide(data.VictimMesh.Vertices[p3]);

                    // whole triangle
                    // 頂点0と頂点1および頂点2がどちらも同じ側にある場合はカットしない
                    if (sides[0] == sides[1] && sides[0] == sides[2])
                    {
                        if (sides[0])
                        {   // left side
                            // GetSideメソッドでポジティブ(true)の場合は左側にあり
                            data.LeftSide.AddTriangle(p1, p2, p3, sub);
                        }
                        else
                        {
                            data.RightSide.AddTriangle(p1, p2, p3, sub);
                        }
                    }
                    else
                    {   // cut the triangle
                        // そうではなく、どちらかの点が平面の反対側にある場合はカットを実行する
                        CutFace(sub, sides, p1, p2, p3, data);
                    }
                }
            }

            // Check separating verticies.
            if (data.LeftSide.Vertices.Count == 0 || data.RightSide.Vertices.Count == 0)
            {
                Debug.Log("No need cutting, because all verticies are in one side.");
                return(null);
            }

            data.LeftSide.SubIndices.Add(new List <int>());
            data.RightSide.SubIndices.Add(new List <int>());

            // カット開始
            Capping(data);

            // 左側のメッシュを生成
            // MeshCutSideクラスのメンバから各値をコピー
            CutterMesh leftHalfMesh = new CutterMesh
            {
                Vertices    = data.LeftSide.Vertices.ToArray(),
                Triangles   = data.LeftSide.Triangles.ToArray(),
                Normals     = data.LeftSide.Normals.ToArray(),
                UVs         = data.LeftSide.UVs.ToArray(),
                BoneWeights = data.LeftSide.BoneWeights.ToArray(),
            };

            int[][] leftSubIndices = new int[data.LeftSide.SubIndices.Count][];
            for (int i = 0; i < data.LeftSide.SubIndices.Count; i++)
            {
                leftSubIndices[i] = data.LeftSide.SubIndices[i].ToArray();
            }
            leftHalfMesh.SetIndices(leftSubIndices);

            // 右側のメッシュも同様に生成
            CutterMesh rightHalfMesh = new CutterMesh
            {
                Vertices    = data.RightSide.Vertices.ToArray(),
                Triangles   = data.RightSide.Triangles.ToArray(),
                Normals     = data.RightSide.Normals.ToArray(),
                UVs         = data.RightSide.UVs.ToArray(),
                BoneWeights = data.RightSide.BoneWeights.ToArray(),
            };

            int[][] rightSubIndices = new int[data.RightSide.SubIndices.Count][];
            for (int i = 0; i < data.RightSide.SubIndices.Count; i++)
            {
                rightSubIndices[i] = data.RightSide.SubIndices[i].ToArray();
            }
            rightHalfMesh.SetIndices(rightSubIndices);

            Debug.Log("cutter finish");

            // 左右のGameObjectの配列を返す
            return(new CutterMesh[] { leftHalfMesh, rightHalfMesh });
        }
Beispiel #4
0
        /// <summary>
        /// カットを実行する。ただし、実際のメッシュの操作ではなく、あくまで頂点の振り分け、事前準備としての実行
        /// </summary>
        /// <param name="submesh">サブメッシュのインデックス</param>
        /// <param name="sides">評価した3頂点の左右情報</param>
        /// <param name="index1">頂点1</param>
        /// <param name="index2">頂点2</param>
        /// <param name="index3">頂点3</param>
        private void CutFace(int submesh, bool[] sides, int index1, int index2, int index3, MeshCutData data)
        {
            // 左右それぞれの情報を保持するための配列郡
            Vector3[]    leftPoints       = new Vector3[2];
            Vector3[]    leftNormals      = new Vector3[2];
            Vector2[]    leftUvs          = new Vector2[2];
            BoneWeight[] leftBoneWeights  = new BoneWeight[2];
            Vector3[]    rightPoints      = new Vector3[2];
            Vector3[]    rightNormals     = new Vector3[2];
            Vector2[]    rightUvs         = new Vector2[2];
            BoneWeight[] rightBoneWeights = new BoneWeight[2];

            bool didset_left  = false;
            bool didset_right = false;

            // 3頂点分繰り返す
            // 処理内容としては、左右を判定して、左右の配列に3頂点を振り分ける処理を行っている
            int p = index1;

            for (int side = 0; side < 3; side++)
            {
                switch (side)
                {
                case 0:
                    p = index1;
                    break;

                case 1:
                    p = index2;
                    break;

                case 2:
                    p = index3;
                    break;
                }

                // sides[side]がtrue、つまり左側の場合
                if (sides[side])
                {
                    // すでに左側の頂点が設定されているか(3頂点が左右に振り分けられるため、必ず左右どちらかは2つの頂点を持つことになる)
                    if (!didset_left)
                    {
                        didset_left = true;

                        // ここは0,1ともに同じ値にしているのは、続く処理で
                        // leftPoints[0,1]の値を使って分割点を求める処理をしているため。
                        // つまり、アクセスされる可能性がある

                        // 頂点の設定
                        leftPoints[0] = data.VictimMesh.Vertices[p];
                        leftPoints[1] = leftPoints[0];

                        // UVの設定
                        leftUvs[0] = data.VictimMesh.UVs[p];
                        leftUvs[1] = leftUvs[0];

                        // 法線の設定
                        leftNormals[0] = data.VictimMesh.Normals[p];
                        leftNormals[1] = leftNormals[0];

                        if (data.VictimMesh.HasBoneWeight)
                        {
                            leftBoneWeights[0] = data.VictimMesh.BoneWeights[p];
                            leftBoneWeights[1] = leftBoneWeights[0];
                        }
                    }
                    else
                    {
                        // 2頂点目の場合は2番目に直接頂点情報を設定する
                        leftPoints[1]  = data.VictimMesh.Vertices[p];
                        leftUvs[1]     = data.VictimMesh.UVs[p];
                        leftNormals[1] = data.VictimMesh.Normals[p];

                        if (data.VictimMesh.HasBoneWeight)
                        {
                            leftBoneWeights[1] = data.VictimMesh.BoneWeights[p];
                        }
                    }
                }
                else
                {
                    // 左と同様の操作を右にも行う
                    if (!didset_right)
                    {
                        didset_right = true;

                        rightPoints[0]  = data.VictimMesh.Vertices[p];
                        rightPoints[1]  = rightPoints[0];
                        rightUvs[0]     = data.VictimMesh.UVs[p];
                        rightUvs[1]     = rightUvs[0];
                        rightNormals[0] = data.VictimMesh.Normals[p];
                        rightNormals[1] = rightNormals[0];

                        if (data.VictimMesh.HasBoneWeight)
                        {
                            rightBoneWeights[0] = data.VictimMesh.BoneWeights[p];
                            rightBoneWeights[1] = rightBoneWeights[0];
                        }
                    }
                    else
                    {
                        rightPoints[1]  = data.VictimMesh.Vertices[p];
                        rightUvs[1]     = data.VictimMesh.UVs[p];
                        rightNormals[1] = data.VictimMesh.Normals[p];

                        if (data.VictimMesh.HasBoneWeight)
                        {
                            rightBoneWeights[1] = data.VictimMesh.BoneWeights[p];
                        }
                    }
                }
            }

            // 分割された点の比率計算のための距離
            float normalizedDistance = 0f;

            // 距離
            float distance = 0f;

            // ---------------------------
            // 左側の処理

            // 定義した面と交差する点を探す。
            // つまり、平面によって分割される点を探す。
            // 左の点を起点に、右の点に向けたレイを飛ばし、その分割点を探る。
            data.Blade.Raycast(new Ray(leftPoints[0], (rightPoints[0] - leftPoints[0]).normalized), out distance);

            // 見つかった交差点を、頂点間の距離で割ることで、分割点の左右の割合を算出する
            normalizedDistance = distance / (rightPoints[0] - leftPoints[0]).magnitude;

            // カット後の新頂点に対する処理。フラグメントシェーダでの補完と同じく、分割した位置に応じて適切に補完した値を設定する
            Vector3 newVertex1 = Vector3.Lerp(leftPoints[0], rightPoints[0], normalizedDistance);
            Vector2 newUv1     = Vector2.Lerp(leftUvs[0], rightUvs[0], normalizedDistance);
            Vector3 newNormal1 = Vector3.Lerp(leftNormals[0], rightNormals[0], normalizedDistance);

            BoneWeight newBoneWeight1 = new BoneWeight();

            if (data.VictimMesh.HasBoneWeight)
            {
                newBoneWeight1.boneIndex0 = leftBoneWeights[0].boneIndex0;
                newBoneWeight1.boneIndex1 = leftBoneWeights[0].boneIndex1;
                newBoneWeight1.boneIndex2 = leftBoneWeights[0].boneIndex2;
                newBoneWeight1.boneIndex3 = leftBoneWeights[0].boneIndex3;
                newBoneWeight1.weight0    = Mathf.Lerp(leftBoneWeights[0].weight0, rightBoneWeights[0].weight0, normalizedDistance);
                newBoneWeight1.weight1    = Mathf.Lerp(leftBoneWeights[0].weight1, rightBoneWeights[0].weight1, normalizedDistance);
                newBoneWeight1.weight2    = Mathf.Lerp(leftBoneWeights[0].weight2, rightBoneWeights[0].weight2, normalizedDistance);
                newBoneWeight1.weight3    = Mathf.Lerp(leftBoneWeights[0].weight3, rightBoneWeights[0].weight3, normalizedDistance);

                // 新ボーンウェイト郡に追加
                data.NewBoneWeights.Add(newBoneWeight1);
            }

            // 新頂点郡に新しい頂点を追加
            data.NewVertices.Add(newVertex1);


            // ---------------------------
            // 右側の処理

            data.Blade.Raycast(new Ray(leftPoints[1], (rightPoints[1] - leftPoints[1]).normalized), out distance);

            normalizedDistance = distance / (rightPoints[1] - leftPoints[1]).magnitude;
            Vector3    newVertex2     = Vector3.Lerp(leftPoints[1], rightPoints[1], normalizedDistance);
            Vector2    newUv2         = Vector2.Lerp(leftUvs[1], rightUvs[1], normalizedDistance);
            Vector3    newNormal2     = Vector3.Lerp(leftNormals[1], rightNormals[1], normalizedDistance);
            BoneWeight newBoneWeight2 = new BoneWeight();

            if (data.VictimMesh.HasBoneWeight)
            {
                newBoneWeight2.boneIndex0 = leftBoneWeights[1].boneIndex0;
                newBoneWeight2.boneIndex1 = leftBoneWeights[1].boneIndex1;
                newBoneWeight2.boneIndex2 = leftBoneWeights[1].boneIndex2;
                newBoneWeight2.boneIndex3 = leftBoneWeights[1].boneIndex3;
                newBoneWeight2.weight0    = Mathf.Lerp(leftBoneWeights[1].weight0, rightBoneWeights[1].weight0, normalizedDistance);
                newBoneWeight2.weight1    = Mathf.Lerp(leftBoneWeights[1].weight1, rightBoneWeights[1].weight1, normalizedDistance);
                newBoneWeight2.weight2    = Mathf.Lerp(leftBoneWeights[1].weight2, rightBoneWeights[1].weight2, normalizedDistance);
                newBoneWeight2.weight3    = Mathf.Lerp(leftBoneWeights[1].weight3, rightBoneWeights[1].weight3, normalizedDistance);

                // 新ボーンウェイト郡に追加
                data.NewBoneWeights.Add(newBoneWeight2);
            }

            // 新頂点郡に新しい頂点を追加
            data.NewVertices.Add(newVertex2);

            // 計算された新しい頂点を使って、新トライアングルを左右ともに追加する
            // memo: どう分割されても、左右どちらかは1つの三角形になる気がするけど、縮退三角形的な感じでとにかく2つずつ追加している感じだろうか?
            data.LeftSide.AddTriangle(
                new Vector3[] { leftPoints[0], newVertex1, newVertex2 },
                new Vector3[] { leftNormals[0], newNormal1, newNormal2 },
                new Vector2[] { leftUvs[0], newUv1, newUv2 },
                new BoneWeight[] { leftBoneWeights[0], newBoneWeight1, newBoneWeight2 },
                newNormal1,
                submesh
                );

            data.LeftSide.AddTriangle(
                new Vector3[] { leftPoints[0], leftPoints[1], newVertex2 },
                new Vector3[] { leftNormals[0], leftNormals[1], newNormal2 },
                new Vector2[] { leftUvs[0], leftUvs[1], newUv2 },
                new BoneWeight[] { leftBoneWeights[0], leftBoneWeights[1], newBoneWeight2 },
                newNormal2,
                submesh
                );

            data.RightSide.AddTriangle(
                new Vector3[] { rightPoints[0], newVertex1, newVertex2 },
                new Vector3[] { rightNormals[0], newNormal1, newNormal2 },
                new Vector2[] { rightUvs[0], newUv1, newUv2 },
                new BoneWeight[] { rightBoneWeights[0], newBoneWeight1, newBoneWeight2 },
                newNormal1,
                submesh
                );

            data.RightSide.AddTriangle(
                new Vector3[] { rightPoints[0], rightPoints[1], newVertex2 },
                new Vector3[] { rightNormals[0], rightNormals[1], newNormal2 },
                new Vector2[] { rightUvs[0], rightUvs[1], newUv2 },
                new BoneWeight[] { rightBoneWeights[0], rightBoneWeights[1], newBoneWeight2 },
                newNormal2,
                submesh
                );
        }