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关于保留插入顺序的讨论

DEM转换为gltf的更多相关文章

  1. 3D模型预处理(格式转换:obj转换为gltf)

    在cesium中导入模型需要的是gltf或glb格式的文件,cesium官方提供了obj转gltf文件的工具,一个obj2gltf的库,地址为https://github.com/Analytical ...

  2. WebGL简易教程(十五):加载gltf模型

    目录 1. 概述 2. 实例 2.1. 数据 2.2. 程序 2.2.1. 文件读取 2.2.2. glTF格式解析 2.2.3. 初始化顶点缓冲区 2.2.4. 其他 3. 结果 4. 参考 5. ...

  3. 【Ceisum】Max转GLTF

    参考资料:https://blog.csdn.net/u011394175/article/details/78919281 1.在3DsMax中加入COLLADA插件:COLLADA-MAX-PC_ ...

  4. glTF格式初步了解

    glTF格式初步了解 近期看到Qt 3D的进展.偶然了解到了一种新的格式:glTF格式.这样的格式据说比现有的3D格式更加符合OpenGL应用的须要.这引起了我的好奇.于是我在Qt 3D的外部链接中找 ...

  5. 3D性能优化 | 说一说glTF文件压缩

    引言 最近做T级互动,需要使用到3D模型.相信大家和我一样,在开始着手的时候,一定会有这么些问题: 1.如何选择3D模型的导出格式 2.如何对模型文件进行优化 3.在大流量的项目中兼容性怎么样 让我们 ...

  6. Cesium中导入三维模型方法(dae到glft/bgltf) 【转】

    http://blog.csdn.net/l491453302/article/details/46766909 目录(?)[+] Cesium中目前支持gltf和bgltf两种格式.“gltf是kh ...

  7. cesium js学习一加载三维模型【转】

    http://blog.csdn.net/tangyajun_168/article/details/50936698 最近项目中用到室外三维模型与室内三维地图交互,室外三维模型的加载我们采用了ces ...

  8. Cesium学习笔记(五):3D 模型 (http://blog.csdn.net/umgsoil/article/details/74572877)

    Cesium支持3D模型,包括关键帧动画,皮肤的改变还有单个节点的选择等,Cesium还提供了了一个基于网络的工具,将COLLADA模型转换为glTF,方便和优化模型添加 还记得我们在实体添加的时候添 ...

  9. Cesium中导入三维模型方法(dae到glft/bgltf)[转]

    Cesium中导入三维模型方法(dae到glft/bgltf) Cesium中目前支持gltf和bgltf两种格式.“gltf是khronos组织(起草OpenGL标准的那家)定义的一种交换格式,用于 ...

随机推荐

  1. Python Selenium定位元素常用解决办法

       在做web应用的自动化测试时,定位元素是必不可少的,这个过程经常会碰到定位不到元素的情况(报selenium.common.exceptions.NoSuchElementException), ...

  2. React 解析/ 第二节 使用 Reac

    官方脚手架 create-react-app React 提供了一个官方的命令行工具(CLI)—— create-react-app,是专门用于快速搭建单页面应用(SPA)的脚手架,它基于 Webpa ...

  3. PKU-3580 SuperMemo(Splay模板题)

    SuperMemo 题目链接 Your friend, Jackson is invited to a TV show called SuperMemo in which the participan ...

  4. Git详解之分布式应用

    前言 为了便于项目中的所有开发者分享代码,我们准备好了一台服务器存放远程 Git 仓库.经过前面几章的学习,我们已经学会了一些基本的本地工作流程中所需用到的命令.接下来,我们要学习下如何利用 Git ...

  5. SpringCloud与微服务Ⅱ --- 微服务概述

    一.什么是微服务 1) Martin Fowler论文对微服务的阐述(中文版) 2) 对单一应用进行拆分 3) 每一个独立的应用都有一个独立的进程 4) 拥有自己独立的数据库 5) 微服务化的核心就是 ...

  6. Git 初级使用 windows & Ubuntu

    目的:有一段代码要进行几个人同时维护,但是传来传去不方便,所以希望在github上实现,前提是每台机器都有git 在github 上新建一个项目 然后会看到,大体上就按这执行就可以 在Windows系 ...

  7. 模块化系列教程 | 深入源码分析阿里JarsLink1.0模块化框架

    1. 概述 1.1 模块动态加载卸载主流程 2. 模块动态加载 2.1 模块加载源码分析 2.1.1 AbstractModuleRefreshScheduler 2.1.2 ModuleLoader ...

  8. JVM性能优化系列-(3) 虚拟机执行子系统

    3. 虚拟机执行子系统 3.1 Java跨平台的基础 Java刚诞生的宣传口号:一次编写,到处运行(Write Once, Run Anywhere),其中字节码是构成平台无关的基石,也是语言无关性的 ...

  9. Spring IoC 容器和 bean 对象

    程序的耦合性: 耦合性(Coupling),又叫耦合度,是对模块间关联程度的度量.耦合的强弱取决于模块间接口的复杂性.调用模块的方式以及通过界面传送数据的多少.模块间的耦合度是指模块之间的依赖关系,包 ...

  10. 用java编写代码实现关机

    public static void main(String[] args) { Runtime runtime = Runtime.getRuntime(); try { runtime.exec( ...