def duplicate_asset(source, **kwargs):
    '''Duplicate asset when it's already appended in the scene, so that blender's append doesn't create duplicated data.'''

    # we need to save selection
    sel = utils.selection_get()
    bpy.ops.object.select_all(action='DESELECT')

    # check visibility
    obs = utils.get_hierarchy(source)
    if not check_all_visible(obs):
        return None
    # check selectability and select in one run
    if not check_selectible(obs):
        return None

    # duplicate the asset objects
    bpy.ops.object.duplicate(linked=True)

    nobs = bpy.context.selected_objects[:]
    #get parent
    for ob in nobs:
        if ob.parent not in nobs:
            parent = ob
            break
    # restore original selection
    utils.selection_set(sel)
    return parent, nobs
Esempio n. 2
0
def append_objects(file_name,
                   obnames=[],
                   location=(0, 0, 0),
                   link=False,
                   **kwargs):
    '''append objects into scene individually'''

    with bpy.data.libraries.load(file_name, link=link,
                                 relative=True) as (data_from, data_to):
        sobs = []
        for ob in data_from.objects:
            if ob in obnames or obnames == []:
                sobs.append(ob)
        data_to.objects = sobs
        # data_to.objects = data_from.objects#[name for name in data_from.objects if name.startswith("house")]

    # link them to scene
    scene = bpy.context.scene
    sel = utils.selection_get()
    bpy.ops.object.select_all(action='DESELECT')

    return_obs = [
    ]  # this might not be needed, but better be sure to rewrite the list.
    main_object = None
    hidden_objects = []
    #
    for obj in data_to.objects:
        if obj is not None:
            # if obj.name not in scene.objects:
            scene.collection.objects.link(obj)
            if obj.parent is None:
                obj.location = location
                main_object = obj
            obj.select_set(True)
            # we need to unhide object so make_local op can use those too.
            if link == True:
                if obj.hide_viewport:
                    hidden_objects.append(obj)
                    obj.hide_viewport = False
            return_obs.append(obj)
    # Only after all objects are in scene! Otherwise gets broken relationships
    if link == True:
        bpy.ops.object.make_local(type='SELECT_OBJECT')
        for ob in hidden_objects:
            ob.hide_viewport = True

    if kwargs.get('rotation') is not None:
        main_object.rotation_euler = kwargs['rotation']

    if kwargs.get('parent') is not None:
        main_object.parent = bpy.data.objects[kwargs['parent']]
        main_object.matrix_world.translation = location

    bpy.ops.object.select_all(action='DESELECT')

    utils.selection_set(sel)

    return main_object, return_obs
Esempio n. 3
0
def link_collection(file_name,
                    obnames=[],
                    location=(0, 0, 0),
                    link=False,
                    parent=None,
                    **kwargs):
    '''link an instanced group - model type asset'''
    sel = utils.selection_get()

    with bpy.data.libraries.load(file_name, link=link,
                                 relative=True) as (data_from, data_to):
        scols = []
        for col in data_from.collections:
            if col == kwargs['name']:
                data_to.collections = [col]

    rotation = (0, 0, 0)
    if kwargs.get('rotation') is not None:
        rotation = kwargs['rotation']

    bpy.ops.object.empty_add(type='PLAIN_AXES',
                             location=location,
                             rotation=rotation)
    main_object = bpy.context.view_layer.objects.active
    main_object.instance_type = 'COLLECTION'

    if parent is not None:
        main_object.parent = bpy.data.objects.get(parent)

    main_object.matrix_world.translation = location

    for col in bpy.data.collections:
        if col.library is not None:
            fp = bpy.path.abspath(col.library.filepath)
            fp1 = bpy.path.abspath(file_name)
            if fp == fp1:
                main_object.instance_collection = col
                break

    #sometimes, the lib might already  be without the actual link.
    if not main_object.instance_collection and kwargs['name']:
        col = bpy.data.collections.get(kwargs['name'])
        if col:
            main_object.instance_collection = col

    main_object.name = main_object.instance_collection.name

    # bpy.ops.wm.link(directory=file_name + "/Collection/", filename=kwargs['name'], link=link, instance_collections=True,
    #                 autoselect=True)
    # main_object = bpy.context.view_layer.objects.active
    # if kwargs.get('rotation') is not None:
    #     main_object.rotation_euler = kwargs['rotation']
    # main_object.location = location

    utils.selection_set(sel)
    return main_object, []
