Ejemplo n.º 1
0
    def test_bbox_intersect(self):
        b = geo.BBox(geo.Point(1., 1., 1.), geo.Point(2., 2., 2.))
        ray = geo.Ray(geo.Point(0., 0., 0.), geo.Vector(1., 1., 1.))
        hit, t1, t2 = b.intersect_p(ray)
        assert hit
        assert_almost_eq(t1, 1.)
        assert_almost_eq(t2, 2.)

        # ambiguity in this case

        ray = geo.Ray(geo.Point(1. - EPS, 1. - EPS, 0.),
                      geo.Vector(-EPS, -EPS, 1.))
        hit, t1, t2 = b.intersect_p(ray)
        assert not hit
        assert_almost_eq(t1, 0.)
        assert_almost_eq(t2, 0.)

        ray = geo.Ray(geo.Point(1. - EPS, 1. - EPS, 1. - EPS),
                      geo.Vector(-1., -1., -1.))
        hit, t1, t2 = b.intersect_p(ray)
        assert not hit
        assert_almost_eq(t1, 0.)
        assert_almost_eq(t2, 0.)

        ray = geo.Ray(geo.Point(0., 0., 0.), geo.Vector(-1., -1., -1.))
        hit, t1, t2 = b.intersect_p(ray)
        assert not hit
        assert_almost_eq(t1, 0.)
        assert_almost_eq(t2, 0.)
Ejemplo n.º 2
0
	def __init__(self, c2w: 'trans.AnimatedTransform', scr_win: [FLOAT],
				 s_open: FLOAT, s_close: FLOAT, lensr: FLOAT, focald: FLOAT, f: 'Film'):
		super().__init__(c2w, trans.Transform.orthographic(0., 1.), scr_win, s_open,
						 s_close, lensr, focald, f)
		# compute differential changes in origin
		self.dxCam = self.r2c(geo.Vector(1., 0., 0.))
		self.dyCam = self.r2c(geo.Vector(0., 1., 0.))
Ejemplo n.º 3
0
    def __init__(self, p: 'np.ndarray', refine_imm: bool):
        super().__init__()
        if refine_imm:
            self.primitives = []
            for prim in p:
                prim.full_refine(self.primitives)
        else:
            self.primitives = p

        # compute bounds and choose grid resolution
        self.bounds = geo.BBox()
        self.n_voxels = np.full(3, 0.)

        for prim in self.primitives:
            self.bounds.union(prim.world_bound())

        delta = self.bounds.pMax - self.bounds.pMin
        max_axis = self.bounds.maximum_extent()
        inv_max_width = 1. / delta[max_axis]
        cube_root = 3. * np.power(len(self.primitives), 1. / 3.)
        voxels_per_unit_dist = cube_root * inv_max_width

        self.width = geo.Vector()
        self.invWidth = geo.Vector()

        for axis in range(3):
            self.n_voxels[axis] = INT(delta[axis] * voxels_per_unit_dist)
            self.n_voxels[axis] = np.clip(self.n_voxels[axis], 1., 64.)

            self.width[axis] = delta[axis] / self.n_voxels[axis]
            self.invWidth[
                axis] = 0. if self.width[axis] == 0. else 1. / self.width[axis]

        nv = np.prod(self.n_voxels).astype(INT)
        self.voxels = np.full(nv, None)

        # add primitives to voxels
        for prim in self.primitives:
            pb = prim.world_bound()
            vmin = [self.pos2voxel(pb.pMin, axis) for axis in range(3)]
            vmax = [self.pos2voxel(pb.pMax, axis) for axis in range(3)]

            for z in range(vmin[2], vmax[2] + 1):
                for y in range(vmin[1], vmax[1] + 1):
                    for x in range(vmin[0], vmax[0] + 1):
                        o = self.offset(x, y, z)

                        if self.voxels[o] is None:
                            # new voxel
                            self.voxels[o] = Voxel([prim])

                        else:
                            # add primitive
                            self.voxels[o].add_primitive(prim)

        # create mutex for grid
        self.lock = threading.Lock()
