def set_parent(blender_object:bpy.types.Object,parent_info:ParentInfo)->None:
    assert isinstance(blender_object,bpy.types.Object)

    blender_object.parent = parent_info.parent
    blender_object.parent_type = parent_info.parent_type

    if parent_info.parent_type == _BONE:
        assert parent_info.parent.type == _ARMATURE and\
               parent_info.parent.data.bones.get(parent_info.parent_bone) is not None

        blender_object.parent_bone = parent_info.parent_bone
示例#2
0
    def check_pose_for_object(obj: bpy.types.Object,
                              position: mathutils.Vector,
                              rotation: mathutils.Vector, bvh_cache: dict,
                              objects_to_check_against: list,
                              list_of_objects_with_no_inside_check: list):
        """
        Checks if a object placed at the given pose intersects with any object given in the list.

        The bvh_cache adds all current objects to the bvh tree, which increases the speed.

        If an object is already in the cache it is removed, before performing the check.

        :param obj: Object which should be checked. Type: :class:`bpy.types.Object`
        :param position: 3D Vector of the location of the object. Type: :class:`mathutils.Vector`
        :param rotation: 3D Vector of the rotation in euler angles. If this is None, the rotation is not changed \
                         Type: :class:`mathutils.Vector`
        :param bvh_cache: Dict of all the bvh trees, removes the `obj` from the cache before adding it again. \
                          Type: :class:`dict`
        :param objects_to_check_against: List of objects which the object is checked again \
                                         Type: :class:`list`
        :param list_of_objects_with_no_inside_check: List of objects on which no inside check is performed. \
                                                     This check is only done for the objects in \
                                                     `objects_to_check_against`. Type: :class:`list`
        :return: Type: :class:`bool`, True if no collision was found, false if at least one collision was found
        """
        # assign it a new pose
        obj.location = position
        if rotation:
            obj.rotation_euler = rotation
        bpy.context.view_layer.update()
        # Remove bvh cache, as object has changed
        if obj.name in bvh_cache:
            del bvh_cache[obj.name]

        no_collision = True
        # Now check for collisions
        for already_placed in objects_to_check_against:
            # First check if bounding boxes collides
            intersection = check_bb_intersection(obj, already_placed)
            # if they do
            if intersection:
                skip_inside_check = already_placed in list_of_objects_with_no_inside_check
                # then check for more refined collisions
                intersection, bvh_cache = check_intersection(
                    obj,
                    already_placed,
                    bvh_cache=bvh_cache,
                    skip_inside_check=skip_inside_check)
            if intersection:
                no_collision = False
                break
        return no_collision
        def extract_plane_from_room(obj: bpy.types.Object,
                                    used_split_height: float,
                                    up_vec: mathutils.Vector,
                                    new_name_for_obj: str):
            """
            Extract a plane from the current room object. This uses the FloorExtractor Module functions

            :param obj: The current room object
            :param used_split_height: The height at which the split should be performed. Usually 0 or self.wall_height
            :param up_vec: The up_vec corresponds to the face.normal of the selected faces
            :param new_name_for_obj: This will be the new name of the created object
            :return: (bool, bpy.types.Object): Returns True if the object was split and also returns the object. \
                                               Else it returns (False, None).
            """
            compare_height = 0.15
            compare_angle = math.radians(7.5)
            obj.select_set(True)
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.mesh.select_all(action='DESELECT')
            bm = bmesh.from_edit_mesh(mesh)
            bm.faces.ensure_lookup_table()
            # split the floor at the wall height
            counter = FloorExtractor.split_at_height_value(
                bm, used_split_height, compare_height,
                mathutils.Vector(up_vec), compare_angle, obj.matrix_world)
            # if any faces are selected split them up
            if counter:
                bpy.ops.mesh.separate(type='SELECTED')
                bpy.ops.object.mode_set(mode='OBJECT')
                bm.free()
                mesh.update()
                cur_selected_objects = bpy.context.selected_objects
                if cur_selected_objects:
                    if len(cur_selected_objects) == 2:
                        cur_selected_objects = [
                            o for o in cur_selected_objects
                            if o != bpy.context.view_layer.objects.active
                        ]
                        cur_selected_objects[0].name = new_name_for_obj
                        cur_created_obj = cur_selected_objects[0]
                    else:
                        raise Exception(
                            "There is more than one selection after splitting, this should not happen!"
                        )
                else:
                    raise Exception("No floor object was constructed!")
                bpy.ops.object.select_all(action='DESELECT')
                return True, cur_created_obj
            else:
                bpy.ops.object.mode_set(mode='OBJECT')
                bpy.ops.object.select_all(action='DESELECT')
                return False, None