Esempio n. 4
0
def append_particle_system(file_name,
                           obnames=[],
                           location=(0, 0, 0),
                           link=False,
                           **kwargs):
    '''link an instanced group - model type asset'''

    pss = []
    with bpy.data.libraries.load(file_name, link=link,
                                 relative=True) as (data_from, data_to):
        for ps in data_from.particles:
            pss.append(ps)
        data_to.particles = pss

    s = bpy.context.scene
    sel = utils.selection_get()

    target_object = bpy.context.scene.objects.get(kwargs['target_object'])
    if target_object is not None and target_object.type == 'MESH':
        target_object.select_set(True)
        bpy.context.view_layer.objects.active = target_object

        for ps in pss:
            # now let's tune this ps to the particular objects area:
            totarea = 0
            for p in target_object.data.polygons:
                totarea += p.area
            count = int(ps.count * totarea)
            if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
                total_count = count * ps.rendered_child_count
                disp_count = count * ps.child_nbr
            else:
                total_count = count
            threshold = 2000
            total_max_threshold = 50000
            # emitting too many parent particles just kills blender now:
            if count > total_max_threshold:
                ratio = round(count / total_max_threshold)

                if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
                    ps.rendered_child_count *= ratio
                else:
                    ps.child_type = 'INTERPOLATED'
                    ps.rendered_child_count = ratio
                count = max(2, int(count / ratio))
            ps.display_percentage = min(
                ps.display_percentage,
                max(1, int(100 * threshold / total_count)))

            ps.count = count
            bpy.ops.object.particle_system_add()
            target_object.particle_systems[-1].settings = ps

        target_object.select_set(False)
    utils.selection_set(sel)
    return target_object, []
def link_group(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs):
    '''link an instanced group - model type asset'''
    sel = utils.selection_get()
    bpy.ops.wm.link(directory=file_name + "/Collection/", filename=kwargs['name'], link=link, instance_collections=True,
                    autoselect=True)

    main_object = bpy.context.active_object
    if kwargs.get('rotation') is not None:
        main_object.rotation_euler = kwargs['rotation']
    main_object.location = location
    utils.selection_set(sel)
    return main_object, []
Esempio n. 6
0
def link_group(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs):
    '''link an instanced group - model type asset'''
    sel = utils.selection_get()
    bpy.ops.wm.link(directory=file_name + "/Collection/", filename=kwargs['name'], link=link, instance_collections=True,
                    autoselect=True)

    main_object = bpy.context.active_object
    if kwargs.get('rotation') is not None:
        main_object.rotation_euler = kwargs['rotation']
    main_object.location = location
    utils.selection_set(sel)
    return main_object, []
Esempio n. 7
0
def append_particle_system(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs):
    '''link an instanced group - model type asset'''

    pss = []
    with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
        for ps in data_from.particles:
            pss.append(ps)
        data_to.particles = pss

    s = bpy.context.scene
    sel = utils.selection_get()

    target_object = bpy.context.scene.objects.get(kwargs['target_object'])
    if target_object is not None and target_object.type == 'MESH':
        target_object.select_set(True)
        bpy.context.view_layer.objects.active = target_object

        for ps in pss:
            # now let's tune this ps to the particular objects area:
            totarea = 0
            for p in target_object.data.polygons:
                totarea += p.area
            count = int(ps.count * totarea)
            if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
                total_count = count * ps.rendered_child_count
                disp_count = count * ps.child_nbr
            else:
                total_count = count
            threshold = 2000
            total_max_threshold = 50000
            # emitting too many parent particles just kills blender now:
            if count > total_max_threshold:
                ratio = round(count / total_max_threshold)

                if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
                    ps.rendered_child_count *= ratio
                else:
                    ps.child_type = 'INTERPOLATED'
                    ps.rendered_child_count = ratio
                count = max(2, int(count / ratio))
            ps.display_percentage = min(ps.display_percentage, max(1, int(100 * threshold / total_count)))

            ps.count = count
            bpy.ops.object.particle_system_add()
            target_object.particle_systems[-1].settings = ps

        target_object.select_set(False)
    utils.selection_set(sel)
    return target_object, []
