/** MeshComponentWrapperから生成する */ static public MeshObject generate(MeshComponentWrapper src) { var ret = new MeshObject() { mesh = src.mesh, matLst = src.materials, bones = src.bones, // ここ、不思議なんだけどどうやらスキンメッシュの場合は // ヒエラルキを無視して自分自身のTransformのみを見て変形するようになっているっぽい。 // したがって、結合時にも自分自身の変換行列のみの影響を受けるようにする l2wMtx = src.bones.Length == 0 ? src.l2wMtx : MeshComponentWrapper.getLocalMtx(src.transform) }; if (ret.mesh.subMeshCount < ret.matLst.Length) { // マテリアルが必要より多く設定されている。 // この場合はマテリアルの一致判定は可能なため、正常な範囲にトリムするだけでOK。 // 逆にマテリアルが足りない場合はマテリアルの一致判定ができないため、 // 何もせずに流して後でエラーにする。 Array.Resize(ref ret.matLst, ret.mesh.subMeshCount); } return(ret); }
/** 結合処理。GameObject全体に対して処理を行う。dstは初期化される */ static public bool combine( GameObject targetGO, MeshObject dst, string dstMeshObjName, //!< 結合後に生成されるプレファブ内の、メッシュ表示用のGameObjectの名前 string[] ignoreList = null //!< 結合対象外とするオブジェクト名のリスト ) { // 結合元となるMesh情報を収集する。最も子供のTransformのものから順に格納する。 var srcMeshes = MeshComponentWrapper.getMeshComponentsInChildren(targetGO); var srcDataLst = srcMeshes .Where(i => i.mesh.blendShapeCount == 0) // BlendShapeがあるものは結合対象外 .Where(i => ignoreList == null || !ignoreList.Contains(i.gameObject.name)) // 無視リストに指定されているオブジェクトは結合対象外 .Select(i => (data: MeshObject.generate(i), trans: i.transform)).ToArray(); // 結合したメッシュを生成 dst.reset(); var isSuccess = true; foreach (var i in srcDataLst) { isSuccess &= addTo(i.data, dst); } // ログに追加 Log.instance.endCombineMesh(isSuccess, srcDataLst.Select(i => i.data.mesh).ToArray(), dst.mesh); if (!isSuccess) { return(false); } // 結合したメッシュを表示するオブジェクトを追加 var combinedMeshObj = new GameObject(dstMeshObjName); combinedMeshObj.transform.SetParent(targetGO.transform, false); if (dst.bones.Length == 0) { var mr = combinedMeshObj.AddComponent <MeshRenderer>(); var mf = combinedMeshObj.AddComponent <MeshFilter>(); mf.sharedMesh = dst.mesh; mr.sharedMaterials = dst.matLst; } else { var smr = combinedMeshObj.AddComponent <SkinnedMeshRenderer>(); smr.sharedMesh = dst.mesh; smr.sharedMaterials = dst.matLst; smr.bones = dst.bones; } // 結合前のオブジェクトを削除 foreach (var i in srcDataLst) { // 子供がない場合はそのまま削除。 // 子供の方から順番にイテレートするので、殆どのものはそのまま削除できるはず if (i.trans.childCount == 0) { UnityEngine.Object.DestroyImmediate(i.trans.gameObject); } else { var mf = i.trans.GetComponent <MeshFilter>(); var mr = i.trans.GetComponent <MeshRenderer>(); var smr = i.trans.GetComponent <SkinnedMeshRenderer>(); if (mf != null) { UnityEngine.Object.DestroyImmediate(mf); } if (mr != null) { UnityEngine.Object.DestroyImmediate(mr); } if (smr != null) { UnityEngine.Object.DestroyImmediate(smr); } } } return(true); }