def G1_GGX(n_dot_vl, alpha): # 2 n_dot_vl 2 # G1 := --------------------------------------------------- = -------------------------------------------- # n_dot_vl + sqrt(alpha^2 + (1 - alpha^2) n_dot_vl^2) 1 + sqrt((alpha/n_dot_vl)^2 + (1 - alpha^2)) alpha2 = sqr(alpha) n_dot_vl2 = sqr(n_dot_vl) return 2.0 * n_dot_vl / (n_dot_vl * sqrt(alpha2 + (1.0 - alpha2) * n_dot_vl2))
def V1_GGX(n_dot_vl, alpha): # 2 # V1 := --------------------------------------------------- # n_dot_vl + sqrt(alpha^2 + (1 - alpha^2) n_dot_vl^2) alpha2 = sqr(alpha) n_dot_vl2 = sqr(n_dot_vl) return 2.0 / (n_dot_vl * sqrt(alpha2 + (1.0 - alpha2) * n_dot_vl2))
def D_TrowbridgeReitz(n_dot_h, alpha): # alpha^2 c # D:= ---------------------------------- = --------------------------------------------- # pi (n_dot_h^2 (alpha^2 - 1) + 1)^2 (alpha^2 * cos(theta_h)^2 + sin(theta_h)^2)^2 alpha2 = sqr(alpha) n_dot_h2 = sqr(n_dot_h) temp1 = n_dot_h2 * (alpha2 - 1.0) + 1.0 return alpha2 / (np.pi * sqr(temp1))
def V_GGX(n_dot_v, n_dot_l, n_dot_h, v_dot_h, alpha): # 2 # V := ------------------------------------------------------------------------------------------------- # n_dot_v sqrt(alpha^2 + (1 - alpha^2) n_dot_l^2) + n_dot_l sqrt(alpha^2 + (1 - alpha^2) n_dot_v^2) alpha2 = sqr(alpha) lambda_v = sqrt(alpha2 + (1.0 - alpha2) * sqr(n_dot_v)) lambda_l = sqrt(alpha2 + (1.0 - alpha2) * sqr(n_dot_l)) return 2.0 / (n_dot_v * lambda_l + n_dot_l * lambda_v)
def D_WardDuer(n_dot_h, alpha): # 1 [ n_dot_h^2 - 1 ] 1 [tan(theta_h)]^2 # D:= ---------- e^[-----------------] = ---------- e^-[------------] # pi alpha^2 [n_dot_h^2 alpha^2] pi alpha^2 [ alpha ] inv_alpha2 = 1.0 / sqr(alpha) n_dot_h2 = sqr(n_dot_h) t2 = sqr_cos_to_sqr_tan(n_dot_h2) return inv_alpha2 * np.exp(-t2 * inv_alpha2) / np.pi
def D_Beckmann(n_dot_h, alpha): # 1 [ n_dot_h^2 - 1 ] 1 [tan(theta_h)]^2 # D:= -------------------- e^[-----------------] = -------------------- e^-[------------] # pi alpha^2 n_dot_h^4 [n_dot_h^2 alpha^2] pi alpha^2 n_dot_h^4 [ alpha ] inv_alpha2 = 1.0 / sqr(alpha) n_dot_h2 = sqr(n_dot_h) inv_n_dot_h4 = 1.0 / sqr(n_dot_h2) t2 = sqr_cos_to_sqr_tan(n_dot_h2) return inv_alpha2 * inv_n_dot_h4 * np.exp(-t2 * inv_alpha2) / np.pi
def D_Berry(n_dot_h, alpha): # alpha^2 - 1 c # D:= --------------------------------------------- = ------------------------------------------- # log(alpha^2) pi (n_dot_h^2 (alpha^2 - 1) + 1) (alpha^2 * cos(theta_h)^2 + sin(theta_h)^2) alpha2 = sqr(alpha) n_dot_h2 = sqr(n_dot_h) temp1 = n_dot_h2 * (alpha2 - 1.0) + 1.0 if alpha >= 1.0: return 1.0 / np.pi else: return (alpha2 - 1.0) / (np.pi * np.log(alpha2) * temp1)
def G1_Beckmann(n_dot_vl, alpha): # n_dot_vl # c := -------------------------- # alpha sqrt(1 - n_dot_vl^2) # # 3.535 c + 2.181 c^2 # G1 := ----------------------- (if c < 1.6) | 1 (otherwise) # 1 + 2.276 c + 2.577 c^2 n_dot_vl2 = sqr(n_dot_vl) c = n_dot_vl2 / (alpha * sqrt(1.0 - n_dot_vl2)) c2 = sqr(c) if c < 1.6: return (3.535 * c + 2.8181 * c2) / (1.0 + 2.276 * c + 2.577 * c2) else: return 1.0
def D_BlinnPhong(n_dot_h, alpha): # 1 [ 2 ] Ns + 2 # D:= ---------- n_dot_h^[------- - 2] = ------ n_dot_h^Ns # pi alpha^2 [alpha^2 ] pi 2 inv_alpha2 = 1.0 / sqr(alpha) Ns = 2.0 * inv_alpha2 - 2.0 return inv_alpha2 * np.power(n_dot_h, Ns) / np.pi
def G_GGX(n_dot_v, n_dot_l, n_dot_h, v_dot_h, alpha): # 2 (n_dot_l) (n_dot_v) # G := ------------------------------------------------------------------------------------------------- # n_dot_v sqrt(alpha^2 + (1 - alpha^2) n_dot_l^2) + n_dot_l sqrt(alpha^2 + (1 - alpha^2) n_dot_v^2) # # 1 # = ----------------------- # 1 + Lambda_v + lambda_l # # sqrt(alpha^2 + (1 - alpha^2) (n_dot_v)^2) 1 # Lambda_v = ----------------------------------------- - - # 2 n_dot_v 2 alpha2 = sqr(alpha) lambda_v = sqrt(alpha2 + (1.0 - alpha2) * sqr(n_dot_v)) lambda_l = sqrt(alpha2 + (1.0 - alpha2) * sqr(n_dot_l)) return (2.0 * n_dot_l * n_dot_v) / (n_dot_v * lambda_l + n_dot_l * lambda_v)
def F_CookTorrance(v_dot_h, F0): # c := v_dot_h # # 1 + sqrt(F0) # eta := ------------ # 1 - sqrt(F0) # # g := sqrt(eta^2 + c^2 - 1) # # 1 [g - c]^2 [ [(g + c) c - 1]^2] # F := - [-----] [1 + [-------------] ] # 2 [g + c] [ [(g - c) c + 1] ] sqrt_F0 = sqrt(F0) eta = (1.0 + sqrt_F0) / (1.0 - sqrt_F0) g = sqrt(sqr(eta) + sqr(v_dot_h) - 1.0) g1 = g + v_dot_h g2 = g - v_dot_h return 0.5 * sqr(g2 / g1) * (1.0 + sqr((g1 * v_dot_h - 1.0) / (g2 * v_dot_h + 1.0)))
def evaluate_V(self, n, l, v, material): alpha = np.maximum(1e-1, sqr(material.roughness)) n_dot_l = sat_dot(n, l) + 1e-5 n_dot_v = sat_dot(n, v) + 1e-5 h = half_direction(l, v) n_dot_h = sat_dot(n, h) + 1e-5 v_dot_h = sat_dot(v, h) + 1e-5 return self.V(n_dot_v=n_dot_v, n_dot_l=n_dot_l, n_dot_h=n_dot_h, v_dot_h=v_dot_h, alpha=alpha)
def __call__(self, n, l, v, material): alpha = np.maximum(1e-1, sqr(material.roughness)) n_dot_l = sat_dot(n, l) + 1e-5 n_dot_v = sat_dot(n, v) + 1e-5 h = half_direction(l, v) n_dot_h = sat_dot(n, h) + 1e-5 v_dot_h = sat_dot(v, h) + 1e-5 D = self.D(n_dot_h=n_dot_h, alpha=alpha) F = self.F(v_dot_h=v_dot_h, F0=material.F0) V = self.V(n_dot_v=n_dot_v, n_dot_l=n_dot_l, n_dot_h=n_dot_h, v_dot_h=v_dot_h, alpha=alpha) return 0.25 * D * F * V
def evaluate_D(self, n, l, v, material): alpha = np.maximum(1e-1, sqr(material.roughness)) h = half_direction(l, v) n_dot_h = sat_dot(n, h) + 1e-5 return self.D(n_dot_h=n_dot_h, alpha=alpha)