DEM(地形文件)自然自帶三維信息,能夠將其轉換成gltf模型文件。DEM是柵格數據,能夠經過GDAL進行讀取;gltf是一種JSON格式,能夠採用nlohmann/json進行讀寫。node
直接把代碼貼出來:ios
#include <iostream> #include <fstream> #include <iomanip> #include <nlohmann\json.hpp> #include "fifo_map.hpp" #include <gdal/gdal_priv.h> using namespace std; using namespace nlohmann; // A workaround to give to use fifo_map as map, we are just ignoring the 'less' compare template<class K, class V, class dummy_compare, class A> using my_workaround_fifo_map = fifo_map<K, V, fifo_map_compare<K>, A>; using my_json = basic_json<my_workaround_fifo_map>; int main() { GDALAllRegister(); CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); //支持中文路徑 my_json gltf; gltf["asset"] = { {"generator", "CL"}, {"version", "2.0"} }; gltf["scene"] = 0; gltf["scenes"] = { {{"nodes", {0} }} }; gltf["nodes"] = { {{"mesh", 0}} }; my_json positionJson; positionJson["POSITION"] = 1; positionJson["TEXCOORD_0"] = 2; my_json primitivesJson; primitivesJson = { {{"attributes", positionJson}, {"indices", 0}, {"material", 0} } }; gltf["meshes"] = { {{"primitives", primitivesJson}} }; my_json pbrJson; pbrJson["baseColorTexture"]["index"] = 0; gltf["materials"] = { {{"pbrMetallicRoughness", pbrJson}} }; size_t pointNum = 0; size_t binBufNum = 0; size_t indicesNum = 0; { string binPath = "D:/Work/WebGLTutorial/Data/new.bin"; ofstream binFile(binPath, std::ios::binary); const char *filePath = "D:/Work/WebGLTutorial/Data/DEM.tif"; GDALDataset* img = (GDALDataset *)GDALOpen(filePath, GA_ReadOnly); if (!img) { printf("Can't Open Image!"); return 0; } int bufWidth = img->GetRasterXSize(); //圖像寬度 int bufHeight = img->GetRasterYSize(); //圖像高度 int bandNum = img->GetRasterCount(); //波段數 if (bandNum != 1) { printf("DEM波段數不爲1"); return 0; } int depth = GDALGetDataTypeSize(img->GetRasterBand(1)->GetRasterDataType()) / 8; //圖像深度 //獲取地理座標信息 double padfTransform[6]; if (img->GetGeoTransform(padfTransform) == CE_Failure) { printf("獲取仿射變換參數失敗"); return 0; } double startX = padfTransform[0]; double dX = padfTransform[1]; double startY = padfTransform[3]; double dY = padfTransform[5]; //申請buf size_t imgBufNum = (size_t)bufWidth * bufHeight * bandNum; float *imgBuf = new float[imgBufNum]; //讀取 img->RasterIO(GF_Read, 0, 0, bufWidth, bufHeight, imgBuf, bufWidth, bufHeight, GDT_Float32, bandNum, nullptr, bandNum*depth, bufWidth*bandNum*depth, depth); pointNum = (size_t)bufWidth * bufHeight; size_t position_texture_num = pointNum * 5; float *position_texture = new float[position_texture_num]; for (int yi = 0; yi < bufHeight; yi++) { for (int xi = 0; xi < bufWidth; xi++) { size_t n = (size_t)(bufWidth * 5) * yi + 5 * xi; position_texture[n] = dX * xi; position_texture[n+1] = dY * yi; size_t m = (size_t)(bufWidth * bandNum) * yi + bandNum * xi; position_texture[n + 2] = imgBuf[m]; position_texture[n + 3] = float(xi) / (bufWidth-1); position_texture[n + 4] = float(yi) / (bufHeight-1); } } //釋放 delete[] imgBuf; imgBuf = nullptr; binFile.write((char*)position_texture, position_texture_num * sizeof(float)); size_t vertexBufNum = position_texture_num * sizeof(float); binBufNum = binBufNum + vertexBufNum; int mod = vertexBufNum % sizeof(uint16_t); if (mod != 0) { int spaceNum = sizeof(float) - mod; char *space = new char[spaceNum]; binBufNum = binBufNum + sizeof(char) * spaceNum; memset(space, 0, sizeof(char) * spaceNum); binFile.write(space, sizeof(char) * spaceNum); delete[] space; space = nullptr; } indicesNum = (size_t)(bufWidth - 1) * (bufHeight - 1) * 2 * 3; uint16_t *indices = new uint16_t[indicesNum]; for (int yi = 0; yi < bufHeight-1; yi++) { for (int xi = 0; xi < bufWidth-1; xi++) { uint16_t m00 = (uint16_t)(bufWidth * yi + xi) ; uint16_t m01 = (uint16_t)(bufWidth * (yi+1) + xi); uint16_t m11 = (uint16_t)(bufWidth * (yi + 1) + xi + 1); uint16_t m10 = (uint16_t)(bufWidth * yi + xi + 1); size_t n = (size_t)(bufWidth - 1) * yi + xi; indices[n * 6] = m00; indices[n * 6 + 1] = m01; indices[n * 6 + 2] = m11; indices[n * 6 + 3] = m11; indices[n * 6 + 4] = m10; indices[n * 6 + 5] = m00; } } binFile.write((char*)indices, sizeof(uint16_t) * indicesNum); binBufNum = binBufNum + sizeof(uint16_t) * indicesNum; delete[] position_texture; position_texture = nullptr; delete[] indices; indices = nullptr; } gltf["textures"] = { {{"sampler", 0}, {"source", 0}} }; gltf["images"] = { {{"uri", "tex.jpg"}} }; gltf["samplers"] = { {{"magFilter", 9729}, {"minFilter", 9987}, {"wrapS", 33648}, {"wrapT", 33648}} }; gltf["buffers"] = { {{"uri", "new.bin"}, {"byteLength", binBufNum}} }; my_json indicesBufferJson; indicesBufferJson["buffer"] = 0; indicesBufferJson["byteOffset"] = pointNum * 5 * 4; indicesBufferJson["byteLength"] = indicesNum * 2; indicesBufferJson["target"] = 34963; my_json positionBufferJson; positionBufferJson["buffer"] = 0; positionBufferJson["byteStride"] = sizeof(float) * 5; positionBufferJson["byteOffset"] = 0; positionBufferJson["byteLength"] = pointNum * 5 * 4; positionBufferJson["target"] = 34962; gltf["bufferViews"] = { indicesBufferJson, positionBufferJson }; my_json indicesAccessors; indicesAccessors["bufferView"] = 0; indicesAccessors["byteOffset"] = 0; indicesAccessors["componentType"] = 5123; indicesAccessors["count"] = indicesNum; indicesAccessors["type"] = "SCALAR"; indicesAccessors["max"] = { 18719 }; indicesAccessors["min"] = { 0 }; my_json positionAccessors; positionAccessors["bufferView"] = 1; positionAccessors["byteOffset"] = 0; positionAccessors["componentType"] = 5126; positionAccessors["count"] = pointNum; positionAccessors["type"] = "VEC3"; positionAccessors["max"] = { 770, 0.0, 1261.151611328125 }; positionAccessors["min"] = { 0.0, -2390, 733.5555419921875 }; my_json textureAccessors; textureAccessors["bufferView"] = 1; textureAccessors["byteOffset"] = sizeof(float) * 3; textureAccessors["componentType"] = 5126; textureAccessors["count"] = pointNum; textureAccessors["type"] = "VEC2"; textureAccessors["max"] = { 1, 1 }; textureAccessors["min"] = { 0, 0 }; gltf["accessors"] = { indicesAccessors, positionAccessors, textureAccessors }; string jsonFile = "D:/Work/WebGLTutorial/Data/new.gltf"; std::ofstream outFile(jsonFile); outFile << std::setw(4) << gltf << std::endl; }
1.這裏使用的DEM是tif格式的圖像,使用GDAL讀取。因爲顯示模型文件不須要大座標,因此沒有把DEM的起始XY座標值算進去。同時附帶了一張紋理貼圖,正好覆蓋整個DEM的範圍。git
2.轉換的的原理很是簡單,就是將DEM的每一個網格繪製成兩個三角形,經過頂點索引進行繪製。gltf具體的規範能夠參看github上的教程,網上還有相關的中文翻譯。github
3.原生的nlohmann/json組件寫出來的JSON格式是根據字符串順序排序不是根據插入順序排序的,查閱的時候不方便。因此這裏使用了nlohmann::fifo_map容器專門化對象類型。json
轉換出來的結果用OSG顯示以下:less
[1] github上的gltf教程
[2] gltf教程中文翻譯
[3] nlohmann/json關於保留插入順序的討論ide