Пример #1
0
def add_particles(context, surface_area: float, height: float, coverage: float, snow_object: bpy.types.Object, ballobj: bpy.types.Object):
    # Approximate the number of particles to be emitted
    number = int(surface_area * 50 * (height ** -2) * ((coverage / 100) ** 2))
    bpy.ops.object.particle_system_add()
    particles = snow_object.particle_systems[0]
    psettings = particles.settings
    psettings.type = 'HAIR'
    psettings.render_type = 'OBJECT'
    # Generate random number for seed
    random_seed = random.randint(0, 1000)
    particles.seed = random_seed
    # Set particles object
    psettings.particle_size = height
    psettings.instance_object = ballobj
    psettings.count = number
    # Convert particles to mesh
    bpy.ops.object.select_all(action='DESELECT')
    context.view_layer.objects.active = ballobj
    ballobj.select_set(True)
    bpy.ops.object.convert(target='MESH')
    snow = bpy.context.active_object
    snow.scale = [0.09, 0.09, 0.09]
    bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
    bpy.ops.object.select_all(action='DESELECT')
    snow_object.select_set(True)
    bpy.ops.object.delete()
    snow.select_set(True)
    return snow
Пример #2
0
def export_geom(filepath: str,
                obj: bpy.types.Object,
                keep_vertex_order=True,
                use_selection=True,
                **kwargs):
    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    bpy.ops.object.select_all(action="DESELECT")
    obj.select_set(True)
    ext = filepath.split('.')[-1]
    if ext == "obj":
        bpy.ops.export_scene.obj(filepath=filepath,
                                 keep_vertex_order=keep_vertex_order,
                                 use_selection=use_selection,
                                 **kwargs)
    elif ext == "fbx":
        bpy.ops.export_scene.fbx(filepath=filepath,
                                 use_selection=use_selection,
                                 **kwargs)
    elif ext == "glb":
        bpy.ops.export_scene.gltf(filepath=filepath, **kwargs)
    elif ext == "x3d":
        bpy.ops.export_scene.x3d(filepath=filepath, **kwargs)
    elif ext == "ply":
        bpy.ops.export_mesh.ply(filepath=filepath, **kwargs)
    elif ext == "stl":
        bpy.ops.export_mesh.stl(filepath=filepath, **kwargs)
    else:
        raise Exception("Illegal extension")
    print(f"Exported {obj.name} to {filepath}")
Пример #3
0
def bake_animation(original_obj: bpy.types.Object, first_frame: int,
                   last_frame: int):
    """Bakes animation between given first and last frame.

    Args:
        original_obj (bpy.types.Object): Object to bake
        first_frame (int): First frame
        last_frame (int): Last Frame
    """
    bpy.context.view_layer.objects.active = original_obj
    original_obj.select_set(True)
    original_name = bpy.context.active_object.name

    bpy.context.scene.frame_current = first_frame
    bpy.ops.node.sverchok_update_all()
    bpy.ops.object.duplicate()
    bpy.context.active_object.name = f"Baked_{original_name}"
    bpy.context.active_object.data.name = f"Baked_{original_name}"
    bpy.data.objects[original_name].select_set(state=True)
    bpy.ops.object.join_shapes()

    for act_frame in range(first_frame + 1, last_frame + 1):
        _bake_frame(act_frame)

    bpy.ops.object.select_all(action="DESELECT")
    bpy.context.view_layer.objects.active = None
Пример #4
0
        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()
            # Select faces at given height that should be separate from the mesh
            counter = FloorExtractor.select_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
Пример #5
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
Пример #6
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)
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 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
Пример #9
0
 def apply(o: bpy.types.Object):
     o.select_set(True)
     bpy.ops.object.transform_apply(location=False,
                                    rotation=True,
                                    scale=False)
     o.select_set(False)
Пример #10
0
def set_select(obj: bpy.types.Object, select: bool) -> None:
    if IS_LEGACY:
        obj.select = select
    else:
        obj.select_set(select)
