Unity加载OSGB倾斜摄影数据

Unity加载OSGB倾斜摄影数据

显而易见有一个最方便的办法就是使用CesiumForUnity确定是可以通过osgb数据转换成3dtiles进行加载的,然而有没有直接加载osgb格式数据的方法呢?

我们知道osgb的osg推出的倾斜摄影数据的数据结构,所以,osg引擎一定是支持osgb最好的三维引擎,研究osgb的加载,了解osg的库也就是必然项!

然而但是,三维引擎方向,UE,Unity一定是主流中的主流了,怎么让osgb在这两个引擎中工作成了大家研究的一个侧重点。有需求才有方向嘛,不然盲人摸象。

所以,我们看看既有的成熟成果:

https://github.com/xarray/UnityOSGB.git

(git上的一个作者写好的项目,下载下来直接运行试试即可,注意下unity版本的使用

 启动项目之后示例项目挂载了ReadOSGB脚本,如下图: 

 加载osgb数据取决于AsOsgbFolder,分:文件夹加载和单个osgb文件加载。

需要注意的是:文件夹加载方式并没有使用lod,所以加载的数据只是data文件夹下,瓦片文件夹下的同名osgb数据(效果如下图所示),并没有加载到层级osgb数据,显示并不尽如人意,需要自己再跟进一下(随后吧,我也没太清楚)!

 文件读取的整体代码量也还好,贴出来,如下:

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace osgEx
{
    public class ReaderOSGB : MonoBehaviour
    {
        const int OSG_HEADER_L = 0x6C910EA1;
        const int OSG_HEADER_H = 0x1AFB4545;

        public Material _template;
        public string _fileOrPathName;
        public bool _asOsgbFolder, _withMeshCollider;

        public int _sceneType = 0, _version = 0;
        public bool _useBrackets = false;
        public bool _useSchemaData = false;
        public bool _useDomains = false;

        public string _currentFileName;
        public Plane[] _currentFrustum;
        public Texture2D _preloadedTexture = null;
        public Dictionary<uint, Object> _sharedObjects = new Dictionary<uint, Object>();
        public Dictionary<uint, Texture2D> _sharedTextures = new Dictionary<uint, Texture2D>();

        public class PagingRequest
        {
            public PagedData pagedData;
            public int childIndex, updatedStamp;
        }
        List<PagingRequest> _loadingRequests = new List<PagingRequest>();
        List<PagingRequest> _unloadingRequests = new List<PagingRequest>();
        Task _pagingRequestHandler;
        object _taskMutex = new object();
        bool _isTaskRunning = false;

        public void RequestLoadingAndUnloading(PagedData data, List<int> toLoad, List<int> toUnload)
        {
            lock (_taskMutex)
            {
                foreach (int index in toLoad)
                {
                    PagingRequest req = _loadingRequests.Find(
                        c => c.pagedData.Equals(data) && c.childIndex.Equals(index));
                    if (req == null)
                    {
                        req = new PagingRequest
                        { pagedData = data, childIndex = index, updatedStamp = Time.frameCount };
                        _loadingRequests.Add(req);
                    }
                    else
                        req.updatedStamp = Time.frameCount;
                }

                foreach (int index in toUnload)
                {
                    PagingRequest req = _unloadingRequests.Find(
                        c => c.pagedData.Equals(data) && c.childIndex.Equals(index));
                    if (req == null)
                    {
                        req = new PagingRequest
                        { pagedData = data, childIndex = index, updatedStamp = Time.frameCount };
                        _unloadingRequests.Add(req);
                    }
                    else
                        req.updatedStamp = Time.frameCount;
                }
            }
        }

        void LoadOrUnloadData(PagedData data, int index, bool toLoad)
        {
            if (toLoad)
            {
                string fileName = data.getFullFileName(index);
                GameObject fineNode = LoadSceneFromFile(fileName);
                if (fineNode != null)
                {
                    fineNode.name = Path.GetFileNameWithoutExtension(fileName);
                    fineNode.transform.SetParent(data.gameObject.transform, false);
                    data._pagedNodes[index] = fineNode;
                    data._pagedNodes[0].SetActive(false);  // FIXME: assume only 1 rough level
                }
                else
                    Debug.LogWarning("Unable to read OSGB data from " + fileName);
            }
            else
            {
                Destroy(data._pagedNodes[index]);
                data._pagedNodes[index] = null;
                data._pagedNodes[0].SetActive(true);  // FIXME: assume only 1 rough level
            }
        }

        IEnumerator PagingTask()
        {
            _isTaskRunning = true;
            while (_isTaskRunning)
            {
                PagedData pData0 = null;
                int index0 = -1, currentFrame = Time.frameCount;
                lock (_taskMutex)
                {
                    foreach (PagingRequest req in _loadingRequests)
                    {
                        if (req.updatedStamp >= currentFrame - 1)  // latest req
                        {
                            pData0 = req.pagedData; index0 = req.childIndex;
                            _loadingRequests.Remove(req); break;
                        }
                    }

                    if (index0 < 0)
                    {
                        for (int i = 0; i < _loadingRequests.Count;)
                        {
                            PagingRequest req = _loadingRequests[i];
                            if (req.updatedStamp < currentFrame - 10)  // too-old req
                                _loadingRequests.RemoveAt(i);
                            else ++i;
                        }
                    }

                    if (_unloadingRequests.Count > 60)
                    {
                        for (int i = 0; i < _unloadingRequests.Count;)
                        {
                            PagingRequest req = _unloadingRequests[i];
                            if (req.updatedStamp >= currentFrame - 1)  // latest req
                            {
                                LoadOrUnloadData(req.pagedData, req.childIndex, false);
                                _unloadingRequests.RemoveAt(i);
                            }
                            else if (req.updatedStamp < currentFrame - 10)  // too-old req
                                _unloadingRequests.RemoveAt(i);
                            else ++i;
                        }
                    }
                }

                if (pData0 && index0 >= 0)
                    LoadOrUnloadData(pData0, index0, true);
                //Debug.Log(_loadingRequests.Count + ", " + _unloadingRequests.Count);
                yield return null;
            }
        }

        IEnumerator StopPagingTask(Task task)
        {
            _isTaskRunning = false;
            yield return null;
            task.Stop();
        }
        //加载场景数据,直接osgb文件
        public GameObject LoadSceneData(string fileName, BinaryReader reader)
        {
            // Load header data
            int magicNumL = reader.ReadInt32();
            int magicNumH = reader.ReadInt32();
            if (magicNumL != OSG_HEADER_L || magicNumH != OSG_HEADER_H)
            {
                Debug.LogWarning("Unmatched magic number");
                return null;
            }

            _sceneType = reader.ReadInt32();
            _version = reader.ReadInt32();
            int attributes = reader.ReadInt32();
            Debug.Log("OSGB file " + fileName + ": version " + _version +
                      ", " + attributes.ToString("X"));

            _useBrackets = (attributes & 0x4) != 0;
            _useSchemaData = (attributes & 0x2) != 0;
            _useDomains = (attributes & 0x1) != 0;
            // TODO: handle attributes

            string compressor = ObjectBase.ReadString(reader);
            if (compressor != "0")
            {
                Debug.LogWarning("Decompressor " + compressor + " not implemented");
                return null;
            }

            // Load root object
            GameObject scene = new GameObject(Path.GetFileNameWithoutExtension(fileName));
            if (!ObjectBase.LoadObject(scene, reader, this))
            {
                Debug.LogWarning("Failed to load scene");
                return null;
            }

            // Clear temperatory variables
            _preloadedTexture = null;
            _sharedObjects.Clear();
            _sharedTextures.Clear();
            return scene;
        }
        //从文件中加载osgb数据 
        public GameObject LoadSceneFromFile(string fileName)
        {
            _currentFileName = fileName;
            if (!File.Exists(fileName))
            {
                Debug.LogWarning("Unable to find file " + fileName);
                return null;
            }

            FileStream stream = File.Open(fileName, FileMode.Open, FileAccess.Read);
            if (!stream.CanRead)
            {
                Debug.LogWarning("Unable to read binary stream from " + fileName);
                return null;
            }

            GameObject gameScene = LoadSceneData(fileName, new BinaryReader(stream));
            stream.Close(); return gameScene;
        }

        void Start()
        {
            _pagingRequestHandler = new Task(PagingTask());
            if (_template == null)
                _template = new Material(Shader.Find("Standard"));

            if (_asOsgbFolder)
            {
                foreach (string folderName in Directory.GetDirectories(_fileOrPathName))
                {
                    //只是取到了子文件夹的同名文件,lod文件没有加载,所以lod层级不足,显示效果不好
                    string rootFile = folderName + Path.DirectorySeparatorChar
                                    + Path.GetFileName(folderName) + ".osgb";
                    GameObject scene = LoadSceneFromFile(rootFile);
                    if (scene != null)
                        scene.transform.SetParent(this.transform, false);
                    else
                        Debug.LogWarning("Unable to read OSGB data from " + rootFile);
                }
            }
            else
            {
                GameObject scene = LoadSceneFromFile(_fileOrPathName);
                if (scene != null)
                    scene.transform.SetParent(this.transform, false);
                else
                    Debug.LogWarning("Unable to read OSGB data from " + _fileOrPathName);
            }

            // Get global center & extents
            MeshFilter[] mfList = GetComponentsInChildren<MeshFilter>();
            Bounds totalBounds = new Bounds();
            for (int j = 0; j < mfList.Length; ++j)
            {
                Matrix4x4 l2w = mfList[j].transform.localToWorldMatrix;
                Vector3[] vertices = mfList[j].sharedMesh.vertices;
                Bounds meshBounds = new Bounds();
                for (int i = 0; i < vertices.Length; ++i)
                {
                    if (i == 0) meshBounds.center = l2w.MultiplyPoint(vertices[i]);
                    else meshBounds.Encapsulate(l2w.MultiplyPoint(vertices[i]));
                }

                if (j == 0) totalBounds = meshBounds;
                else totalBounds.Encapsulate(meshBounds);
            }
            this.transform.position = -totalBounds.center;
        }

        void Update()
        {
            _currentFrustum = GeometryUtility.CalculateFrustumPlanes(Camera.main);
        }

        void OnDestroy()
        {
            StopPagingTask(_pagingRequestHandler);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jennifer33K

美好的一天,有我也有你!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值