Ejemplo n.º 4
0
    def __call__(self, arg, dtype=None):
        if isinstance(arg, geo.Point) or (isinstance(arg, np.ndarray)
                                          and dtype == geo.Point):
            res = self.m[0:4, 0:3].dot(arg) + self.m[0:4, 3]
            p = geo.Point(res[0], res[1], res[2])
            if util.ne_unity(res[3]):
                p /= res[3]
            return p

        elif isinstance(arg, geo.Vector) or (isinstance(arg, np.ndarray)
                                             and dtype == geo.Vector):
            res = self.m[0:3, 0:3].dot(arg)
            return geo.Vector(res[0], res[1], res[2])

        elif isinstance(arg, geo.Normal) or (isinstance(arg, np.ndarray)
                                             and dtype == geo.Normal):
            # must be transformed by inverse transpose
            res = self.m_inv[0:3, 0:3].T.dot(arg)
            return geo.Normal(res[0], res[1], res[2])

        elif isinstance(arg, geo.RayDifferential):
            r = geo.RayDifferential.from_rd(arg)
            r.o = self(r.o)
            r.d = self(r.d)
            return r

        elif isinstance(arg, geo.Ray):
            r = geo.Ray.from_ray(arg)
            r.o = self(r.o)
            r.d = self(r.d)
            return r

        elif isinstance(arg, geo.BBox):
            res = geo.BBox.from_bbox(arg)
            x = geo.Vector(res.pMax.x - res.pMin.x, 0., 0.)
            y = geo.Vector(0., res.pMax.y - res.pMin.y, 0.)
            z = geo.Vector(0., 0., res.pMax.z - res.pMin.z)
            res.pMin = self(res.pMin)
            x = self(x)
            y = self(y)
            z = self(z)
            res.pMax = res.pMin + (x + y + z)
            return res

        else:
            raise TypeError(
                'Transform can only be called on geo.Point, geo.Vector, geo.Normal, geo.Ray or geo.geo.BBox'
            )
Ejemplo n.º 5
0
    def decompose(
            m: 'np.ndarray'
    ) -> ['geo.Vector', 'quat.Quaternion', 'np.ndarray']:
        """
		decompose into
		m = T R S
		Assume m is an affine transformation
		"""
        if not np.shape(m) == (4, 4):
            raise TypeError

        T = geo.Vector(m[0, 3], m[1, 3], m[2, 3])
        M = m.copy()
        M[0:3, 3] = M[3, 0:3] = 0
        M[3, 3] = 1

        # polar decomposition
        norm = 2 * EPS
        R = M.copy()

        for _ in range(100):
            if norm < EPS:
                break
            Rit = np.linalg.inv(R.T)
            Rnext = .5 * (Rit + R)
            D = np.fabs(Rnext - Rit)[0:3, 0:3]
            norm = max(norm, np.max(np.sum(D, axis=0)))
            R = Rnext

        from pytracer.transform.quat import from_arr
        Rquat = from_arr(R)
        S = np.linalg.inv(R).dot(M)

        return T, Rquat, S
Ejemplo n.º 6
0
	def sample_l(self, p: 'geo.Point', pEps: FLOAT, ls: 'LightSample',
			time: FLOAT,) -> ['Spectrum', 'geo.Vector', FLOAT, 'VisibilityTester']:	
		# find (u, v) sample coords in inf. light texture
		uv, pdf = self.dist.sample_cont(ls.u_pos[0], ls.u_pos[1])

		# convert inf light sample pnt to direction
		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)

		wi = self.l2w(geo.Vector(st * cp, st * sp, ct))

		# compute pdf for sampled inf light direction
		if st == 0.:
			pdf = 0.
		pdf = pdf / (2. * PI * PI * st)


		# return radiance value
		vis = VisibilityTester()
		vis.set_ray(p, pEps, wi, time)

		return [Spectrum.from_rgb(self.radMap.look_up([uv[0], uv[1]]), SpectrumType.ILLUMINANT),
					wi, pdf, vis]
Ejemplo n.º 7
0
 def test_ray_differential_scale(self, vec, pnt):
     ray = geo.RayDifferential(pnt, vec)
     ray.rxOrigin = ray.ryOrigin = pnt
     ray.rxDirection = vec + geo.Vector(rng(), rng(), rng())
     ray.ryDirection = vec + geo.Vector(rng(), rng(), rng())
     s = rng()
     r = geo.RayDifferential.from_rd(ray)
     ray.scale_differential(s)
     assert ray.rxOrigin == r.o + (r.rxOrigin - r.o) * s
     assert ray.ryOrigin == r.o + (r.ryOrigin - r.o) * s
     assert ray.rxDirection == r.d + (r.rxDirection - r.d) * s
     assert ray.ryDirection == r.d + (r.ryDirection - r.d) * s
     assert isinstance(ray.rxOrigin, geo.Point)
     assert isinstance(ray.ryOrigin, geo.Point)
     assert isinstance(ray.rxDirection, geo.Vector)
     assert isinstance(ray.ryDirection, geo.Vector)
Ejemplo n.º 8
0
	def generate_ray(self, sample: 'CameraSample') -> [FLOAT, 'geo.Ray']:
		"""
		Generate ray based on image sample.
		Returned ray direction is normalized
		"""
		# generate raster and camera samples
		Pras = geo.Point(sample.imageX, sample.imageY, 0.)
		Pcam = self.r2c(Pras)

		ray = geo.Ray(Pcam, geo.Vector(0., 0., 1.), 0., np.inf)

		# modify ray for dof
		if self.lens_rad > 0.:
			# sample point on lens

			from pytracer.montecarlo import concentric_sample_disk
			lens_u, lens_v = \
				concentric_sample_disk(sample.lens_u, sample.lens_v)
			lens_u *= self.lens_rad
			lens_v *= self.lens_rad

			# compute point on focal plane
			ft = self.focal_dist / ray.d.z
			Pfoc = ray(ft)

			# update ray
			ray.o = geo.Point(lens_u, lens_v, 0.)
			ray.d = geo.normalize(Pfoc - ray.o)

		ray.time = util.lerp(sample.time, self.s_open, self.s_close)
		ray = self.c2w(ray)
		return [1., ray]
Ejemplo n.º 9
0
	def w2l(self, v: 'geo.Vector') -> 'geo.Vector':
		"""
		w2l()

		Transform a `geo.Vector` in world in the local
		surface normal coord. system
		"""
		return geo.Vector(v.dot(self.sn), v.dot(self.tn), v.dot(self.nn))
Ejemplo n.º 10
0
 def test_rotate_x(self, x_axis, y_axis, z_axis):
     t = Transform.rotate_x(45)
     assert_elem_eq(t(x_axis), x_axis)
     v = t(y_axis)
     assert_elem_eq(v, geo.Vector(0., np.sqrt(2) / 2., np.sqrt(2) / 2.))
     vv = t(v)
     assert_elem_eq(vv, z_axis)
     vv = t.inverse()(v)
     assert_elem_eq(vv, y_axis)
Ejemplo n.º 11
0
    def sample_f(self, wo: 'geo.Vector', u1: FLOAT,
                 u2: FLOAT) -> [FLOAT, 'geo.Vector', 'Spectrum']:
        # find direction
        wi = geo.Vector(-wo.x, -wo.y, wo.z)

        return [
            1., wi,
            self.fresnel(cos_theta(wo)) * self.R / abs_cos_theta(wi)
        ]  # 1. suggests no MC samples needed
Ejemplo n.º 12
0
	def l2w(self, v: 'geo.Vector') -> 'geo.Vector':
		"""
		l2w()

		Transform a `geo.Vector` in the local system
		to the world system
		"""
		return geo.Vector(self.sn.x * v.x + self.tn.x * v.x + self.nn.x * v.x,
		                  self.sn.y * v.y + self.tn.y * v.y + self.nn.y * v.y,
		                  self.sn.z * v.z + self.tn.z * v.z + self.nn.z * v.z)
Ejemplo n.º 13
0
def uniform_sample_hemisphere(u1: FLOAT, u2: FLOAT) -> 'geo.Vector':
    """
	uniform_sample_hemisphere()

	Sampling unifromly
	on a unit hemishpere.
	`u1` and `u2` are two
	random numbers passed in.
	"""
    r = np.sqrt(max(0., 1. - u1 * u1))
    phi = 2. * PI * u2
    return geo.Vector(r * np.cos(phi), r * np.sin(phi), u1)
Ejemplo n.º 14
0
    def test_rotate_bbox(self):
        t = Transform.rotate(180., geo.Vector(1., 1., 1.))
        p1 = geo.Point(0., 0., 0.)
        p2 = geo.Point(1., 1., 1.)
        box = geo.BBox(p1, p2)
        b = t(box)
        pmax = t(box.pMax)
        pmin = t(box.pMin)

        assert_elem_eq(b.pMin, pmin)
        assert_elem_eq(b.pMax, pmax)

        bb = t(b)
        pmax = t(pmax)
        pmin = t(pmin)
        assert_elem_eq(bb.pMin, pmin)
        assert_elem_eq(bb.pMax, pmax)
Ejemplo n.º 15
0
	def __init__(self, c2w: 'trans.AnimatedTransform', proj: 'trans.Transform', scr_win: [FLOAT],
				 s_open: FLOAT, s_close: FLOAT, lensr: FLOAT, focald: FLOAT, f: 'Film'):
		super().__init__(c2w, s_open, s_close, f)

		# set dof prarms
		self.lens_rad = lensr
		self.focal_dist = focald

		# compute transfomations
		self.c2s = proj
		## compute projective screen transfomations
		s2r = trans.Transform.scale(f.xResolution, f.yResolution, 1.) * \
			  trans.Transform.scale(1. / (scr_win[1] - scr_win[0]),
							  1. / (scr_win[2] - scr_win[3]), 1.) * \
			  trans.Transform.translate(geo.Vector(-scr_win[0], -scr_win[3], 0.))  # upper-left corner to origin

		r2s = s2r.inverse()
		self.r2c = self.c2s.inverse() * r2s
Ejemplo n.º 16
0
    def generate_ray(self, sample: 'CameraSample') -> [FLOAT, 'geo.Ray']:
        """
		Generate ray based on image sample.
		Returned ray direction is normalized
		"""
        time = util.lerp(sample.time, self.s_open, self.s_close)

        # compute ray direction
        theta = np.pi * sample.imageY / self.film.yResolution
        phi = 2 * np.pi * sample.imageX / self.film.xResolution
        stheta = np.sin(theta)

        ray = self.c2w(
            geo.Ray(
                geo.Point(0., 0., 0.),
                geo.Vector(stheta * np.cos(phi), np.cos(theta),
                           stheta * np.sin(phi)), 0., np.inf, time))
        return [1., ray]
Ejemplo n.º 17
0
    def test_rotate(self, x_axis, y_axis, z_axis):
        t = Transform.rotate(45., x_axis)
        assert_elem_eq(t(x_axis), x_axis)
        v = t(y_axis)
        assert_elem_eq(v, geo.Vector(0., np.sqrt(2) / 2., np.sqrt(2) / 2.))
        vv = t(v)
        assert_elem_eq(vv, z_axis)
        vv = t.inverse()(v)
        assert_elem_eq(vv, y_axis)

        t = Transform.rotate(30., y_axis)
        assert_elem_eq(t(y_axis), y_axis)
        p = geo.Point.from_arr(z_axis)
        pp = t(t(t(p)))
        assert_elem_eq(pp, x_axis)

        t = Transform.rotate(90., z_axis)
        assert_elem_eq(t(z_axis), z_axis)
        n = geo.Normal.from_arr(y_axis)
        nn = t(t(t(n)))
        assert_elem_eq(nn, x_axis)
Ejemplo n.º 18
0
def uniform_sample_cone(u1: FLOAT,
                        u2: FLOAT,
                        ct_max: FLOAT,
                        x: 'geo.Vector' = None,
                        y: 'geo.Vector' = None,
                        z: 'geo.Vector' = None) -> 'geo.Vector':
    """
	uniform_sample_cone()

	Sample from a uniform distribution
	over the cone of directions.
	"""
    if x is None or y is None or z is None:
        ct = (1. - u1) + u1 * ct_max
        st = np.sqrt(1. - ct * ct)
        phi = u2 * 2. * PI
        return geo.Vector(np.scos(phi) * st, np.sin(phi) * st, ct)
    else:
        ct = util.lerp(u1, ct_max, 1.)
        st = np.sqrt(1. - ct * ct)
        phi = u2 * 2. * PI
        return np.cos(phi) * st * x + np.sin(phi) * st * y + ct * z
