/************************************************************************* * Copyright © 2018-2023 Liwen All rights reserved. *------------------------------------------------------------------------ * File : LoadPagedLodFromFileManager.cs * Description : Load root tile file and initialize child lod config. *------------------------------------------------------------------------ * Author : Liwen * Version : 1.0.0 * Date : 1/5/2019 * Description : Initial development version. *************************************************************************/ using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using System; using UnityEngine.EventSystems; using UnityEngine.Scripting; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; namespace AIPagedLod { [System.Serializable] public class LoadPagedLodFromFileConfig { /////////////////////////////editor parameter/////////////////////// public string mDataName = string.Empty; public string mDataPath = string.Empty; public int mStartLevel = -1; //public int mMeshLayer = -1; public int mLoadPagedLodCount = 6; public bool mLoadStartLevelFlag = false; public int mStartLoadLevel = 17; public bool mIsDaJiangData = false; public bool mIsGenerateCollider = false; /////////////////////////////runtime parameter/////////////////////// public bool mIsUpdate = true; public string mBaseUrl; } public class LoadPagedLodFromFileManager : MonoBehaviour { public LoadPagedLodFromFileConfig mConfig = new LoadPagedLodFromFileConfig(); public List mPagedLodList = null; public static Vector3 mCameraPosition = Vector3.zero; private void Start() { } void InitPagedLodList() { mPagedLodList = new List(GetComponentsInChildren(true)); for (int i = 0; i < mPagedLodList.Count; ++i) { #if !UNITY_WEBGL && UNITY_ANDROID if (PagedLodConfig.mInstance.mTileDataType == TileDataType.B3DM) { mPagedLodList[i].LoadTileSetJsonFile(); } #endif mPagedLodList[i].mIsRootTile = true; mPagedLodList[i].RecaculateBounds(); mPagedLodList[i].InitBasicInfoDictFromList(); } } public string GetDataPath() { if (PagedLodConfig.mInstance != null && PagedLodConfig.mInstance.mDataPathDict.ContainsKey(mConfig.mDataName)) { return PagedLodConfig.mInstance.mDataPathDict[mConfig.mDataName].mDataPath; } string dataPath = mConfig.mDataPath; if(!Directory.Exists(dataPath)) //数据路径不存在则停止更新 { mConfig.mIsUpdate = false; } return dataPath; } void Update() { if (mConfig.mIsUpdate) { if (mPagedLodList.Count == 0) { InitPagedLodList(); } UpdatePagedLod(mPagedLodList); } } private void LateUpdate() { if (Input.GetKeyDown(KeyCode.Escape)) { Application.Quit(); } } public static int SortLodByDistance(PagedLod left, PagedLod right) { if(left.mIsVisiable && right.mIsVisiable) { float d1 = Vector3.Distance(left.mWorldCenter, mCameraPosition); float d2 = Vector3.Distance(right.mWorldCenter, mCameraPosition); if (d1 < d2) return 1; else if (d1 > d2) return -1; else return 0; } else { //根据是否可见 if (left.mIsVisiable && !right.mIsVisiable) return 1; else if (!right.mIsVisiable && right.mIsVisiable) return -1; else return 0; } } public static void UpdatePagedLod(List pagedLodList) { mCameraPosition = Camera.main.transform.position; if (!PagedLodUpdateController.IsUpdateEnabled()) return; #if UNITY_WEBGL || UNITY_ANDROID pagedLodList.Sort(SortLodByDistance); TraverseUpdateDepthFirst(pagedLodList); #else PagedLodThreadPool.RunAsync(() => { pagedLodList.Sort(SortLodByDistance); PagedLodThreadPool.QueueOnMainThread(() => { TraverseUpdateDepthFirst(pagedLodList); }); }); #endif } public static void TraverseUpdateBreadthFirst(List pagedLodList) { Queue tileQueue = new Queue(); for (int i = 0; i < pagedLodList.Count; ++i) { tileQueue.Enqueue(pagedLodList[i]); } while (tileQueue.Count > 0) { PagedLod currentTile = tileQueue.Dequeue(); bool isUpdateChild = currentTile.UpdatePagedLod(); if (isUpdateChild) { for (int i = 0; i < currentTile.mChildTileList.Count; ++i) { PagedLod childPagedLod = currentTile.mChildTileList[i].mPagedLod; if (childPagedLod != null) { tileQueue.Enqueue(childPagedLod); } } } } } //深度优先遍历四叉树 public static void TraverseUpdateDepthFirst(List pagedLodList) { Stack tileStack =new Stack(); for (int i = 0; i < pagedLodList.Count; ++i) { tileStack.Push(pagedLodList[i]); } while (tileStack.Count > 0) { PagedLod currentTile = tileStack.Pop(); bool isUpdateChild = currentTile.UpdatePagedLod(); if (isUpdateChild) { for (int i = 0; i < currentTile.mChildTileList.Count; ++i) { PagedLod childPagedLod = currentTile.mChildTileList[i].mPagedLod; if (childPagedLod != null) { tileStack.Push(childPagedLod); } } } } } public static int GetTileFileLevel(string tileDirName, string tileFileName) { string tileFileBaseName = tileFileName.Replace(PagedLodConfig.mInstance.GetFileSufix(), ""); if (tileFileBaseName == tileDirName) return -1; string tempTileDirName = tileDirName + "_"; if (tileFileBaseName.Contains(tempTileDirName)) { string strLevel = tileFileBaseName.Replace(tempTileDirName, ""); strLevel = strLevel.Replace("L", ""); string[] tempArray = strLevel.Split('_'); if (tempArray.Length > 0) { return int.Parse(tempArray[0]); } } return -1; } public static int GetDataStartLevel(string dataPath) { #if !UNITY_WEBGL && !UNITY_ANDROID if (!Directory.Exists(dataPath)) return 0; DirectoryInfo dataDir = new DirectoryInfo(dataPath); List dirInfos = new List(dataDir.GetDirectories()); foreach (var tileDir in dirInfos) { foreach (var fileInfo in tileDir.GetFiles("*"+ PagedLodConfig.mInstance.GetFileSufix())) { int level = GetTileFileLevel(tileDir.Name, fileInfo.Name); if (level > 0) { return level - 1; } } } #endif return -1; } //编辑器初始化加载数据 //运行时初始化加载数据 public static PagedLod LoadPagedLod(PagedLodFileLoader loader,Transform parent) { GameObject tileObj = new GameObject(); tileObj.name = loader.mTileName; tileObj.transform.SetParent(parent); tileObj.transform.localPosition = Vector3.zero; tileObj.transform.localRotation = Quaternion.identity; tileObj.transform.localScale = Vector3.one; PagedLod pagedLod = tileObj.AddComponent(); pagedLod.mSelfLevel = loader.mLevel; pagedLod.mTileDirPath = loader.mTileDirPath; pagedLod.LoadRenderNode(loader); return pagedLod; } public static void GenerateColliderObject(PagedLod pagedLod) { GameObject tileCollider = new GameObject("TileCollider"); tileCollider.transform.SetParent(pagedLod.transform); tileCollider.transform.localPosition = Vector3.zero; tileCollider.transform.localRotation = Quaternion.identity; tileCollider.transform.localScale = Vector3.one; MeshFilter[] meshFilters = pagedLod.GetComponentsInChildren(); for (int i = 0; i < meshFilters.Length; ++i) { GameObject meshColliderObj = new GameObject("MeshCollider"); meshColliderObj.transform.SetParent(tileCollider.transform); meshColliderObj.transform.localPosition = Vector3.zero; meshColliderObj.transform.localRotation = Quaternion.identity; meshColliderObj.transform.localScale = Vector3.one; MeshCollider meshCollider = meshColliderObj.AddComponent(); meshCollider.sharedMesh = meshFilters[i].sharedMesh; meshColliderObj.layer = PagedLodConfig.mInstance == null ? 8 : PagedLodConfig.mInstance.mMeshLayer; } } } }