Beispiel #1
0
    def execute(self, context, scene, ray_origin, ray_vector):
        up_vector, right_vector, plane_normal = sprytile_utils.get_current_grid_vectors(
            context.scene)
        hit_loc, normal, face_index, distance = self.modal.raycast_object(
            context.object, ray_origin, ray_vector, world_normal=True)
        if face_index is None:
            return

        normal.normalize()

        self.modal.add_virtual_cursor(hit_loc)
        # Change the uv of the given face
        grid_id = context.object.sprytile_gridid
        grid = sprytile_utils.get_grid(context, grid_id)
        tile_xy = (grid.tile_selection[0], grid.tile_selection[1])

        face_up, face_right = self.modal.get_face_up_vector(
            context, face_index)
        data = context.scene.sprytile_data

        rotate_normal = plane_normal
        if face_up is not None and face_right is not None:
            rotate_normal = face_up.cross(face_right)

        rotate_matrix = Quaternion(-rotate_normal, data.mesh_rotate)
        if face_up is not None:
            up_vector = rotate_matrix * face_up
        if face_right is not None:
            right_vector = rotate_matrix * face_right

        up_vector.normalize()
        right_vector.normalize()
        # print("Up vector:", up_vector, "Right vector:", right_vector)
        # print("Up mag:", up_vector.magnitude, "Right mag:", right_vector.magnitude)
        sprytile_uv.uv_map_face(context, up_vector, right_vector, tile_xy,
                                face_index, self.modal.bmesh)
Beispiel #2
0
    def construct_face(self,
                       context,
                       grid_coord,
                       tile_xy,
                       origin_xy,
                       grid_up,
                       grid_right,
                       up_vector,
                       right_vector,
                       plane_normal,
                       face_index=None,
                       check_exists=True,
                       shift_vec=None,
                       threshold=None,
                       add_cursor=True):
        """
        Create a new face at grid_coord or remap the existing face
        :param context:
        :param grid_coord:
        :param tile_xy:
        :param origin_xy:
        :param grid_up:
        :param grid_right:
        :param up_vector:
        :param right_vector:
        :param plane_normal:
        :param face_index:
        :param check_exists:
        :param shift_vec:
        :param threshold:
        :param add_cursor:
        :return:
        """
        scene = context.scene
        data = scene.sprytile_data
        hit_loc = None
        hit_normal = None
        if check_exists:
            hit_loc, hit_normal, face_index, hit_dist = self.raycast_grid_coord(
                context, grid_coord[0], grid_coord[1], grid_up, grid_right,
                plane_normal)

        did_build = False
        # No face index, assume build face
        if face_index is None or face_index < 0:
            face_position = scene.cursor_location + grid_coord[
                0] * grid_right + grid_coord[1] * grid_up
            face_verts = self.get_build_vertices(face_position, grid_right,
                                                 grid_up, up_vector,
                                                 right_vector)
            face_index = self.create_face(context, face_verts)
            did_build = True
        # Face index was given and check exists flag is off, check for actual face
        elif check_exists is False:
            hit_loc, hit_normal, face_index, hit_dist = self.raycast_grid_coord(
                context, grid_coord[0], grid_coord[1], grid_up, grid_right,
                plane_normal)

        if face_index is None or face_index < 0:
            return None

        # Didn't create face, only want to remap face. Check for coplanarity and dot
        if did_build is False:
            check_dot = abs(plane_normal.dot(hit_normal))
            check_dot -= 1
            check_coplanar = distance_point_to_plane(hit_loc,
                                                     scene.cursor_location,
                                                     plane_normal)

            check_coplanar = abs(check_coplanar) < 0.05
            check_dot = abs(check_dot) < 0.05
            # Can't remap face
            if not check_coplanar or not check_dot:
                return None

        sprytile_uv.uv_map_face(context, up_vector, right_vector, tile_xy,
                                origin_xy, face_index, self.bmesh)

        if did_build and data.auto_merge:
            if threshold is None:
                threshold = (1 / data.world_pixels) * 1.25

            face = self.bmesh.faces[face_index]

            face_position += grid_right * 0.5 + grid_up * 0.5
            face_position += plane_normal * 0.01
            face_index = self.merge_doubles(context, face, face_position,
                                            -plane_normal, threshold)

        # Auto merge refreshes the mesh automatically
        self.refresh_mesh = not data.auto_merge

        if add_cursor and hit_loc is not None:
            self.add_virtual_cursor(hit_loc)
        return face_index
