空の記録-Gallery of Atmospheric Optics

三重県で空を撮っています ときどきビーチコーミングの記事も書きます   当ブログはリンクフリーです

大気光学現象のシミュレーション作成#3-3 環天頂アーク、環水平アーク、幻日環のシミュレーション

2023-05-09(書いているのは2023-11-20)

 

注!)今回も揺れと太陽の視野角は考慮していません。

Unityで大気光学現象のシミュレーションはできるのか気になったので挑戦してみる5

 

今回は、前回の幻日と同じプレート配向の環天頂アーク、環水平アーク、幻日環を描画します。

①環天頂アークと幻日の違うところは

②入射角はランダムではなく90-h(下図参照)

③90°プリズムの現象

④回転の方向

環天頂アークの光路

 

①から③は前回変数にしておいたので簡単に変更できます。

④は縦方向に回転しますが、幻日とは違って偏角Dをそのまま回転の角度に代入することができません。回転する角度を求めていきましょう。



環天頂アークの高度

 

直線L//直線BC・・・①

iの左隣のh°と書かれている角と∠ABCは同位角で、①より平行線の同位角は等しいので

∠ABC=h°

 

三角形の内角の和は180°なので

∠ACB=180°-h°-D°・・・②

 

∠ACBの左隣の角は

180°-∠ACB

=180°-(180°-h°-D°)

=h+D・・・③

 

よって回転の角度は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°

 

これからはカラム配向も再現していこうと思います。