DEM converted to gltf

1 Overview

On DEM (terrain file) comes natural three-dimensional information, it may be converted into gltf model file. DEM raster data can be read by GDAL; gltf a JSON format may be employed nlohmann / json read and write.

2. Detailed

Directly to the code stickers:

#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 used herein is an image format, used to read GDAL. Since no large display model coordinates file, so there is no starting the XY coordinate value of DEM enumerated. At the same time it comes with a texture map, just to cover the entire range of DEM.

2. The principle of the conversion is very simple, is to draw each grid DEM into two triangles, drawn through the vertex indices. gltf specific specifications can be found in the github tutorials , online as well as the relevant Chinese translation .

nlohmann 3. Native / json assembly JSON format is written in the sort order is not a character string is inserted according to the order of sorting, inspection time is inconvenient. So here we used nlohmann :: fifo_map specialized container object type.

3. Results

OSG out by the conversion results are shown below:

Terrain gltf

4. Reference

[. 1] gltf tutorial on GitHub
[2] gltf course in Chinese
[. 3] nlohmann / JSON discussion of the inserted sequence reservations

Guess you like

Origin www.cnblogs.com/charlee44/p/12152435.html