詳細論述了通過osgEarth加載傾斜攝影資料的過程。
目錄
- 1. 概述
- 2. 詳論
- 2.1. 位置
- 2.2. 着色
- 2.3. 其他
- 3. 結果
- 4. 參考
我在《OSG加載傾斜攝影資料》這篇博文中論述了如何通過OSG生成一個整體的索引檔案,通過這個索引檔案來正确顯示ContextCapture(Smart3D)生成的傾斜攝影模型資料。這類傾斜攝影模型資料一般都會有個中繼資料metadata.xml,通過這個中繼資料,可以将其正确顯示在osgEarth的數字地球上。
metadata.xml中的内容一般如下所示:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuMjNyYzNwgTM10yNxgzNwcDMxEDNyUDMwIDMy0CMxQDMwATMvwVNwAjMwIzLcBTM0ADMwEzLcd2bsJ2Lc12bj5ycn9Gbi52YuAjMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
SRS就是空間坐标參考的意思,ENU表示是東北天站心坐标系,站心點的經緯度坐标為(108.9594, 34.2196)。這個站心點對應的應該是傾斜攝影模型的中心點,那麼思路就很簡單了,隻需要平移旋轉這個傾斜攝影模型,使模型的中心點對應于站心點。這其實是個地心坐标系于站心坐标系轉換的問題:
在osgEarth中可以不用關心這個問題,其直接封裝了一個類osgEarth::GeoTransform,可以直接通過這個類的接口來加載傾斜攝影模型:
std::string filePath = "D:/Data/scene/Dayanta/Data.osgb";
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(filePath);
osg::ref_ptr<osgEarth::GeoTransform> xform = new osgEarth::GeoTransform();
xform->addChild(node);
xform->setTerrain(mapNode->getTerrain());
osgEarth::GeoPoint point(map->getSRS(), 108.9594, 34.2196, -410); //使用絕對高,正高
xform->setPosition(point);
osg::ref_ptr<osgEarth::ModelLayer> modelLayer = new osgEarth::ModelLayer("oblic", xform);
map->addLayer(modelLayer);
給osgEarth::GeoTransform傳入的osgEarth::GeoPoint就是站心點。不過這種類型的metadata.xml似乎都沒有給出準确的高程值,是以需要自己調整高程來貼地。可能因為我這裡試用的傾斜攝影資料都是網上找的,不太可能給出準确的地理坐标。
另外一點要注意的是直接讀取加載的傾斜攝影模型是沒有顔色資訊的,這點和OSG還不太一樣,在幫助文檔裡面論述了這個問題:
是以一定要記得加上着色器渲染,否則傾斜攝影模型會變成白模:
osgEarth::Registry::shaderGenerator().run(node);
有的metadata.xml裡面的内容是這樣的:
這個中繼資料的意思是這個傾斜攝影模型是根據EPSG編号為2384的空間參考坐标系下建構的。簡單查了一下這個坐标系應該是xian80高斯克呂格平面投影直角坐标系,因為是用于三維資料,是以加上一個高程形成一個三維立體直角坐标系。嚴格意義上來講,是需要将地球展成這個立體直角坐标系,将這個傾斜攝影模型放置到SRSOrigin的地理位置才是最準确的。但是一般的投影東向和北向的方向是不會變的,仍然可以将SRSOrigin的地理位置當成一個站心位置,隻不過這個站心位置不再是經緯度而是EPSG:2384的平面坐标值(加上高程)。
是以像這種類型的資料,隻需要将SRSOrigin的地理位置值轉換成經緯度值,就變成2.1中描述的情況了。
具體的實作代碼如下:
#include <Windows.h>
#include <iostream>
#include <string>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgEarth/MapNode>
#include <osgEarthDrivers/gdal/GDALOptions>
#include <osgEarthDrivers/cache_filesystem/FileSystemCache>
#include <osgEarth/ImageLayer>
#include <osgEarth/Viewpoint>
#include <osgEarth/GeoTransform>
#include <osgEarth/ModelLayer>
#include <osgEarth/Registry>
#include <osgEarthUtil/EarthManipulator>
#include <gdal_priv.h>
using namespace std;
void AddModel(osg::ref_ptr<osgEarth::Map> map, osg::ref_ptr<osgEarth::MapNode> mapNode)
{
//
std::string filePath = "D:/Data/scene/Dayanta/Data.osgb";
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(filePath);
osg::ref_ptr<osgEarth::GeoTransform> xform = new osgEarth::GeoTransform();
xform->addChild(node);
xform->setTerrain(mapNode->getTerrain());
osgEarth::GeoPoint point(map->getSRS(), 108.9594, 34.2196, -410); //使用絕對高,正高
xform->setPosition(point);
osg::ref_ptr<osgEarth::ModelLayer> modelLayer = new osgEarth::ModelLayer("oblic", xform);
map->addLayer(modelLayer);
osgEarth::Registry::shaderGenerator().run(node);
}
int main()
{
CPLSetConfigOption("GDAL_DATA", "D:/Work/OSGNewBuild/OpenSceneGraph-3.6.4/3rdParty/x64/gdal-data");
//string wktString = "EPSG:3857"; //web墨卡托投影
//string wktString = "EPSG:4326"; //wgs84
osgEarth::ProfileOptions profileOpts;
//profileOpts.srsString() = wktString;
//osgEarth::Bounds bs(535139, 3365107, 545139, 3375107);
//osgEarth::Bounds bs(73, 3, 135, 53);
//profileOpts.bounds() = bs;
//地圖配置:設定緩存目錄
osgEarth::Drivers::FileSystemCacheOptions cacheOpts;
string cacheDir = "D:/Work/OSGNewBuild/tmp";
cacheOpts.rootPath() = cacheDir;
//
osgEarth::MapOptions mapOpts;
mapOpts.cache() = cacheOpts;
//mapOpts.coordSysType() = osgEarth::MapOptions::CSTYPE_PROJECTED;
mapOpts.profile() = profileOpts;
//建立地圖節點
osg::ref_ptr<osgEarth::Map> map = new osgEarth::Map(mapOpts);
osg::ref_ptr<osgEarth::MapNode> mapNode = new osgEarth::MapNode(map);
osgEarth::Drivers::GDALOptions gdal;
//gdal.url() = "D:/Work/OSGNewBuild/osgearth-2.10.1/data/world.tif";
//gdal.url() = "D:/Work/SinianGIS/bin/Resource/BlueMarbleNASA.jpg";
gdal.url() = "D:/Work/SinianGIS/bin/Resource/baseMap.jpg";
osg::ref_ptr<osgEarth::ImageLayer> imgLayer = new osgEarth::ImageLayer("BlueMarble", gdal);
map->addLayer(imgLayer);
AddModel(map, mapNode);
osgViewer::Viewer viewer;
viewer.getCamera()->setClearColor(osg::Vec4(0, 0, 0, 0));
viewer.setSceneData(mapNode);
osg::ref_ptr< osgEarth::Util::EarthManipulator> mainManipulator = new osgEarth::Util::EarthManipulator;
viewer.setCameraManipulator(mainManipulator);
osgEarth::Viewpoint vp;
osgEarth::GeoPoint newPoint(map->getSRS(), 108.9594, 34.2196, 0);
vp.focalPoint() = newPoint;
vp.heading() = 0;
vp.pitch() = -90;
vp.range() = 1000;
mainManipulator->setViewpoint(vp);
viewer.setUpViewInWindow(100, 100, 800, 600);
return viewer.run();
}
運作結果如下:
- GNSS學習筆記-坐标轉換