Blender Asked on November 5, 2021
I have the following blender scene setup:
(notice the python script, will be mentioned soon in question)
As you can see, there are many boards being duplicated to form a wall.
The thing is: in real life, the middle support board is usually different for each board, like this:
So basically, I want to randomly set the Z position within the range of the top beam and bottom beam (of the boards in my scene) so that the middle support-beam is randomly positioned, reapplied for each array instance. So I went ahead and made a python script that randomly sets the beam’ss Z position from the top beam to bottom beam, and currently whenever I hit “Run Script”, it re-randomly sets the position of the beam, exactly how I wanted.
The problem:
As you can see, all of the array instances are the same, but I want it to randomly move the beam (a.k.a., somehow re-apply the script) for every array instance, but I have absolutely no idea how to do this.
Anyone?
Distribute copies.
Further to @moonboots answer can copy and distribute the object. Each copy shares the one mesh.
import bpy
from mathutils import Vector
from random import uniform
def array(context, count, rel_offset=Vector(), rnd_var_range=(0, 0), rnd_var_dir=Vector()):
scene = context.scene
for ob in context.selected_objects:
mw = ob.matrix_world
R = mw.to_quaternion().to_matrix()
offset = R * rel_offset.dot(ob.dimensions) * rel_offset.normalized()
copies = count - 1
for i in range(copies):
copy = ob.copy()
t = copy.matrix_world.translation
t += (i + 1) * offset
copy.delta_location = uniform(*rnd_var_range) * rnd_var_dir
copy.select = True
scene.objects.link(copy)
# test call
context = bpy.context
array(context,
count = 5,
rel_offset = Vector((1.1 , 0, 0)),
rnd_var_dir = Vector((0, 1, 0)),
rnd_var_range = (-1, 1))
array(context,
count = 5,
rel_offset = Vector((0, 0, 1.1)),
rnd_var_dir = Vector((0, 1, 0)),
rnd_var_range = (-1, 1))
Result of running script with Suzanne selected. The variation of both arrays in test call are in local Y direction.
The same script updated to Blender 2.8 API
import bpy
from mathutils import Vector
from random import uniform
def array(context, count, rel_offset=Vector(), rnd_var_range=(0, 0), rnd_var_dir=Vector()):
scene = context.scene
for ob in context.selected_objects:
mw = ob.matrix_world
R = mw.to_quaternion().to_matrix()
offset = R @ (rel_offset.dot(ob.dimensions) * rel_offset.normalized())
copies = count - 1
for i in range(copies):
copy = ob.copy()
t = copy.matrix_world.translation
t += (i + 1) * offset
copy.delta_location = uniform(*rnd_var_range) * rnd_var_dir
context.collection.objects.link(copy)
copy.select_set(state=True)
context.view_layer.objects.active = copy
# test call
context = bpy.context
array(context,
count = 5,
rel_offset = Vector((1.1 , 0, 0)),
rnd_var_dir = Vector((0, 1, 0)),
rnd_var_range = (-1, 1))
array(context,
count = 5,
rel_offset = Vector((0, 0, 1.1)),
rnd_var_dir = Vector((0, 1, 0)),
rnd_var_range = (-1, 1))
Main changes are:
copy.select_set(state=True)
Answered by batFINGER on November 5, 2021
set the object name to something meaningful like "bar" or whatever. apply the modifier ass it is with no Z variation. then press [TAB] to enter edit mode, press [A] to select all, press [P] and select separate by loose parts. press [tab] back to object mode. and run:
import bpy, random as r
objs = bpy.data.objects
for i in objs:
if "bar" in i.name: #"bar" name of the array obj "Cube" to you n
i.select=True
bpy.context.object.location[2] =1+r.randint(-20,20)/10 #"here your random funct"
...i think this should do the thing.
Answered by Javier on November 5, 2021
I am not sure if you can change the data for individual instance of the array modifier, since, I guess, the instances share the same data block.
One option is to apply the modifier, so as to combine the data of all objects into the parent object. This will complicate the calculations, though. The other option would be creating separate object for each instance. The most obvious way to do this is to copy the mesh data mesh = bpy.data.objects[x].data.copy()
and use it to create a new objectobj = bpy.data.objects.new('new_obj', mesh)
followed by bpy.context.scene.objects.link(obj)
. The objects location can be changed after it's linked into the scene.
Answered by Blender Dadaist on November 5, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP