예제 #1
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 });
        }
예제 #2
0
        /// <summary>
        /// カットされたメッシュ情報を元にオブジェクトを生成する
        /// </summary>
        private void CreateCuttedObjects(CutterInfo info)
        {
            CutterTarget target = info.CutterTarget;

            if (target == null)
            {
                return;
            }

            // 設定されているマテリアル配列を取得
            Material[] mats = GetMaterials(target.GameObject);

            // カット面分増やしたマテリアル配列を準備
            Material[] newMats = new Material[mats.Length + 1];

            // 既存のものを新しい配列にコピー
            mats.CopyTo(newMats, 0);

            // 新しいマテリアル配列の最後に、カット面用マテリアルを追加
            newMats[mats.Length] = (target.CutMaterial != null) ? target.CutMaterial : _cutDefaultMaterial;

            // 生成したマテリアルリストを再設定
            mats = newMats;

            CutterObject cutterObject = info.CutterObject;

            CutterMesh[] cuttedMeshes = info.CutterMeshes;
            GameObject[] cuttedObject = new GameObject[cuttedMeshes.Length];

            // 生成されたメッシュ分、オブジェクトを生成する
            for (int i = 0; i < cuttedMeshes.Length; i++)
            {
                #region ### Create new object ###
                GameObject newObj = new GameObject("[Cutterd]" + target.Name + i);
                newObj.transform.position   = target.transform.position;
                newObj.transform.rotation   = target.transform.rotation;
                newObj.transform.localScale = target.transform.localScale;
                #endregion ### Create new object ###

                #region ### Create new mesh ###
                Mesh mesh = new Mesh();
                mesh.name         = "Split Mesh";
                mesh.vertices     = cuttedMeshes[i].Vertices;
                mesh.triangles    = cuttedMeshes[i].Triangles;
                mesh.normals      = cuttedMeshes[i].Normals;
                mesh.uv           = cuttedMeshes[i].UVs;
                mesh.subMeshCount = cuttedMeshes[i].SubMeshCount;
                for (int j = 0; j < cuttedMeshes[i].SubMeshCount; j++)
                {
                    mesh.SetIndices(cuttedMeshes[i].GetIndices(j), MeshTopology.Triangles, j);
                }
                #endregion ### Create new mesh ###

                GameObject obj;

                // アニメーションが必要な場合はボーンのセットアップを行う
                if (_needAnimation)
                {
                    SkinnedMeshRenderer oriRenderer = target.GameObject.GetComponent <SkinnedMeshRenderer>();
                    Transform           newRootBone = Instantiate(oriRenderer.rootBone.gameObject).transform;
                    newRootBone.name = newRootBone.name.Replace("(Clone)", "");

                    Transform[] newBones = new Transform[oriRenderer.bones.Length];
                    for (int j = 0; j < oriRenderer.bones.Length; j++)
                    {
                        Transform bone    = oriRenderer.bones[j];
                        Transform newBone = SearchBone(bone.name, newRootBone);
                        newBones[j] = newBone;
                    }

                    Animator          oriAnim   = target.GetComponent <Animator>();
                    AnimatorStateInfo stateInfo = oriAnim.GetCurrentAnimatorStateInfo(0);

                    newRootBone.SetParent(newObj.transform);
                    Animator anim = newObj.AddComponent <Animator>();
                    anim.runtimeAnimatorController = oriAnim.runtimeAnimatorController;
                    anim.avatar = target.GetComponent <Animator>().avatar;
                    anim.Play(stateInfo.fullPathHash, 0, stateInfo.normalizedTime);

                    mesh.bindposes   = cutterObject.Bindposes;
                    mesh.boneWeights = cuttedMeshes[i].BoneWeights;

                    obj = new GameObject("Split Object", new[] {
                        typeof(SkinnedMeshRenderer)
                    });
                    obj.transform.position = target.MeshTransform.position;
                    obj.transform.rotation = target.MeshTransform.rotation;

                    SkinnedMeshRenderer renderer = obj.GetComponent <SkinnedMeshRenderer>();
                    renderer.sharedMesh = mesh;
                    renderer.materials  = mats;
                    renderer.bones      = newBones;
                    renderer.rootBone   = newRootBone;
                }
                else
                {
                    obj = new GameObject("Split Object " + i, new[] {
                        typeof(MeshFilter),
                        typeof(MeshRenderer),
                        typeof(Rigidbody),
                        typeof(MeshCollider),
                        typeof(CutterTarget),
                    });
                    obj.transform.position   = target.MeshTransform.position;
                    obj.transform.rotation   = target.MeshTransform.rotation;
                    obj.transform.localScale = target.MeshTransform.lossyScale;
                    obj.GetComponent <MeshCollider>().sharedMesh  = mesh;
                    obj.GetComponent <MeshCollider>().convex      = true;
                    obj.GetComponent <MeshCollider>().material    = target.GetComponent <Collider>().material;
                    obj.GetComponent <MeshFilter>().mesh          = mesh;
                    obj.GetComponent <MeshRenderer>().materials   = mats;
                    obj.GetComponent <CutterTarget>().CutMaterial = target.CutMaterial;
                    obj.GetComponent <Rigidbody>().constraints    = target.Rigidbody.constraints;
                }

                cuttedObject[i] = obj;
                obj.transform.SetParent(newObj.transform);

                if (cutterObject.NeedsScaleAdjust)
                {
                    obj.transform.localScale = target.transform != target.MeshTransform ? target.MeshTransform.localScale : Vector3.one;
                }
                cutAnim.Anim(target, obj.GetComponent <CutterTarget>());
            }

            // Notify end of cutting.
            target.Cutted(cuttedObject);

            if (_autoDestroyTarget)
            {
                // Destroy target object.
                target.transform.localScale = Vector3.zero;
                target.gameObject.SetActive(false);
                //Destroy(target.gameObject);
            }

            if (OnCutted != null)
            {
                OnCutted.Invoke(cuttedObject, info.CutterPlane);
            }

            if (info.CutterCallback != null)
            {
                info.CutterCallback.Invoke(true, cuttedObject, info.CutterPlane, info.UserData);
            }
        }