我們追蹤一條光線,考慮它碰到的物體,考慮光碰到物體表面發生的漫反射和鏡面反射。
在考慮了這些問題以上,我們還有並沒有考慮到的問題--影。
影子說起來也很容易考慮,就是如果在某點與光之間有物體阻礙的話,那麼這點將是沒有光的,否則這點是被點亮的。
我們依舊用L來指向光源,考慮我們想研究的P點狀況:
對於P點來說,由它出髮指向方向光的路上如果碰到阻礙,那麼就說明P點應該為暗,否則P點為亮。
這裡實際上我們依舊有工具來計算一條射線與球的最近相交點了,所以工具可以繼續使用,這裡的
對於點光源來說
指向光源的L我們很容易我們也容易求得,是 , 不過這裡對應的 ,因為別忘了我們的L是用來指向光源的, 就是物體本身所處位置, 就是點光源所在位置。
這裡我們還需要注意一點,那就是我們需要當 t = 0 時,實際上物體會在它本身上留下陰影,所以我們取一個極小的t值,比如 t = 0.001 來處理這種狀況。
至於環境管,它是均勻分布的,就不用考慮它了。
這是提取出來,我們用來算從某點射出射線D在給定 t_min, t_max 的情況下跟球的相交和最近的交點。
ClosestIntersection(O, D, t_min, t_max){ closest_t = inf closest_sphere = NULL for sphere in scene.Spheres { t1, t2 = IntersectRaySphere(O, D, sphere) if t1 in [t_min, t_max] and t1 < closest_t closest_t = t1 closest_sphere = sphere if t2 in [t_min, t_max] and t2 < closest_t closest_t = t2 closest_sphere = sphere }
return closest_sphere, closest_t }
TraceRay依舊不變,依舊是算的這條光線應該看到的顏色。
TraceRay(O, D, t_min, t_max){ closest_sphere , closest_t = ClosestIntersection(O, D, t_min, t_max)
if closest_sphere == NULL return BACKGROUND_COLOR
P = O + closest_t * D #交點P的位置 N = P - closest_sphere.center #計算P處的法向量 N = N / length(N) #normalize 法向量 return closest_sphere.color * ComputeLighting(P, N, -D, sphere.specular) }
在這裡我們增加了檢查陰影的部分,如果我們中間碰到了阻礙,那麼我們就不用計算光了,它就是暗色 i = 0,否則我們才計算響應的顏色,這裡還採用了 0.001 來避免物體在其自身的表面形成陰影。
ComputeLighting(P, N, V, s) { i = 0.0 for light in scene.Lights { if light.type == ambient { i += light.intensity } else { if light.type == point { L = light.position - P t_max = 1 } else { L = light.direction t_max = inf }
# shadow check shadow_sphere, shadow_t = ClosestIntersection(P, L, 0.001, t_max) if shadow_sphere != NULL continue
# diffuse n_dot_l = dot(N, L) if n_dot_l > 0 i += light.intensity*n_dot_l/(length(N)*length(L))
# specular if s!= -1 { R = 2*N*dot(N,L) -L r_dot_v = dot(R, V) if r_dot_v > 0 i += light.intensity*pow(r_dot_v/length(R)*length(V)),s) } } } return i }
看結果: