Formation of Double Rainbows
Group 1
The Formation of Rainbows
Two refractions and one reflection
Useful Functions
def Rotate(v, theta):
s = sin(theta)
c = cos(theta)
return vec(v.x * c - v.y * s, v.x * s + v.y * c, 0)
Rotate v counterclockwise theta (rad)
Useful Classes
class Ray:
def __init__(self, where, col, n):
self.ball = sphere(pos = where, color = col, radius = 1, make_trail=True)
self.v = c * -vec(cos(Ori_Ray_Angle), sin(Ori_Ray_Angle), 0)
self.collision_time = 0
self.in_water = False
self.n_water = n
- ball, v
are used to simulations - collision_time is used to record the number of reflection.
- in_water records the status of the ray
- n_water stores the refractive index of its color of
ray
Useful Classes
class Beam:
# From Red to Purple
def __init__(self, where):
self.kind = 0
self.rays = []
self.target = 0
for i in range(6):
self.rays.append(Ray(where + 5 * Droplet_Radius * \
vec(cos(Ori_Ray_Angle), sin(Ori_Ray_Angle), 0), colors[i], N_WATER[i]))
- kind is used determine it is a primary rainbow or the secondary rainbow
- collision_time is used to record the number of reflection.
- in_water records the status of the ray
- n_water stores the refractive index of its color of
ray
Implementation
nv = r.ball.pos - droplet.pos
if r.in_water == False:
# Refract into the droplet
if mag(nv) <= droplet.radius + EPS:
r.in_water = True
t1 = acos(dot(nv, r.v) / (mag(nv) * mag(r.v)))
t1 = pi - t1 if t1 >= pi / 2 else t1
t2 = asin(sin(t1) / r.n_water)
r.v = Rotate(-mag(r.v) * norm(nv), t2) / r.n_water
else:
if mag(nv) >= droplet.radius - EPS:
# Reflect in the droplet
if r.collision_time < 1:
r.collision_time += 1
t1 = acos(dot(nv, r.v) / (mag(nv) * mag(r.v)))
t1 = pi - t1 if t1 >= pi / 2 else t1
t2 = asin(sin(t1) / r.n_water)
r.v = Rotate(-mag(r.v) * norm(nv), t1)
# Refract out of the droplet
else:
r.in_water = False
t1 = acos(dot(norm(nv), norm(r.v)))
t1 = pi - t1 if t1 >= pi / 2 else t1
t2 = asin(sin(t1) * r.n_water)
r.v = Rotate(mag(r.v) * norm(nv), -t2) * r.n_water
Simulation of Rainbows
This is what we expect to see
The Formation of Secondary Rainbows
Two refractions and two reflections
Implementation
nv = r.ball.pos - droplet.pos
if r.in_water == False:
# Refract into the droplet
if mag(nv) <= droplet.radius + EPS:
r.in_water = True
t1 = acos(dot(nv, r.v) / (mag(nv) * mag(r.v)))
t1 = pi - t1 if t1 >= pi / 2 else t1
t2 = asin(sin(t1) / r.n_water)
r.v = rotate(-mag(r.v) * norm(nv), -t2) / r.n_water
else:
if mag(nv) >= droplet.radius - EPS:
# Reflect in the droplet
if r.collision_time < 2:
r.collision_time += 1
t1 = acos(dot(nv, r.v) / (mag(nv) * mag(r.v)))
t1 = pi - t1 if t1 >= pi / 2 else t1
t2 = asin(sin(t1))
t3 = asin(sin(t1) / r.n_water)
r.v = rotate(-mag(r.v) * norm(nv), -t2)
# Refract out of the droplet
else:
r.in_water = False
t1 = acos(dot(nv, r.v) / (mag(nv) * mag(r.v)))
t1 = pi - t1 if t1 >= pi / 2 else t1
t2 = asin(sin(t1) * r.n_water)
r.v = rotate(mag(r.v) * norm(nv), t2) * r.n_water
Simulation of Secondary Rainbows
This is what we expect to see
Light Weakening
Partial Reflect and Refract
Fresnel Equations
Here we neglect the polarization of light and take the average of Rs and Rp.
The formula of reflectance
def weaken(t1, t2):
Rs = (sin(t2 - t1) / sin(t1 + t2))**2
Rp = (tan(t2 - t1) / tan(t1 + t2))**2
return (Rs + Rp) / 2
r.ball.opacity *= weaken(t1, t2) ** 0.3
Normally, the light rays become very dim compared to the incident sun rays.
To visualize the effect better,
we de-emphasized the weakening by a power of 0.3
r.ball.opacity *= (1-weaken(t1, t2)) ** 0.3
Rainbow Weakening
Secondary
Rainbow
Weakening
More Water Droplets and Beams
After we have the class Ray and Beam, we can expand the number of water droplets and beams more easily.
beams = []
droplets = []
for i in range (n_droplets):
dy=i*2.2*Droplet_Radius
droplets.append(sphere(pos=vector(2 * Droplet_Radius, 2 * Droplet_Radius+dy, 0),
radius = Droplet_Radius,opacity=0.3))
for i in range (n_beams):
beams.append(Beam(droplets[0].pos + vec(0, 3750 * (i + 1), 0)))
Before we start
Rotate, Assign to Meow
for b in beams:
suc = 0
r = b.rays[0]
tmp_pos = r.ball.pos
while True:
tmp_pos += r.v * dt
for d in droplets:
nv = tmp_pos - d.pos
if mag(nv) <= d.radius + EPS:
b.target = d
suc = 1
break
if suc == 1:
break
Instead of brute-force in every time slot, this helps us to determine the droplet the ray is going to hit.
Simulation
How we see a rainbow
Rainbows
Red = 0.9243 (rad) = 52.96 (deg)
Purple = 0.8958 (rad) = 51.33 (deg)
0 (deg)
180 (deg)
Secondary Raonbows
Red = 1.20983 (rad) = 69.31 (deg)
Purple = 1.37293 (rad) = 78.66 (deg)
180 (deg)
0 (deg)
Compare
Secondary Rainbows
Red = 1.20983 (rad) = 69.31 (deg)
Purple = 1.37293 (rad) = 78.66 (deg)
Rainbows
Red = 0.9243 (rad) = 52.96 (deg)
Purple = 0.8958 (rad) = 51.33 (deg)
We can find that the formation angle of the secondary rainbow is usually higher than the rainbow.
0 (deg)
0 (deg)
180 (deg)
180 (deg)
Relation between angle of sun and brightness of rainbow
42 degrees
matching scientific results
Rainbows not easy to form when sun is at high angle
(close to noon)
The secondary rainbow is harder to form and dimmer, so we seldom see them
Conclusion
Through our project, we investigated the formation of two kinds of rainbows, showed how human eye visualize rainbows, and examined the diagrams to compare with facts of rainbows we searched online.
Thank You
Formation of Rainbows and Auroras
By Howard Yang
Formation of Rainbows and Auroras
- 105