Ejemplo n.º 1
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.º 2
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.º 3
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.º 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)

		# 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.º 5
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