Beispiel #3
0
    def construct_face(self,
                       context,
                       grid_coord,
                       grid_size,
                       tile_xy,
                       tile_origin,
                       grid_up,
                       grid_right,
                       up_vector,
                       right_vector,
                       plane_normal,
                       require_base_layer=False,
                       work_layer_mask=0,
                       threshold=None):
        """
        Create a new face at grid_coord or remap the existing face
        :type work_layer_mask: bitmask integer
        :param context:
        :param grid_coord: Grid coordinate to create at
        :param grid_size: Tile unit size of face
        :param tile_xy: Tilegrid coordinate to map
        :param tile_origin: Origin of tilegrid coordinate, for mapping data
        :param grid_up:
        :param grid_right:
        :param up_vector:
        :param right_vector:
        :param plane_normal:
        :param require_base_layer:
        :param threshold:
        :return:
        """
        scene = context.scene
        data = scene.sprytile_data

        # Run a raycast on target work layer mask
        hit_loc, hit_normal, face_index, hit_dist = self.raycast_grid_coord(
            context,
            grid_coord[0],
            grid_coord[1],
            grid_up,
            grid_right,
            plane_normal,
            work_layer_mask=work_layer_mask)

        # Didn't hit target layer, and require base layer
        if face_index is None and require_base_layer:
            # Check if there is a base layer underneath
            base_hit_loc, hit_normal, base_face_index, base_hit_dist = self.raycast_grid_coord(
                context, grid_coord[0], grid_coord[1], grid_up, grid_right,
                plane_normal)
            # Didn't hit required base layer, do nothing
            if base_face_index is None:
                return None

        # Calculate where the origin of the grid is
        grid_origin = scene.cursor_location.copy()
        # If doing mesh decal, offset the grid origin
        if data.work_layer == 'DECAL_1':
            grid_origin += plane_normal * data.mesh_decal_offset

        did_build = False
        # No face index, assume build face
        if face_index is None or face_index < 0:
            face_position = grid_origin + grid_coord[
                0] * grid_right + grid_coord[1] * grid_up

            face_verts = self.get_build_vertices(face_position,
                                                 grid_right * grid_size[0],
                                                 grid_up * grid_size[1],
                                                 up_vector, right_vector)
            face_index = self.create_face(context, face_verts)
            did_build = True

        if face_index is None or face_index < 0:
            return None

        # Didn't create face, only want to remap face. Check for coplanarity and dot
        if did_build is False:
            check_dot = abs(plane_normal.dot(hit_normal))
            check_dot -= 1
            check_coplanar = distance_point_to_plane(hit_loc, grid_origin,
                                                     plane_normal)

            check_coplanar = abs(check_coplanar) < 0.05
            check_dot = abs(check_dot) < 0.05
            # Can't remap face
            if not check_coplanar or not check_dot:
                return None

        sprytile_uv.uv_map_face(context, up_vector, right_vector, tile_xy,
                                tile_origin, face_index, self.bmesh, grid_size)

        if did_build and data.auto_merge:
            if threshold is None:
                threshold = (1 / data.world_pixels) * 1.25

            face = self.bmesh.faces[face_index]

            face_position += grid_right * 0.5 + grid_up * 0.5
            face_position += plane_normal * 0.01
            face_index = self.merge_doubles(context, face, face_position,
                                            -plane_normal, threshold)

        # Auto merge refreshes the mesh automatically
        self.refresh_mesh = not data.auto_merge

        return face_index
Beispiel #4
0
    def execute(self, context, scene, ray_origin, ray_vector):
        grid = sprytile_utils.get_grid(context, context.object.sprytile_gridid)
        tile_xy = (grid.tile_selection[0], grid.tile_selection[1])

        up_vector, right_vector, plane_normal = sprytile_utils.get_current_grid_vectors(
            scene)
        hit_loc, hit_normal, face_index, hit_dist = self.modal.raycast_object(
            context.object, ray_origin, ray_vector)

        # Used to move raycast slightly along ray vector
        shift_vec = ray_vector.normalized() * 0.001

        # If raycast hit the mesh...
        if face_index is not None:
            # The face is valid for painting if hit face
            # is facing same way as plane normal and is coplanar to target plane
            check_dot = abs(plane_normal.dot(hit_normal))
            check_dot -= 1
            check_coplanar = distance_point_to_plane(hit_loc,
                                                     scene.cursor_location,
                                                     plane_normal)

            check_coplanar = abs(check_coplanar) < 0.05
            check_dot = abs(check_dot) < 0.05
            # Hit a face that is valid for painting
            if check_dot and check_coplanar:
                self.modal.add_virtual_cursor(hit_loc)
                # Change UV of this face instead
                face_up, face_right = self.modal.get_face_up_vector(
                    context, face_index)
                if face_up is not None and face_up.dot(up_vector) < 0.95:
                    data = context.scene.sprytile_data
                    rotate_matrix = Matrix.Rotation(data.mesh_rotate, 4,
                                                    hit_normal)
                    up_vector = rotate_matrix * face_up
                    right_vector = rotate_matrix * face_right
                sprytile_uv.uv_map_face(context, up_vector, right_vector,
                                        tile_xy, face_index, self.modal.bmesh)
                if scene.sprytile_data.cursor_flow:
                    self.modal.flow_cursor(context, face_index, hit_loc)
                return

        # Raycast did not hit the mesh, raycast to the virtual grid
        face_position, x_vector, y_vector, plane_cursor = sprytile_utils.raycast_grid(
            scene, context, up_vector, right_vector, plane_normal, ray_origin,
            ray_vector)
        # Failed to hit the grid
        if face_position is None:
            return

        # If raycast hit mesh, compare distance of grid hit and mesh hit
        if hit_loc is not None:
            grid_hit_dist = (face_position - ray_origin).magnitude
            # Mesh hit closer than grid hit, don't do anything
            if hit_dist < grid_hit_dist:
                return

        # store plane_cursor, for deciding where to move actual cursor if auto cursor mode is on
        self.modal.add_virtual_cursor(plane_cursor)
        # Build face and UV map it
        face_vertices = self.modal.get_build_vertices(face_position, x_vector,
                                                      y_vector, up_vector,
                                                      right_vector)
        face_index = self.modal.create_face(context, face_vertices)

        face_up, face_right = self.modal.get_face_up_vector(
            context, face_index)
        if face_up is not None and face_up.dot(up_vector) < 0.95:
            data = context.scene.sprytile_data
            rotate_matrix = Matrix.Rotation(data.mesh_rotate, 4, plane_normal)
            up_vector = rotate_matrix * face_up
            right_vector = rotate_matrix * face_right

        sprytile_uv.uv_map_face(context, up_vector, right_vector, tile_xy,
                                face_index, self.modal.bmesh)

        if scene.sprytile_data.auto_merge:
            face = self.modal.bmesh.faces[face_index]
            face.select = True
            # Find the face center, to raycast from later
            face_center = context.object.matrix_world * face.calc_center_bounds(
            )
            # Move face center back a little for ray casting
            face_center -= shift_vec

            threshold = (1 / context.scene.sprytile_data.world_pixels) * 2
            bpy.ops.mesh.remove_doubles(threshold=threshold,
                                        use_unselected=True)

            for el in [
                    self.modal.bmesh.faces, self.modal.bmesh.verts,
                    self.modal.bmesh.edges
            ]:
                el.index_update()
                el.ensure_lookup_table()

            # Modified the mesh, refresh and raycast to find the new face index
            self.modal.update_bmesh_tree(context)
            loc, norm, new_face_idx, hit_dist = self.modal.raycast_object(
                context.object, face_center, ray_vector)
            if new_face_idx is not None:
                self.modal.bmesh.faces[new_face_idx].select = False
                face_index = new_face_idx
            else:
                face_index = -1

        # Auto merge refreshes the mesh automatically
        self.modal.refresh_mesh = not scene.sprytile_data.auto_merge

        if scene.sprytile_data.cursor_flow and face_index is not None and face_index > -1:
            self.modal.flow_cursor(context, face_index, plane_cursor)