示例#4
0
    def clear_selection(mesh_obj: bpy.types.Object):
        """Make sure that the editor is in the following state:
            * OBJECT_MODE
            * selected: one object, the mesh object.
            * active: the mesh object.
        """

        # Switch to OBJECT mode
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.object.select_all(action='DESELECT')  # Deselect all objects

        # The MESH object will be the active and the only selected object
        mesh_obj.select_set(True)
        bpy.context.view_layer.objects.active = mesh_obj
示例#5
0
 def apply_ob_props(ob: bpy.types.Object,
                    new_name: str = name) -> bpy.types.Object:
     ob.name = new_name
     ob.location = [
         location[0] * 0.01, location[1] * -0.01, location[2] * 0.01
     ]
     ob.rotation_mode = 'XYZ'
     ob.rotation_euler = [
         radians(rotation[2]),
         radians(-rotation[0]),
         radians(-rotation[1])
     ]
     ob.scale = scale
     return ob
示例#6
0
    def from_blender(self, lookup: Lookup, armature: bpy.types.Object,
                     action: bpy.types.Action):
        if not armature:
            frame = RestFrame(self.settings)
            self.frames.append(frame)

        elif not action:
            frame = RestFrame(self.settings)
            frame.from_blender(lookup, armature)
            self.frames.append(frame)

        else:
            if not armature.animation_data:
                new_animation_data = armature.animation_data_create()
            else:
                new_animation_data = None

            original_action = armature.animation_data.action
            armature.animation_data.action = action

            if not original_action:
                pose_backup = {}

                for pose_bone in armature.pose.bones:
                    pose_bone: bpy.types.PoseBone
                    pose_backup[pose_bone] = pose_bone.matrix.copy()

            original_frame = bpy.context.scene.frame_current

            start = int(action.frame_range[0])
            end = int(action.frame_range[1])

            for time in range(start, end + 1):
                bpy.context.scene.frame_set(time)

                frame = PoseFrame(self.settings)
                frame.from_blender(lookup, armature, time)
                self.frames.append(frame)

            bpy.context.scene.frame_set(original_frame)

            if not original_action:
                for pose_bone, matrix in pose_backup.items():
                    pose_bone.matrix = matrix

            if new_animation_data:
                armature.animation_data_clear()
            else:
                armature.animation_data.action = original_action
示例#7
0
 def visible_face_from_vertex(
         vertex: bpy.types.MeshVertex, scene: bpy.types.Scene,
         mesh_object: bpy.types.Object) -> bpy.types.MeshPolygon:
     """Convert the vertex's coordinates into camera space, and check
     whether its coordinates are within the frustum. Then cast a ray at it
     to see whether it's occluded."""
     cam = scene.camera
     cc = world_to_camera_view(scene, cam,
                               mesh_object.matrix_world @ vertex.co)
     cs = cam.data.clip_start
     ce = cam.data.clip_end
     # If the vertex's screen coordinates are within camera view
     if 0.0 < cc.x < 1.0 and 0.0 < cc.y < 1.0 and cs < cc.z < ce:
         # Convert the screen coordinates to a 3D vector
         frame = cam.data.view_frame(scene=scene)
         top_left = frame[3]
         pixel_vector = Vector((cc.x, cc.y, top_left[2]))
         pixel_vector.rotate(cam.matrix_world.to_quaternion())
         # Convert to target object space
         wmatrix_inv = mesh_object.matrix_world.inverted()
         origin = wmatrix_inv @ (pixel_vector +
                                 cam.matrix_world.translation)
         # Destination is the original vertex, in the same object space
         destination = wmatrix_inv @ vertex.co
         direction = (destination - origin).normalized()
         # Cast a ray from those screen coordinates to the vertex
         result, location, normal, index = mesh_object.ray_cast(
             origin, direction)
         if result and index > -1:
             # Return the face the vertex belongs to
             return mesh_object.data.polygons[index]
     return False
def setting_object_duplicate(arg_object: bpy.types.Object) -> bpy.types.Object:
    """指定オブジェクトを複製して複製元の名称を付けるなどの設定を行う

    Args:
        arg_object (bpy.types.Object): 複製元オブジェクト

    Returns:
        bpy.types.Object: 複製オブジェクトの参照
    """

    # 指定オブジェクトが存在するか確認する
    if arg_object == None:
        # 指定オブジェクトが存在しない場合は処理しない
        return None

    # オブジェクトがメッシュであるか確認する
    if arg_object.type != 'MESH':
        # 指定オブジェクトがメッシュでない場合は処理しない
        return None

    # 対象オブジェクトを複製する
    duplicate_object = singlecopy_object_target(arg_object=arg_object)

    # 複製元オブジェクトの名前を取得する
    base_name = arg_object.name

    # 複製元オブジェクトの名前を変更する
    arg_object.name = base_name + "_base"

    # 複製オブジェクトに複製元オブジェクトの名前を設定する
    duplicate_object.name = base_name

    return duplicate_object
