PLATEAU+Unityで日照をシミュレートしてみた

当社の学生スタッフに研究開発として依頼した事例として、PLATEAUの3D都市モデルの活用方法をご紹介します。

PLATEAUとは

「国土交通省が主導する、日本全国の3D都市モデルの整備・活用・オープンデータ化プロジェクト」です。
建物等の地物が3次元モデルとして表現されていることに加え、名称や用途、建設年といった都市活動情報が付与されていることが特徴です。

やったこと、結果

PLATEAUの3D建物モデルをUnityに読み込ませて、建物の日照時間をシミュレート・可視化してみました。
東京23区のデータについては、Unityで読み込むことができるFBX形式でも公開されているため今回はそれを使います。

以下の動画では、指定した年月日の太陽の位置と建物への直射日光を10分間隔で計算し、1日の日照時間に応じて建物を色分けしています。(日照時間が長いほど赤に近くなる)
ちなみに動画中には示されていませんが、西暦2021年の日本標準時0時~24時という条件です。

日照シミュレーション実装の概要

このシミュレーションでは日照を以下のように定義し、問題を単純化しています。

  • 各建物に向かう直射日光は、いずれも太陽から都市の中心座標へ向けた高度・方位から来るものとする。
    (太陽が無限遠点にあり、太陽光は地表へ平行に当たる)
  • 建物の中心座標と太陽の間に遮るもの(他の建物または地表面)がない場合、日照があると判定する。
    日射量の程度は考慮しない。

直射日光の判定は、建物の中心座標から日光の方向に向けてレイ(Physics.Raycast)を飛ばして行っています。
建物群と地表(DEMデータ)に当たり判定となるColliderコンポーネントをつけるのを忘れないようにしましょう。

また、太陽位置は視赤緯と時角を計算で求めています。パラメータは西暦年、月、日、緯度、経度です。
C#のソースコードを以下に示します。

C#
    // 年、1月1日を1とした日数、時刻(日本標準時)、緯度、経度 から 太陽高度角 h 、方位角 a を求める
    public void Calc(int year, int day, float hour, float lat, float lon, out float h, out float a)
    {
        float latRad = lat * Mathf.Deg2Rad;

        // 赤緯と均時差の計算
        int n = year - 1968;
        float d0 = 3.71f + 0.2596f * n - (int)((n + 3) / 4);
        float M_deg = 0.9856f * (day - d0);
        float M = M_deg * Mathf.Deg2Rad;
        float eps_deg = 12.3901f + 0.0172f * (n + M_deg / 360f);
        float eps = eps_deg * Mathf.Deg2Rad;
        float v_deg = M_deg + 1.914f * Sin(M) + 0.02f * Sin(2f * M);
        float v = v_deg * Mathf.Deg2Rad;
        float Et1 = M - v;
        float Et2 = Mathf.Atan2((0.043f * Sin(2 * (v + eps))), (1f - 0.043f * Cos(2 * (v + eps))));

        // 均時差
        float Et = Et1 - Et2;

        const float delta0 = -23.4393f * Mathf.Deg2Rad;

        // 太陽の視赤緯
        float delta = Mathf.Asin(Cos(v + eps) * Sin(delta0));

        // 時角
        float t = (15 * (hour - 12) + (lon - 135)) * Mathf.Deg2Rad + Et;

        // 太陽高度角
        h = Mathf.Asin(Sin(latRad) * Sin(delta) + Cos(latRad) * Cos(delta) * Cos(t));

        float sinA = (Cos(delta) * Sin(t)) / Cos(h);
        float cosA = (Sin(h) * Sin(latRad) - Sin(delta)) / (Cos(h) * Cos(latRad));

        // 太陽方位角 南が0度になるようにPIを足す
        a = Mathf.Atan2(sinA, cosA) + Mathf.PI;
    }

    private float Cos(float theta) {
        return Mathf.Cos(theta);
    }

    private float Sin(float theta) {
        return Mathf.Sin(theta);
    }

上記のソースコードはご自由に利用して頂いて構いませんが、利用したことによる一切の責任を負いかねます。

ついでに光源(Directional Light)をGameObjectにくっつけて太陽に見立てれば完成です!

まとめ

この研究開発事例の主眼は3D地図の活用で、PLATEAUのデータを単なる3Dモデルとして利用しています。
しかしPLATEAUの本領は、都市活動情報やLODを利用できるCityGMLデータにあります。
さらにUnityと組み合わせることで高い表現力・インタラクティブ性を実現できることは間違いないので、これからも研究を続けていきます。


学生スタッフについては以下の記事もご覧ください。絶賛募集中です!

学生スタッフについて

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA