LoginSignup
3
1

Unityにリアルワールドを簡単に導入する!

Last updated at Posted at 2023-12-24

はじめに

こんにちは.Life is Tech Advent Calendar 2023の24日目を担当しますえふじといいます!

今回はUnityで現実世界の3Dマップを簡単に導入する方法を紹介したいと思います.

Cesium for Unityについて

まずはじめにCesiumとは何かというと,
「Cesium(セシウム)は、オープンソースとして提供される3D地理空間可視化プラットフォームです。」

ここにGoogleの地図データを読み込ませてあげればこのように地球の地図データの全てをUnityに持ってくることができるのです!
スクリーンショット 2023-12-24 15.37.58.png
拡大してみると...
宮下パーク
スクリーンショット 2023-12-24 15.40.30.png
結構綺麗

導入方法

GoogleのMap tiles APIを取得

https://developers.google.com/maps/documentation/embed/get-api-key?hl=ja
ここのURLから認証情報ページに飛ぶ
スクリーンショット 2023-12-24 15.45.03.png
プロジェクトを作成すると,APIKeyが表示されるのでどこかにメモっておく.(1度しか表示されないよ!)
上部の検索欄からMap tiles APIと検索し,Map tiles APIを有効にしておく
スクリーンショット 2023-12-24 15.47.32.png

注意
Google API keyの取得にはクレカ情報が必要になります.デバッグ程度であれば十分無料枠の中で使用できると思いますが,適切に上限等の設定を行なってください

UnityにCesiumを導入

ここからはUnityにCesiumを導入する作業です.ちなみにバージョンが古すぎるとできないです!私の場合は2022.3.0を使用しています.

まずはProjectを3D(URP)or3D(HDRP)で作成します.
Edit > Project Setting > Package ManagerのScoped RegistriesにCesiumのパッケージを設定します.
スクリーンショット 2023-12-24 15.55.41.png

名称:Cesium
URL: https://unity.pkg.cesium.com
スコープ: com.cesium.unity

その後Package ManagerからCesiumをインストールするとメニューバーにCesiumが表示されると思うので,Cesiumを選択してCesiumウィンドウを開いてください!
スクリーンショット 2023-12-24 16.01.31.png

Blank 3D Tiles Tilesetのプラスアイコンをクリックすると,ヒエラルキーにCesium3DTilesetというオブジェクトが生成されるのでInspectorから Tileset SorceをFrom Url に設定する.
URLはhttps://tile.googleapis.com/v1/3dtiles/root.json?key=<自分のAPIKey>を入れておく

するとSceneウィンドウに地球が表示されるはず!されなかったら再起動
これだけの設定で現実世界のマップを導入することができました!

CesiumGeoreferenceの子オブジェクトであるDynamicCameraのCesiumGlobeAnchorをいじると色々できます.

スクリーンショット 2023-12-24 16.08.36.png

例えば,Input fieldに入力した場所の緯度経度を取得してその場所に移動するサンプルコードは以下のようになります.

LocationFetcher
using UnityEngine;
using UnityEngine.Networking;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using TMPro;
using UnityEngine.UI;
using CesiumForUnity;

public class LocationFetcher : MonoBehaviour
{
    [System.Serializable]
    public class Location
    {
        public float lat;
        public float lng;
    }

    [System.Serializable]
    public class Geometry
    {
        public Location location;
    }

    [System.Serializable]
    public class Result
    {
        public Geometry geometry;
    }

    [System.Serializable]
    public class Root
    {
        public Result[] results;
    }

    [SerializeField]
    TMP_InputField inputField;
    [SerializeField]
    Button fetchButton;

    private CesiumGlobeAnchor globeAnchor;
    [SerializeField]
    TMP_InputField inputText;
    TextMeshProUGUI placeholderText;

    private async void Start()
    {
        inputText = GameObject.Find("PromptField").GetComponent<TMP_InputField>();
        placeholderText = inputText.placeholder as TextMeshProUGUI;
        fetchButton.onClick.AddListener(async () => await GetLocation(inputField.text));
    }

    public async Task GetLocation(string address)
    {
        string apiKey = "自分のAPIKey";
        string url = $"https://maps.googleapis.com/maps/api/geocode/json?address={address}&key={apiKey}";

        using (UnityWebRequest request = UnityWebRequest.Get(url))
        {
            await request.SendWebRequest();

            if (request.result == UnityWebRequest.Result.Success)
            {
                string json = request.downloadHandler.text;
                Root root = JsonUtility.FromJson<Root>(json);

                if (root.results.Length > 0)
                {
                    float latitude = root.results[0].geometry.location.lat;
                    float longitude = root.results[0].geometry.location.lng;

                    Debug.Log("Latitude: " + latitude);
                    Debug.Log("Longitude: " + longitude);
                    GameObject dynamicCamera = GameObject.Find("DynamicCamera");
                    globeAnchor = dynamicCamera.GetComponent<CesiumGlobeAnchor>();
                    globeAnchor.SetPositionLongitudeLatitudeHeight(longitude, latitude, 200);
                }
                else
                {
                    Debug.LogError("No results found");
                }
            }
            else
            {
                Debug.LogError("Request failed: " + request.error);
            }
        }

        inputText.text = "";
    }
}

注意
このサンプルコードではコード内にAPIKeyをベタ書きしているのでpublic repoなど他人の目にふれるところには公開しないようにしてください

おわり

アイデア次第で面白いゲームが色々作れそうな気がします.皆さんもぜひ試してください!

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1