示例#9
0
def __get_channel_groups(blender_action: bpy.types.Action, blender_object: bpy.types.Object):
    targets = {}
    for fcurve in blender_action.fcurves:
        target_property = get_target_property_name(fcurve.data_path)
        object_path = get_target_object_path(fcurve.data_path)

        # find the object affected by this action
        if not object_path:
            target = blender_object
        else:
            try:
                target = blender_object.path_resolve(object_path)
            except ValueError:
                # if the object is a mesh and the action target path can not be resolved, we know that this is a morph
                # animation.
                if blender_object.type == "MESH":
                    # if you need the specific shape key for some reason, this is it:
                    # shape_key = blender_object.data.shape_keys.path_resolve(object_path)
                    target = blender_object.data.shape_keys
                else:
                    gltf2_io_debug.print_console("WARNING", "Can not export animations with target {}".format(object_path))
                    continue

        # group channels by target object and affected property of the target
        target_properties = targets.get(target, {})
        channels = target_properties.get(target_property, [])
        channels.append(fcurve)
        target_properties[target_property] = channels
        targets[target] = target_properties

    groups = []
    for p in targets.values():
        groups += list(p.values())

    return map(tuple, groups)
示例#10
0
def disposable_mode(bl_obj: bpy.types.Object, mode='OBJECT'):
    '''
    モードを変更して元のモードに戻る
    '''
    bpy.context.view_layer.objects.active = bl_obj
    bl_obj.select_set(True)

    restore = MODE_MAP[bpy.context.mode]
    try:
        if restore != mode:
            bpy.ops.object.mode_set(mode=mode, toggle=False)
        yield None
    finally:
        if bpy.context.mode != restore:
            bpy.ops.object.mode_set(mode=restore, toggle=False)
        bl_obj.select_set(False)
示例#11
0
    def _get_shapenet_attribute(shapenet_obj: bpy.types.Object,
                                attribute_name: str):
        """ Returns the value of the requested attribute for the given object.

        :param shapenet_obj: The ShapeNet object.
        :param attribute_name: The attribute name.
        :return: The attribute value.
        """

        if attribute_name == "used_synset_id":
            return shapenet_obj.get("used_synset_id", "")
        elif attribute_name == "used_source_id":
            return shapenet_obj.get("used_source_id", "")
        else:
            return WriterUtility.get_common_attribute(shapenet_obj,
                                                      attribute_name)
示例#12
0
    def __init__(self, blenderObject: bpy.types.Object) -> None:
        # When true, keyframes and Custom Animation Properties
        # are included in OBJ
        # True for split parent feature or not visible
        self.export_animation_only = blenderObject.hide_get(
        ) or blenderObject.hide_viewport
        self.blenderObject = blenderObject

        #This is assigned and tied together in in XPlaneBone's constructor
        self.xplaneBone = None  # type: xplane_bone.XPlaneBone
        self.name = blenderObject.name  # type: str
        self.type = self.blenderObject.type  # type: str
        self.datarefs = {}  # type: Dict[str,str]
        self.bakeMatrix = None  # type: Optional[mathutils.Matrix]

        self.attributes = XPlaneAttributes()
        self.cockpitAttributes = XPlaneAttributes()
        self.animAttributes = XPlaneAttributes()
        self.conditions = [
        ]  # type: List[io_xplane2blender.xplane_props.XPlaneCondition]

        # This represents all specializations of lods, on this subject,
        # including it's parents. Set in XPlaneBone's constructor
        self.effective_buckets: Tuple[...] = (False, ) * 4
        for i, dataref in self.blenderObject.xplane.datarefs.items():
            self.datarefs[dataref.path] = dataref

        self.setWeight()
示例#13
0
def object_duplicate_helper(obj: bpy.types.Object,
                            name: str) -> bpy.types.Object:
    """
    オブジェクトに任意の名前をつけて複製するヘルパー 複製したオブジェクトを返す
    """
    _mode = bpy.context.mode
    temp_name = random_name(10)
    orig_name = obj.name
    obj.name = temp_name
    bpy.ops.object.duplicate({"selected_objects": [obj]})
    obj.name = orig_name
    new_obj = bpy.data.objects[temp_name + ".001"]
    new_obj.name = name
    bpy.ops.object.mode_set(mode=_mode)
    new_obj.select_set(False)
    return new_obj
