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://imgur.com/a/uGRNtyF

^ 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$
  • $\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 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$ – cxnt1 Aug 8 at 13:42
  • 1
    $\begingroup$ I added a link and some more information @lemon $\endgroup$ – cxnt1 Aug 8 at 13:46
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$
  • $\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$ – cxnt1 Aug 8 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 at 14:43
  • $\begingroup$ I dont really get how to use it. Can you give me an example? @lemon $\endgroup$ – cxnt1 Aug 8 at 14:48
  • $\begingroup$ @cxnt1, sure, which random function have you imported? $\endgroup$ – lemon Aug 8 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$ – cxnt1 Aug 8 at 14:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.