Ejemplo n.º 1
0
        //=========================================================================================
        /// <summary>
        /// 事前データ作成
        /// </summary>
        /// <param name="scr"></param>
        private void CreateData(MagicaVirtualDeformer scr)
        {
            Debug.Log("Started creating. [" + scr.name + "]");

            // 子メッシュの検証
            if (VerifyChildData(scr.Deformer) == false)
            {
                // error
                Debug.LogError("Setup failed. Invalid RenderDeformer data.");
                return;
            }

            serializedObject.FindProperty("deformer.targetObject").objectReferenceValue = scr.gameObject;

            // 新規メッシュデータ
            var meshData = ShareDataObject.CreateShareData <MeshData>("VirtualMeshData_" + scr.name);

            // 設計時スケール
            meshData.baseScale = scr.transform.lossyScale;

            // 仮想メッシュ作成
            var reductionMesh = new MagicaReductionMesh.ReductionMesh();

            reductionMesh.WeightMode = MagicaReductionMesh.ReductionMesh.ReductionWeightMode.Average; // 平均法(v1.5.2)
            reductionMesh.MeshData.MaxWeightCount   = scr.Deformer.MaxWeightCount;
            reductionMesh.MeshData.WeightPow        = scr.Deformer.WeightPow;
            reductionMesh.MeshData.SameSurfaceAngle = scr.Deformer.SameSurfaceAngle;
            for (int i = 0; i < scr.Deformer.RenderDeformerCount; i++)
            {
                var deformer = scr.Deformer.GetRenderDeformer(i).Deformer;
                if (deformer != null)
                {
                    var sren = deformer.TargetObject.GetComponent <SkinnedMeshRenderer>();
                    List <Transform> boneList = new List <Transform>();
                    if (sren)
                    {
                        boneList = new List <Transform>(sren.bones);
                    }
                    else
                    {
                        boneList.Add(deformer.TargetObject.transform);
                    }
                    reductionMesh.AddMesh(
                        deformer.MeshData.isSkinning,
                        deformer.SharedMesh,
                        boneList,
                        deformer.SharedMesh.bindposes,
                        deformer.SharedMesh.boneWeights
                        );
                }
            }

            //reductionMesh.DebugData.DispMeshInfo("リダクション前");

            // リダクション
            reductionMesh.Reduction(
                scr.Deformer.MergeVertexDistance > 0.0f ? 0.0001f : 0.0f,
                scr.Deformer.MergeVertexDistance,
                scr.Deformer.MergeTriangleDistance,
                false
                );

            // (1)ゼロ距離リダクション
            //if (scr.Deformer.MergeVertexDistance > 0.0f)
            //    reductionMesh.ReductionZeroDistance();

            //// (2)頂点距離マージ
            //if (scr.Deformer.MergeVertexDistance > 0.0001f)
            //    reductionMesh.ReductionRadius(scr.Deformer.MergeVertexDistance);

            //// (3)トライアングル接続マージ
            //if (scr.Deformer.MergeTriangleDistance > 0.0f)
            //    reductionMesh.ReductionPolygonLink(scr.Deformer.MergeTriangleDistance);

            //// (4)未使用ボーンの削除
            //reductionMesh.ReductionBone();

            // (5)頂点の最大接続トライアングル数制限
            //reductionMesh.ReductionTriangleConnect(6);

            //reductionMesh.DebugData.DispMeshInfo("リダクション後");

            // 最終メッシュデータ取得
            var final = reductionMesh.GetFinalData(scr.gameObject.transform);

            // メッシュデータシリアライズ
            meshData.isSkinning  = final.IsSkinning;
            meshData.vertexCount = final.VertexCount;

            List <uint> vlist;
            List <MeshData.VertexWeight> wlist;

            CreateVertexWeightList(
                final.VertexCount, final.vertices, final.normals, final.tangents, final.boneWeights, final.bindPoses,
                out vlist, out wlist
                );
            meshData.vertexInfoList   = vlist.ToArray();
            meshData.vertexWeightList = wlist.ToArray();
            meshData.boneCount        = final.BoneCount;

            meshData.uvList        = final.uvs.ToArray();
            meshData.lineCount     = final.LineCount;
            meshData.lineList      = final.lines.ToArray();
            meshData.triangleCount = final.TriangleCount;
            meshData.triangleList  = final.triangles.ToArray();

            List <uint> vertexToTriangleInfoList = new List <uint>();

            for (int i = 0; i < final.VertexCount; i++)
            {
                int tcnt   = final.vertexToTriangleCountList[i];
                int tstart = final.vertexToTriangleStartList[i];
                vertexToTriangleInfoList.Add(DataUtility.Pack8_24(tcnt, tstart));
            }
            meshData.vertexToTriangleInfoList  = vertexToTriangleInfoList.ToArray();
            meshData.vertexToTriangleIndexList = final.vertexToTriangleIndexList.ToArray();

            // 子メッシュ情報
            for (int i = 0; i < final.MeshCount; i++)
            {
                var minfo     = final.meshList[i];
                var rdeformer = scr.Deformer.GetRenderDeformer(i).Deformer;
                var mdata     = new MeshData.ChildData();

                mdata.childDataHash = rdeformer.GetDataHash();
                mdata.vertexCount   = minfo.VertexCount;

                // 頂点ウエイト情報作成
                CreateVertexWeightList(
                    minfo.VertexCount, minfo.vertices, minfo.normals, minfo.tangents, minfo.boneWeights, final.vertexBindPoses,
                    out vlist, out wlist
                    );

                mdata.vertexInfoList   = vlist.ToArray();
                mdata.vertexWeightList = wlist.ToArray();

                mdata.parentIndexList = minfo.parents.ToArray();

                meshData.childDataList.Add(mdata);
            }

            // レイヤー情報
            //for (int i = 0; i < final.LayerCount; i++)
            //{
            //    var linfo = new MeshData.LayerInfo();
            //    linfo.triangleList = new List<int>(final.layerList[i].triangleList);
            //    meshData.layerInfoList.Add(linfo);
            //}

            // 検証
            meshData.CreateVerifyData();
            serializedObject.FindProperty("deformer.meshData").objectReferenceValue = meshData;

            // ボーン
            var property = serializedObject.FindProperty("deformer.boneList");

            property.arraySize = final.bones.Count;
            for (int i = 0; i < final.bones.Count; i++)
            {
                property.GetArrayElementAtIndex(i).objectReferenceValue = final.bones[i];
            }

            serializedObject.ApplyModifiedProperties();

            // デフォーマーデータの検証とハッシュ
            scr.Deformer.CreateVerifyData();
            serializedObject.ApplyModifiedProperties();

            // コアコンポーネントの検証とハッシュ
            scr.CreateVerifyData();
            serializedObject.ApplyModifiedProperties();

            EditorUtility.SetDirty(meshData);

            Debug.Log("Setup completed. [" + scr.name + "]");
        }
        /// <summary>
        /// メッシュデータ作成
        /// </summary>
        void CreateMeshData(MagicaBoneCloth scr)
        {
            // 共有データオブジェクト作成
            string   dataname = "BoneClothMeshData_" + scr.name;
            MeshData mdata    = ShareDataObject.CreateShareData <MeshData>(dataname);

            // トランスフォームリスト作成
            var transformList = scr.GetTransformList();

            if (transformList.Count == 0)
            {
                return;
            }

            // 頂点作成
            int            vcnt     = transformList.Count;
            List <Vector3> wposList = new List <Vector3>();
            List <Vector3> wnorList = new List <Vector3>();
            List <Vector4> wtanList = new List <Vector4>();
            List <Vector3> lposList = new List <Vector3>();
            List <Vector3> lnorList = new List <Vector3>();
            List <Vector3> ltanList = new List <Vector3>();
            Transform      myt      = scr.transform;

            for (int i = 0; i < transformList.Count; i++)
            {
                var t = transformList[i];

                // 頂点追加
                var pos  = t.position;
                var lpos = myt.InverseTransformDirection(pos - myt.position);
                var lnor = myt.InverseTransformDirection(t.forward);
                var ltan = myt.InverseTransformDirection(t.up);
                wposList.Add(pos);
                wnorList.Add(t.forward);
                wtanList.Add(t.up);
                lposList.Add(lpos);
                lnorList.Add(lnor);
                ltanList.Add(ltan);
            }
            var vertexInfoList   = new List <uint>();
            var vertexWeightList = new List <MeshData.VertexWeight>();

            for (int i = 0; i < lposList.Count; i++)
            {
                // 1ウエイトで追加
                uint vinfo = DataUtility.Pack4_28(1, i);
                vertexInfoList.Add(vinfo);
                var vw = new MeshData.VertexWeight();
                vw.parentIndex = i;
                vw.weight      = 1.0f;
                vw.localPos    = lposList[i];
                vw.localNor    = lnorList[i];
                vw.localTan    = ltanList[i];
            }
            mdata.vertexInfoList   = vertexInfoList.ToArray();
            mdata.vertexWeightList = vertexWeightList.ToArray();
            mdata.vertexCount      = lposList.Count;

            // デプスリスト作成
            var        sel       = scr.ClothSelection.GetSelectionData(null, null);
            List <int> depthList = new List <int>();

            for (int i = 0; i < transformList.Count; i++)
            {
                int depth = 0;
                var t     = transformList[i];

                while (t && transformList.Contains(t))
                {
                    int index = transformList.IndexOf(t);
                    if (sel[index] != SelectionData.Move)
                    {
                        break;
                    }

                    depth++;
                    t = t.parent;
                }

                depthList.Add(depth);
                //Debug.Log($"[{transformList[i].name}] depth:{depth}");
            }


            // 構造ライン
            HashSet <uint> lineSet = new HashSet <uint>();

            for (int i = 0; i < transformList.Count; i++)
            {
                var t  = transformList[i];
                var pt = t.parent;
                if (pt != null && transformList.Contains(pt))
                {
                    int  v0   = i;
                    int  v1   = transformList.IndexOf(pt);
                    uint pair = DataUtility.PackPair(v0, v1);
                    lineSet.Add(pair);
                }
            }

            // グリッドによるトライアングル
            List <int> triangleList = new List <int>();

            if (scr.ClothTarget.Connection == BoneClothTarget.ConnectionMode.Mesh)
            {
                HashSet <uint> triangleLineSet = new HashSet <uint>(lineSet);

                // 周りのボーンを調べ一定範囲内のボーンを接続する
                for (int i = 0; i < transformList.Count; i++)
                {
                    //if (sel[i] != SelectionData.Move)
                    //    continue;

                    var   t       = transformList[i];
                    int   depth   = depthList[i];
                    float mindist = 10000.0f;

                    List <int>   linkList = new List <int>();
                    List <float> distList = new List <float>();

                    for (int j = 0; j < transformList.Count; j++)
                    {
                        if (i == j || depthList[j] != depth)
                        {
                            continue;
                        }

                        linkList.Add(j);
                        var dist = Vector3.Distance(t.position, transformList[j].position);
                        distList.Add(dist);
                        mindist = Mathf.Min(mindist, dist);
                    }

                    // 最短距離より少し長めの範囲の頂点以外は削除する
                    HashSet <int> removeSet = new HashSet <int>();
                    mindist *= 1.5f;
                    for (int j = 0; j < linkList.Count; j++)
                    {
                        if (distList[j] > mindist)
                        {
                            removeSet.Add(j);
                        }
                    }

#if true
                    // 方向が一定以内ならば最も近い接続以外を削除する
                    for (int j = 0; j < linkList.Count - 1; j++)
                    {
                        for (int k = j + 1; k < linkList.Count; k++)
                        {
                            if (removeSet.Contains(j))
                            {
                                continue;
                            }
                            if (removeSet.Contains(k))
                            {
                                continue;
                            }

                            int index0 = linkList[j];
                            int index1 = linkList[k];

                            var ang = Vector3.Angle(transformList[index0].position - t.position, transformList[index1].position - t.position);
                            if (ang <= 45.0f)
                            {
                                removeSet.Add(distList[j] < distList[k] ? k : j);
                            }
                        }
                    }
#endif
                    // 登録
                    for (int j = 0; j < linkList.Count; j++)
                    {
                        if (removeSet.Contains(j))
                        {
                            continue;
                        }
                        // 接続する
                        uint pair = DataUtility.PackPair(i, linkList[j]);
                        triangleLineSet.Add(pair);
                    }
                }

                // 一旦各頂点の接続頂点リストを取得
                var vlink = MeshUtility.GetVertexLinkList(mdata.vertexCount, triangleLineSet);

                // トライアングル情報作成
                HashSet <ulong> registTriangleSet = new HashSet <ulong>();
                for (int i = 0; i < vlink.Count; i++)
                {
                    var linkset = vlink[i];
                    var t       = transformList[i];
                    var move    = sel[i] == SelectionData.Move;

                    foreach (var j in linkset)
                    {
                        var t2    = transformList[j];
                        var v     = (t2.position - t.position).normalized;
                        var move2 = sel[j] == SelectionData.Move;

                        foreach (var k in linkset)
                        {
                            if (j == k)
                            {
                                continue;
                            }

                            // j-kのエッジがtriangleLineSetに含まれていない場合は無効
                            //if (triangleLineSet.Contains(DataUtility.PackPair(j, k)) == false)
                            //    continue;

                            var t3    = transformList[k];
                            var v2    = (t3.position - t.position).normalized;
                            var move3 = sel[k] == SelectionData.Move;

                            // すべて固定頂点なら無効
                            if (move == false && move2 == false && move3 == false)
                            {
                                continue;
                            }

                            // 面積が0のトライアングルは除外する
                            var n    = Vector3.Cross(t2.position - t.position, t3.position - t.position);
                            var clen = n.magnitude;
                            if (clen < 1e-06f)
                            {
                                //Debug.Log($"clen == 0 ({i},{j},{k})");
                                continue;
                            }

                            var ang = Vector3.Angle(v, v2); // deg
                            if (ang <= 100)
                            {
                                // i - j - k をトライアングルとして登録する
                                var thash = DataUtility.PackTriple(i, j, k);
                                if (registTriangleSet.Contains(thash) == false)
                                {
                                    triangleList.Add(i);
                                    triangleList.Add(j);
                                    triangleList.Add(k);
                                    registTriangleSet.Add(thash);
                                }
                            }
                        }
                    }
                }
            }

            // トライアングルの法線を揃える
            HashSet <ulong> triangleSet = new HashSet <ulong>();
            if (triangleList.Count > 0)
            {
                // リダクションメッシュを作成する
                // ただ現在は面法線を揃える用途にしか使用しない
                var reductionMesh = new MagicaReductionMesh.ReductionMesh();
                reductionMesh.WeightMode = MagicaReductionMesh.ReductionMesh.ReductionWeightMode.Distance;
                reductionMesh.MeshData.MaxWeightCount   = 1;
                reductionMesh.MeshData.WeightPow        = 1;
                reductionMesh.MeshData.SameSurfaceAngle = scr.ClothTarget.SameSurfaceAngle; // 80?
                reductionMesh.AddMesh(myt, wposList, wnorList, wtanList, null, triangleList);

                // リダクション(面法線を整えるだけでリダクションは行わない)
                reductionMesh.Reduction(0.0f, 0.0f, 0.0f, false);

                // 最終メッシュデータ取得
                var final = reductionMesh.GetFinalData(myt);
                Debug.Assert(vcnt == final.VertexCount);

                // トライアングルデータ取得
                triangleList = final.triangles;
            }

            // 近接ライン接続
            //if (scr.ClothTarget.LineConnection)
            //{
            //    CreateNearLine(scr, lineSet, wposList, mdata);
            //}

#if false
            // トライアングル接続されているエッジはラインセットから削除する
            for (int i = 0; i < triangleList.Count / 3; i++)
            {
                int v0, v1, v2;
                int index = i * 3;
                v0 = triangleList[index];
                v1 = triangleList[index + 1];
                v2 = triangleList[index + 2];

                var pair0 = DataUtility.PackPair(v0, v1);
                var pair1 = DataUtility.PackPair(v1, v2);
                var pair2 = DataUtility.PackPair(v2, v0);

                lineSet.Remove(pair0);
                lineSet.Remove(pair1);
                lineSet.Remove(pair2);
            }
#endif

            // todo:test
            //lineSet.Clear();

            // ライン格納
            if (lineSet.Count > 0)
            {
                List <int> lineList = new List <int>();
                foreach (var pair in lineSet)
                {
                    int v0, v1;
                    DataUtility.UnpackPair(pair, out v0, out v1);
                    lineList.Add(v0);
                    lineList.Add(v1);
                }
                mdata.lineList  = lineList.ToArray();
                mdata.lineCount = lineList.Count / 2;
            }

            // トライアングル格納
            //if (triangleSet.Count > 0)
            //{
            //    List<int> triangleList = new List<int>();
            //    foreach (var tpack in triangleSet)
            //    {
            //        int v0, v1, v2;
            //        DataUtility.UnpackTriple(tpack, out v0, out v1, out v2);
            //        triangleList.Add(v0);
            //        triangleList.Add(v1);
            //        triangleList.Add(v2);
            //    }
            //    mdata.triangleCount = triangleSet.Count;
            //    mdata.triangleList = triangleList.ToArray();
            //}
            if (triangleList.Count > 0)
            {
                mdata.triangleCount = triangleList.Count / 3;
                mdata.triangleList  = triangleList.ToArray();
            }

            serializedObject.FindProperty("meshData").objectReferenceValue = mdata;
            serializedObject.ApplyModifiedProperties();

            // 使用トランスフォームシリアライズ
            var property    = serializedObject.FindProperty("useTransformList");
            var propertyPos = serializedObject.FindProperty("useTransformPositionList");
            var propertyRot = serializedObject.FindProperty("useTransformRotationList");
            var propertyScl = serializedObject.FindProperty("useTransformScaleList");
            property.arraySize    = transformList.Count;
            propertyPos.arraySize = transformList.Count;
            propertyRot.arraySize = transformList.Count;
            propertyScl.arraySize = transformList.Count;
            for (int i = 0; i < transformList.Count; i++)
            {
                property.GetArrayElementAtIndex(i).objectReferenceValue = transformList[i];
                propertyPos.GetArrayElementAtIndex(i).vector3Value      = transformList[i].localPosition;
                propertyRot.GetArrayElementAtIndex(i).quaternionValue   = transformList[i].localRotation;
                propertyScl.GetArrayElementAtIndex(i).vector3Value      = transformList[i].localScale;
            }
            serializedObject.ApplyModifiedProperties();

            // データ検証とハッシュ
            mdata.CreateVerifyData();
            serializedObject.ApplyModifiedProperties();

            EditorUtility.SetDirty(mdata);
        }