def __gather_node(channels: typing.Tuple[bpy.types.FCurve],
                  blender_object: bpy.types.Object,
                  export_settings,
                  bake_bone: typing.Union[str, None],
                  driver_obj
                  ) -> gltf2_io.Node:

    if driver_obj is not None:
        return gltf2_blender_gather_nodes.gather_node(driver_obj,
            driver_obj.library.name if driver_obj.library else None,
            None, None, export_settings)

    if blender_object.type == "ARMATURE":
        # TODO: get joint from fcurve data_path and gather_joint

        if bake_bone is not None:
            blender_bone = blender_object.pose.bones[bake_bone]
        else:
            blender_bone = blender_object.path_resolve(channels[0].data_path.rsplit('.', 1)[0])

        if isinstance(blender_bone, bpy.types.PoseBone):
            if export_settings["gltf_def_bones"] is False:
                obj = blender_object.proxy if blender_object.proxy else blender_object
                return gltf2_blender_gather_joints.gather_joint(obj, blender_bone, export_settings)
            else:
                bones, _, _ = gltf2_blender_gather_skins.get_bone_tree(None, blender_object)
                if blender_bone.name in [b.name for b in bones]:
                    obj = blender_object.proxy if blender_object.proxy else blender_object
                    return gltf2_blender_gather_joints.gather_jointb(obj, blender_bone, export_settings)

    return gltf2_blender_gather_nodes.gather_node(blender_object,
        blender_object.library.name if blender_object.library else None,
        None, None, export_settings)
示例#15
0
    def generate_evaluated_mesh(self,
                                mesh_object: bpy.types.Object,
                                reference_frame: mathutils.Matrix = None):
        if self.i3d.get_setting('apply_modifiers'):
            self.object = mesh_object.evaluated_get(self.i3d.depsgraph)
            self.logger.debug(f"is exported with modifiers applied")
        else:
            self.object = mesh_object
            self.logger.debug(f"is exported without modifiers applied")

        self.mesh = self.object.to_mesh(preserve_all_data_layers=False,
                                        depsgraph=self.i3d.depsgraph)

        # If a reference is given transform the generated mesh by that frame to place it somewhere else than center of
        # the mesh origo
        if reference_frame is not None:
            self.mesh.transform(
                reference_frame.inverted() @ self.object.matrix_world)

        conversion_matrix = self.i3d.conversion_matrix
        if self.i3d.get_setting('apply_unit_scale'):
            self.logger.debug(f"applying unit scaling")
            conversion_matrix = \
                mathutils.Matrix.Scale(bpy.context.scene.unit_settings.scale_length, 4) @ conversion_matrix

        self.mesh.transform(conversion_matrix)
        if conversion_matrix.is_negative:
            self.mesh.flip_normals()
            self.logger.debug(
                f"conversion matrix is negative, flipping normals")

        # Calculates triangles from mesh polygons
        self.mesh.calc_loop_triangles()
        # Recalculates normals after the scaling has messed with them
        self.mesh.calc_normals_split()
示例#16
0
def export_filepath(ob: bpy.types.Object, ext: str = "fbx") -> Path:
    """
    Generates a valid export file path.

    Args:
        ob (bpy.types.Object): The object at the stem of the path.
        ext (str, optional): The path extension. Defaults to "fbx".

    Returns:
        Path: A WindowsPath to the export file.
    """
    scene = bpy.context.scene
    obj_type = objects.get_type(ob)
    name = ob.name

    if obj_type != "COLLISION":
        name = f"{ob.export_prefix}{name}"

    name = f"{name}.{ext}"

    filepath = Path(bpy.path.abspath(scene.export_path))

    if ob.export_subpath != "":
        ob.export_subpath = ob.export_subpath.lstrip("\\/")
        filepath = filepath / ob.export_subpath

    filepath = filepath / name

    return filepath