Beispiel #5
0
    def construct_fill(self, context, scene, sprytile_data, cell_coord,
                       plane_size, face_idx_array, paint_setting_layer,
                       tile_xy, ray_vector, shift_vec, threshold, up_vector,
                       right_vector, plane_normal, grid_up, grid_right):

        grid_coord = [
            -plane_size[0] + cell_coord[0], plane_size[1] - 1 - cell_coord[1]
        ]

        # Check face index array, if -1, create face
        face_index = face_idx_array[cell_coord[1]][cell_coord[0]]
        did_build = False
        # If no existing face, build it
        if face_index < 0:
            did_build = True
            face_position = scene.cursor_location + grid_coord[
                0] * grid_right + grid_coord[1] * grid_up
            face_verts = self.modal.get_build_vertices(face_position,
                                                       grid_right, grid_up,
                                                       up_vector, right_vector)
            face_index = self.modal.create_face(context, face_verts)
        # Face existing...
        else:
            # Raycast to get the face index of the face, could have changed
            hit_loc, hit_normal, face_index, hit_dist = self.modal.raycast_grid_coord(
                context, context.object, grid_coord[0], grid_coord[1], grid_up,
                grid_right, plane_normal)

            # use the face paint settings for the UV map step
            face = self.modal.bmesh.faces[face_index]
            if sprytile_data.fill_lock_transform and paint_setting_layer is not None:
                paint_setting = face[paint_setting_layer]
                sprytile_utils.from_paint_settings(context.scene.sprytile_data,
                                                   paint_setting)

        face_up, face_right = self.modal.get_face_up_vector(
            context, face_index)
        if face_up is not None and face_up.dot(up_vector) < 0.95:
            data = context.scene.sprytile_data
            rotate_matrix = Matrix.Rotation(data.mesh_rotate, 4, plane_normal)
            up_vector = rotate_matrix * face_up
            right_vector = rotate_matrix * face_right

        sprytile_uv.uv_map_face(context, up_vector, right_vector, tile_xy,
                                face_index, self.modal.bmesh)

        if did_build and sprytile_data.auto_merge:
            face = self.bmesh.faces[face_index]
            face.select = True
            # Find the face center, to raycast from later
            face_center = context.object.matrix_world * face.calc_center_bounds(
            )
            # Move face center back a little for ray casting
            face_center += shift_vec

            bpy.ops.mesh.remove_doubles(threshold=threshold,
                                        use_unselected=True)

            for el in [
                    self.modal.bmesh.faces, self.modal.bmesh.verts,
                    self.modal.bmesh.edges
            ]:
                el.index_update()
                el.ensure_lookup_table()

            # Modified the mesh, refresh and raycast to find the new face index
            self.modal.update_bmesh_tree(context)
            loc, norm, new_face_idx, hit_dist = self.modal.raycast_object(
                context.object, face_center, ray_vector, 0.1)
            if new_face_idx is not None:
                self.modal.bmesh.faces[new_face_idx].select = False