Ejemplo n.º 19
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.º 20
0
    def sample_f(self, wo: 'geo.Vector', u1: FLOAT,
                 u2: FLOAT) -> [FLOAT, 'geo.Vector', 'Spectrum']:
        # find eta pair
        ei, et = self.ei, self.et
        if cos_theta(wo) > 0.:
            ei, et = et, ei

        # compute transmited ray direction
        si_sq = sin_theta_sq(wo)
        eta = ei / et
        st_sq = eta * eta * si_sq

        if st_sq >= 1.:
            return [0., None, None]

        ct = np.sqrt(max(0., 1. - st_sq))
        if cos_theta(wo) > 0.:
            ct = -ct
        wi = geo.Vector(eta * (-wo.x), eta * (-wo.y), ct)

        F = self.fresnel(cos_theta(wo))

        return [1., wi, (et * et) / (ei * ei) * (Spectrum(1.) - F) * \
                self.T / abs_cos_theta(wi)]  # 1. suggests no MC samples needed
Ejemplo n.º 21
0
    def intersect(
            self,
            r: 'geo.Ray') -> (bool, FLOAT, FLOAT, 'geo.DifferentialGeometry'):
        """
		Returns:
		 - bool: specify whether intersects
		 - tHit: hit point param
		 - rEps: error tolerance
		 - dg: geo.DifferentialGeometry object
		"""
        # transform ray to object space
        ray = self.w2o(r)

        # parallel ray has not intersection
        if np.fabs(ray.d.z) < EPS:
            return [False, None, None, None]

        thit = (self.height - ray.o.z) / ray.d.z
        if thit < ray.mint or thit > ray.maxt:
            return [False, None, None, None]

        phit = ray(thit)

        # check radial distance
        dt2 = phit.x * phit.x + phit.y * phit.y
        if dt2 > self.radius * self.radius or \
            dt2 < self.inner_radius * self.inner_radius:
            return [False, None, None, None]

        # check angle
        phi = np.arctan2(phit.y, phit.x)
        if phi < 0:
            phi += 2. * np.pi

        if phi > self.phiMax:
            return [False, None, None, None]

        # otherwise ray hits the disk
        # initialize the differential structure
        u = phi / self.phiMax
        v = 1. - ((np.sqrt(dt2 - self.inner_radius)) /
                  (self.radius - self.inner_radius))

        # find derivatives
        dpdu = geo.Vector(-self.phiMax * phit.y, self.phiMax * phit.x, 0.)
        dpdv = geo.Vector(-phit.x / (1. - v), -phit.y / (1. - v), 0.)
        dpdu *= self.phiMax * INV_2PI
        dpdv *= (self.radius - self.inner_radius) / self.radius

        # derivative of geo.Normals
        dndu = geo.Normal(
            0.,
            0.,
            0.,
        )
        dndv = geo.Normal(
            0.,
            0.,
            0.,
        )

        o2w = self.o2w
        dg = geo.DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv),
                                      o2w(dndu), o2w(dndv), u, v, self)
        return True, thit, EPS * thit, dg