Пример #11
0
def setup_material(material: bpy.types.Material,
                   empty: bpy.types.Object = None):
    """Setup material nodes for the metal tool cap"""
    # TODO: refactor into smaller node-creation functions that can be re-used elsewhere

    # logger = get_logger()
    tree = material.node_tree
    nodes = tree.nodes

    # check if we have default nodes
    n_output, n_bsdf = mutil.check_default_material(material)

    # set BSDF default values
    n_bsdf.inputs['Subsurface'].default_value = 0.6
    n_bsdf.inputs['Subsurface Color'].default_value = (0.8, 0.444, 0.444, 1.0)
    n_bsdf.inputs['Metallic'].default_value = 1.0

    # thin metallic surface lines (used primarily for normal/bump map computation)
    n_texcoord_bump = nodes.new('ShaderNodeTexCoord')
    # setup empty (reference for distance computations)
    if empty is None:
        # get currently selected object
        obj = bpy.context.object

        # add empty
        bpy.ops.object.empty_add(type='PLAIN_AXES')
        empty = bpy.context.object

        # locate at the top of the object
        v0 = Vector(obj.bound_box[1])
        v1 = Vector(obj.bound_box[2])
        v2 = Vector(obj.bound_box[5])
        v3 = Vector(obj.bound_box[6])
        empty.location = (v0 + v1 + v2 + v3) / 4
        # rotate into object space. afterwards we'll have linkage via parenting
        empty.location = obj.matrix_world @ empty.location
        # copy rotation
        empty.rotation_euler = obj.rotation_euler

        # deselect all
        bpy.ops.object.select_all(action='DESELECT')

        # take care to re-select everything
        empty.select_set(state=True)
        obj.select_set(state=True)

        # make obj active again (will become parent of all selected objects)
        bpy.context.view_layer.objects.active = obj

        # make parent, keep transform
        bpy.ops.object.parent_set(type='OBJECT',
                                  xmirror=False,
                                  keep_transform=True)
    # set the empty as input for the texture
    n_texcoord_bump.object = empty

    # (dot)^2 (distance from empty)
    n_dot = nodes.new('ShaderNodeVectorMath')
    n_dot.operation = 'DOT_PRODUCT'
    tree.links.new(n_texcoord_bump.outputs['Object'], n_dot.inputs[0])
    tree.links.new(n_texcoord_bump.outputs['Object'], n_dot.inputs[1])

    n_pow = nodes.new('ShaderNodeMath')
    n_pow.operation = 'POWER'
    tree.links.new(n_dot.outputs[1], n_pow.inputs[0])

    # mapping input from empty to noise
    n_mapping = nodes.new('ShaderNodeMapping')
    tree.links.new(n_texcoord_bump.outputs['Object'], n_mapping.inputs[0])

    # generate and link up required noise textures
    n_noise0 = nodes.new('ShaderNodeTexNoise')
    n_noise0.inputs['Scale'].default_value = 1.0
    n_noise0.inputs['Detail'].default_value = 1.0
    n_noise0.inputs['Distortion'].default_value = 2.0
    tree.links.new(n_pow.outputs[0], n_noise0.inputs[0])

    n_noise1 = nodes.new('ShaderNodeTexNoise')
    n_noise1.inputs['Scale'].default_value = 300.0
    n_noise1.inputs['Detail'].default_value = 0.0
    n_noise1.inputs['Distortion'].default_value = 0.0
    tree.links.new(n_pow.outputs[0], n_noise1.inputs[0])

    # XXX: is this noise required?
    n_noise2 = nodes.new('ShaderNodeTexNoise')
    n_noise2.inputs['Scale'].default_value = 0.0
    n_noise2.inputs['Detail'].default_value = 0.0
    n_noise2.inputs['Distortion'].default_value = 0.1
    tree.links.new(n_mapping.outputs['Vector'], n_noise2.inputs[0])

    n_noise3 = nodes.new('ShaderNodeTexNoise')
    n_noise3.inputs['Scale'].default_value = 5.0
    n_noise3.inputs['Detail'].default_value = 2.0
    n_noise3.inputs['Distortion'].default_value = 0.0
    tree.links.new(n_mapping.outputs['Vector'], n_noise3.inputs[0])

    # color output
    n_colorramp_col = nodes.new('ShaderNodeValToRGB')
    n_colorramp_col.color_ramp.color_mode = 'RGB'
    n_colorramp_col.color_ramp.interpolation = 'LINEAR'
    n_colorramp_col.color_ramp.elements[0].position = 0.118
    n_colorramp_col.color_ramp.elements[1].position = 0.727
    tree.links.new(n_noise0.outputs['Fac'], n_colorramp_col.inputs['Fac'])

    n_output_color = nodes.new('ShaderNodeMixRGB')
    n_output_color.inputs['Fac'].default_value = 0.400
    n_output_color.inputs['Color1'].default_value = (0.485, 0.485, 0.485, 1.0)
    tree.links.new(n_colorramp_col.outputs['Color'],
                   n_output_color.inputs['Color2'])

    # roughness finish
    n_mul_r = nodes.new('ShaderNodeMath')
    n_mul_r.operation = 'MULTIPLY'
    n_mul_r.inputs[1].default_value = 0.100
    tree.links.new(n_noise3.outputs['Fac'], n_mul_r.inputs[0])

    n_output_roughness = nodes.new('ShaderNodeMath')
    n_output_roughness.operation = 'ADD'
    n_output_roughness.inputs[1].default_value = 0.050
    tree.links.new(n_mul_r.outputs[0], n_output_roughness.inputs[0])

    # math nodes to mix noise with distance and get ring-effect (modulo), leading to bump map
    n_add0 = nodes.new('ShaderNodeMath')
    n_add0.operation = 'ADD'
    tree.links.new(n_pow.outputs[0], n_add0.inputs[0])
    tree.links.new(n_noise2.outputs['Fac'], n_add0.inputs[1])

    n_mul0 = nodes.new('ShaderNodeMath')
    n_mul0.operation = 'MULTIPLY'
    n_mul0.inputs[1].default_value = 300.000
    tree.links.new(n_add0.outputs[0], n_mul0.inputs[0])

    n_mod0 = nodes.new('ShaderNodeMath')
    n_mod0.operation = 'MODULO'
    n_mod0.inputs[1].default_value = 2.000
    tree.links.new(n_mul0.outputs[0], n_mod0.inputs[0])

    n_mul1 = nodes.new('ShaderNodeMath')
    n_mul1.operation = 'MULTIPLY'
    tree.links.new(n_noise1.outputs['Fac'], n_mul1.inputs[0])
    tree.links.new(n_mod0.outputs[0], n_mul1.inputs[1])

    n_min_n = nodes.new('ShaderNodeMath')
    n_min_n.operation = 'MINIMUM'
    tree.links.new(n_noise1.outputs['Fac'], n_min_n.inputs[0])
    tree.links.new(n_mul1.outputs[0], n_min_n.inputs[1])

    n_colorramp_rough = nodes.new('ShaderNodeValToRGB')
    n_colorramp_rough.color_ramp.color_mode = 'RGB'
    n_colorramp_rough.color_ramp.interpolation = 'LINEAR'
    n_colorramp_rough.color_ramp.elements[0].position = 0.159
    n_colorramp_rough.color_ramp.elements[1].position = 0.541
    tree.links.new(n_min_n.outputs[0], n_colorramp_rough.inputs[0])

    n_output_normal = nodes.new('ShaderNodeBump')
    n_output_normal.inputs['Strength'].default_value = 0.075
    n_output_normal.inputs['Distance'].default_value = 1.000
    tree.links.new(n_colorramp_rough.outputs['Color'],
                   n_output_normal.inputs['Height'])

    # output nodes:
    #   n_output_color -> color / outputs['Color']
    #   n_output_roughness -> roughness / outputs['Value']
    #   n_output_normal -> normal / outputs['Normal']
    # hook to bsdf shader node
    tree.links.new(n_output_color.outputs['Color'],
                   n_bsdf.inputs['Base Color'])
    tree.links.new(n_output_roughness.outputs['Value'],
                   n_bsdf.inputs['Roughness'])
    tree.links.new(n_output_normal.outputs['Normal'], n_bsdf.inputs['Normal'])