示例#17
0
    def export_object(self, parent: Optional[Node], o: bpy.types.Object, indent: str='')->Node:
        node = Node(o.name, o.matrix_world.to_translation(), parent)
        self.nodes.append(node)

        # only mesh
        if o.type == 'MESH':

            # copy
            new_obj = o.copy()
            new_obj.data = o.data.copy()
            bpy.data.scenes[0].objects.link(new_obj)

            mesh = new_obj.data

            # apply modifiers
            for m in new_obj.modifiers:
                if m.type == 'ARMATURE':
                    # skin
                    node.skin = self.get_or_create_skin(node, m.object)

            # export
            bone_names = [
                b.name for b in node.skin.object.data.bones] if node.skin else []
            node.mesh = self.export_mesh(mesh, o.vertex_groups, bone_names)

        elif o.type == 'ARMATURE':
            skin = self.get_or_create_skin(node, o)

        for child in o.children:
            child_node = self.export_object(node, child, indent+self.indent)
            node.children.append(child_node)

        return node
示例#18
0
 def set_object_location(self,
                         position_properties: WorkpiecePosition,
                         scene: bpy.types.Scene,
                         scene_object: bpy.types.Object,
                         selected_objects):
     if position_properties.origin_location == "3D cursor":
         scene_object.location = scene.cursor_location
     elif position_properties.origin_location == "position":
         scene_object.location = position_properties.location_coordinates
     elif position_properties.origin_location == "selected":
         if len(selected_objects) == 1:
             selected = selected_objects[0]
             scene_object.location = selected.location + \
                                     Vector(position_properties.distance)
         else:
             self.report({'WARNING'},
                         "Woodworking: One object should be selected")
示例#19
0
文件: base.py 项目: j20232/bnp
def change_rotation_mode(obj: bpy.types.Object,
                         rotation_mode: str,
                         normalized: bool = True):
    if rotation_mode == "rotation_axis_angle":
        rotation_mode = "AXIS_ANGLE"
    elif rotation_mode == "rotation_quaternion":
        rotation_mode = "QUATERNION"
    elif rotation_mode == "rotation_euler":
        rotation_mode = "XYZ"
    obj.rotation_mode = rotation_mode
    if normalized and obj.rotation_mode == "AXIS_ANGLE":
        axis_angle = normalize_axis_angle(vec2np(obj.rotation_axis_angle))[0]
        obj.rotation_axis_angle = (axis_angle[0], axis_angle[1], axis_angle[2],
                                   axis_angle[3])
    elif normalized and obj.rotation_mode == "QUATERNION":
        quat = normalize_quaternion(vec2np(obj.rotation_quaternion))[0]
        obj.rotation_quaternion = (quat[0], quat[1], quat[2], quat[3])
def set_rotation(blender_object: bpy.types.Object, rotation: Any,
                 rotation_mode: str) -> None:
    """
    Sets the rotation of a Blender Object and takes care of picking which
    rotation type to give the value to
    """
    if rotation_mode == "AXIS_ANGLE":
        assert len(rotation[1]) == 3
        blender_object.rotation_axis_angle = rotation
    elif rotation_mode == "QUATERNION":
        assert len(rotation) == 4
        blender_object.rotation_quaternion = rotation
    elif set(rotation_mode) == {"X", "Y", "Z"}:
        assert len(rotation) == 3
        blender_object.rotation_euler = rotation
    else:
        assert False, "Unsupported rotation mode: " + blender_object.rotation_mode
def project_uv_normal(
        arg_object: bpy.types.Object) -> bpy.types.MeshUVLoopLayer:
    """通常のUV展開を実行する

    Args:
        arg_object (bpy.types.Object): 指定オブジェクト

    Returns:
        bpy.types.MeshUVLoopLayer: 作成UVマップレイヤーの参照
    """

    # 不要なオブジェクトを選択しないように
    # 全てのオブジェクトを走査する
    for ob in bpy.context.scene.objects:
        # 非選択状態に設定する
        ob.select_set(False)

    # オブジェクトを選択状態にする
    arg_object.select_set(True)

    # 対象オブジェクトをアクティブに変更する
    bpy.context.view_layer.objects.active = arg_object

    # 編集モードに移行する
    bpy.ops.object.mode_set(mode='EDIT', toggle=False)

    # 頂点を全選択した状態とする
    bpy.ops.mesh.select_all(action='SELECT')

    # 通常のUV展開を実行する
    # 方式:アングルベース,穴を埋める:True,アスペクト比の補正:True,
    # 細分化モディファイアを使用:False,余白:0.1
    bpy.ops.uv.unwrap(method='ANGLE_BASED',
                      fill_holes=True,
                      correct_aspect=True,
                      use_subsurf_data=False,
                      margin=0.1)

    # オブジェクトモードに移行する
    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

    # 対象オブジェクトに追加されたUVマップを取得する
    active_uvlayer = arg_object.data.uv_layers[-1]

    return active_uvlayer
def sync(rpr_context, obj: bpy.types.Object, **kwargs):
    """ Converts object into blender's mesh and exports it as mesh """

    try:
        # This operation adds new mesh into bpy.data.meshes, that's why it should be removed after usage.
        # obj.to_mesh() could also return None for META objects.
        new_mesh = obj.to_mesh()
        log("sync", obj, new_mesh)

        if new_mesh:
            mesh.sync(rpr_context, obj, mesh=new_mesh, **kwargs)
            return True

        return False

    finally:
        # it's important to clear created mesh
        obj.to_mesh_clear()
示例#23
0
def send_object_visibility(client: Client, object_: bpy.types.Object):
    logger.debug("send_object_visibility %s", object_.name_full)
    buffer = (common.encode_string(object_.name_full) +
              common.encode_bool(object_.hide_viewport) +
              common.encode_bool(object_.hide_select) +
              common.encode_bool(object_.hide_render) +
              common.encode_bool(object_.hide_get()))
    client.add_command(
        common.Command(common.MessageType.OBJECT_VISIBILITY, buffer, 0))
示例#24
0
def GetListOfOrientationsToRender(cameraPoint: bpy.types.Object) -> list:
    """ From blender data, grab all objects of type Orientation
        which have the cameraPoint as their parent. """

    parentId: str = cameraPoint.get("zag.uuid")
    return [
        obj for obj in bpy.data.objects if obj.get("zag.type") == "Orientation"
        and obj.parent.get("zag.uuid") == parentId
    ]
def look_at(obj: bpy.types.Object, target: Vector):
    """Rotate an object such that it looks at a target.

    The object's Y axis will point upwards, and the -Z axis towards the
    target. This is the 'correct' rotation for cameras and lights."""
    t = obj.location
    dir = target - t
    quat = dir.to_track_quat('-Z', 'Y')
    obj.rotation_euler = quat.to_euler()
def bake_frame(ob: bpy.types.Object, frame: int, export_obj=None):
    scene = bpy.context.scene

    shape_name = 'cache__F{:04d}'.format(frame)
    data_path = 'key_blocks["{}"].value'.format(shape_name)

    ## clean out the old keys
    if ob.data.shape_keys.animation_data and ob.data.shape_keys.animation_data.action:
        action = ob.data.shape_keys.animation_data.action
        for curve in action.fcurves:
            if curve.data_path == data_path:
                action.fcurves.remove(curve)
                break

    scene.frame_set(frame)

    mesh = ob.to_mesh(scene, apply_modifiers=True, settings="RENDER")
    shape = add_shape_key(ob, shape_name)

    for index in range(len(ob.data.vertices)):
        shape.data[index].co = mesh.vertices[index].co

    ## this keys them on for the duration of the animation
    shape.value = 0.0
    ob.data.shape_keys.keyframe_insert(data_path, frame=frame - 1)
    shape.value = 1.0
    ob.data.shape_keys.keyframe_insert(data_path, frame=frame)
    shape.value = 0.0
    ob.data.shape_keys.keyframe_insert(data_path, frame=frame + 1)

    if export_obj:
        ## the blender OBJ importer adjusts for Y up in other packages
        ## so rotate the mesh here before export
        rotate_mat = mathutils.Matrix.Rotation(-math.pi / 2, 4, 'X')
        mesh.transform(rotate_mat)

        ## man the OBJ format is simple. No wonder people love it.
        print('+ Exporting frame {} to "{}"'.format(frame, export_obj))
        with open(export_obj, 'w') as fp:
            for v in mesh.vertices:
                fp.write('v {:6f} {:6f} {:6f}\n'.format(
                    v.co[0], v.co[1], v.co[2]))

            ## smoothing
            # fp.write( 's 1\n' )

            for f in mesh.polygons:
                msg = "f"
                for v in f.vertices:
                    msg += ' {:d}'.format(v + 1)
                msg += '\n'
                fp.write(msg)

            ## one extra line at the end
            fp.write('\n')

    bpy.data.meshes.remove(mesh)
def _get_camera_space_bounding_box(context: bpy.types.Context,
                                   camera_obj: bpy.types.Object,
                                   target_obj: bpy.types.Object) -> Bounds2D:
    # TODO support more than just meshes (esp. metaballs)
    if target_obj.type != 'MESH':
        raise Exception(f"Target object {target_obj} is not a mesh")

    # Get latest version of target object with modifiers such as armature applied
    depsgraph = context.evaluated_depsgraph_get()
    target_obj = target_obj.evaluated_get(depsgraph)

    m_obj_to_world = target_obj.matrix_world
    m_world_to_cam = camera_obj.rotation_euler.to_matrix().inverted()

    obj_verts = target_obj.to_mesh().vertices
    cam_verts = [m_world_to_cam @ (m_obj_to_world @ v.co) for v in obj_verts]

    return Bounds2D.from_points(cam_verts)
