Unity Geospatial Data

Welcome to the Unity portion of the geospatial data visualization tutorial! Make sure that you have completed the Data Gathering, Cleaning and Conversion portion first.


Open up Unity, and create a new project. 

Click GameObject->Create Empty. Name it "Manager". On the right side, under Components select Add Components and select New Script. Name it ReadCSV. Paste the following code there:

using System.Collections;

using System.Collections.Generic;

using UnityEngine;


public class ReadCSV : MonoBehaviour

{


  public Transform prefab;


 void Awake() {

 

        List<Dictionary<string,object>> data = CSVReader.Read("csv_data");


   // fall,geolocation,id,mass,name,nametype,recclass,reclat,reclong,year,X,Y,Z

        for(var i=0; i < data.Count; i++) {            

            Instantiate(prefab, new Vector3((float)data[i]["X"],(float)data[i]["Y"],(float)data[i]["Z"]), Quaternion.identity);

        }

 

    }

 // public TextAsset t;

    // Start is called before the first frame update

    void Start()

    {

        // var result = new JavaScriptSerializer().Deserialize<List<Meteoroid>>(t.text);

        // Debug.Log(result);

    }


    // Update is called once per frame

    void Update()

    {

        

    }

}


We'll need a few things before we can visualize the data. First, a rudimentary csv parser, since Unity doesn't have one builtin. Luckily there are quite a few open source ones online. Create a new script and name it CSVReader.cs.

using UnityEngine;

using System;

using System.Collections;

using System.Collections.Generic;

using System.Text.RegularExpressions;

 

public class CSVReader

{

    static string SPLIT_RE = @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))";

    static string LINE_SPLIT_RE = @"\r\n|\n\r|\n|\r";

    static char[] TRIM_CHARS = { '\"' };

 

    public static List<Dictionary<string, object>> Read(string file)

    {

        var list = new List<Dictionary<string, object>>();

        TextAsset data = Resources.Load (file) as TextAsset;

    Debug.Log(file);

        var lines = Regex.Split (data.text, LINE_SPLIT_RE);

 

        if(lines.Length <= 1) return list;

 

        var header = Regex.Split(lines[0], SPLIT_RE);

        for(var i=1; i < lines.Length; i++) {

 

            var values = Regex.Split(lines[i], SPLIT_RE);

            if(values.Length == 0 ||values[0] == "") continue;

 

            var entry = new Dictionary<string, object>();

            for(var j=0; j < header.Length && j < values.Length; j++ ) {

                string value = values[j];

                value = value.TrimStart(TRIM_CHARS).TrimEnd(TRIM_CHARS).Replace("\\", "");

                object finalvalue = value;

                int n;

                float f;

                if(int.TryParse(value, out n)) {

                    finalvalue = n;

                } else if (float.TryParse(value, out f)) {

                    finalvalue = f;

                }

                entry[header[j]] = finalvalue;

            }

            list.Add (entry);

        }

        return list;

    }

}

The next step is creating the sphere that we'll be using to represent meteorites. Click GameObject->3D Object->Sphere. Drag it down to the Assets section to create a prefab out of it. 

We want to tell our Manager that this is the prefab it should use when instantiating the points. To do this, select the Manager in the hierarchy and drag the newly created prefab to the "Prefab" field in the script (ReadCSV) component.

Finally, we want to add the csv_file so that Unity can find it. To do this, create a folder named Resources, and import the csv_file.csv in it. 

We are ready! Click the Play button, and wait for Unity to create all the points (can take ~20 seconds on slower machines). 


Bonus:

To make the experience more interesting, we can make the camera rotate around the globe. To do this, attach a new script to MainCamera. Name it Rotate Camera. Paste the following code, which takes a center point and make the camera go around it.

using System.Collections;

using System.Collections.Generic;

using UnityEngine;


public class RotateCameraScript : MonoBehaviour

{

  public Transform target;

 public float speed = 3;

    // Start is called before the first frame update

    void Start()

    {

        

    }

     

    void Update(){

        transform.LookAt(target);

        transform.Translate(Vector3.right * Time.deltaTime * speed);

    }


}

Now drag the manager to the target field of the script, and set the speed to something low (I use 3). Enjoy the show!