Ejemplo n.º 1
0
	def sample_p(self, pnt: 'geo.Point', u1: FLOAT, u2: FLOAT) -> ['geo.Point', 'geo.Normal']:
		"""
		uniformly sample the sphere
		visible (of certain solid angle)
		to the point
		"""
		# compute coords for sampling
		ctr = self.o2w(geo.Point(0., 0., 0.))
		wc = geo.normalize(ctr - pnt)
		_, wc_x, wc_y = geo.coordinate_system(wc)

		# sample uniformly if p is inside
		if pnt.sq_dist(ctr) - self.radius * self.radius < EPS:
			return self.sample(u1, u2)

		# sample inside subtended cone
		st_max_sq = self.radius * self.radius / pnt.sq_dist(ctr)
		ct_max = np.sqrt(max(0., 1. - st_max_sq))

		from pytracer.montecarlo import uniform_sample_cone
		r = geo.Ray(pnt, uniform_sample_cone(u1, u2, ct_max, wc_x, wc_y, wc), EPS)

		hit, thit, _, _ = self.intersect(r)

		if not hit:
			thit = (ctr - pnt).dot(geo.normalize(r.d))

		ps = r(thit)
		ns = geo.Normal.from_arr(geo.normalize(ps - ctr))
		if self.ro:
			ns *= -1.

		return [ps, ns]
Ejemplo n.º 2
0
	def sample_r(self, scene: 'Scene', ls: 'LightSample', u1: FLOAT, 
					u2: FLOAT, time: FLOAT) -> ['geo.Ray', 'geo.Normal', FLOAT, 'Spectrum']:
		"""
		Create a bounding disk
		and uniformly sample
		on it.
		"""
		# choose point on disk oriented towards light
		ctr, rad = scene.world_bound().bounding_sphere()
		_, v1, v2 = geo.coordinate_system(self.di)
		d1, d2 = mc.concentric_sample_disk(ls.u_pos[0], ls.u_pos[1])
		pnt = ctr + rad * (d1 * v1 + d2 * v2)

		# set ray
		ray = geo.Ray(pnt + rad * self.di, -self.di, 0., np.inf, time)
		Ns = geo.Normal.fromVector(ray.d)
		pdf = 1. / (PI * rad * rad)
		return [ray, Ns, pdf, self.l]
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
	def sample_r(self, scene: 'Scene', ls: 'LightSample', u1: FLOAT, 
					u2: FLOAT, time: FLOAT) -> ['geo.Ray', 'geo.Normal', FLOAT, 'Spectrum']:
		"""
		Create a bounding disk
		and uniformly sample
		on it.
		"""
		# find (u, v) sample coords in inf. light texture
		uv, pdf = self.dist.sample_cont(ls.u_pos[0], ls.u_pos[1])
		if pdf == 0.:
			return [None, None, 0., Spectrum(0.)]

		theta = uv[1] * PI
		phi = uv[0] * 2. * PI
		ct = np.cos(theta)
		st = np.sin(theta)
		sp = np.sin(phi)
		cp = np.cos(phi)
		d = -self.l2w(geo.Vector(st * cp, st * sp, ct))
		Ns = geo.Normal.fromVector(d)

		# choose point on disk oriented towards light
		ctr, rad = scene.world_bound().bounding_sphere()
		_, v1, v2 = geo.coordinate_system(self.di)
		d1, d2 = mc.concentric_sample_disk(ls.u_pos[0], ls.u_pos[1])
		pnt = ctr + rad * (d1 * v1 + d2 * v2)

		# set ray
		ray = geo.Ray(pnt + rad * (-d), d, 0., np.inf, time)

		# compute pdf
		dir_pdf = pdf / (2. * PI * PI * st)
		area_pdf = 1. / (PI * rad * rad)
		pdf = dir_pdf * area_pdf
		if st == 0.:
			pdf == 0.

		return [ray, Ns, pdf, Spectrum.from_rgb(self.radMap.look_up([uv[0], uv[1]]), SpectrumType.ILLUMINANT)]
Ejemplo n.º 5
0
 def test_coordinate_system(self, vec):
     x, y, z = geo.coordinate_system(vec)
     assert_almost_eq(x.dot(y), 0.)
     assert_almost_eq(x.dot(z), 0.)
     assert_almost_eq(y.dot(z), 0.)