Пример #12
0
def set_select(obj: bpy.types.Object, select: bool) -> None:
    if IS_LEGACY:
        obj.select = select
    else:
        obj.select_set(select)
def bake_roughness_only(arg_object: bpy.types.Object,
                        arg_refobjects: list = [],
                        arg_bakemargin: int = 0,
                        arg_onesample: bool = False,
                        arg_GPUuse: bool = False):
    """指定オブジェクトのカラー情報のみをベイクする

    Args:
        arg_object (bpy.types.Object): 指定オブジェクト
        arg_refobjects (list): ベイク参照元オブジェクトリスト. Defaults to [].
        arg_bakemargin (int, optional): ベイク余白. Defaults to 0.
        arg_onesample (bool, optional): 簡易サンプリング指定. Defaults to False.
        arg_GPUuse (bool, optional): GPU利用指定. Defaults to False.
    """

    # [選択->アクティブ]のベイクフラグを作成する
    selected_to_active = False

    # 参照元オブジェクトが設定されているか確認する
    if len(arg_refobjects) > 0:
        # 参照元オブジェクトが設定されている場合は[選択->アクティブ]のベイクを実行する
        selected_to_active = True

    # 全てのオブジェクトを非選択状態にする
    for obj in bpy.context.scene.objects:
        # 選択状態を解除する
        obj.select_set(False)

    # [選択->アクティブ]のベイクか確認する
    if selected_to_active == True:
        # 参照元オブジェクトリストを走査する
        for refobject in arg_refobjects:
            # [選択->アクティブ]のベイクの場合、参照元オブジェクトを選択状態にする
            refobject.select_set(True)

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

    # 指定オブジェクトをアクティブにする
    bpy.context.view_layer.objects.active = arg_object

    # レンダリングエンジンを CYCLES に切り替える
    bpy.context.scene.render.engine = 'CYCLES'

    # GPUの利用有無を確認する
    if arg_GPUuse == True:
        # 利用設定ならGPUの設定を行う
        bpy.context.scene.cycles.device = 'GPU'
        # CUDAを選択する
        bpy.context.preferences.addons[
            'cycles'].preferences.compute_device_type = 'CUDA'
        # デバイスの一覧を取得する
        for devices in bpy.context.preferences.addons[
                'cycles'].preferences.get_devices():
            for device in devices:
                # デバイスタイプがCUDAならば利用対象とする
                if device.type == 'CUDA':
                    device.use = True

    # render.bake の設定項目を予め設定する
    bake_setting = bpy.context.scene.render.bake

    # [選択->アクティブ]のベイクか確認する
    if selected_to_active == True:
        # [選択->アクティブ]のベイクを有効化する
        bake_setting.use_selected_to_active = True

        # レイの距離を 0.001 (近距離)に設定する
        bake_setting.cage_extrusion = 0.01
    else:
        # [選択->アクティブ]のベイクを無効化する
        bake_setting.use_selected_to_active = False

    # 現在のサンプリング数を記録する
    current_samples = bpy.context.scene.cycles.samples
    current_preview_samples = bpy.context.scene.cycles.preview_samples

    # 簡易サンプリングが有効かチェックする
    if arg_onesample == True:
        # サンプリング数を減らす
        bpy.context.scene.cycles.samples = 1
        bpy.context.scene.cycles.preview_samples = 1

    # 「粗さ」タイプのベイクを実行する
    # ベイクの種類
    # ('COMBINED', 'AO', 'SHADOW', 'NORMAL', 'UV', 'ROUGHNESS',
    # 'EMIT', 'ENVIRONMENT', 'DIFFUSE', 'GLOSSY', 'TRANSMISSION')
    # (render.bake 以外の設定は引数で指定する必要あり)
    bpy.ops.object.bake(type='ROUGHNESS', margin=arg_bakemargin)

    # サンプリング数を元に戻す
    bpy.context.scene.cycles.samples = current_samples
    bpy.context.scene.cycles.preview_samples = current_preview_samples

    return
