//========================================================================================= /// <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); }