Exemplo n.º 1
0
    def sample(self, u1: FLOAT, u2: FLOAT) -> ['geo.Point', 'geo.Normal']:
        z = util.lerp(u1, self.zmin, self.zmax)
        t = u2 * self.phiMax
        p = geo.Point(self.radius * np.cos(t), self.radius * np.sin(t), z)
        Ns = geo.normalize(self.o2w(geo.Normal(p.x, p.y, 0.)))

        if self.ro:
            Ns *= -1.

        return [self.o2w(p), Ns]
Exemplo n.º 2
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'
            )
Exemplo n.º 3
0
	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]
Exemplo n.º 4
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
Exemplo n.º 5
0
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.,
        0.,
    ),
Exemplo 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
Exemplo 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