zoukankan      html  css  js  c++  java
  • DEM转换为gltf

    1. 概述

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

    2. 详细

    直接把代码贴出来:

    #include <iostream>
    #include <fstream>
    #include <iomanip>
    #include <nlohmannjson.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显示如下:

    地形gltf

    4. 参考

    [1] github上的gltf教程
    [2] gltf教程中文翻译
    [3] nlohmann/json关于保留插入顺序的讨论

  • 相关阅读:
    文件查找和比较命令 来自: http://man.linuxde.net/find
    Docker学习计划
    Mybatis各种模糊查询
    linux下vi命令大全
    mac下的环境变量
    slf4j输出变量
    使用lombok中的log
    idea中的java web项目(添加jar包介绍)和java maven web项目目录结构
    slf4j+logback&logback.xml
    日志框架
  • 原文地址:https://www.cnblogs.com/charlee44/p/12152435.html
Copyright © 2011-2022 走看看