DEM转换为gltf

目录

  • 1. 概述
  • 2. 详细
  • 3. 结果
  • 4. 参考

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

原文地址:https://www.cnblogs.com/charlee44/p/12152435.html

时间: 2024-10-12 12:53:20

DEM转换为gltf的相关文章

obj文件转换为gltf的方法

首先需要安装gltf转换工具 npm install --save obj2gltf 安装成功后,执行下列语句即可成功转换,-i表示输入文件,-o表示输出文件 obj2gltf -i model.obj -o model.gltf 原文地址:https://www.cnblogs.com/kkevin/p/10083128.html

glTF格式初步了解

glTF格式初步了解 最近看到Qt 3D的进展,偶然了解到了一种新的格式:glTF格式.这种格式据说比现有的3D格式更加符合OpenGL应用的需要,这引起了我的好奇,于是我在Qt 3D的外部链接中找到了有关glTF的相关链接. 上海萌梦信息科技有限公司(微博:http://weibo.com/qtdream)原创文章,首发地址:http://qtdream.com/topic/140.欢迎同行前来探讨. glTF的官网介绍在这里.它介绍了glTF的一些特性.发起者以及应用情景.官网中,介绍了gl

【Ceisum】Max转GLTF

参考资料:https://blog.csdn.net/u011394175/article/details/78919281 1.在3DsMax中加入COLLADA插件:COLLADA-MAX-PC_Max2017_v1.6.63 2.使用3DsMax加载模型文件,将物体设置到原点 3.导出OpenCOLLADA格式的DAE文件 4.下载COLLADA2GLTF-v2.1.4-windows-Release-x64 5.使用COLLADA2GLTF将DAE转换为GLTF格式,   在Window

在AcGIS中用大数据生成DEM

在ArcGIS中生成DEM时,采用的数据源往往是一些高程点.等高线,这些高程点.等高线比较密集,可能有好几千万个,甚至上亿个高程点.等高线.若利用这些矢量数据生成TIN,一般是不能实现的,因为生成TIN时,支持的最大结点数只能有几千万个(依据电脑性能,受限于内存).另外矢量信息的存储也是比较讲究的,如果把这些矢量信息存储在shp文件中,往往会出现问题(比如在arcmap中加载时出现的绘制错误).综合以上问题,感觉采用如下办法比较可取. 1. 矢量信息存储在Geodatabase中 把矢量信息用统

osgEarth开发数据准备(一)——DEM与纹理影像(遥感)下载与处理 (转)

osgEarth开发数据准备(一)——DEM与纹理影像(遥感)下载与处理 分类: Open Source GIS 2013-06-14 17:24 1418人阅读 评论(0) 收藏 举报 osgEarthdem遥感地理信息google 影像 目录(?)[+] 获取数据的方式 如何在网络上获取数据 国内重要的数据库 其他 更多 国外的重要的数据库 马里兰大学 哈佛大学 nasa ASTER GDEM 其他重要资源 个人网站形式的数据源 借用商业数据 如何选择数据 参考 关于第一节国际科学数据平台更

ArcGIS教程:将表面数据转换为矢量数据

虽然不规则三角网 (TIN) 和 terrain 数据集被视为向量表面,但它们实际上包含基于要素的其他信息,而该信息在处于像点.线或面这样的原始格式时可能更有用.在 ArcGIS 中,您可以很轻松地将表面数据转换为矢量要素.通过在选择.叠加.编辑或多图层建模的过程中应用这种转换操作,将增强您的分析能力. 您可能希望将三种表面转换为点.线和面等矢量数据.可以使用三种不同的方法将栅格.TIN 和 Terrain 数据集表面转换为矢量数据. 栅格表面转矢量要素 包含高程的栅格表面通常被提取为面要素数据

将DataTable转换为List,将List转换为DataTable的实现类

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace Xmh.DBUnit { /// <summary> /// 将DataTable转换为List,将

Node.JS 文件读写,把Sheet图集转换为龙骨动画图集

Node.JS 文件读写,把Sheet图集数据转换为龙骨动画图集数据 var fs = require("fs") var readline = require("readline"); var rl = readline.createInterface({ input:process.stdin, output:process.stdout }); var path = undefined; var dbName = undefined; rl.question(

将一个字符串转换为对应的整数

例: 将"1234"转换为数字1234. 将"-1234"转换为数字-1234. 将"+1234"转换为1234. 分析: 先设置一个标签sign=1, 一个一个读取字符,读到第一个字符判断它是不是'-'和'+':如果是'-'那么令标记sign=-1,并且读取字符指针向后移一位,若果是'+',那么sign不变,指针向后移一位,将新读到的字符如'1',用'1'-'0',得到的值是数字1,设置变量num=0,每次读到的字符转换成数字与num*10相加