Last active
December 30, 2020 16:40
-
-
Save rstecca/7fe38e3846749c0118e6bd20cb83c39c to your computer and use it in GitHub Desktop.
Blender Python script to process Array Modifiers to create transformed Object clones rather than just geometry
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
from mathutils import Vector, Matrix, Quaternion, Euler | |
from random import uniform | |
# Uses Array modifier data to generate OBJECTS rather than just geometry | |
# Find this Gist at https://gist.github.com/rstecca/7fe38e3846749c0118e6bd20cb83c39c | |
# github.com/rstecca | |
# Only works with Array Modifiers with ObjectOffset | |
# Tested in Blender 2.83.1 | |
# HOW TO USE | |
# - Select an object that has at least 1 Array Modifier | |
# - Make sure all Array Modifiers on that object have an Object Offset set and active | |
# (those that aren't set or active will be skipped) | |
# - Optionally disable the Render/Realtime Display of each Array modifiers so you won't see the Blender's result | |
# - Launch this script with Alt+P | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Removes all modifiers from an object | |
## Needed to cleanup the clones | |
def RemoveModifiers(_obj): | |
for mod in _obj.modifiers: | |
_obj.modifiers.remove(mod) | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Recursively applies the affine transformation | |
# copying _obj and applying the transformation described by _matrix to its copies, relatively to the currently processed object matrix | |
# writes all cloned objects to _clonelist | |
## _OT is the original object transformation matrix | |
def CopyAffine(_context, _obj, _matrix, _count, _clonelist): | |
copy = _obj.copy() | |
RemoveModifiers(copy) | |
_clonelist.append(copy) | |
copy.matrix_world = _obj.matrix_world @ _matrix #@ _obj.matrix_world @ _matrix.inverted() # _matrix @ _obj.matrix_world # | |
_context.collection.objects.link(copy) | |
c = _count - 1 | |
if (c > 1): | |
CopyAffine(_context, copy, _matrix, c, _clonelist) | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Gets all array modifiers from _obj | |
def GetArrayModifiers(_obj): | |
arrModifiers = [] | |
allModifiers = _obj.modifiers | |
for mod in allModifiers: | |
if(mod.name.startswith("Array")): | |
arrModifiers.append(mod) | |
return arrModifiers | |
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
# Process all Array Modifiers | |
def ApplyArrayModifiers(_context, _targetObject): | |
arrModifiers = GetArrayModifiers(_targetObject) | |
if(len(arrModifiers) == 0): | |
print("No Array modifiers found in " + _targetObject.name) | |
else: | |
objs = [] | |
objs.append(_targetObject) | |
arrModifiers.reverse() # we have to go backwards, from the last modifiers to the first | |
for aMod in arrModifiers: | |
count = aMod.count | |
clones = [] | |
# Here we need to counter the target object's transformation. Can this be seen as a change of base? | |
D = _targetObject.matrix_world.inverted() | |
if(aMod.use_object_offset): | |
D = D @ aMod.offset_object.matrix_world | |
for obj in objs: | |
CopyAffine(_context, obj, D, count, clones) | |
objs = objs + clones # concatenate clones to all objects for the next iteration | |
###################################### | |
print(" - - - - - - - - - - - - - - ") | |
context = bpy.context | |
A = context.view_layer.objects.active | |
ApplyArrayModifiers(context, A) |
Rev. 8: rolled back to a version that works well but for Object Offset only
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In rev. 7 there's an attempt to make constant and relative offset work nicely in all cases (when the root object is not (0,0,0), combined with other offsets, when there's more than one Array Modifier, etc...).