Ejemplo n.º 1
0
    def __init__(self, origin, filename, scale, *args, **kwargs):
        """
        A mesh TracerObject that understands smooth/flat shading by reading in vertex normals from the .obj file

        :param origin: np.array, [X,Y,Z]
        :param filename: name of the .obj file to load
        :param scale: spatial dimensions of the object are multiplied by this number
        :param kwargs: TracerObject's kwargs
        """
        super().__init__(origin, *args, **kwargs)
        with open(filename, 'r') as f:
            lines = f.readlines()
        # Read in the vertices and rotate them according to rot
        verts = np.array([np.array(l[2:-1].split(" ")).astype(float) for l in lines if l[:2] == 'v '])
        verts = jm.rotate(verts, self._rot)
        verts = verts * scale + self.origin
        faces = np.array([[int(v.split("/")[0]) - 1 for v in l[2:-1].split(" ")] for l in lines if l[:2] == 'f '])

        # Read in and rotate the normals
        vns = np.array([np.array(l[3:-1].split(" ")).astype(float) for l in lines if l[:3] == 'vn '])
        vns = jm.rotate(vns, self._rot)
        # Assign normals to vertices
        vni = np.array([[int(v.split("/")[2]) - 1 for v in l[2:-1].split(" ")] for l in lines if l[:2] == 'f '])
        self.na = normalize_array(vns[vni[:, 0]])
        self.nb = normalize_array(vns[vni[:, 1]])
        self.nc = normalize_array(vns[vni[:, 2]])
        self.scale = scale

        self.a = verts[faces[:, 0]]
        self.edge1 = verts[faces[:, 1]] - self.a
        self.edge2 = verts[faces[:, 2]] - self.a
        self._normals = None
Ejemplo n.º 2
0
    def __init__(self, origin, normal, *args, **kwargs):
        """
        Create a surface with an origin and a normal.

        :param origin: np.array, [X,Y,Z]
        :param normal: np.array, [X,Y,Z] for the plane's normal vector. Doesn't have to be a unit vector
        :param kwargs: TracerObject's kwargs
        """
        super().__init__(origin, *args, **kwargs)
        self._normal = jm.rotate(np.array([normalize(np.array(normal))]), self._rot)[0]
        self.along = np.array([self._normal[1], -self._normal[0]]).astype(float)
Ejemplo n.º 3
0
    def __init__(self, origin, a, b, c, *args, **kwargs):
        """
        Create a triangle. The orientation of the triangle (its normal direction) depends on the order a, b, c
        is provided in.

        :param origin: np.array, [X,Y,Z]
        :param a: np.array, [X,Y,Z]
        :param b: np.array, [X,Y,Z]
        :param c: np.array, [X,Y,Z] - three vertices of the triangle, relative to the origin
        :param kwargs: TracerObject's kwargs
        """
        origin = np.array([0, 0, 0]) if origin is None else np.array(origin)
        super().__init__(origin, *args, **kwargs)
        a, b, c = jm.rotate(np.array([a, b, c]), self._rot)
        self.a = self.origin + a
        self.b = self.origin + b
        self.c = self.origin + c
        self.edge1 = self.b-self.a
        self.edge2 = self.c-self.a
        self._normal = normalize(np.cross(self.edge1, self.edge2))
Ejemplo n.º 4
0
    def __init__(self, origin, n_out=1., n_in=1., ang_origin=None, rot=(1,0,0,0), reflective=False, active=True):
        """
        Create a new TracerObject.

        NOTE about refractive indices: the Rays *do not* keep track of the refractive index of the medium.
        The refraction angle is calculated completely locally, on the assumption that all "volumes" are correctly
        constrained with TracerObjects that have correctly set n_in and n_out.

        This means that when constructing a flat glass slab, you have to make sure that the Surface objects
        constraining it have the same n_in, otherwise you *will* get unphysical behaviour.

        :param origin: Coordinates of the object's centre - [X, Y]
        :param n_out: Refractive index outside of the object
        :param n_in: Refractive index inside of the object
        :param reflective: a boolean switch for making the object reflect all rays
        :param active: a boolean switch for whether the object should be counted towards the scene's total accumulated
                       momentum. Useful for systems that include a lens for example
        :param ang_origin: [X, Y, Z], can be provided if the point around which angular momentum transfer should be
                           calculated is different than the origin
        :param rot: a quaternion, [q_r, q_i, q_j, q_k], representing the object's rotational position (the rotation is
                    performed around ang_origin)
        """
        self.origin = np.array(origin).astype(float)
        self.ang_origin = self.origin if ang_origin is None else np.array(ang_origin).astype(float)
        self._rot = np.array(rot).astype(float)
        # Calculate the origin after rotations - rotations always occur around ang_origin, so the origin may change
        offset = jm.rotate(np.array([self.origin - self.ang_origin]), self._rot)[0]
        self.origin = self.ang_origin + offset
        self.n_out = float(n_out)
        self.n_in = float(n_in)
        self.momentum = np.zeros(3)
        self.ang_momentum = np.zeros(3)
        self.active = active
        # The object's ray-acting function is assigned to the general "act_rays" function,
        # which is what the scene will call,
        # unless reflective is None, in which case act_rays is left as is.
        if reflective:
            self.act_rays = self.reflect
        elif reflective is False:
            self.act_rays = self.refract
Ejemplo n.º 5
0
    def __init__(self, origin, filename, scale, *args, **kwargs):
        """
        First implementaion of the Mesh TracerObject. You should probably use SmoothMeshTO, which respects smooth/flat
        shading, unless your .obj file doesn't include vertex normal data.

        :param origin: np.array, [X,Y,Z]
        :param filename: name of the .obj file to load
        :param scale: spatial dimensions of the object are multiplied by this number
        :param kwargs: TracerObject's kwargs
        """
        super().__init__(origin, *args, **kwargs)
        # Load and process the .obj file
        with open(filename, 'r') as f:
            lines = f.readlines()
        verts = np.array([np.array(l[2:-1].split(" ")).astype(float) for l in lines if l[:2] == 'v '])
        verts = jm.rotate(verts, self._rot)
        verts = verts*scale + self.origin
        faces = np.array([[int(v.split("/")[0]) - 1 for v in l[2:-1].split(" ")] for l in lines if l[:2] == 'f '])
        self.scale = scale
        self.a = verts[faces[:, 0]]
        self.edge1 = verts[faces[:, 1]] - self.a
        self.edge2 = verts[faces[:, 2]] - self.a
        self._normals = normalize_array(np.cross(self.edge1, self.edge2))
        self._d = None