0
$\begingroup$

I have a collection of leaves in my scene which calls Lines: enter image description here

Here's a little snippet that creates another leaf from leaf and randomize it:

bpy.ops.object.duplicate() 
rotateX = round(uniform(-20,20), 2)
rotateY = round(uniform(10,50), 2)
scaleX = round(uniform(0.3,1), 2)
scaleY = round(uniform(0.3,1), 2)
scaleZ = round(uniform(0.3,1), 2)
bpy.context.object.scale = ( scaleX, scaleY, scaleZ )
bpy.context.active_object.rotation_euler = (radians(rotateX),radians(rotateY),radians(-90))

And here's a brief look of what my script does

From:

enter image description here

To:

enter image description here

My goal is to apply my script to other leaf objects, so I can easily generate a little procedural garden with random leaves.

I'm pretty new to blender, and I don't know of it's possibilities, and how powerful it is. If you could suggest a better option or way to solve my problem I'd be grateful! May be it's even better to use particle system, and if so, how do I randomize the scale and leaf shape if it was generated by particle system?

I want to achieve something similar to this: https://i.stack.imgur.com/eBXN1.jpg

^ here I manually select and make objects active to apply my script on them on by one, but I want a script that does it

$\endgroup$
3
  • $\begingroup$ We are ok that particle system could nearly do all that automatically, as seen in one of your previous questions? you want to randomize differently? How will you place the resulting plants after that? $\endgroup$
    – lemon
    Aug 8, 2019 at 13:21
  • $\begingroup$ They aren't exactly the same, but 95% of them look same, when I use particular system with all scale and randomness settings. I need them to have random scale and random leaf shape, so most of them would look really different @lemon $\endgroup$
    – cxnt
    Aug 8, 2019 at 13:42
  • 1
    $\begingroup$ I added a link and some more information @lemon $\endgroup$
    – cxnt
    Aug 8, 2019 at 13:46

1 Answer 1

1
$\begingroup$

Here is a little commented script to iterate over a collection and populate a second one from copies of the meshes of the first.

import bpy
from math import radians
from random import uniform

# get an existing collection or create it if it does not exist
# if created, the collection is added to the scene main collection
def get_or_create_collection( scene, collection_name ):
    collection = bpy.data.collections.get( collection_name )
    if collection is None:
        collection = bpy.data.collections.new( collection_name )
        scene.collection.children.link( collection )
    return collection

# duplicate an object and link it to a collection
# copy_data allow to know if the objects will share their data or not (are dupli or not)
def duplicate( obj, collection, copy_data ):
    new_obj = obj.copy()
    if copy_data:
        new_obj.data = obj.data.copy()
    collection.objects.link( new_obj )
    return new_obj

# get the scene
scene = bpy.context.scene

# names of the collection
source_collection_name = 'Collection'
destination_collection_name = 'Collection2'

# get the source collection
source_collection = bpy.data.collections.get( source_collection_name )

if source_collection is None:
    print( 'will not work' )
else:
    # get the destination collection
    destination_collection = get_or_create_collection( scene, destination_collection_name )

    # enumerate mesh objects in the source collection
    for obj in [o for o in source_collection.objects if o.type == 'MESH']:
        # get a copy of the object
        new_obj = duplicate( obj, destination_collection, False )
        # ** Make your random transforms here ** 
        rotateX = round(uniform(-20,20), 2)
        rotateY = round(uniform(10,50), 2)
        scaleX = round(uniform(0.3,1), 2)
        scaleY = round(uniform(0.3,1), 2)
        scaleZ = round(uniform(0.3,1), 2)
        new_obj.scale = ( scaleX, scaleY, scaleZ )
        new_obj.rotation_euler = (radians(rotateX),radians(rotateY),radians(-90))
$\endgroup$
9
  • $\begingroup$ That's not working for me. Is there any way to simply select an object and make it active? I mean real ACTIVE, just like if you clicked with lmb on it $\endgroup$
    – cxnt
    Aug 8, 2019 at 14:40
  • $\begingroup$ why do you need 'active'? just use new_obj instead of bpy.context.object or active_object. $\endgroup$
    – lemon
    Aug 8, 2019 at 14:43
  • $\begingroup$ I dont really get how to use it. Can you give me an example? @lemon $\endgroup$
    – cxnt
    Aug 8, 2019 at 14:48
  • $\begingroup$ @cxnt1, sure, which random function have you imported? $\endgroup$
    – lemon
    Aug 8, 2019 at 14:52
  • $\begingroup$ rotateX = round(uniform(-20,20), 2) rotateY = round(uniform(10,50), 2) scaleX = round(uniform(0.3,1), 2) scaleY = round(uniform(0.3,1), 2) scaleZ = round(uniform(0.3,1), 2) bpy.context.object.scale = ( scaleX, scaleY, scaleZ ) bpy.context.active_object.rotation_euler = (radians(rotateX),radians(rotateY),radians(-90)) $\endgroup$
    – cxnt
    Aug 8, 2019 at 14:54

You must log in to answer this question.

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