示例#28
0
 def set_object_rotation(context,
                         position_properties: WorkpiecePosition,
                         scene_object: bpy.types.Object):
     rotations = WorkpieceOperator.visible_surface_rotation(
         position_properties.visible_surface)
     rotations.extend(WorkpieceOperator.view_rotation(
         context,
         position_properties.view))
     rotations.extend(WorkpieceOperator.orientation_rotation(
         context,
         position_properties.orientation,
         position_properties.view))
     scene_object.rotation_mode = 'QUATERNION'
     object_rotations = scene_object.rotation_quaternion.copy()
     for rotation in rotations:
         object_rotations = WorkpieceOperator.quaternion_rotation(
             rotation, object_rotations)
     scene_object.rotation_quaternion = object_rotations
def project_uv_smart(
        arg_object: bpy.types.Object) -> bpy.types.MeshUVLoopLayer:
    """スマートUV展開を実行する

    Args:
        arg_object (bpy.types.Object): 指定オブジェクト

    Returns:
        bpy.types.MeshUVLoopLayer: 作成UVマップレイヤーの参照
    """

    # 不要なオブジェクトを選択しないように
    # 全てのオブジェクトを走査する
    for ob in bpy.context.scene.objects:
        # 非選択状態に設定する
        ob.select_set(False)

    # オブジェクトを選択状態にする
    arg_object.select_set(True)

    # 対象オブジェクトをアクティブに変更する
    bpy.context.view_layer.objects.active = arg_object

    # 編集モードに移行する
    bpy.ops.object.mode_set(mode='EDIT', toggle=False)

    # 頂点を全選択した状態とする
    bpy.ops.mesh.select_all(action='SELECT')

    # スマートUV展開を実行する
    # 角度制限:66,島の余白:0.1,エリアウェイト:0,アスペクト比の補正:True,UV境界に合わせる:True
    bpy.ops.uv.smart_project(angle_limit=66,
                             island_margin=0.1,
                             user_area_weight=0,
                             use_aspect=True,
                             stretch_to_bounds=True)

    # オブジェクトモードに移行する
    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

    # 対象オブジェクトに追加されたUVマップを取得する
    active_uvlayer = arg_object.data.uv_layers[-1]

    return active_uvlayer
示例#30
0
def obj2np(obj: bpy.types.Object, dtype: type = np.float32, apply_modifier: bool = False,
           frame: int = bpy.context.scene.frame_current, geo_type: str = "position",
           is_local: bool = False, as_homogeneous: bool = False, mode: str = "dynamic") -> np.ndarray:
    # Input: obj(bpy.types.Object), Output: positions or normals
    bpy.context.scene.frame_set(frame)
    if type(obj.data) == bpy.types.Mesh :
        if apply_modifier:
            depsgraph = bpy.context.evaluated_depsgraph_get()
            obj = obj.evaluated_get(depsgraph)
            mesh = obj.to_mesh()
            return np.array([vec2np(v.co) for v in mesh.vertices], dtype=dtype)
        world_matrix = world_matrix2np(obj, dtype=dtype)  # (4, 4)
        return mesh2np(obj.data, world_matrix=world_matrix, geo_type=geo_type, dtype=dtype,
                       is_local=is_local, frame=frame, as_homogeneous=as_homogeneous)
    elif type(obj.data) == bpy.types.Armature:
        return armature2np(obj.data, dtype=dtype, mode=mode, frame=frame)
    else:
        raise NotImplementedError(
            f"{type(obj.data)} is not supported with obj2np")
def __gather_node(channels: typing.Tuple[bpy.types.FCurve],
                  blender_object: bpy.types.Object,
                  export_settings
                  ) -> gltf2_io.Node:
    if blender_object.type == "ARMATURE":
        # TODO: get joint from fcurve data_path and gather_joint
        blender_bone = blender_object.path_resolve(channels[0].data_path.rsplit('.', 1)[0])
        return gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings)

    return gltf2_blender_gather_nodes.gather_node(blender_object, export_settings)