Ejemplo n.º 22
0
	def intersect(self, r: 'geo.Ray') -> [bool, FLOAT, FLOAT, 'geo.DifferentialGeometry']:
		"""
		Returns:
		 - bool: specify whether intersects
		 - tHit: hit point param
		 - rEps: error tolerance
		 - dg: geo.DifferentialGeometry object
		"""
		# transform ray to object space
		ray = self.w2o(r)

		# solve quad eqn
		A = ray.d.sq_length()
		B = 2 * ray.d.dot(ray.o)
		C = ray.o.sq_length() - self.radius * self.radius

		D = B * B - 4. * A * C
		if D <= 0.:
			return [False, None, None, None]

		# validate solutions
		[t0, t1] = np.roots([A, B, C])
		if t0 > t1:
			t0, t1 = t1, t0
		if t0 > ray.maxt or t1 < ray.mint:
			return [False, None, None, None]
		thit = t0
		if t0 < ray.mint:
			thit = t1
			if thit > ray.maxt:
				return [False, None, None, None]

		# sphere hit position
		phit = ray(thit)
		if phit.x == 0. and phit.y == 0.:
			phit.x = EPS * self.radius
		phi = np.arctan2(phit.y, phit.x)
		if phi < 0.:
			phi += 2. * np.pi

		# test intersection against clipping params
		if (self.zmin > -self.radius and phit.z < self.zmin) or \
				(self.zmax < self.radius and phit.z > self.zmax) or \
						phi > self.phiMax:
			if thit == t1 or t1 > ray.maxt:
				return [False, None, None, None]

			# try again with t1
			thit = t1
			phit = ray(thit)
			if phit.x == 0. and phit.y == 0.:
				phit.x = EPS * self.radius
			phi = np.arctan2(phit.y, phit.x)
			if phi < 0.:
				phi += 2. * np.pi
			if (self.zmin > -self.radius and phit.z < self.zmin) or \
					(self.zmax < self.radius and phit.z > self.zmax) or \
							phi > self.phiMax:
				return [False, None, None, None]

		# otherwise ray hits the sphere
		# initialize the differential structure
		u = phi / self.phiMax
		theta = np.arccos(np.clip(phit.z / self.radius, -1., 1.))
		delta_theta = self.thetaMax - self.thetaMin
		v = (theta - self.thetaMin) * delta_theta

		# find derivatives
		dpdu = geo.Vector(-self.phiMax * phit.y, self.phiMax * phit.x, 0.)
		zrad = np.sqrt(phit.x * phit.x + phit.y * phit.y)
		inv_zrad = 1. / zrad
		cphi = phit.x * inv_zrad
		sphi = phit.y * inv_zrad
		dpdv = delta_theta \
		       * geo.Vector(phit.z * cphi, phit.z * sphi, -self.radius * np.sin(theta))

		# derivative of Normals
		# given by Weingarten Eqn
		d2pduu = -self.phiMax * self.phiMax * geo.Vector(phit.x, phit.y, 0.)
		d2pduv = delta_theta * phit.z * self.phiMax * geo.Vector(-sphi, cphi, 0.)
		d2pdvv = -delta_theta * delta_theta * geo.Vector(phit.x, phit.y, phit.z)

		# fundamental forms
		E = dpdu.dot(dpdu)
		F = dpdu.dot(dpdv)
		G = dpdv.dot(dpdv)
		N = geo.normalize(dpdu.cross(dpdv))
		e = N.dot(d2pduu)
		f = N.dot(d2pduv)
		g = N.dot(d2pdvv)

		invEGFF = 1. / (E * G - F * F)
		dndu = geo.Normal.from_arr((f * F - e * G) * invEGFF * dpdu +
		                         (e * F - f * E) * invEGFF * dpdv)
		dndv = geo.Normal.from_arr((g * F - f * G) * invEGFF * dpdu +
		                         (f * F - g * E) * invEGFF * dpdv)

		o2w = self.o2w
		dg = geo.DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv), o2w(dndu), o2w(dndv), u, v, self)
		return True, thit, EPS * thit, dg
Ejemplo n.º 23
0
 def switch(w: 'geo.Vector'):
     return geo.Vector(w.x, w.y, -w.z)