Пример #14
0
def create_armature_mesh(scene: bpy.types.Scene,
                         armature_object: bpy.types.Object,
                         mesh_name: str) -> bpy.types.Object:
    assert armature_object.type == 'ARMATURE', 'Error'
    assert len(armature_object.data.bones) != 0, 'Error'

    def add_rigid_vertex_group(target_object: bpy.types.Object, name: str,
                               vertex_indices: Iterable[int]) -> None:
        new_vertex_group = target_object.vertex_groups.new(name=name)
        for vertex_index in vertex_indices:
            new_vertex_group.add([vertex_index], 1.0, 'REPLACE')

    def generate_bone_mesh_pydata(
            radius: float,
            length: float) -> Tuple[List[mathutils.Vector], List[List[int]]]:
        base_radius = radius
        top_radius = 0.5 * radius

        vertices = [
            # Cross section of the base part
            mathutils.Vector((-base_radius, 0.0, +base_radius)),
            mathutils.Vector((+base_radius, 0.0, +base_radius)),
            mathutils.Vector((+base_radius, 0.0, -base_radius)),
            mathutils.Vector((-base_radius, 0.0, -base_radius)),

            # Cross section of the top part
            mathutils.Vector((-top_radius, length, +top_radius)),
            mathutils.Vector((+top_radius, length, +top_radius)),
            mathutils.Vector((+top_radius, length, -top_radius)),
            mathutils.Vector((-top_radius, length, -top_radius)),

            # End points
            mathutils.Vector((0.0, -base_radius, 0.0)),
            mathutils.Vector((0.0, length + top_radius, 0.0))
        ]

        faces = [
            # End point for the base part
            [8, 1, 0],
            [8, 2, 1],
            [8, 3, 2],
            [8, 0, 3],

            # End point for the top part
            [9, 4, 5],
            [9, 5, 6],
            [9, 6, 7],
            [9, 7, 4],

            # Side faces
            [0, 1, 5, 4],
            [1, 2, 6, 5],
            [2, 3, 7, 6],
            [3, 0, 4, 7],
        ]

        return vertices, faces

    armature_data: bpy.types.Armature = armature_object.data

    vertices: List[mathutils.Vector] = []
    faces: List[List[int]] = []
    vertex_groups: List[Dict[str, Any]] = []

    for bone in armature_data.bones:
        radius = 0.10 * (0.10 + bone.length)
        temp_vertices, temp_faces = generate_bone_mesh_pydata(
            radius, bone.length)

        vertex_index_offset = len(vertices)

        temp_vertex_group = {'name': bone.name, 'vertex_indices': []}
        for local_index, vertex in enumerate(temp_vertices):
            if bpy.app.version >= (2, 80, 0):
                vertices.append(bone.matrix_local @ vertex)
            else:
                vertices.append(bone.matrix_local * vertex)
            temp_vertex_group['vertex_indices'].append(local_index +
                                                       vertex_index_offset)
        vertex_groups.append(temp_vertex_group)

        for face in temp_faces:
            if len(face) == 3:
                faces.append([
                    face[0] + vertex_index_offset,
                    face[1] + vertex_index_offset,
                    face[2] + vertex_index_offset,
                ])
            else:
                faces.append([
                    face[0] + vertex_index_offset,
                    face[1] + vertex_index_offset,
                    face[2] + vertex_index_offset,
                    face[3] + vertex_index_offset,
                ])

    new_object = create_mesh_from_pydata(scene, vertices, faces, mesh_name,
                                         mesh_name)
    new_object.matrix_world = armature_object.matrix_world

    for vertex_group in vertex_groups:
        add_rigid_vertex_group(new_object, vertex_group['name'],
                               vertex_group['vertex_indices'])

    armature_modifier = new_object.modifiers.new('Armature', 'ARMATURE')
    armature_modifier.object = armature_object
    armature_modifier.use_vertex_groups = True

    add_subdivision_surface_modifier(new_object, 1, is_simple=True)
    add_subdivision_surface_modifier(new_object, 2, is_simple=False)

    # Set the armature as the parent of the new object
    bpy.ops.object.select_all(action='DESELECT')
    if bpy.app.version >= (2, 80, 0):
        new_object.select_set(True)
        armature_object.select_set(True)
        bpy.context.view_layer.objects.active = armature_object
    else:
        new_object.select = True
        armature_object.select = True
        bpy.context.scene.objects.active = armature_object
    bpy.ops.object.parent_set(type='OBJECT')

    return new_object
