5
$\begingroup$

I currently have a method that does:

self.myCol = bpy.data.collections.new(self.collection_name)
bpy.context.scene.collection.children.link(myCol)

This method creates and adds a new collection to the outliner. Next, I want to create a bunch of cubes and add those cubes to the collection. How can I tell blender to create objects only within that particular collection?

Something like:

bpy.ops.mesh.primitive_cube_add(collection='name', size=2, location=(0, 0, 0))

Obvious cube_add doesn't have the param for it, so what's the proper way to do this?

$\endgroup$

4 Answers 4

10
$\begingroup$

Your answer is actually wrong.

If your active collection is another as the main collection, when running your script the object will not be removed from this.

import bpy

bpy.ops.mesh.primitive_cube_add()
# our created cube is the active one
obj = bpy.context.active_object
# Remove object from all collections not used in a scene
bpy.ops.collection.objects_remove_all()
# add it to our specific collection
bpy.data.collections['MyCollection'].objects.link(obj)

About remove all: https://docs.blender.org/api/blender2.8/bpy.ops.collection.html#bpy.ops.collection.objects_remove_all

$\endgroup$
2
$\begingroup$

I figured it out. C is bpy.context btw.

self.master_collection = bpy.context.scene.collection

self.layer_collection = bpy.data.collections[ collection_name ]

for i in range(...):

    bpy.ops.mesh.primitive_cube_add(size=2, view_align=False, enter_editmode=False, location=(0, 0, 0))
    # Create the cubes

    self.layer_collection.objects.link(C.object) #link it with collection

    self.master_collection.objects.unlink(C.object) #unlink it from master collection
$\endgroup$
1
$\begingroup$

Set the active collection.

IMO the key here if adding a new object with an operator is setting the context collection. See Change active collection

python console test.

Set the context collection to scene "master collection" scene.collection and add cube to it.

>>> lc = C.view_layer.layer_collection
>>> C.view_layer.active_layer_collection = lc
>>> C.collection
bpy.data.scenes['Scene'].collection

>>> bpy.ops.mesh.primitive_cube_add()
{'FINISHED'}

Set to another collection in the scene, eg "Collection" in default startup file ie scene.collection.children['Collection']

>>> lc = C.view_layer.layer_collection.children['Collection']
>>> C.view_layer.active_layer_collection = lc
>>> C.collection
bpy.data.collections['Collection']

>>> bpy.ops.mesh.primitive_cube_add()
$\endgroup$
0
$\begingroup$

OBJ Importing

The script imports .obj files from a specified folder and pastes them to the scene by collections. Import.py creates the empty collections and temporary moves objects to data-block. Paste.py moves objects from data-block to the scene and distributes them by collections. Also added the scale and rotation corrections.

The important moment that can help with the question happens here: at first the objects creates from the meshes data-block using bpy.data.objects.new(mesh.name, mesh) and continue store in the objects data-block (not linked with the scene). After they are distributed across the collections using the name matching.

Import.py

import bpy
import os.path as path
import glob

root = path.abspath(path.join('' ,".."))
files = glob.glob(root + '\*.obj')

for f in files:
    bpy.ops.import_scene.obj(filepath=f)
    name = path.split(f)[1].replace('.obj', '')
    col = bpy.data.collections.new(name)
    bpy.context.scene.collection.children.link(col)
    
    indexes = len([ob for ob in bpy.context.selected_objects if ob.tag == False])
    
    for i in range(indexes):
         bpy.context.selected_objects[i].name = '{}-{}'.format(name, i)
         bpy.context.selected_objects[i].data.name = '{}-{}'.format(name, i)
    
    bpy.ops.collection.objects_remove_all()
    
    for ob in bpy.data.objects:
        bpy.data.objects.remove(ob)
    
    for m in bpy.data.materials:
        m.user_clear()
        bpy.data.materials.remove(m)

for mesh in bpy.data.meshes:
    ob = bpy.data.objects.new(mesh.name, mesh)
    ob.active_material_index = 0
    for i in range(len(ob.material_slots)):
        bpy.ops.object.material_slot_remove({'object': ob})

Paste.py

import bpy
from mathutils import Vector, Euler
from math import radians

for ob in bpy.data.objects:
    for col in bpy.data.collections:
       if col.name == ob.name.split('-')[0]:
            col.objects.link(ob)

for ob in bpy.context.scene.objects:
    ob.scale = Vector=((0.5, 0.5, 0.5))
    ob.rotation_euler = Euler((radians(180), 0.0, 0.0), 'XYZ')

Note: DON’T use a symbol - in names

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .