今更ですが、約1年前2021年7月のハッカソンで、私のチームが作成したものの中から、私が作成した部分について書きました。
作ったもの
土石流のシミュレーションを Unity でビジュアル化しました。
土石流のシミュレーションデータ作成
まずは、土石流のシミュレーションデータを作成します。
iRIC Software で、土石流の分布や堆積高さを計算し、csv で保存。
(このやり方は割愛します)
こんなcsvデータができます。
1つ1つ土砂の粒の位置情報で、40402行あります。
これが1つの瞬間の土砂の位置情報
このハッカソンのときは、時系列(何秒ごとか不明)で22個のcsvファイル(Result-1.csv から Result-22.csv )を作成した。
Unity に再現
国土交通省の3D都市データ PLATEAU を使いました。
まず、PLATEAU のデータを FBXに変換して、Unity に持っていきます。
方法はこちらを参考
『PLATEAU』の都市3Dデータ形式CityGMLをFBXに変換してUnityで遊ぶ
このUnity上の3D都市モデルに、iRICで作成した土石流シミュレーションをプロット します。
2022.6.20 追加
まず、砂のオブジェクトをSphere で作り、プレハブ化します。
(プレハブにしなくてもいいかも)
砂のオブジェクトを
iRIC のシミュレーションデータで算出した土砂の位置情報(平面直角座標)をUnityの座標に変換して、Unity 上にプロットしていきます。
以下の画像のように、どこでもいいので、適当にUnity上に基準点をもうけて、Unityの座標とそれに対応する平面直角座標を求めます。
平面直角座標はこちらで計算しました。
https://vldb.gsi.go.jp/sokuchi/surveycalc/surveycalc/bl2xyf.html
地図を目視して、だいたいな位置をもとに計算しましたので、計算結果は大雑把です。
ハッカソンだから許されると思いますが、正式な業務や研究にはこのやり方は多分よろしくないと思います。
ここまで求めたら、プログラミング
コードは以下(C#)
変数の説明:
unityX , unityY , unityZ : 土砂をプロットするUnity の座標
unityX_origin = 6715.52 : Unityの原点X座標
unityZ_origin = 1709.992 : Unityの原点Z座標
unityX_length = 19.84 :unityの範囲のX軸の幅 (iRICの座標と対比し縮尺を求めるため)
unityZ_length = 19.862 :unityの範囲のZ軸の幅
gridX , gridY : iRIC Software で算出された座標
depth , hight : iRIC Software で算出された深度、高さ
これから先は先ほど紹介した平面直角座標のサイトで計算しました。
gridX_origin = -195173.3455 : unity の原点Zに対応するiRIC の座標
gridY_origin = 35302.4731 : unity の原点Yに対応するiRIC の座標
gridY_length = 1833.526 :Unity の範囲の幅に対する iRIC のY軸の幅
gridX_length = 2225.453 : Unity の範囲の幅に対する iRIC のX軸の幅
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
public class sandDisplay : MonoBehaviour
{
public GameObject sandObject;
private GameObject obj;
void Start()
{
StartCoroutine("Main");
}
IEnumerator Main()
{
float unityX;
float unityX_length = 19.84f;
float unityX_origin = 6715.52f;
float gridX;
float gridX_length = 2225.453f;
float gridX_origin = -195173.3455f;
float unityZ;
float unityZ_length = 19.862f;
float unityZ_origin = 1709.992f;
float gridY;
float gridY_length = 1833.526f;
float gridY_origin = 35302.4731f;
float depth;
float hight;
float unityY;
for (int j = 1; j < 22; j++)
{
yield return new WaitForSeconds(0.5f);
string file_name;
TextAsset csvFile; // CSVファイル
List<string[]> csvDatas = new List<string[]>(); // CSVの中身を入れるリスト;
file_name = "Result_" + j; //csvのファイル名
// Resoucesフォルダに保存したiRICのCSVを読み込む
csvFile = Resources.Load(file_name) as TextAsset;
StringReader reader = new StringReader(csvFile.text);
// , で分割しつつ一行ずつ読み込み、リストに追加していく
int n = 0;
while (reader.Peek() != -1) // reader.Peaekが-1になるまで
{
string line = reader.ReadLine(); // 一行ずつ読み込み
csvDatas.Add(line.Split(',')); // , 区切りでリストに追加
n = n + 1;
}
for (int i = 1; i < n; i++)
{
gridX = float.Parse(csvDatas[i][3]); // iRICのY座標(csvファイル D列)
gridY = float.Parse(csvDatas[i][2]); // iRICのX座標(csvファイル C列)
depth = float.Parse(csvDatas[i][4]); // iRICのDepth(csvファイル E列)
hight = float.Parse(csvDatas[i][5]); // iRICのElevation(csvファイル F列)
// ここでUnity の座標(unityX , unityY, unityZ)に変換している。
// Unity のXZ軸 は iRIC では YX軸
unityX = unityX_origin - (Mathf.Abs(gridY - gridY_origin) * (unityX_length / gridY_length));
unityZ = unityZ_origin - (Mathf.Abs(gridX - gridX_origin) * (unityZ_length / gridX_length));
unityY = hight / 100;
if (depth > 0)
{
//土砂をプロット
var _obj = (GameObject)Instantiate(sandObject, new Vector3(unityX, unityY +(depth/10) , unityZ), Quaternion.identity);
// 視認しやすく、1つおきに土砂の色を変えている
if (i % 2 == 1) //奇数の場合
{
_obj.GetComponent<Renderer>().material.color = Color.red;
}
else
{
_obj.GetComponent<Renderer>().material.color = Color.blue;
}
}
}
}
}
}
2022.6.20 追加
このスクリプト sandDisplay.cs を空のオブジェクト(ここでは Sandcontroller ) にアタッチする。
Sand Display の Sand Object に 砂のプレハブ (ここでは sand )を指定する。
以上です。
本当にこんなやり方でいいのか、プロの方からコメントいただければ幸いです。