diff --git a/README.md b/README.md index 0625d10..8b0bb5b 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # About Project -1. 整体参考https://github.com/fanvanzh/3dtiles,向作者致敬,市面上唯一的开源好用的3DTILES转换工具,在学习过程中,从中收获很多,对3DTiles、OSGB、GLTF等数据格式有了进一步了解。 +1. 整体参考[https://github.com/fanvanzh/3dtiles](https://github.com/fanvanzh/3dtiles), 向作者致敬,市面上唯一的开源好用的3DTILES转换工具,在学习过程中,从中收获很多,对3DTiles、OSGB、GLTF等数据格式有了进一步了解。 2. 原工程基于C++、C和Rust,本人本身对Rust不了解,但是学习过程中难免涉及到调试,也看了整个代码,个人理解作者采用Rust和C++混编应该是两个问题: 1. OpenSceneGraph没有除了C++之外其他版本,而且我们在用这个工具时,最主要的就是OSGB转3DTILES - 1. 本身C++可以跨平台,但是C++对字符串、文件系统支持不够好,Rust可以很好满足这一点,并且Rust也便于和C++交互 - 2. 综合下来,原作者使用了Rust和C++来编写,一是保证跨平台,二是保证了性能。 + 2. 本身C++可以跨平台,但是C++对字符串、文件系统支持不够好,Rust可以很好满足这一点,并且Rust也便于和C++交互 + 3. 综合下来,原作者使用了Rust和C++来编写,一是保证跨平台,二是保证了性能。 -本人本身是对Qt比较熟悉的,就萌生了这个想法,用C++和Qt,从新梳理整个框架,刚好今年春节一个人,秉着学习想法,使用纯C++(加了Qt)重写了该工程,新的工程基于C++ 17标准重写,使用了Qt5.15,主要作者本身写C++大部分时候都是基于Qt,对Qt也稍微了解,同时也借助Qt很好的跨平台特性,性能没有变化,并且也便于调试学习。 -1. 整个工程开源,但是鉴于Qt一些限制,该程序采用LGPL协议。 -2. 后续会与作者同步保持更新,后期希望可以加入自己一些特色功能。 +3. 本人本身是对Qt比较熟悉的,就萌生了这个想法,用C++和Qt,从新梳理整个框架,刚好今年春节一个人,秉着学习想法,使用纯C++(加了Qt)重写了该工程,新的工程基于C++ 17标准重写,使用了Qt5.15,主要作者本身写C++大部分时候都是基于Qt,对Qt也稍微了解,同时也借助Qt很好的跨平台特性,性能没有变化,并且也便于调试学习。 + 1. 整个工程开源,但是鉴于Qt一些限制,该程序采用LGPL协议。 + 2. 后续会与作者同步保持更新,后期希望可以加入自己一些特色功能。 # 简介 @@ -25,37 +25,36 @@ ## 命令行格式 ```sh -Cesium3DTilesConverter.exe --format --input --output [OPTIONS] +Converter.exe --format --input --output [OPTIONS] ``` ## 示例命令 ```sh # from osgb dataset -Cesium3DTilesConverter.exe -f osgb -i E:\osgb_path -o E:\out_path -Cesium3DTilesConverter.exe -f osgb -i E:\osgb_path -o E:\out_path -c "{\"offset\": 0}" +Converter.exe --format osgb -input E:\osgb_path -o E:\out_path # from single shp file -Cesium3DTilesConverter.exe -f shape -i E:\Data\aa.shp -o E:\Data\aa --height height +Converter.exe --format gdal --input --output --field height --layer # from gdb file -Cesium3DTilesConverter.exe -f shape -i E:\Data\aa.shp -o E:\Data\aa --height height +Converter.exe --format gdal --input --output --field height --layer ``` ## 参数说明 - `-f, --format ` 输入数据格式。 - `FORMAT` 可选:osgb, gis + `FORMAT` 可选:OSGB, GDAL - `osgb` 为倾斜摄影格式数据, `gis` 为面(Polygon)数据 + `可选:OSGB` 为倾斜摄影格式数据, `GDAL` 为GDAL支持的面(Polygon)数据 -- `--input ` 输入数据的目录,osgb数据截止到 `/Data` 目录的上一级,其他格式具体到文件名。 +- `--input ` 输入数据的目录,osgb数据截止到 `/Data` 目录的上一级,GDAL参考GDAL数据格式。 -- `--output ` 输出目录。输出的数据文件位于 `/Data` 目录。 - -- `--field` 高度字段。指定shapefile中的高度属性字段,此项为转换 shp 时的必须参数。 +- `--output ` 输出目录。OSGB转换的3DTiles输出的数据文件位于 `/Data` 目录, GDAL转换的3DTiles输出的数据文件位于`/Tile`目录,`tileset.json`位于``根目录。 +- `--field` 高度字段。指定GDAL数据集中的高度属性字段,此项为转换 GDAL 时的必须参数。 +- `--offset` OSGB高度偏移字段。 # 数据要求及说明 @@ -63,8 +62,8 @@ Cesium3DTilesConverter.exe -f shape -i E:\Data\aa.shp -o E:\Data\aa --height hei 倾斜摄影数据仅支持 smart3d 格式的 osgb 组织方式: -- 数据目录必须有一个 `“Data”` 目录的总入口; -- `“Data”` 目录同级放置一个 `metadata.xml` 文件用来记录模型的位置信息; +- 数据目录必须有一个 `Data` 目录的总入口; +- `Data` 目录同级放置一个 `metadata.xml` 文件用来记录模型的位置信息; - 每个瓦片目录下,必须有个和目录名同名的 osgb 文件,否则无法识别根节点; 正确的目录结构示意: @@ -72,23 +71,21 @@ Cesium3DTilesConverter.exe -f shape -i E:\Data\aa.shp -o E:\Data\aa --height hei ``` - Your-data-folder ├ metadata.xml - └ Data\Tile_000_000\Tile_000_000.osgb + └ Data/Tile_000_000/Tile_000_000.osgb ``` -### Shapefile +### GDAL -目前仅支持 Shapefile 的面数据,可用于建筑物轮廓批量生成 3D-Tiles. +目前仅支持GDAL格式的面数据,可用于建筑物轮廓批量生成3DTiles. -Shapefile 中需要有字段来表示高度信息。 +图层中需要有字段来表示高度信息。 -# How To Build -1、vcpkg install "osg" "osg[plugins]" -2、如果没有Qt5.15 - 1. 通过Qt官网安装 - 2. vcpkg install "qt5[all]" -3. mkdir build -4. cd build -5. cmake .. && make -6. 把OSGPlugins文件夹复制到build目录下 +# How To Build (Windows) +1. vcpkg install "osg" "osg[plugins]" +2. 如果没有Qt5.15,可以通过以下两种方式安装: + 1. 通过Qt官网安装 + 2. vcpkg install "qt5[all]" +3. VS2019选择CMakeLists.txt,导入工程,编译 +4. 把OSGPlugins文件夹复制到编译目录下 # About Author diff --git a/src/DxtImage.cpp b/src/DxtImage.cpp index 9f49b6f..cf48178 100644 --- a/src/DxtImage.cpp +++ b/src/DxtImage.cpp @@ -83,7 +83,7 @@ namespace scially { int imgSize = img->getImageSizeInBytes(); int x_pos = 0; int y_pos = 0; - for (size_t i = 0; i < imgSize; i += 8) + for (int i = 0; i < imgSize; i += 8) { // 64 bit matrix unsigned short color0, color1; diff --git a/src/OSGBConvert.cpp b/src/OSGBConvert.cpp index b672976..bb76209 100644 --- a/src/OSGBConvert.cpp +++ b/src/OSGBConvert.cpp @@ -1,10 +1,8 @@ -#pragma once - #include +#include #include #include #include -#include #include #include #include @@ -12,6 +10,8 @@ #include #include +#include +#include #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION #define TINYGLTF_IMPLEMENTATION @@ -57,32 +57,13 @@ namespace scially { if (glbBuffer.isEmpty()) return QByteArray(); - QString featureTable = R"({"BATCH_LENGTH":1})"; - while (featureTable.size() % 4 != 0) { - featureTable.append(' '); - } - - QString batchTable = R"({"batchId":[0],"name":["mesh_0"]})"; - while (batchTable.size() % 4 != 0) { - batchTable.append(' '); - } - - int totalSize = 28 /*header size*/ + featureTable.size() + batchTable.size() + glbBuffer.size(); - - b3dmStream.writeRawData("b3dm", 4); - b3dmStream << 1; // version - b3dmStream << totalSize; - b3dmStream << featureTable.size(); - b3dmStream << 0; - b3dmStream << batchTable.size(); - b3dmStream << 0; - - // DataStream << will write byte length first, so invoke wrteRawData - b3dmStream.writeRawData(featureTable.toStdString().data(), featureTable.size()); - b3dmStream.writeRawData(batchTable.toStdString().data(), batchTable.size()); - b3dmStream.writeRawData(glbBuffer.data(), glbBuffer.size()); + Batched3DModel b3dm; + b3dm.glbBuffer = glbBuffer; + b3dm.batchLength = 1; + b3dm.batchID = { 0 }; + b3dm.names = {"mesh_0"}; - return b3dmBuffer; + return b3dm.write(); } QByteArray OSGBConvert::convertGLB() { diff --git a/src/main.cpp b/src/main.cpp index 39f3b24..1f2b719 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,7 +19,7 @@ int main(int argc, char** argv){ parser.addOption(inputOption); const QCommandLineOption outputOption("output", "output path", "output"); parser.addOption(outputOption); - const QCommandLineOption formatOption("format", "", "format"); + const QCommandLineOption formatOption("format", "", "format"); parser.addOption(formatOption); const QCommandLineOption maxLvlOption("level", "max level", "level", "-1"); parser.addOption(maxLvlOption); @@ -60,7 +60,7 @@ int main(int argc, char** argv){ osgbConvert.setMaxLevel(maxLevel); osgbConvert.run(); } - else if (format == "SHAPE"){ + else if (format == "GDAL"){ if(!parser.isSet(fieldOption)){ qCritical() << "Commandline field is requested"; return 1;