スネルの法則を使って屈折方向の計算
スネルの法則で3次元空間上の屈折方向ベクトルを求めるのをPythonで実装.
ベクトルで解く
各要素の関係は以下.ただし各ベクトルの大きさを1とする.
入射ベクトル:
法線ベクトル:
出射ベクトル(これを求める):
入射角:
出射角(これもわかってない):
入射側屈折率:
入射側屈折率:
スネルの法則
つまり,はぐりぐりやればわかる.
ここで,入射ベクトル,法線ベクトル,出射ベクトルは同一平面上にあるから,(ともにスカラ)を使って以下のように表現できる.
まずから求める.
式(1)の両辺について,法線ベクトルとの外積をとって,更にその大きさをとると,各ベクトルの大きさが1であること,最後は式(0)を用いてが決まる.
次にを求める.
式(1)の両辺について,法線ベクトルとの内積をとると,先程と同様に各ベクトルの大きさが1であることを用いてが決まる.が残っているが,式(0)から求めることができる.
Python実装
import numpy as np def snell(v_inter,v_norm,n_inter,n_exit): #3次元スネルの公式の適用結果を返す関数 #入力:入射光線の方向ベクトル,入射点での法線ベクトル,入射元の屈折率,入射先の屈折率 #入力されたベクトルの正規化 v_inter = v_inter / np.linalg.norm(v_inter) v_norm = v_norm / np.linalg.norm(v_norm) #係数a a = n_inter/n_exit cos_t_inter = -1.0*np.dot(v_inter,v_norm) #量子化誤差対策 if cos_t_inter<-1.: cos_t_inter = -1. elif cos_t_inter>1.: cos_t_inter = 1. sin_t_inter = (1.0 - cos_t_inter**2)**(1/2) sin_t_exit = sin_t_inter*a if sin_t_exit>1.0: #全反射する場合 return np.zeros(3), False cos_t_exit = (1 - sin_t_exit**2)**(1/2) #係数b b = -1.0*cos_t_exit + a*cos_t_inter #出射光線の方向ベクトル v_exit = a*v_inter + b*v_norm #正規化 v_exit = v_exit / np.linalg.norm(v_exit) return v_exit, True vi = np.array([0.08584,0.17301,0.9811726]) vn = np.array([0.050, 0.060, -0.9969453]) ni = 1.0 ne = 1.5 snell(vi,vn,ni,ne)#(array([0.0401461 , 0.0948433 , 0.99468238]), True) #方向ベクトルなどの実値参考: #https://www.cybernet.co.jp/optical/course/optics/opt02/opt06.html