Пример #15
0
def only_select(obj: bpy.types.Object):
    '''Make object the only one selected. Requires object mode.'''
    bpy.ops.object.select_all(action='DESELECT')
    obj.select_set(True)
def bake_ambientocclusion(arg_object: bpy.types.Object,
                          arg_bakemargin: int = 0,
                          arg_onesample: bool = False,
                          arg_GPUuse: bool = False,
                          arg_aofactor: float = 1.0,
                          arg_distance: float = 10.0):
    """指定オブジェクトのアンビエントオクルージョンをベイクする

    Args:
        arg_object (bpy.types.Object): 指定オブジェクト
        arg_bakemargin (int, optional): ベイク余白. Defaults to 0.
        arg_onesample (bool, optional): 簡易サンプリング指定. Defaults to False.
        arg_GPUuse (bool, optional): GPU利用指定. Defaults to False.
        arg_aofactor (float, optional): AO係数. Defaults to 1.0.
        arg_distance (float, optional): AO距離. Defaults to 10.0.
    """

    # 全てのオブジェクトを非選択状態にする
    for obj in bpy.context.scene.objects:
        # 選択状態を解除する
        obj.select_set(False)

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

    # 指定オブジェクトをアクティブにする
    bpy.context.view_layer.objects.active = arg_object

    # レンダリングエンジンを CYCLES に切り替える
    bpy.context.scene.render.engine = 'CYCLES'

    # GPUの利用有無を確認する
    if arg_GPUuse == True:
        # 利用設定ならGPUの設定を行う
        bpy.context.scene.cycles.device = 'GPU'
        # CUDAを選択する
        bpy.context.preferences.addons[
            'cycles'].preferences.compute_device_type = 'CUDA'
        # デバイスの一覧を取得する
        for devices in bpy.context.preferences.addons[
                'cycles'].preferences.get_devices():
            for device in devices:
                # デバイスタイプがCUDAならば利用対象とする
                if device.type == 'CUDA':
                    device.use = True

    # render.bake の設定項目を予め設定する
    bake_setting = bpy.context.scene.render.bake

    # [選択->アクティブ]のベイクを無効化する
    bake_setting.use_selected_to_active = False

    # 現在のワールド参照を取得する
    context_world = bpy.context.scene.world

    # アンビエントオクルージョンを有効化する
    context_world.light_settings.use_ambient_occlusion = True

    # 係数の設定を行う
    context_world.light_settings.ao_factor = arg_aofactor

    # 距離の設定を行う
    context_world.light_settings.distance = arg_distance

    # 現在のサンプリング数を記録する
    current_samples = bpy.context.scene.cycles.samples
    current_preview_samples = bpy.context.scene.cycles.preview_samples

    # 簡易サンプリングが有効かチェックする
    if arg_onesample == True:
        # サンプリング数を減らす
        bpy.context.scene.cycles.samples = 1
        bpy.context.scene.cycles.preview_samples = 1

    # ディフューズタイプのベイクを実行する
    # ベイクの種類
    # ('COMBINED', 'AO', 'SHADOW', 'NORMAL', 'UV', 'ROUGHNESS',
    # 'EMIT', 'ENVIRONMENT', 'DIFFUSE', 'GLOSSY', 'TRANSMISSION')
    # (render.bake 以外の設定は引数で指定する必要あり)
    bpy.ops.object.bake(type='AO', margin=arg_bakemargin)

    # サンプリング数を元に戻す
    bpy.context.scene.cycles.samples = current_samples
    bpy.context.scene.cycles.preview_samples = current_preview_samples

    return
Пример #17
0
def only_visible(obj: bpy.types.Object):
    '''Make object the only one selected and visible. Requires object mode.'''
    bpy.ops.object.select_all(action='DESELECT')
    obj.select_set(True)
    bpy.ops.object.hide_view_set(unselected=True)