Esempio n. 8
0
def append_objects(file_name, obnames=[], location=(0, 0, 0), link=False, **kwargs):
    '''append objects into scene individually'''
    with bpy.data.libraries.load(file_name, link=link, relative=True) as (data_from, data_to):
        sobs = []
        for ob in data_from.objects:
            if ob in obnames or obnames == []:
                sobs.append(ob)
        data_to.objects = sobs
        # data_to.objects = data_from.objects#[name for name in data_from.objects if name.startswith("house")]

    # link them to scene
    scene = bpy.context.scene
    sel = utils.selection_get()
    bpy.ops.object.select_all(action='DESELECT')

    return_obs = []  # this might not be needed, but better be sure to rewrite the list.
    main_object = None
    hidden_objects = []
    #
    for obj in data_to.objects:
        if obj is not None:
            # if obj.name not in scene.objects:
            scene.collection.objects.link(obj)
            if obj.parent is None:
                obj.location = location
                main_object = obj
            obj.select_set(True)
            # we need to unhide object so make_local op can use those too.
            if link == True:
                if obj.hide_viewport:
                    hidden_objects.append(obj)
                    obj.hide_viewport = False
            return_obs.append(obj)

    # Only after all objects are in scene! Otherwise gets broken relationships
    if link == True:
        bpy.ops.object.make_local(type='SELECT_OBJECT')
        for ob in hidden_objects:
            ob.hide_viewport = True

    if kwargs.get('rotation') is not None:
        main_object.rotation_euler = kwargs['rotation']
    bpy.ops.object.select_all(action='DESELECT')

    utils.selection_set(sel)
    return main_object, return_obs
Esempio n. 9
0
def append_particle_system(file_name,
                           obnames=[],
                           location=(0, 0, 0),
                           link=False,
                           **kwargs):
    '''link an instanced group - model type asset'''

    pss = []
    with bpy.data.libraries.load(file_name, link=link,
                                 relative=True) as (data_from, data_to):
        for ps in data_from.particles:
            pss.append(ps)
        data_to.particles = pss

    s = bpy.context.scene
    sel = utils.selection_get()

    target_object = bpy.context.scene.objects.get(kwargs['target_object'])
    if target_object is not None and target_object.type == 'MESH':
        target_object.select_set(True)
        bpy.context.view_layer.objects.active = target_object

        for ps in pss:
            # now let's tune this ps to the particular objects area:
            totarea = 0
            for p in target_object.data.polygons:
                totarea += p.area
            count = int(ps.count * totarea)

            if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
                total_count = count * ps.rendered_child_count
                disp_count = count * ps.child_nbr
            else:
                total_count = count

            bbox_threshold = 25000
            display_threshold = 200000
            total_max_threshold = 2000000
            # emitting too many parent particles just kills blender now.

            #this part tuned child count, we'll leave children to artists only.
            # if count > total_max_threshold:
            #     ratio = round(count / total_max_threshold)
            #
            #     if ps.child_type in ('INTERPOLATED', 'SIMPLE'):
            #         ps.rendered_child_count *= ratio
            #     else:
            #         ps.child_type = 'INTERPOLATED'
            #         ps.rendered_child_count = ratio
            #     count = max(2, int(count / ratio))

            #1st level of optimizaton - switch t bounding boxes.
            if total_count > bbox_threshold:
                target_object.display_type = 'BOUNDS'
            # 2nd level of optimization - reduce percentage of displayed particles.
            ps.display_percentage = min(
                ps.display_percentage,
                max(1, int(100 * display_threshold / total_count)))
            #here we can also tune down number of children displayed.
            #set the count
            ps.count = count
            #add the modifier
            bpy.ops.object.particle_system_add()
            # 3rd level - hide particle system from viewport - is done on the modifier..
            if total_count > total_max_threshold:
                target_object.modifiers[-1].show_viewport = False

            target_object.particle_systems[-1].settings = ps

        target_object.select_set(False)
    utils.selection_set(sel)
    return target_object, []
