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_waterSimulation 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_waterSimulation 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) / 2r.ball.opacity *= weaken(t1, t2) ** 0.3Normally, 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.3Rainbow 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:
breakInstead 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
- 155