Ejemplo n.º 24
0
"""
from __future__ import absolute_import

import numpy as np
import pytest
from pytracer import pyEPS as EPS
import pytracer.geometry as geo

N_TEST_CASE = 5
VAR = 10.
np.random.seed(1)
rng = np.random.rand

testdata = {
    'vector':
    [geo.Vector(rng(), rng(), rng()) * VAR for _ in range(N_TEST_CASE)],
    'normal':
    [geo.Normal(rng(), rng(), rng()) * VAR for _ in range(N_TEST_CASE)],
    'point':
    [geo.Point(rng(), rng(), rng()) * VAR for _ in range(N_TEST_CASE)],
    'theta': [np.random.uniform(0., np.pi) for _ in range(N_TEST_CASE)],
    'phi': [np.random.uniform(0., 2 * np.pi) for _ in range(N_TEST_CASE)],
}
testdata['vector'].extend([
    geo.Vector(0., 0., 0.),
    geo.Vector(1., 0., 0.),
    geo.Vector(
        0.,
        1.,
        0.,
    ),
Ejemplo n.º 25
0
    def intersect(
            self,
            r: 'geo.Ray') -> (bool, FLOAT, FLOAT, 'geo.DifferentialGeometry'):
        """
		Returns:
		 - bool: specify whether intersects
		 - tHit: hit point param
		 - rEps: error tolerance
		 - dg: geo.DifferentialGeometry object
		"""
        # transform ray to object space
        ray = self.w2o(r)

        # solve quad eqn
        A = ray.d.x * ray.d.x + ray.d.y * ray.d.y
        B = 2 * (ray.d.x * ray.o.x + ray.d.y * ray.o.y)
        C = ray.o.x * ray.o.x + ray.o.y * ray.o.y - self.radius * self.radius

        D = B * B - 4. * A * C
        if D <= 0.:
            return [False, None, None, None]

        # validate solutions
        [t0, t1] = np.roots([A, B, C])
        if t0 > t1:
            t0, t1 = t1, t0
        if t0 > ray.maxt or t1 < ray.mint:
            return [False, None, None, None]
        thit = t0
        if t0 < ray.mint:
            thit = t1
            if thit > ray.maxt:
                return [False, None, None, None]

        # cylinder hit position
        phit = ray(thit)
        phi = np.arctan2(phit.y, phit.x)
        if phi < 0.:
            phi += 2. * np.pi

        # test intersection against clipping params
        if phit.z < self.zmin or phit.z > self.zmax or phi > self.phiMax:
            if thit == t1 or t1 > ray.maxt:
                return [False, None, None, None]

            # try again with t1
            thit = t1
            phit = ray(thit)
            phi = np.arctan2(phit.y, phit.x)
            if phi < 0.:
                phi += 2. * np.pi

            if phit.z < self.zmin or phit.z > self.zmax or phi > self.phiMax:
                if thit == t1 or t1 > ray.maxt:
                    return [False, None, None, None]

        # otherwise ray hits the cylinder
        # initialize the differential structure
        u = phi / self.phiMax
        v = (phit.z - self.zmin) / (self.thetaMax - self.thetaMin)

        # find derivatives
        dpdu = geo.Vector(-self.phiMax * phit.y, self.phiMax * phit.x, 0.)
        dpdv = geo.Vector(0., 0., self.zmax - self.zmin)

        # derivative of geo.Normals
        # given by Weingarten Eqn
        d2pduu = -self.phiMax * self.phiMax * geo.Vector(phit.x, phit.y, 0.)
        d2pduv = geo.Vector(0., 0., 0.)
        d2pdvv = geo.Vector(0., 0., 0.)

        # fundamental forms
        E = dpdu.dot(dpdu)
        F = dpdu.dot(dpdv)
        G = dpdv.dot(dpdv)
        N = geo.normalize(dpdu.cross(dpdv))
        e = N.dot(d2pduu)
        f = N.dot(d2pduv)
        g = N.dot(d2pdvv)

        invEGFF = 1. / (E * G - F * F)
        dndu = geo.Normal.from_arr((f * F - e * G) * invEGFF * dpdu +
                                   (e * F - f * E) * invEGFF * dpdv)

        dndv = geo.Normal.from_arr((g * F - f * G) * invEGFF * dpdu +
                                   (f * F - g * E) * invEGFF * dpdv)

        o2w = self.o2w
        dg = geo.DifferentialGeometry(o2w(phit), o2w(dpdu), o2w(dpdv),
                                      o2w(dndu), o2w(dndv), u, v, self)
        return True, thit, EPS * thit, dg
Ejemplo n.º 26
0
from numpy.testing import assert_array_almost_equal
import pytest
from pytracer import FLOAT
import pytracer.geometry as geo
from pytracer.transform import Transform
import pytracer.transform.quat as quat

N_TEST_CASE = 5
VAR = 10.
EPS = 6
np.random.seed(1)
rng = np.random.rand

test_data = {
    'vector':
    [geo.Vector(rng(), rng(), rng()) * VAR for _ in range(N_TEST_CASE)],
    'normal':
    [geo.Normal(rng(), rng(), rng()) * VAR for _ in range(N_TEST_CASE)],
    'point':
    [geo.Point(rng(), rng(), rng()) * VAR for _ in range(N_TEST_CASE)],
    'quat': [
        quat.Quaternion(rng(), rng(), rng(), rng()) * VAR
        for _ in range(N_TEST_CASE)
    ],
}
test_data['vector'].extend([
    geo.Vector(0., 0., 0.),
    geo.Vector(1., 0., 0.),
    geo.Vector(
        0.,
        1.,
Ejemplo n.º 27
0
 def orthographic(cls, znear: FLOAT, zfar: FLOAT):
     return cls.scale(1., 1., 1. / (zfar - znear)) * cls.translate(
         geo.Vector(0., 0., -znear))