示例#32
0
def fix_cube_rotation(obj: bpy.types.Object):
    '''
    Rotate the bounding box of a cuboid so  it's aligned with
    the cube rotation. The scale and rotation of the object must
    be in default position for this function to work.

    :param obj: blender object with cuboid mesh.
    '''
    # Get coordinates of 3 points (a,b and c) from any polygon
    # I'm assuming this is a cuboid so I also can assume that
    # vectors u and v are not planar:
    # u = vector(b, a) and v = (b, c)
    poly = obj.data.polygons[0]

    vertices = obj.data.vertices
    a = vertices[poly.vertices[0]].co
    b = vertices[poly.vertices[1]].co
    c = vertices[poly.vertices[2]].co

    # Calculate the normal vector of the surface with points
    # a, b and c
    u: mathutils.Vector = (a-b).normalized()
    v: mathutils.Vector = (c-b).normalized()

    # The cross product creates the 3rd vector that defines
    # the rotated space
    w = u.cross(v).normalized()
    # Recalculate V to make sure that all of the vectors are at
    # the right angle (even though they should be)
    v = w.cross(u).normalized()

    # Create rotation matrix (unit vectors x, y, z in columns)
    rotation_matrix = mathutils.Matrix((w, v, -u))
    # (w, v, -u) - this order of normals in rotation matrix is set up in
    # such way that applying the operator to the default cube (without
    # rotations) will not change its rotation and won't flip its scale to -1.
    # It will have no effect.


    # Rotate the mesh
    for vertex in obj.data.vertices:
        vertex.co = rotation_matrix @ vertex.co

    # Counter rotate object around its origin
    counter_rotation = rotation_matrix.to_4x4().inverted()

    loc, rot, scl = obj.matrix_local.decompose()
    loc_mat = mathutils.Matrix.Translation(loc)
    rot_mat = rot.to_matrix().to_4x4()
    scl_mat =  (
        mathutils.Matrix.Scale(scl[0],4,(1,0,0)) @
        mathutils.Matrix.Scale(scl[1],4,(0,1,0)) @
        mathutils.Matrix.Scale(scl[2],4,(0,0,1)))

    obj.matrix_local = loc_mat @ counter_rotation @ rot_mat @ scl_mat
示例#33
0
    def from_blender(self, lookup: Lookup, armature: bpy.types.Object,
                     object: bpy.types.Object):
        if object.type not in {'MESH', 'CURVE', 'SURFACE', 'FONT'}:
            return

        collection = bpy.data.collections.new('SourceOps')
        bpy.context.scene.collection.children.link(collection)
        object = object.copy()
        collection.objects.link(object)

        mod: bpy.types.TriangulateModifier = object.modifiers.new(
            'Triangulate', 'TRIANGULATE')
        mod.min_vertices = 4
        mod.quad_method = 'FIXED'
        mod.ngon_method = 'CLIP'
        mod.keep_custom_normals = True

        for mod in getattr(object, 'modifiers', []):
            if mod.type == 'ARMATURE':
                mod.show_viewport = False

        bpy.context.view_layer.update()
        depsgraph: bpy.types.Depsgraph = bpy.context.evaluated_depsgraph_get()
        evaluated: bpy.types.Object = object.evaluated_get(depsgraph)
        mesh = bpy.data.meshes.new_from_object(evaluated,
                                               preserve_all_data_layers=True,
                                               depsgraph=depsgraph)

        if not self.settings.ignore_transforms:
            mesh.transform(object.matrix_world)
        mesh.calc_normals_split()

        for poly in mesh.polygons:
            triangle = Triangle(self.settings)
            triangle.from_blender(lookup, armature, object, mesh, poly)
            self.triangles.append(triangle)

        mesh.free_normals_split()
        bpy.data.meshes.remove(mesh)

        bpy.data.objects.remove(object)
        bpy.data.collections.remove(collection)
def __gather_node(channels: typing.Tuple[bpy.types.FCurve],
                  blender_object: bpy.types.Object,
                  export_settings
                  ) -> gltf2_io.Node:
    if blender_object.type == "ARMATURE":
        # TODO: get joint from fcurve data_path and gather_joint
        blender_bone = blender_object.path_resolve(channels[0].data_path.rsplit('.', 1)[0])
        if isinstance(blender_bone, bpy.types.PoseBone):
            return gltf2_blender_gather_joints.gather_joint(blender_bone, export_settings)

    return gltf2_blender_gather_nodes.gather_node(blender_object, export_settings)
def get_select(obj: bpy.types.Object) -> bool:
    if IS_LEGACY:
        return obj.select

    return obj.select_get()
def set_select(obj: bpy.types.Object, select: bool) -> None:
    if IS_LEGACY:
        obj.select = select
    else:
        obj.select_set(select)
def set_hide(obj: bpy.types.Object, hide: bool):
    if IS_LEGACY:
        obj.hide = hide

    else:
        obj.hide_viewport = hide