def test_spherical(self, theta, phi): st = np.sin(theta) ct = np.cos(theta) v = geo.spherical_direction(st, ct, phi) theta_ret = geo.spherical_theta(v) phi_ret = geo.spherical_phi(v) assert_almost_eq(theta, theta_ret) assert_almost_eq(phi, phi_ret)
def sample(self, u1: FLOAT, u2: FLOAT) -> ['geo.Point', 'geo.Normal']: """ account for partial sphere """ from pytracer.montecarlo import uniform_sample_sphere v = uniform_sample_sphere(u1, u2) phi = geo.spherical_theta(v) * self.phiMax * INV_2PI theta = self.thetaMin + geo.spherical_theta(v) * (self.thetaMax - self.thetaMin) v = geo.spherical_direction(np.sin(theta), np.cos(theta), phi) * self.radius v.z = self.zmin + v.z * (self.zmax - self.zmin) p = geo.Point.from_arr(v) Ns = geo.normalize(self.o2w(geo.Normal(p.x, p.y, p.z))) if self.ro: Ns *= -1. return [self.o2w(p), Ns]
def sample_hg(w: 'geo.Vector', g: FLOAT, u1: FLOAT, u2: FLOAT) -> 'geo.Vector': """ sample_hg() Sampling from Henyey-Greestein phase function, i.e., $$ \cos(\theta) = \frac{1}{2g}\left(1 + g^2 - \left( \frac{1-g^2}{1-g+2g\zeta} \right) ^2 \right)) $$ """ if np.fabs(g) < EPS: ct = 1. - 2. * u1 else: sqr = (1. - g * g) / (1. - g + 2. * g * u1) ct = (1. + g * g - sqr * sqr) / (2. * g) st = np.sqrt(max(0., 1 - ct * ct)) phi = 2. * PI * u2 _, v1, v2 = geo.coordinate_system(w) return geo.spherical_direction(st, ct, phi, v1, v2, w)
def sample_f(self, wo: 'geo.Vector', u1: FLOAT, u2: FLOAT) -> [FLOAT, 'geo.Vector']: # compute sampled half-angle vector ct = np.power(u1, 1. / (self.e + 1)) st = np.sqrt(max(0., 1. - ct * ct)) phi = u2 * 2. * PI wh = geo.spherical_direction(st, ct, phi) if wo.z * wh.z <= 0.: wh *= -1. # incident direction by reflection wi = -wo + 2. * wo.dot(wh) * wh # pdf pdf = ((self.e + 1.) * np.power(ct, self.e)) / \ (2. * PI * 4. * wo.dot(wh)) if wo.dot(wh) <= 0.: pdf = 0. return [pdf, wi]
def sample_f(self, wo: 'geo.Vector', u1: FLOAT, u2: FLOAT) -> [FLOAT, 'geo.Vector']: # sample from first quadrant and remap to hemisphere to sample w_h if u1 < .25: phi, ct = self.__sample_first_quad(4. * u1, u2) elif u1 < .5: u1 = 4. * (.5 - u1) phi, ct = self.__sample_first_quad(u1, u2) phi = PI - phi elif u1 < .75: u1 = 4. * (u1 - .5) phi, ct = self.__sample_first_quad(u1, u2) phi += PI else: u1 = 4. * (1. - u1) phi, ct = self.__sample_first_quad(u1, u2) phi = 2. * PI - phi st = np.sqrt(max(0., 1. - ct * ct)) wh = geo.spherical_direction(st, ct, phi) if wo.z * wh.z <= 0.: wh *= -1. # incident direction by reflection wi = -wo + 2. * wo.dot(wh) * wh # compute pdf for w_i ct = abs_cos_theta(wh) ds = 1. - ct * ct if ds > 0. and wo.dot(wh) > 0.: return [(np.sqrt((self.ex + 1.) * (self.ey + 1.)) * INV_2PI * np.power(ct, ( self.ex * wh.x * wh.x + self.ey * wh.y * wh.y) / ds)) / \ (4. * wo.dot(wh)), wi] else: return [0., wi]