2023-05-09(書いているのは2023-11-20)
注!)今回も揺れと太陽の視野角は考慮していません。
Unityで大気光学現象のシミュレーションはできるのか気になったので挑戦してみる5
今回は、前回の幻日と同じプレート配向の環天頂アーク、環水平アーク、幻日環を描画します。
①環天頂アークと幻日の違うところは
②入射角はランダムではなく90-h(下図参照)
③90°プリズムの現象
④回転の方向
環天頂アークの光路
①から③は前回変数にしておいたので簡単に変更できます。
④は縦方向に回転しますが、幻日とは違って偏角Dをそのまま回転の角度に代入することができません。回転する角度を求めていきましょう。
環天頂アークの高度
・・・①
iの左隣のh°と書かれている角と∠ABCは同位角で、①より平行線の同位角は等しいので
三角形の内角の和は180°なので
・・・②
∠ACBの左隣の角は
・・・③
よって回転の角度はh+Dと分かりました。
ではコードを書きましょう。
parhelion(幻日)メソッドをコピペして、名前をparhelionからCZAに変更します。
Updateメソッドでcount <number_of_raysのみ呼び出すようにしていますが、これだけでは不十分です。parhelionメソッドでcountが増やされるので、それでcount == number_of_raysになる可能性があるためです。なのでメソッド内の全文をif文で囲ってcount <number_of_raysの時のみ実行するようにします。また、太陽高度が0°だと屈折が起きないようなので、同じif文にh != 0という条件を付けたします。
変数の値を変更して、
i=90-h
a=90 にします。
氷晶のY軸(垂直な軸)の回転を表す変数IceAngle_Yを追加して、0.0以上60.0未満の値をとるようにします。六角柱は60°回転させると元に戻ります。
計算式は幻日と変わりません。そのまま使います。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class manager : MonoBehaviour
{
public float h = 0;//太陽高度
public float n = 1.309f;//屈折率
public int number_of_Lays = 100;
int count = 0;
public GameObject LayPrefab;
public GameObject SunPrefab;
void Start()
{
GameObject Sun = Instantiate(SunPrefab); Sun.transform.position = new Vector3(0, 0, 0);
Sun.transform.Rotate(-h, 0, 0);
}
void Update()
{
if (count < number_of_Lays)
{
parhelion(); CZA(); } }
void parhelion()
{
float i = UnityEngine.Random.Range(0.0f, 90.0f);//入射角
float a = 60;//プリズム角
double fh_n = Math.Sqrt(((n * n) - (Math.Sin(h * (Math.PI / 180)) * Math.Sin(h * (Math.PI / 180)))) / (1 - Math.Sin(h * (Math.PI / 180)) * Math.Sin(h * (Math.PI / 180))));//光が斜めに入った時の屈折率
double critical_angle = Math.Asin(1 / fh_n) * 180 / Math.PI;//臨界角
double r = Math.Asin(Math.Sin(i * (Math.PI / 180)) / fh_n) * (180 / Math.PI);
double r2 = a - r;
if (r2 <= critical_angle)
{
double i2 = Math.Asin(fh_n * (Math.Sin(r2 * (Math.PI / 180)))) * 180 / Math.PI;
double D = i + i2 - a;
float floatD = (float)D;
GameObject Lay_right = Instantiate(LayPrefab);
Lay_right.transform.position = new Vector3(0, 0, 0);
Lay_right.transform.Rotate(-h, floatD, 0);
GameObject Lay_left = Instantiate(LayPrefab);
Lay_left.transform.position = new Vector3(0, 0, 0);
Lay_left.transform.Rotate(-h, -floatD, 0);
count += 2;
}
}
void CZA() { if (count < number_of_Lays && h != 0) { float i = 90 - h;//CZAはi = 90 - h float a = 90;//プリズム角 float IceAngle_Y = UnityEngine.Random.Range(0.0f, 60.0f); double critical_angle = Math.Asin(1 / n) * 180 / Math.PI; double r = Math.Asin(Math.Sin(i * (Math.PI / 180)) / n) * (180 / Math.PI); double r2 = a - r; if (r2 <= critical_angle) { double i2 = Math.Asin(n * (Math.Sin(r2 * (Math.PI / 180)))) * 180 / Math.PI; double D = i + i2 - a; float floatD = (float)D; GameObject Lay_right = Instantiate(LayPrefab); Lay_right.transform.position = new Vector3(0, 0, 0); Lay_right.transform.Rotate(-h - floatD, IceAngle_Y, 0); GameObject Lay_left = Instantiate(LayPrefab); Lay_left.transform.position = new Vector3(0, 0, 0); Lay_left.transform.Rotate(-h - floatD, -IceAngle_Y, 0); count += 2; } } } }
プレハブの角度は、式③で求めたh+floatDとIceAngle_Yだけ回転させます。
式③の符号が逆なのは、前回と同じ理由で回転の角度が逆だったからです。
太陽高度22°でUnityで実行すると、いい感じです。
また、実際と同じように太陽高度が32°あたりで消えてくれました。
次に環水平アークを書きます。
図を書くと入射角は太陽高度で、屈折角の高度はh-D(偏角)と分かりました。
また太陽高度が90°の時に屈折は起きません。
環天頂アークとの違いはこれだけです。
void CHA() { if (count < number_of_Lays && h != 90) { float i = h;//CZAはi = h float a = 90;//プリズム角 float IceAngle_Y = UnityEngine.Random.Range(0.0f, 60.0f); double critical_angle = Math.Asin(1 / n) * 180 / Math.PI; double fh_n = Math.Sqrt(((n * n) - (Math.Sin(h * (Math.PI / 180)) * Math.Sin(h * (Math.PI / 180)))) / (1 - Math.Sin(h * (Math.PI / 180)) * Math.Sin(h * (Math.PI / 180))));//光が斜めに入った時の屈折角() double r = Math.Asin(Math.Sin(i * (Math.PI / 180)) / n) * (180 / Math.PI); double r2 = a - r; if (r2 <= critical_angle) { double i2 = Math.Asin(n * (Math.Sin(r2 * (Math.PI / 180)))) * 180 / Math.PI; double D = i + i2 - a; float floatD = (float)D; GameObject Lay_right = Instantiate(LayPrefab); Lay_right.transform.position = new Vector3(0, 0, 0); Lay_right.transform.Rotate(-h + floatD, IceAngle_Y, 0); GameObject Lay_left = Instantiate(LayPrefab); Lay_left.transform.position = new Vector3(0, 0, 0); Lay_left.transform.Rotate(-h + floatD, -IceAngle_Y, 0); count += 2; } } }
Updateメソッドのif内にCHA();を追加します。
太陽高度58°で実行してみるとこのようになりました。
最後に幻日環を描画します。
幻日環は反射させるだけなので(強度も考えると屈折を計算する必要がありますが)
垂直の軸は0~180°のランダムの値、水平の軸は太陽高度回転させると出来上がり。2分ほどで終わりました。
void Parhelic_circle() { if (count < number_of_Lays) { float IceAngle_Y = UnityEngine.Random.Range(0.0f, 180.0f); GameObject Lay_right = Instantiate(LayPrefab); Lay_right.transform.position = new Vector3(0, 0, 0); Lay_right.transform.Rotate(-h, IceAngle_Y, 0); GameObject Lay_left = Instantiate(LayPrefab); Lay_left.transform.position = new Vector3(0, 0, 0); Lay_left.transform.Rotate(-h, -IceAngle_Y, 0); count += 2; } } }
Updateメソッドのif内にParhelic_circle();を追加します。
実行してみます。太陽高度22°
太陽高度58°
これからはカラム配向も再現していこうと思います。