有些物體表面是不光滑的,但是它們具有高光。比如拋光的瓷磚地面、光澤塗料和白板等。高光在表面上會隨著視點的移動而移動。
比如下圖:
圖中白色的部分就是高光,並且我們在不同的角度看它,它會在不同的位置高光。
高光依靠的就是純粹的一個數學模擬。它其實就是一個反射光。
L依舊指向光射入光線,N依舊為法向量,R為反射形成的光,它有著這樣的特別之處,那就是我們從觀察方向V來看,隨著 角度的增大,這個光會銳減的很快。
看函數 ,當 為0的時候,這個值剛好為1,當 增加到90°時候,這個值剛好減少到0.
所以我們可以用函數 來模擬物體的鏡面指數。
那麼高光將會造成的 在觀看角度 的值的計算如下:
代入可得
所以從 方向得到的高光強度是:
依舊記住我們只需要考慮大於0的狀況.
之前的偽碼依舊適用,我們需要考慮的是:
我們首先給每個小球添加s,s越大會越閃亮(s = -1 表示物體並沒有),按照作者的邏輯,同時我們添加一個巨大的小球,這樣它就會像一個平面一樣。
在計算高光的時候我們使用上方的公式,我們已經有 , s是小球本身的性質,我們也已經添加,需要的還有 ,這是我們觀察的方向,view direction,記住我們光線追蹤的初衷,是從眼睛看出來,所以view direction特別簡單,就是 .
所以調整計算光的部分如下
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 else L = -light.direction
# 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 }
TraceRay(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 }
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) }
看結果: