在Unity3D中從ASC文本生成地形

在Unity3D中從ASC文本生成地形

簡單說說ASC文件

ASC文件是GIS行業的領導者ESRI為格網數據自己定義的文本文件格式(ASCII),被其他軟件廣泛的支持。ASC文件非常簡單,并且用任何的文本編輯器都能夠編輯。一個ASC文件以簡短的文件頭開始,描述了位置信息以及格網的大小。文件頭后面就是一行一行的高程數據了。看下面這個例子:

NCOLS xxx
NROWS xxx
XLLCENTER xxx | XLLCORNER xxx
YLLCENTER xxx | YLLCORNER xxx
CELLSIZE xxx
NODATA_VALUE xxx
row 1
row 2
...
row n

文件頭包括六行,前兩行("ncols" and "nrows")指定了格網的大小。第三行和第四行指定了格網左下角位置的橫向("xllcorner") 和縱向("yllcorner") 坐標。 "cellsize"是兩個相鄰行列之間的距離。最后一行 ("NODATA_value")是可選的,指定一個認為是認為是“無數值”的值。接著下面就是一行一行的數據了, row 1,row 2.....

從ASC文本生成地形

對于ASC文本的處理可以通過ArcGIS或者GDAL等軟件的處理,生成高度圖(height),然后把高度圖導入到Unity3D里面生成地形。但是仔細想想,其實沒有必要經過這么一層轉換,自己把文本里面的數據讀進數組,賦給Unity3D里面的TerrainData對象就可以了,這樣就省去轉換的步驟了。

思想很簡單,下面看下代碼:

Terrain terrain = null;
TerrainData trnData = null;
private int xDataRes = 731;//我的數據就是這么大
private int yDataRes = 437;
private int xRes = 1024;//按照1024來做吧
private int yRes = 1024;
private const int nodata_trn = 9999;
private float[,] trn_heights = null;
 
void Start () {
    terrain = Terrain.activeTerrain;
    trnData = terrain.terrainData;
    Vector3 size = new Vector3(xRes, 100, yRes);
    trnData.size = size;
    trnData.heightmapResolution = 1025;//官方說必須這么做
    trn_heights = new float[xRes, yRes];
 
    //dem1.txt文件必須在Resources文件夾下面
    TextAsset demdata = (TextAsset)Resources.Load("dem1", typeof(TextAsset));
    StringReader reader = new StringReader(demdata.text);
    if ( reader == null ){
        Debug.Log("dem1.txt not found or not readable");
    }else{
        string line;
        int index = 0;
        //terrain data
        while((line = reader.ReadLine()) != null){
            string[] values = line.Trim().Split(new char[]{' '});
            if(values.Length != xDataRes){
                continue;
            }else{
                for(int i = 0; i < xDataRes; i++){
                    float v = float.Parse(values[i]);
                    if(Mathf.Approximately(v, nodata_trn)){
                        v = 0.0f;
                    }
                    trn_heights[index, i] = v/trnData.size.y;//這里很重要!
                }
                index++;
            }
        }
        trnData.SetHeights(0, 0, trn_heights);//設置高程數據
    }
    reader.Close();
}

這里只能給出工程中的部分代碼,僅供參考。

這里有一個坑

在設置高度的地方著實讓人迷惑了很久,主要是設置高度、獲取高度這幾個接口實在是讓人摸不清頭腦。最后查了好多文檔,還好有人提到過這個問題,在此再記錄一下:

It's quite simple. I've done a small test like you did. This are the results:
 
    * GetHeight returns the height value in the range [0.0f, Terrain Height]
    * GetHeights returns the height values in the range of [0.0f,1.0f]
    * SetHeights expect the height values in the range of [0.0f,1.0f].
 
So when using GetHeight you have to manually divide the value by theTerrain.activeTerrain.terrainData.size.y which is the configured height ("Terrain Height") of the terrain.   
The behaviour of GetHeight seems a bit strange and does not return what you would expect. This might be a bug / might be a feature, however without a proper documentation it's more likely a bug.  

也就是說,GetHeight返回的是0-地形總高度之間的高度值,GetHeights返回的是0.0-1.0之間的浮點數,SetHeights設置的也是0.0-1.0之間的浮點數,知道前面為什么要除以地形總高度了吧!
更奇怪的是,有GetHeight接口卻沒有SetHeight接口......

效果截圖

最后加上洪水,來個效果圖:

terrain-in-unity3d
terrain-plus-flood

參考

http://www.reliefshading.com/analytical/dem_file_formats.html
http://resources.esri.com/help/9.3/arcgisengine/java/GP_ToolRef/spatial_analyst_tools/esri_ascii_raster_format.htm
http://answers.unity3d.com/questions/193780/how-do-i-use-terrain-setheights-and-getheights.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容