Esempio n. 10
0
def append_objects(file_name,
                   obnames=[],
                   location=(0, 0, 0),
                   link=False,
                   **kwargs):
    '''append objects into scene individually'''
    #simplified version of append
    if kwargs.get('name'):
        # by now used for appending into scene
        scene = bpy.context.scene
        sel = utils.selection_get()
        bpy.ops.object.select_all(action='DESELECT')

        path = file_name + "\\Collection\\"
        collection_name = kwargs.get('name')
        fc = utils.get_fake_context(bpy.context, area_type='VIEW_3D')
        bpy.ops.wm.append(fc, filename=collection_name, directory=path)

        return_obs = []
        to_hidden_collection = []
        collection = None
        for ob in bpy.context.scene.objects:
            if ob.select_get():
                return_obs.append(ob)
                if not ob.parent:
                    main_object = ob
                    ob.location = location
                # check for object that should be hidden
                if ob.users_collection[0].name == collection_name:
                    collection = ob.users_collection[0]
                else:
                    to_hidden_collection.append(ob)

        if kwargs.get('rotation'):
            main_object.rotation_euler = kwargs['rotation']

        if kwargs.get('parent') is not None:
            main_object.parent = bpy.data.objects[kwargs['parent']]
            main_object.matrix_world.translation = location

        #move objects that should be hidden to a sub collection
        if len(to_hidden_collection) > 0 and collection is not None:
            hidden_collection_name = collection_name + '_hidden'
            h_col = bpy.data.collections.new(name=hidden_collection_name)
            collection.children.link(h_col)
            for ob in to_hidden_collection:
                ob.users_collection[0].objects.unlink(ob)
                h_col.objects.link(ob)
            utils.exclude_collection(hidden_collection_name)

        bpy.ops.object.select_all(action='DESELECT')
        utils.selection_set(sel)

        return main_object, return_obs
    #this is used for uploads:
    with bpy.data.libraries.load(file_name, link=link,
                                 relative=True) as (data_from, data_to):
        sobs = []
        # for col in data_from.collections:
        #     if col == kwargs.get('name'):
        for ob in data_from.objects:
            if ob in obnames or obnames == []:
                sobs.append(ob)
        data_to.objects = sobs
        # data_to.objects = data_from.objects#[name for name in data_from.objects if name.startswith("house")]

    # link them to scene
    scene = bpy.context.scene
    sel = utils.selection_get()
    bpy.ops.object.select_all(action='DESELECT')

    return_obs = [
    ]  # this might not be needed, but better be sure to rewrite the list.
    main_object = None
    hidden_objects = []
    #
    for obj in data_to.objects:
        if obj is not None:
            # if obj.name not in scene.objects:
            scene.collection.objects.link(obj)
            if obj.parent is None:
                obj.location = location
                main_object = obj
            obj.select_set(True)
            # we need to unhide object so make_local op can use those too.
            if link == True:
                if obj.hide_viewport:
                    hidden_objects.append(obj)
                    obj.hide_viewport = False
            return_obs.append(obj)

    # Only after all objects are in scene! Otherwise gets broken relationships
    if link == True:
        bpy.ops.object.make_local(type='SELECT_OBJECT')
        for ob in hidden_objects:
            ob.hide_viewport = True

    if kwargs.get('rotation') is not None:
        main_object.rotation_euler = kwargs['rotation']

    if kwargs.get('parent') is not None:
        main_object.parent = bpy.data.objects[kwargs['parent']]
        main_object.matrix_world.translation = location

    bpy.ops.object.select_all(action='DESELECT')

    utils.selection_set(sel)

    return main_object, return_obs