Ejemplo n.º 6
0
    def get_shading_geometry(
            self, o2w: 'trans.Transform',
            dg: 'geo.DifferentialGeometry') -> 'geo.DifferentialGeometry':
        if self.mesh.n is None or self.mesh.s is None:
            return dg
        # compute barycentric coord
        uvs = self.get_uvs()
        A = np.array([[uvs[1][0] - uvs[0][0], uvs[2][0] - uvs[0][0]],
                      [uvs[1][1] - uvs[0][1], uvs[2][1] - uvs[0][1]]],
                     dtype=FLOAT)
        C = np.array([dg.u - uvs[0][0], dg.v - uvs[0][1]])
        try:
            b = np.linalg.solve(A, C)
        except:
            b = [1. / 3, 1. / 3, 1. / 3]

        else:
            b = [1. - b[0] - b[1], b[0], b[1]]

        # compute shading tangents
        if self.mesh.n is not None:
            ns = geo.normalize(
                o2w(b[0] * self.mesh.n[self.v] +
                    b[1] * self.mesh.n[self.v + 1] +
                    b[2] * self.mesh.n[self.v + 2]))
        else:
            ns = dg.nn

        if self.mesh.s is not None:
            ss = geo.normalize(
                o2w(b[0] * self.mesh.s[self.v] +
                    b[1] * self.mesh.s[self.v + 1] +
                    b[2] * self.mesh.s[self.v + 2]))
        else:
            ss = geo.normalize(dg.dpdu)

        ts = ss.cross(ns)
        if ts.sq_length() > 0.:
            ts.normalize()
            ss = ts.cross(ns)
        else:
            _, ss, ts = geo.coordinate_system(ns)

        # compute dndu and dndv
        if self.mesh.n is not None:
            du1 = uvs[0][0] - uvs[2][0]
            du2 = uvs[1][0] - uvs[2][0]
            dv1 = uvs[0][1] - uvs[2][1]
            dv2 = uvs[1][1] - uvs[2][1]
            dn1 = self.mesh.n[self.mesh.vertexIndex[self.v]] - self.mesh.n[
                self.mesh.vertexIndex[self.v + 2]]
            dn2 = self.mesh.n[self.mesh.vertexIndex[self.v + 1]] - self.mesh.n[
                self.mesh.vertexIndex[self.v + 2]]
            det = du1 * dv2 - du2 * dv1
            if det == 0.:
                # choose an arbitrary system
                dndu = dndv = geo.Normal(0., 0., 0.)
            else:
                detInv = 1. / det
                dndu = (dv2 * dn1 - dv1 * dn2) * detInv
                dndv = (-du2 * dn1 + du1 * dn2) * detInv
        else:
            dndu = geo.Normal(0., 0., 0.)
            dndv = geo.Normal(0., 0., 0.)

        dgs = geo.DifferentialGeometry(dg.p, ss, ts, self.mesh.o2w(dndu),
                                       self.mesh.o2w(dndv), dg.u, dg.v,
                                       dg.shape)
        dgs.dudx = dg.dudx
        dgs.dvdx = dg.dvdx
        dgs.dudy = dg.dudy
        dgs.dvdy = dg.dvdy
        dgs.dpdx = dg.dpdx
        dgs.dpdy = dg.dpdy

        return dgs
Ejemplo n.º 7
0
    def intersect_p(self, r: 'Ray') -> bool:
        """
		Determine whether intersects
		using Barycentric coordinates
		"""
        # compute s1
        p1 = self.mesh.p[self.mesh.vertexIndex[self.v]]
        p2 = self.mesh.p[self.mesh.vertexIndex[self.v + 1]]
        p3 = self.mesh.p[self.mesh.vertexIndex[self.v + 2]]

        e1 = p2 - p1  # geo.Vector
        e2 = p3 - p1
        s1 = r.d.cross(e2)
        div = s1.dot(e1)

        if div == 0.:
            return False
        divInv = 1. / div

        # compute barycentric coordinate
        ## first one
        d = r.o - p1
        b1 = d.dot(s1) * divInv
        if b1 < 0. or b1 > 1.:
            return False
        ## second one
        s2 = d.cross(e1)
        b2 = r.d.dot(s2) * divInv
        if b2 < 0. or (b1 + b2) > 1.:
            return False

        # compute intersection
        t = e2.dot(s2) * divInv
        if t < r.mint or t > r.maxt:
            return False

        # compute partial derivatives
        uvs = self.get_uvs()
        du1 = uvs[0][0] - uvs[2][0]
        du2 = uvs[1][0] - uvs[2][0]
        dv1 = uvs[0][1] - uvs[2][1]
        dv2 = uvs[1][1] - uvs[2][1]
        dp1 = p1 - p3
        dp2 = p2 - p3

        det = du1 * dv2 - du2 * dv1
        if det == 0.:
            # choose an arbitrary system
            _, dpdu, dpdv = geo.coordinate_system(geo.normalize(e2.cross(e1)))
        else:
            detInv = 1. / det
            dpdu = (dv2 * dp1 - dv1 * dp2) * detInv
            dpdv = (-du2 * dp1 + du1 * dp2) * detInv

        # interpolate triangle parametric coord.
        b0 = 1. - b1 - b2
        tu = b0 * uvs[0][0] + b1 * uvs[1][0] + b2 * uvs[2][0]
        tv = b0 * uvs[0][1] + b1 * uvs[1][1] + b2 * uvs[2][1]

        # test alpha texture
        dg = geo.DifferentialGeometry(r(t), dpdu, dpdv, geo.Normal(0., 0., 0.),
                                      geo.Normal(0., 0., 0.), tu, tv, self)

        if self.mesh.alphaTexture is not None:
            # alpha mask presents
            if self.mesh.alphaTexture.evaluate(dg) == 0.:
                return False

        # have a hit
        return True