需求说明:
在使用Cesium unity开发的时候,遇到一个需求需要根据经纬度获取对应的地形高度。经过查询资料,这个功能在Cesium网页端比较简单,但是在Unity端并没有相关的功能接口。于是需要自己通过其他方式实现。
经过查询资料,发现GDAL开源库可以直接实现该功能,并且性能极高。于是确定采用GDAL进行计算。
集成步骤:
网上有很多中集成方式,有自己下载源码编译的,有在Unity中试用NuGet for unity下载的,还有一些其他的,但是都很麻烦。
下面我介绍一下我使用的集成方式,非常简单方便,目前没有发现有什么问题,如果有谁知道这种方式有什么问题,还请留言交流。
1.新建一个c# VS工程:
2.打开NuGet的管理窗口
3.下载安装两个包:gdal、gdal.native
4.写个获取高度的代码运行一下:
using System;
using GDALTest;
using OSGeo.GDAL;
using OSGeo.OSR;
class Program
{
static void Main()
{
GdalConfiguration.ConfigureGdal();
Gdal.AllRegister();
string demFilePath = "D:/gisdata/450mDEM.tif"; // 替换为实际的 DEM 文件路径
double longitude = 120.0; // 替换为实际的经度
double latitude = 30.0; // 替换为实际的纬度
double height = CalculateHeight(demFilePath, longitude, latitude);
Console.WriteLine($"指定经纬度的高度为: {height}");
Console.ReadLine();
}
static double CalculateHeight(string filePath, double longitude, double latitude)
{
Dataset ds = Gdal.Open(filePath, Access.GA_ReadOnly);
if (ds == null)
{
Console.WriteLine("无法打开文件");
return -1;
}
double[] adfGeoTransform = new double[6];
ds.GetGeoTransform(adfGeoTransform);
double dTemp = adfGeoTransform[1] * adfGeoTransform[5] - adfGeoTransform[2] * adfGeoTransform[4];
double dCol = (adfGeoTransform[5] * (longitude - adfGeoTransform[0]) - adfGeoTransform[2] * (latitude - adfGeoTransform[3])) / dTemp + 0.5;
double dRow = (adfGeoTransform[1] * (latitude - adfGeoTransform[3]) - adfGeoTransform[4] * (longitude - adfGeoTransform[0])) / dTemp + 0.5;
int dc = Convert.ToInt32(dCol);
int dr = Convert.ToInt32(dRow);
Band band = ds.GetRasterBand(1);
float[] data = new float[1 * 1];
CPLErr err = band.ReadRaster(dc, dr, 1, 1, data, 1, 1, 0, 0);
band.Dispose();
return (double)data[0];
}
}
5.运行后,进入后生成的exe文件夹,将文件夹中的除了exe之外的其他文件全部复制,粘贴到Unity的Plugins文件夹中。
gdal文件夹里有x64和x86两个平台的库。进到Unity里后,你需要删除不用的那个
7.Unity中新建一个测试脚本,挂到场景里物体上运行:
using OSGeo.GDAL;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GDALTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Gdal.AllRegister();
string demFilePath = "D:/gisdata/450mDEM.tif"; // 替换为实际的 DEM 文件路径
double longitude = 120.0; // 替换为实际的经度
double latitude = 30.0; // 替换为实际的纬度
double height = CalculateHeight(demFilePath, longitude, latitude);
}
static double CalculateHeight(string filePath, double longitude, double latitude)
{
Dataset ds = Gdal.Open(filePath, Access.GA_ReadOnly);
if (ds == null)
{
Console.WriteLine("无法打开文件");
return -1;
}
double[] adfGeoTransform = new double[6];
ds.GetGeoTransform(adfGeoTransform);
double dTemp = adfGeoTransform[1] * adfGeoTransform[5] - adfGeoTransform[2] * adfGeoTransform[4];
double dCol = (adfGeoTransform[5] * (longitude - adfGeoTransform[0]) - adfGeoTransform[2] * (latitude - adfGeoTransform[3])) / dTemp + 0.5;
double dRow = (adfGeoTransform[1] * (latitude - adfGeoTransform[3]) - adfGeoTransform[4] * (longitude - adfGeoTransform[0])) / dTemp + 0.5;
int dc = Convert.ToInt32(dCol);
int dr = Convert.ToInt32(dRow);
Band band = ds.GetRasterBand(1);
float[] data = new float[1 * 1];
CPLErr err = band.ReadRaster(dc, dr, 1, 1, data, 1, 1, 0, 0);
band.Dispose();
return (double)data[0];
}
}
8.调用成功
9.总结
总的来说一共就3步:
第一步:在VS工程里下载好库,生成一下。
第二步:生成的文件放到Unity的Plugins文件夹下,并且删除不用的平台库文件。
第三步:成功。
在性能上,GDAL非常高校,经过测试,读取5个G的地形文件,一次性进行5万次高度计算获取,总耗时50ms,完全不会影响效率。