DEM转换为gltf

简介: DEM转换为gltf

DEM转换为gltf

目录

1. 概述

DEM(地形文件)天然自带三维信息,可以将其转换成gltf模型文件。DEM是栅格数据,可以通过GDAL进行读取;gltf是一种JSON格式,可以采用nlohmann/json进行读写。

2. 详细

直接把代码贴出来:

#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的范围。

2.转换的的原理非常简单,就是将DEM的每个网格绘制成两个三角形,通过顶点索引进行绘制。gltf具体的规范可以参看github上的教程,网上还有相关的中文翻译

3.原生的nlohmann/json组件写出来的JSON格式是根据字符串顺序排序不是根据插入顺序排序的,查阅的时候不方便。所以这里使用了nlohmann::fifo_map容器专门化对象类型。

3. 结果

转换出来的结果用OSG显示如下:

4. 参考

[1] github上的gltf教程

[2] gltf教程中文翻译

[3] nlohmann/json关于保留插入顺序的讨论

分类: GIS , Cesium

标签: DEM , gltf , 纹理 , 模型


相关文章
|
6月前
|
XML 数据格式 C++
AMF/GLTF格式在线转换
3D模型在线转换是一个可以进行3D模型格式转换的在线工具,支持多种3D模型格式进行在线预览和互相转换。
101 0
AMF/GLTF格式在线转换
|
6月前
|
XML 数据格式
3MF/GLTF格式在线转换
3D模型在线转换是一个可以进行3D模型格式转换的在线工具,支持多种3D模型格式进行在线预览和互相转换。
124 0
3MF/GLTF格式在线转换
|
JavaScript 前端开发 关系型数据库
GIS开发:GeoJSON坐标和WKT的转换
GIS开发:GeoJSON坐标和WKT的转换
709 0
|
算法 数据安全/隐私保护
TSCAN + TMODEL处理点云数据生成DEM
TSCAN + TMODEL处理点云数据生成DEM
641 0
TSCAN + TMODEL处理点云数据生成DEM
|
定位技术
【gis】gdal 切分遥感 tif 格式图片
【gis】gdal 切分遥感 tif 格式图片
509 0
【gis】gdal 切分遥感 tif 格式图片
|
3月前
|
Python
从bag包中提取图片和点云数据为pcd格式点云文件
从bag包中提取图片和点云数据为pcd格式点云文件
136 0
|
6月前
|
存储 算法 编译器
【ffmpeg 到Qt的图片格式转换】精彩的像素:深入解析 AVFrame 到 QImage 的转换
【ffmpeg 到Qt的图片格式转换】精彩的像素:深入解析 AVFrame 到 QImage 的转换
229 0
ENVI Classic:如何加载栅格数据(Img/DEM)和矢量数据(evf of ROI)?
ENVI Classic:如何加载栅格数据(Img/DEM)和矢量数据(evf of ROI)?
698 0
ENVI Classic: 如何进行波段合成、矢量栅格叠加显示、窗口链接、图像格式转换、头文件编辑、重采样等(详细)2
ENVI Classic: 如何进行波段合成、矢量栅格叠加显示、窗口链接、图像格式转换、头文件编辑、重采样等(详细)
409 0
|
6月前
|
传感器 编解码 人工智能
pie engine——数字高程模型DEM/ALOS_DEM_12.5m数据集
pie engine——数字高程模型DEM/ALOS_DEM_12.5m数据集
182 0