鏡面夾角反射之模擬
建國中學一年二十三班
江昱勳、賴嵩霖、翁證騏
研究動機
於2010年上映的美國科幻動作驚悚片《全面啟動》,探討著夢境與現實的關聯,藉由分享夢境空間探索人的想法-進入夢境且分享夢。在進入他人的潛意識後進而竊取他人的思想、機密,甚至是從外部植入想法。
而在夢境中,任何的想像都不無可能,在電影中也有出現造夢者試著讓夢的場景違反物理定律的橋段。令我最印象深刻的是利用鏡子造出無限長廊的那一幕,兩面互相平行的鏡子,光線遵從反射定律而產生無限多個像,在鏡子被破壞後,原本有限的空間瞬間延展成為無限,十分震撼。
對於平行的鏡面,我產生了疑問,如果並非互相平行呢?如果鏡面成夾角,像的數量是否仍為無限多個?角度的大小和光源的位置會不會影響像的數量?成像的位置是否能預測?一個看似簡單的國中課程是否還能衍生出更深層的討論與結果?
研究目的
- 應用反射定律,探討鏡面夾角大小與成像數量和成像位置的關係。
- 應用反射定律,探討物體位置與成像數量和成像位置的關係。
研究方法
運用Python程式語言搭配方便使用的Vpython套件,在輕易繪製出3D物件的同時,也搭配上物理定律的使用,讓Vpython也可以拿來模擬物理實驗。此外,因為使用程式模擬,我們不再需要大量的手動運算以得知物體在各個時刻的狀態,對於沒有完善公式的鏡面反射實驗有了很大的益處,因為我們可以在不借助實驗的情況下瞭解在各種角度各個位置的成像(因為有時角度太小實驗起來看不太到)
模擬與實驗
30度


60度


90度

120度

如何模擬
自訂函數
def getColor(a, b, c):
return (a/255, b/255, c/255)
def deg2rad(a):
return acos(-1)*a/180scene = display(x=0, y=0, width=800, height=800, background=(0,0,0), center=(0,0,0))
BOARD_theta = 60
BOARD_Theta = deg2rad(BOARD_theta)
BOARD_Length = 5
#board config
BOXES = [box(pos=(BOARD_Length*cos(BOARD_Theta/2), BOARD_Length*sin(BOARD_Theta/2),0),
length=BOARD_Length*2, height=0.1, width=2, axis=(1, 1*tan(BOARD_Theta/2), 0)),
box(pos=(BOARD_Length*cos(BOARD_Theta/2),-1*BOARD_Length*sin(BOARD_Theta/2),0),
length=BOARD_Length*2, height=0.1, width=2, axis=(1, -1*tan(BOARD_Theta/2), 0))]
#make two boards with BOARD_theta and position at (0,0,0)
ddg = text(text="%f degree"%BOARD_theta, pos=(-10,10,0), color=getColor(255.,0.,255.),
height=0.5, depth=0.01)
#show current degree基礎設置
Lights_N = 24
Lights_pos = vector(4,0,0)
#Lights config
Lights = [sphere(pos=Lights_pos, radius=0.01, color=getColor(255.,255.,0.),
theta=deg2rad(360/Lights_N*(_+0.5)), make_trail=True) for _ in range(Lights_N)]
#show Lights_N lights using sphere with trail
Reflects = []
#the reflection of lights will be insert into Reflects
BALL = sphere(pos=Lights_pos, radius=0.1, color=getColor(255.,255.,0.))
#show the thing that will be reflected光源設置
for Light in Reflects:
Light.pos -= vector(cos(Light.theta), sin(Light.theta), 0)*dt
for Light in Lights:
Light.pos -= vector(cos(Light.theta), sin(Light.theta), 0)*dt
for BOX in BOXES:
a = BOX.axis.y/BOX.axis.x
b = -1
c = BOX.pos.y-(BOX.axis.y/BOX.axis.x)*BOX.pos.x
dis = abs(a*Light.x+b*Light.y+c) / sqrt(a*a+b*b)
if dis <= Light.radius*2.5:
BOX_theta = atan2(BOX.axis.y, BOX.axis.x)
Light.theta = 2*(BOX_theta + acos(-1)) - Light.theta
Reflects.append(sphere(pos=Light.pos, radius=0.01, color=getColor(255.,255.,255.),
theta=Light.theta+acos(-1), make_trail=True))
Reflects[-1].pos.x-=cos(Light.theta)*dt*2
Reflects[-1].pos.y-=sin(Light.theta)*dt*2反射核心
def changeLight(evt):
global Lights_pos, pause, Reflects, Lights, BALL, paused
if evt.key=='left':
Lights_pos.x-=0.1
elif evt.key=='right':
Lights_pos.x+=0.1
elif evt.key=='up':
Lights_pos.y+=0.1
elif evt.key=='down':
Lights_pos.y-=0.1
elif evt.key=='p':
paused=not paused
return;
else:
return
if not pause:
for _ in Reflects:
_.trail_object.visible=False
_.visible=False
Reflects=[]
for _ in Lights:
_.trail_object.visible=False
_.visible=False
pause=True
BALL.visible=False
BALL = sphere(pos=Lights_pos, radius=0.1, color=getColor(255.,255.,0))
#handle keydown event and change the thing's position鍵盤操作光源
def renderLight(evt):
global Lights, Lights_N, Reflects, pause, paused
if pause:
pause=False
Lights = [sphere(pos=Lights_pos, radius=0.01, color=getColor(255.,255.,0.),
theta=deg2rad(360/Lights_N*(_+0.5)), make_trail=True) for _ in range(Lights_N)]
#reperform the experiment
scene.bind('keydown', changeLight)
scene.bind('keyup', renderLight)鍵盤操作光源
def DOWN(evt):
global down, pre, pause
down=True
pre=evt.pos.y
pause = True
#handle the mousedown event滑鼠控制夾角
def CHANGE(evt):
global pre, BOARD_theta, BOARD_Theta, BOXES, ddg
if down:
BOARD_theta+= (evt.pos.y-pre)*10
if BOARD_theta < 0:
BOARD_theta=0
elif BOARD_theta > 180:
BOARD_theta=180
ddg.visible=False
for _ in BOXES:
_.visible=False
BOARD_Theta = deg2rad(BOARD_theta)
BOXES=[box(pos=(BOARD_Length*cos(BOARD_Theta/2),BOARD_Length*sin(BOARD_Theta/2),0),
length=BOARD_Length*2, height=0.1, width=2, axis=(1, 1*tan(BOARD_Theta/2), 0)),
box(pos=(BOARD_Length*cos(BOARD_Theta/2),-1*BOARD_Length*sin(BOARD_Theta/2),0),
length=BOARD_Length*2, height=0.1, width=2, axis=(1, -1*tan(BOARD_Theta/2), 0))]
ddg = text(text="%f degree"%BOARD_theta, pos=(-10,10,0),
color=getColor(255.,0.,255.), height=0.5)
pre=evt.pos.y
#change the board's theta while mousemove滑鼠控制夾角
def UP():
global down, pre, pause, Lights, Lights_N, Reflects, Lights_pos
down=False
pause=False
for _ in Reflects:
_.trail_object.visible=False
_.visible=False
Reflects=[]
for _ in Lights:
_.trail_object.visible=False
_.visible=False
Lights = [sphere(pos=Lights_pos, radius=0.01, color=getColor(255.,255.,0.),
theta=deg2rad(360/Lights_N*(_+0.5)), make_trail=True) for _ in range(Lights_N)]
#reperform the reflect experiment
scene.bind('mousedown', DOWN)
scene.bind('mousemove', CHANGE)
scene.bind('mouseup', UP)滑鼠控制夾角
完整程式碼
結論
透過模擬,我們並不需要實體上的實驗,僅需使用Python就可以看到與真實相符的結果,對於一些不方便實驗的現象如這次的實驗就有很大的幫助,而且也不需要過於複雜的計算,對於沒有太多物理知識背景的人來說真的很輕鬆。
VpythonReflection
By Tommy Chiang
VpythonReflection
Simulating Reflection with Vpython
- 423