From 2aa13cb25adfe95bbc57f4c7442c91f020df5f2d Mon Sep 17 00:00:00 2001 From: lijenstina Date: Sat, 8 Apr 2017 00:24:05 +0200 Subject: Sapling Tree Gen: Cleanup, fix warning Bumped version to 0.3.3 Fix star imports Pep8 cleanup Fix RNA Warning: Current value "0" matches no enum The EnumProperty function were passed an empty list if there were no adequate objects in the scene --- add_curve_sapling/__init__.py | 788 ++++++++++++++++++++++++--------------- add_curve_sapling/utils.py | 841 +++++++++++++++++++++++++----------------- 2 files changed, 988 insertions(+), 641 deletions(-) (limited to 'add_curve_sapling') diff --git a/add_curve_sapling/__init__.py b/add_curve_sapling/__init__.py index fd6f5e97..1c91c1c7 100644 --- a/add_curve_sapling/__init__.py +++ b/add_curve_sapling/__init__.py @@ -1,4 +1,4 @@ -#====================== BEGIN GPL LICENSE BLOCK ====================== +# ##### BEGIN GPL LICENSE BLOCK ##### # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -14,18 +14,18 @@ # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -#======================= END GPL LICENSE BLOCK ======================== +# ##### END GPL LICENSE BLOCK ##### bl_info = { "name": "Sapling Tree Gen", "author": "Andrew Hale (TrumanBlending), Aaron Buchler", - "version": (0, 3, 2), + "version": (0, 3, 3), "blender": (2, 77, 0), "location": "View3D > Add > Curve", "description": ("Adds a parametric tree. The method is presented by " "Jason Weber & Joseph Penn in their paper 'Creation and Rendering of " - "Realistic Trees'."), - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/" + "Realistic Trees'"), + "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/" "Scripts/Curve/Sapling_Tree", "category": "Add Curve"} @@ -40,14 +40,21 @@ import time import os import ast -#import cProfile - -from mathutils import * -from math import pi, sin, degrees, radians, atan2, copysign -from random import random, uniform, seed, choice, getstate, setstate -from bpy.props import * - -from add_curve_sapling.utils import * +# import cProfile + +from bpy.types import ( + Operator, + Menu, + ) +from bpy.props import ( + BoolProperty, + EnumProperty, + FloatProperty, + FloatVectorProperty, + IntProperty, + IntVectorProperty, + StringProperty, + ) useSet = False @@ -97,16 +104,17 @@ branchmodes = [("original", "Original", "rotate around each branch"), ("rotate", "Rotate", "evenly distribute branches to point outward from center of tree"), ("random", "Random", "choose random point")] + def getPresetpath(): """Support user defined scripts directory Find the first ocurrence of add_curve_sapling/presets in possible script paths and return it as preset path""" - #presetpath = "" - #for p in bpy.utils.script_paths(): + # presetpath = "" + # for p in bpy.utils.script_paths(): # presetpath = os.path.join(p, 'addons', 'add_curve_sapling_3', 'presets') # if os.path.exists(presetpath): # break - #return presetpath + # return presetpath # why not just do this script_file = os.path.realpath(__file__) @@ -114,6 +122,7 @@ def getPresetpath(): directory = os.path.join(directory, "presets") return directory + def getPresetpaths(): """Return paths for both local and user preset folders""" userDir = os.path.join(bpy.utils.script_path_user(), 'presets', 'operator', 'add_curve_sapling') @@ -129,7 +138,8 @@ def getPresetpaths(): return (localDir, userDir) -class ExportData(bpy.types.Operator): + +class ExportData(Operator): """This operator handles writing presets to file""" bl_idname = 'sapling.exportdata' bl_label = 'Export Preset' @@ -139,24 +149,24 @@ class ExportData(bpy.types.Operator): def execute(self, context): # Unpack some data from the input data, filename, overwrite = eval(self.data) - -# try: -# # Check whether the file exists by trying to open it. -# f = open(os.path.join(getPresetpaths()[1], filename + '.py'), 'r') -# f.close() -# # If it exists then report an error -# self.report({'ERROR_INVALID_INPUT'}, 'Preset Already Exists') -# return {'CANCELLED'} -# except IOError: -# if data: -# # If it doesn't exist, create the file with the required data -# f = open(os.path.join(getPresetpaths()[1], filename + '.py'), 'w') -# f.write(data) -# f.close() -# return {'FINISHED'} -# else: -# return {'CANCELLED'} - + """ + try: + # Check whether the file exists by trying to open it. + f = open(os.path.join(getPresetpaths()[1], filename + '.py'), 'r') + f.close() + # If it exists then report an error + self.report({'ERROR_INVALID_INPUT'}, 'Preset Already Exists') + return {'CANCELLED'} + except IOError: + if data: + # If it doesn't exist, create the file with the required data + f = open(os.path.join(getPresetpaths()[1], filename + '.py'), 'w') + f.write(data) + f.close() + return {'FINISHED'} + else: + return {'CANCELLED'} + """ fpath1 = os.path.join(getPresetpaths()[0], filename + '.py') fpath2 = os.path.join(getPresetpaths()[1], filename + '.py') @@ -165,7 +175,7 @@ class ExportData(bpy.types.Operator): self.report({'ERROR_INVALID_INPUT'}, 'Can\'t have same name as built-in preset') return {'CANCELLED'} elif (not os.path.exists(fpath2)) or (os.path.exists(fpath2) and overwrite): - #if (it does not exist) or (exists and overwrite) then write file + # if (it does not exist) or (exists and overwrite) then write file if data: # If it doesn't exist, create the file with the required data f = open(os.path.join(getPresetpaths()[1], filename + '.py'), 'w') @@ -179,10 +189,11 @@ class ExportData(bpy.types.Operator): self.report({'ERROR_INVALID_INPUT'}, 'Preset Already Exists') return {'CANCELLED'} -class ImportData(bpy.types.Operator): + +class ImportData(Operator): """This operator handles importing existing presets""" - bl_idname = 'sapling.importdata' - bl_label = 'Import Preset' + bl_idname = "sapling.importdata" + bl_label = "Import Preset" filename = StringProperty() @@ -196,15 +207,15 @@ class ImportData(bpy.types.Operator): f = open(os.path.join(getPresetpaths()[1], self.filename), 'r') settings = f.readline() f.close() - #print(settings) + # print(settings) settings = ast.literal_eval(settings) - #use old attractup + # use old attractup if type(settings['attractUp']) == float: atr = settings['attractUp'] settings['attractUp'] = [0, 0, atr, atr] - #use old leaf rotations + # use old leaf rotations if 'leafDownAngle' not in settings: l = settings['levels'] settings['leafDownAngle'] = settings['downAngle'][min(l, 3)] @@ -212,14 +223,15 @@ class ImportData(bpy.types.Operator): settings['leafRotate'] = settings['rotate'][min(l, 3)] settings['leafRotateV'] = settings['rotateV'][min(l, 3)] - #zero leaf bend + # zero leaf bend settings['bend'] = 0 # Set the flag to use the settings useSet = True return {'FINISHED'} -class PresetMenu(bpy.types.Menu): + +class PresetMenu(Menu): """Create the preset menu by finding all preset files in the preset directory""" bl_idname = "sapling.presetmenu" @@ -234,7 +246,8 @@ class PresetMenu(bpy.types.Menu): for p in presets: layout.operator("sapling.importdata", text=p[:-3]).filename = p -class AddTree(bpy.types.Operator): + +class AddTree(Operator): bl_idname = "curve.tree_add" bl_label = "Sapling: Add Tree" bl_options = {'REGISTER', 'UNDO'} @@ -242,16 +255,13 @@ class AddTree(bpy.types.Operator): def objectList(self, context): objects = [] bObjects = bpy.data.objects -# try: -# bObjects = bpy.data.objects -# except AttributeError: -# pass -# else: + for obj in bObjects: if (obj.type in ['MESH', 'CURVE', 'SURFACE']) and (obj.name not in ['tree', 'leaves']): objects.append((obj.name, obj.name, "")) - return objects + return (objects if objects else + [('NONE', "No objects", "No appropriate objects in the Scene")]) def update_tree(self, context): self.do_update = True @@ -265,419 +275,606 @@ class AddTree(bpy.types.Operator): def no_update_tree(self, context): self.do_update = False - do_update = BoolProperty(name='Do Update', - default=True, options={'HIDDEN'}) - - chooseSet = EnumProperty(name='Settings', + do_update = BoolProperty( + name='Do Update', + default=True, options={'HIDDEN'} + ) + chooseSet = EnumProperty( + name='Settings', description='Choose the settings to modify', items=settings, - default='0', update=no_update_tree) - bevel = BoolProperty(name='Bevel', + default='0', update=no_update_tree + ) + bevel = BoolProperty( + name='Bevel', description='Whether the curve is beveled', - default=False, update=update_tree) - prune = BoolProperty(name='Prune', + default=False, update=update_tree + ) + prune = BoolProperty( + name='Prune', description='Whether the tree is pruned', - default=False, update=update_tree) - showLeaves = BoolProperty(name='Show Leaves', + default=False, update=update_tree + ) + showLeaves = BoolProperty( + name='Show Leaves', description='Whether the leaves are shown', - default=False, update=update_tree) - useArm = BoolProperty(name='Use Armature', + default=False, update=update_tree + ) + useArm = BoolProperty( + name='Use Armature', description='Whether the armature is generated', - default=False, update=update_tree) - seed = IntProperty(name='Random Seed', + default=False, update=update_tree + ) + seed = IntProperty( + name='Random Seed', description='The seed of the random number generator', - default=0, update=update_tree) - handleType = IntProperty(name='Handle Type', + default=0, update=update_tree + ) + handleType = IntProperty( + name='Handle Type', description='The type of curve handles', min=0, max=1, - default=0, update=update_tree) - levels = IntProperty(name='Levels', + default=0, update=update_tree + ) + levels = IntProperty( + name='Levels', description='Number of recursive branches (Levels)', min=1, max=6, soft_max=4, - default=3, update=update_tree) - length = FloatVectorProperty(name='Length', + default=3, update=update_tree + ) + length = FloatVectorProperty( + name='Length', description='The relative lengths of each branch level (nLength)', min=0.000001, default=[1, 0.3, 0.6, 0.45], - size=4, update=update_tree) - lengthV = FloatVectorProperty(name='Length Variation', + size=4, update=update_tree + ) + lengthV = FloatVectorProperty( + name='Length Variation', description='The relative length variations of each level (nLengthV)', min=0.0, max=1.0, default=[0, 0, 0, 0], - size=4, update=update_tree) - taperCrown = FloatProperty(name='Taper Crown', + size=4, update=update_tree + ) + taperCrown = FloatProperty( + name='Taper Crown', description='Shorten trunk splits toward outside of tree', min=0.0, soft_max=1.0, - default=0, update=update_tree) - branches = IntVectorProperty(name='Branches', + default=0, update=update_tree + ) + branches = IntVectorProperty( + name='Branches', description='The number of branches grown at each level (nBranches)', min=0, default=[50, 30, 10, 10], - size=4, update=update_tree) - curveRes = IntVectorProperty(name='Curve Resolution', + size=4, update=update_tree + ) + curveRes = IntVectorProperty( + name='Curve Resolution', description='The number of segments on each branch (nCurveRes)', min=1, default=[3, 5, 3, 1], - size=4, update=update_tree) - curve = FloatVectorProperty(name='Curvature', + size=4, update=update_tree + ) + curve = FloatVectorProperty( + name='Curvature', description='The angle of the end of the branch (nCurve)', default=[0, -40, -40, 0], - size=4, update=update_tree) - curveV = FloatVectorProperty(name='Curvature Variation', + size=4, update=update_tree + ) + curveV = FloatVectorProperty( + name='Curvature Variation', description='Variation of the curvature (nCurveV)', default=[20, 50, 75, 0], - size=4, update=update_tree) - curveBack = FloatVectorProperty(name='Back Curvature', + size=4, update=update_tree + ) + curveBack = FloatVectorProperty( + name='Back Curvature', description='Curvature for the second half of a branch (nCurveBack)', default=[0, 0, 0, 0], - size=4, update=update_tree) - baseSplits = IntProperty(name='Base Splits', + size=4, update=update_tree + ) + baseSplits = IntProperty( + name='Base Splits', description='Number of trunk splits at its base (nBaseSplits)', min=0, - default=0, update=update_tree) - segSplits = FloatVectorProperty(name='Segment Splits', + default=0, update=update_tree + ) + segSplits = FloatVectorProperty( + name='Segment Splits', description='Number of splits per segment (nSegSplits)', min=0, soft_max=3, default=[0, 0, 0, 0], - size=4, update=update_tree) - splitByLen = BoolProperty(name='Split relative to length', + size=4, update=update_tree + ) + splitByLen = BoolProperty( + name='Split relative to length', description='Split proportional to branch length', - default=False, update=update_tree) - rMode = EnumProperty(name="", #"Branching Mode" + default=False, update=update_tree + ) + rMode = EnumProperty( + name="", # "Branching Mode" description='Branching and Rotation Mode', items=branchmodes, - default="rotate", update=update_tree) - splitAngle = FloatVectorProperty(name='Split Angle', + default="rotate", update=update_tree + ) + splitAngle = FloatVectorProperty( + name='Split Angle', description='Angle of branch splitting (nSplitAngle)', default=[0, 0, 0, 0], - size=4, update=update_tree) - splitAngleV = FloatVectorProperty(name='Split Angle Variation', + size=4, update=update_tree + ) + splitAngleV = FloatVectorProperty( + name='Split Angle Variation', description='Variation in the split angle (nSplitAngleV)', default=[0, 0, 0, 0], - size=4, update=update_tree) - scale = FloatProperty(name='Scale', + size=4, update=update_tree + ) + scale = FloatProperty( + name='Scale', description='The tree scale (Scale)', min=0.0, default=13.0, update=update_tree) scaleV = FloatProperty(name='Scale Variation', description='The variation in the tree scale (ScaleV)', - default=3.0, update=update_tree) - attractUp = FloatVectorProperty(name='Vertical Attraction', + default=3.0, update=update_tree + ) + attractUp = FloatVectorProperty( + name='Vertical Attraction', description='Branch upward attraction', default=[0, 0, 0, 0], - size=4, update=update_tree) - attractOut = FloatVectorProperty(name='Outward Attraction', + size=4, update=update_tree + ) + attractOut = FloatVectorProperty( + name='Outward Attraction', description='Branch outward attraction', default=[0, 0, 0, 0], min=0.0, max=1.0, - size=4, update=update_tree) - shape = EnumProperty(name='Shape', + size=4, update=update_tree + ) + shape = EnumProperty( + name='Shape', description='The overall shape of the tree (Shape)', items=shapeList3, - default='7', update=update_tree) - shapeS = EnumProperty(name='Secondary Branches Shape', + default='7', update=update_tree + ) + shapeS = EnumProperty( + name='Secondary Branches Shape', description='The shape of secondary splits', items=shapeList4, - default='4', update=update_tree) - customShape = FloatVectorProperty(name='Custom Shape', + default='4', update=update_tree + ) + customShape = FloatVectorProperty( + name='Custom Shape', description='custom shape branch length at (Base, Middle, Middle Position, Top)', size=4, min=.01, max=1, - default=[.5, 1.0, .3, .5], update=update_tree) - branchDist = FloatProperty(name='Branch Distribution', + default=[.5, 1.0, .3, .5], update=update_tree + ) + branchDist = FloatProperty( + name='Branch Distribution', description='Adjust branch spacing to put more branches at the top or bottom of the tree', min=0.1, soft_max=10, - default=1.0, update=update_tree) - nrings = IntProperty(name='Branch Rings', + default=1.0, update=update_tree + ) + nrings = IntProperty( + name='Branch Rings', description='grow branches in rings', min=0, - default=0, update=update_tree) - baseSize = FloatProperty(name='Trunk Height', + default=0, update=update_tree + ) + baseSize = FloatProperty( + name='Trunk Height', description='Fraction of tree height with no branches (Base Size)', min=0.0, max=1.0, - default=0.4, update=update_tree) - baseSize_s = FloatProperty(name='Secondary Base Size', + default=0.4, update=update_tree + ) + baseSize_s = FloatProperty( + name='Secondary Base Size', description='Factor to decrease base size for each level', min=0.0, max=1.0, - default=0.25, update=update_tree) - splitHeight = FloatProperty(name='Split Height', + default=0.25, update=update_tree + ) + splitHeight = FloatProperty( + name='Split Height', description='Fraction of tree height with no splits', min=0.0, max=1.0, - default=0.2, update=update_tree) - splitBias = FloatProperty(name='splitBias', + default=0.2, update=update_tree + ) + splitBias = FloatProperty( + name='splitBias', description='Put more splits at the top or bottom of the tree', soft_min=-2.0, soft_max=2.0, - default=0.0, update=update_tree) - ratio = FloatProperty(name='Ratio', + default=0.0, update=update_tree + ) + ratio = FloatProperty( + name='Ratio', description='Base radius size (Ratio)', min=0.0, - default=0.015, update=update_tree) - minRadius = FloatProperty(name='Minimum Radius', + default=0.015, update=update_tree + ) + minRadius = FloatProperty( + name='Minimum Radius', description='Minimum branch Radius', min=0.0, - default=0.0, update=update_tree) - closeTip = BoolProperty(name='Close Tip', + default=0.0, update=update_tree + ) + closeTip = BoolProperty( + name='Close Tip', description='Set radius at branch tips to zero', - default=False, update=update_tree) - rootFlare = FloatProperty(name='Root Flare', + default=False, update=update_tree + ) + rootFlare = FloatProperty( + name='Root Flare', description='Root radius factor', min=1.0, - default=1.0, update=update_tree) - autoTaper = BoolProperty(name='Auto Taper', + default=1.0, update=update_tree + ) + autoTaper = BoolProperty( + name='Auto Taper', description='Calculate taper automaticly based on branch lengths', - default=True, update=update_tree) - taper = FloatVectorProperty(name='Taper', + default=True, update=update_tree + ) + taper = FloatVectorProperty( + name='Taper', description='The fraction of tapering on each branch (nTaper)', min=0.0, max=1.0, default=[1, 1, 1, 1], - size=4, update=update_tree) - radiusTweak = FloatVectorProperty(name='Tweak Radius', + size=4, update=update_tree + ) + radiusTweak = FloatVectorProperty( + name='Tweak Radius', description='multiply radius by this factor', min=0.0, max=1.0, default=[1, 1, 1, 1], - size=4, update=update_tree) - ratioPower = FloatProperty(name='Branch Radius Ratio', + size=4, update=update_tree + ) + ratioPower = FloatProperty( + name='Branch Radius Ratio', description=('Power which defines the radius of a branch compared to ' 'the radius of the branch it grew from (RatioPower)'), min=0.0, - default=1.2, update=update_tree) - downAngle = FloatVectorProperty(name='Down Angle', + default=1.2, update=update_tree + ) + downAngle = FloatVectorProperty( + name='Down Angle', description=('The angle between a new branch and the one it grew ' 'from (nDownAngle)'), default=[90, 60, 45, 45], - size=4, update=update_tree) - downAngleV = FloatVectorProperty(name='Down Angle Variation', - description='Angle to decrease Down Angle by towards end of parent branch (negative values add random variation)', + size=4, update=update_tree + ) + downAngleV = FloatVectorProperty( + name='Down Angle Variation', + description="Angle to decrease Down Angle by towards end of parent branch " + "(negative values add random variation)", default=[0, -50, 10, 10], - size=4, update=update_tree) - useOldDownAngle = BoolProperty(name='Use old down angle variation', - default=False, update=update_tree) - useParentAngle = BoolProperty(name = 'Use parent angle', - description = '(first level) Rotate branch to match parent branch', - default=True, update=update_tree) - rotate = FloatVectorProperty(name='Rotate Angle', - description='The angle of a new branch around the one it grew from (negative values rotate opposite from the previous)', + size=4, update=update_tree + ) + useOldDownAngle = BoolProperty( + name='Use old down angle variation', + default=False, update=update_tree + ) + useParentAngle = BoolProperty( + name='Use parent angle', + description='(first level) Rotate branch to match parent branch', + default=True, update=update_tree + ) + rotate = FloatVectorProperty( + name='Rotate Angle', + description="The angle of a new branch around the one it grew from " + "(negative values rotate opposite from the previous)", default=[137.5, 137.5, 137.5, 137.5], - size=4, update=update_tree) - rotateV = FloatVectorProperty(name='Rotate Angle Variation', + size=4, update=update_tree + ) + rotateV = FloatVectorProperty( + name='Rotate Angle Variation', description='Variation in the rotate angle (nRotateV)', default=[0, 0, 0, 0], - size=4, update=update_tree) - scale0 = FloatProperty(name='Radius Scale', + size=4, update=update_tree + ) + scale0 = FloatProperty( + name='Radius Scale', description='The scale of the trunk radius (0Scale)', min=0.0, - default=1.0, update=update_tree) - scaleV0 = FloatProperty(name='Radius Scale Variation', + default=1.0, update=update_tree + ) + scaleV0 = FloatProperty( + name='Radius Scale Variation', description='Variation in the radius scale (0ScaleV)', min=0.0, max=1.0, - default=0.2, update=update_tree) - pruneWidth = FloatProperty(name='Prune Width', + default=0.2, update=update_tree + ) + pruneWidth = FloatProperty( + name='Prune Width', description='The width of the envelope (PruneWidth)', min=0.0, - default=0.4, update=update_tree) - pruneBase = FloatProperty(name='Prune Base Height', + default=0.4, update=update_tree + ) + pruneBase = FloatProperty( + name='Prune Base Height', description='The height of the base of the envelope, bound by trunk height', min=0.0, max=1.0, - default=0.3, update=update_tree) - pruneWidthPeak = FloatProperty(name='Prune Width Peak', - description=('Fraction of envelope height where the maximum width ' - 'occurs (PruneWidthPeak)'), + default=0.3, update=update_tree + ) + pruneWidthPeak = FloatProperty( + name='Prune Width Peak', + description=("Fraction of envelope height where the maximum width " + "occurs (PruneWidthPeak)"), min=0.0, - default=0.6, update=update_tree) - prunePowerHigh = FloatProperty(name='Prune Power High', + default=0.6, update=update_tree + ) + prunePowerHigh = FloatProperty( + name='Prune Power High', description=('Power which determines the shape of the upper portion ' 'of the envelope (PrunePowerHigh)'), - default=0.5, update=update_tree) - prunePowerLow = FloatProperty(name='Prune Power Low', + default=0.5, update=update_tree + ) + prunePowerLow = FloatProperty( + name='Prune Power Low', description=('Power which determines the shape of the lower portion ' 'of the envelope (PrunePowerLow)'), - default=0.001, update=update_tree) - pruneRatio = FloatProperty(name='Prune Ratio', + default=0.001, update=update_tree + ) + pruneRatio = FloatProperty( + name='Prune Ratio', description='Proportion of pruned length (PruneRatio)', min=0.0, max=1.0, - default=1.0, update=update_tree) - leaves = IntProperty(name='Leaves', - description='Maximum number of leaves per branch (negative values grow leaves from branch tip (palmate compound leaves))', - default=25, update=update_tree) - - leafDownAngle = FloatProperty(name='Leaf Down Angle', + default=1.0, update=update_tree + ) + leaves = IntProperty( + name='Leaves', + description="Maximum number of leaves per branch (negative values grow " + "leaves from branch tip (palmate compound leaves))", + default=25, update=update_tree + ) + leafDownAngle = FloatProperty( + name='Leaf Down Angle', description='The angle between a new leaf and the branch it grew from', - default=45, update=update_leaves) - leafDownAngleV = FloatProperty(name='Leaf Down Angle Variation', - description='Angle to decrease Down Angle by towards end of parent branch (negative values add random variation)', - default=10, update=update_tree) - leafRotate = FloatProperty(name='Leaf Rotate Angle', - description='The angle of a new leaf around the one it grew from (negative values rotate opposite from previous)', - default=137.5, update=update_tree) - leafRotateV = FloatProperty(name='Leaf Rotate Angle Variation', + default=45, update=update_leaves + ) + leafDownAngleV = FloatProperty( + name='Leaf Down Angle Variation', + description="Angle to decrease Down Angle by towards end of parent branch " + "(negative values add random variation)", + default=10, update=update_tree + ) + leafRotate = FloatProperty( + name='Leaf Rotate Angle', + description="The angle of a new leaf around the one it grew from " + "(negative values rotate opposite from previous)", + default=137.5, update=update_tree + ) + leafRotateV = FloatProperty( + name='Leaf Rotate Angle Variation', description='Variation in the rotate angle', - default=0.0, update=update_leaves) - - leafScale = FloatProperty(name='Leaf Scale', + default=0.0, update=update_leaves + ) + leafScale = FloatProperty( + name='Leaf Scale', description='The scaling applied to the whole leaf (LeafScale)', min=0.0, - default=0.17, update=update_leaves) - leafScaleX = FloatProperty(name='Leaf Scale X', + default=0.17, update=update_leaves + ) + leafScaleX = FloatProperty( + name='Leaf Scale X', description=('The scaling applied to the x direction of the leaf ' '(LeafScaleX)'), min=0.0, - default=1.0, update=update_leaves) - leafScaleT = FloatProperty(name='Leaf Scale Taper', + default=1.0, update=update_leaves + ) + leafScaleT = FloatProperty( + name='Leaf Scale Taper', description='scale leaves toward the tip or base of the patent branch', - min = -1.0, - max = 1.0, - default=0.0, update=update_leaves) - leafScaleV = FloatProperty(name='Leaf Scale Variation', + min=-1.0, + max=1.0, + default=0.0, update=update_leaves + ) + leafScaleV = FloatProperty( + name='Leaf Scale Variation', description='randomize leaf scale', - min = 0.0, - max = 1.0, - default=0.0, update=update_leaves) - leafShape = EnumProperty(name='Leaf Shape', + min=0.0, + max=1.0, + default=0.0, update=update_leaves + ) + leafShape = EnumProperty( + name='Leaf Shape', description='The shape of the leaves', - items=(('hex', 'Hexagonal', '0'), ('rect', 'Rectangular', '1'), ('dFace', 'DupliFaces', '2'), ('dVert', 'DupliVerts', '3')), - default='hex', update=update_leaves) - leafDupliObj = EnumProperty(name='Leaf Object', + items=(('hex', 'Hexagonal', '0'), ('rect', 'Rectangular', '1'), + ('dFace', 'DupliFaces', '2'), ('dVert', 'DupliVerts', '3')), + default='hex', update=update_leaves + ) + leafDupliObj = EnumProperty( + name='Leaf Object', description='Object to use for leaf instancing if Leaf Shape is DupliFaces or DupliVerts', items=objectList, - update=update_leaves) - -# bend = FloatProperty(name='Leaf Bend', -# description='The proportion of bending applied to the leaf (Bend)', -# min=0.0, -# max=1.0, -# default=0.0, update=update_leaves) - - leafangle = FloatProperty(name='Leaf Angle', + update=update_leaves + ) + """ + bend = FloatProperty( + name='Leaf Bend', + description='The proportion of bending applied to the leaf (Bend)', + min=0.0, + max=1.0, + default=0.0, update=update_leaves + ) + """ + leafangle = FloatProperty( + name='Leaf Angle', description='Leaf vertical attraction', - default=0.0, update=update_leaves) - horzLeaves = BoolProperty(name='Horizontal leaves', + default=0.0, update=update_leaves + ) + horzLeaves = BoolProperty( + name='Horizontal leaves', description='Leaves face upwards', - default=True, update=update_leaves) - leafDist = EnumProperty(name='Leaf Distribution', + default=True, update=update_leaves + ) + leafDist = EnumProperty( + name='Leaf Distribution', description='The way leaves are distributed on branches', items=shapeList4, - default='6', update=update_tree) - bevelRes = IntProperty(name='Bevel Resolution', + default='6', update=update_tree + ) + bevelRes = IntProperty( + name='Bevel Resolution', description='The bevel resolution of the curves', min=0, max=32, - default=0, update=update_tree) - resU = IntProperty(name='Curve Resolution', + default=0, update=update_tree + ) + resU = IntProperty( + name='Curve Resolution', description='The resolution along the curves', min=1, - default=4, update=update_tree) - handleType = EnumProperty(name='Handle Type', + default=4, update=update_tree + ) + handleType = EnumProperty( + name='Handle Type', description='The type of handles used in the spline', items=handleList, - default='0', update=update_tree) - - armAnim = BoolProperty(name='Armature Animation', + default='0', update=update_tree + ) + armAnim = BoolProperty( + name='Armature Animation', description='Whether animation is added to the armature', - default=False, update=update_tree) - previewArm = BoolProperty(name='Fast Preview', + default=False, update=update_tree + ) + previewArm = BoolProperty( + name='Fast Preview', description='Disable armature modifier, hide tree, and set bone display to wire, for fast playback', - ##Disable skin modifier and hide tree and armature, for fast playback - default=False, update=update_tree) - leafAnim = BoolProperty(name='Leaf Animation', + # Disable skin modifier and hide tree and armature, for fast playback + default=False, update=update_tree + ) + leafAnim = BoolProperty( + name='Leaf Animation', description='Whether animation is added to the leaves', - default=False, update=update_tree) - frameRate = FloatProperty(name='Animation Speed', + default=False, update=update_tree + ) + frameRate = FloatProperty( + name='Animation Speed', description=('Adjust speed of animation, relative to scene frame rate'), min=0.001, - default=1, update=update_tree) - loopFrames = IntProperty(name='Loop Frames', + default=1, update=update_tree + ) + loopFrames = IntProperty( + name='Loop Frames', description='Number of frames to make the animation loop for, zero is disabled', min=0, - default=0, update=update_tree) - -# windSpeed = FloatProperty(name='Wind Speed', -# description='The wind speed to apply to the armature', -# default=2.0, update=update_tree) -# windGust = FloatProperty(name='Wind Gust', -# description='The greatest increase over Wind Speed', -# default=0.0, update=update_tree) - - wind= FloatProperty(name='Overall Wind Strength', + default=0, update=update_tree + ) + """ + windSpeed = FloatProperty( + name='Wind Speed', + description='The wind speed to apply to the armature', + default=2.0, update=update_tree + ) + windGust = FloatProperty( + name='Wind Gust', + description='The greatest increase over Wind Speed', + default=0.0, update=update_tree + ) + """ + wind = FloatProperty( + name='Overall Wind Strength', description='The intensity of the wind to apply to the armature', - default=1.0, update=update_tree) - - gust = FloatProperty(name='Wind Gust Strength', + default=1.0, update=update_tree + ) + gust = FloatProperty( + name='Wind Gust Strength', description='The amount of directional movement, (from the positive Y direction)', - default=1.0, update=update_tree) - - gustF = FloatProperty(name='Wind Gust Fequency', + default=1.0, update=update_tree + ) + gustF = FloatProperty( + name='Wind Gust Fequency', description='The Fequency of directional movement', - default=0.075, update=update_tree) - - af1 = FloatProperty(name='Amplitude', + default=0.075, update=update_tree + ) + af1 = FloatProperty( + name='Amplitude', description='Multiplier for noise amplitude', - default=1.0, update=update_tree) - af2 = FloatProperty(name='Frequency', + default=1.0, update=update_tree + ) + af2 = FloatProperty( + name='Frequency', description='Multiplier for noise fequency', - default=1.0, update=update_tree) - af3 = FloatProperty(name='Randomness', + default=1.0, update=update_tree + ) + af3 = FloatProperty( + name='Randomness', description='Random offset in noise', - default=4.0, update=update_tree) - - makeMesh = BoolProperty(name='Make Mesh', + default=4.0, update=update_tree + ) + makeMesh = BoolProperty( + name='Make Mesh', description='Convert curves to mesh, uses skin modifier, enables armature simplification', - default=False, update=update_tree) - armLevels = IntProperty(name='Armature Levels', + default=False, update=update_tree + ) + armLevels = IntProperty( + name='Armature Levels', description='Number of branching levels to make bones for, 0 is all levels', min=0, - default=2, update=update_tree) - boneStep = IntVectorProperty(name='Bone Length', + default=2, update=update_tree + ) + boneStep = IntVectorProperty( + name='Bone Length', description='Number of stem segments per bone', min=1, default=[1, 1, 1, 1], - size=4, update=update_tree) - - presetName = StringProperty(name='Preset Name', + size=4, update=update_tree + ) + presetName = StringProperty( + name='Preset Name', description='The name of the preset to be saved', default='', - subtype='FILE_NAME', update=no_update_tree) - limitImport = BoolProperty(name='Limit Import', + subtype='FILE_NAME', update=no_update_tree + ) + limitImport = BoolProperty( + name='Limit Import', description='Limited imported tree to 2 levels & no leaves for speed', - default=True, update=no_update_tree) - overwrite = BoolProperty(name='Overwrite', + default=True, update=no_update_tree + ) + overwrite = BoolProperty( + name='Overwrite', description='When checked, overwrite existing preset files when saving', - default=False, update=no_update_tree) - -# startCurv = FloatProperty(name='Trunk Starting Angle', -# description=('The angle between vertical and the starting direction ' -# 'of the trunk'), -# min=0.0, -# max=360, -# default=0.0, update=update_tree) + default=False, update=no_update_tree + ) + """ + startCurv = FloatProperty( + name='Trunk Starting Angle', + description=('The angle between vertical and the starting direction' + 'of the trunk'), + min=0.0, + max=360, + default=0.0, update=update_tree + ) + """ @classmethod def poll(cls, context): return context.mode == 'OBJECT' def draw(self, context): - layout = self.layout # Branch specs - #layout.label('Tree Definition') + # layout.label('Tree Definition') layout.prop(self, 'chooseSet') @@ -711,7 +908,9 @@ class AddTree(bpy.types.Operator): # Unfortunately as_keyword doesn't work with vector properties, # so we need something custom. This is it data = [] - for a, b in (self.as_keywords(ignore=("chooseSet", "presetName", "limitImport", "do_update", "overwrite", "leafDupliObj"))).items(): + for a, b in (self.as_keywords( + ignore=("chooseSet", "presetName", "limitImport", + "do_update", "overwrite", "leafDupliObj"))).items(): # If the property is a vector property then add the slice to the list try: len(b) @@ -856,8 +1055,8 @@ class AddTree(bpy.types.Operator): box.prop(self, 'horzLeaves') box.prop(self, 'leafangle') - #box.label(" ") - #box.prop(self, 'bend') + # box.label(" ") + # box.prop(self, 'bend') elif self.chooseSet == '6': box = layout.box() @@ -878,9 +1077,9 @@ class AddTree(bpy.types.Operator): box.prop(self, 'frameRate') box.prop(self, 'loopFrames') - #row = box.row() - #row.prop(self, 'windSpeed') - #row.prop(self, 'windGust') + # row = box.row() + # row.prop(self, 'windSpeed') + # row.prop(self, 'windGust') box.label('Wind Settings:') box.prop(self, 'wind') @@ -897,7 +1096,7 @@ class AddTree(bpy.types.Operator): # Ensure the use of the global variables global settings, useSet start_time = time.time() - #bpy.ops.ImportData.filename = "quaking_aspen" + # bpy.ops.ImportData.filename = "quaking_aspen" # If we need to set the properties from a preset then do it here if useSet: for a, b in settings.items(): @@ -908,29 +1107,32 @@ class AddTree(bpy.types.Operator): useSet = False if not self.do_update: return {'PASS_THROUGH'} - addTree(self) - #cProfile.runctx("addTree(self)", globals(), locals()) - print("Tree creation in %0.1fs" %(time.time()-start_time)) + utils.addTree(self) + # cProfile.runctx("addTree(self)", globals(), locals()) + print("Tree creation in %0.1fs" % (time.time() - start_time)) + return {'FINISHED'} def invoke(self, context, event): -# global settings, useSet -# useSet = True - bpy.ops.sapling.importdata(filename = "quaking_aspen.py") + bpy.ops.sapling.importdata(filename="quaking_aspen.py") return self.execute(context) + def menu_func(self, context): self.layout.operator(AddTree.bl_idname, text="Sapling Tree Gen", icon='CURVE_DATA') + def register(): bpy.utils.register_module(__name__) bpy.types.INFO_MT_curve_add.append(menu_func) + def unregister(): bpy.utils.unregister_module(__name__) bpy.types.INFO_MT_curve_add.remove(menu_func) + if __name__ == "__main__": register() diff --git a/add_curve_sapling/utils.py b/add_curve_sapling/utils.py index 55c0f14f..e33df130 100644 --- a/add_curve_sapling/utils.py +++ b/add_curve_sapling/utils.py @@ -16,17 +16,19 @@ # # ##### END GPL LICENSE BLOCK ##### -print("version 3 imported") import bpy import time import copy -from mathutils import * +from mathutils import ( + Euler, + Matrix, + Vector, + ) from math import pi, sin, degrees, radians, atan2, copysign, cos, acos -from math import floor, ceil +from math import floor from random import random, uniform, seed, choice, getstate, setstate, randint -from bpy.props import * from collections import deque, OrderedDict tau = 2 * pi @@ -37,9 +39,11 @@ zAxis = Vector((0, 0, 1)) yAxis = Vector((0, 1, 0)) xAxis = Vector((1, 0, 0)) + # This class will contain a part of the tree which needs to be extended and the required tree parameters class stemSpline: - def __init__(self, spline, curvature, curvatureV, attractUp, segments, maxSegs, segLength, childStems, stemRadStart, stemRadEnd, splineNum, ofst, pquat): + def __init__(self, spline, curvature, curvatureV, attractUp, segments, maxSegs, + segLength, childStems, stemRadStart, stemRadEnd, splineNum, ofst, pquat): self.spline = spline self.p = spline.bezier_points[-1] self.curv = curvature @@ -60,19 +64,24 @@ class stemSpline: # This method determines the quaternion of the end of the spline def quat(self): if len(self.spline.bezier_points) == 1: - return ((self.spline.bezier_points[-1].handle_right - self.spline.bezier_points[-1].co).normalized()).to_track_quat('Z', 'Y') + return ((self.spline.bezier_points[-1].handle_right - + self.spline.bezier_points[-1].co).normalized()).to_track_quat('Z', 'Y') else: - return ((self.spline.bezier_points[-1].co - self.spline.bezier_points[-2].co).normalized()).to_track_quat('Z', 'Y') + return ((self.spline.bezier_points[-1].co - + self.spline.bezier_points[-2].co).normalized()).to_track_quat('Z', 'Y') + # Determine the declination def dec(self): tempVec = zAxis.copy() tempVec.rotate(self.quat()) return zAxis.angle(tempVec) + # Update the end of the spline and increment the segment count def updateEnd(self): self.p = self.spline.bezier_points[-1] self.seg += 1 + # This class contains the data for a point where a new branch will sprout class childPoint: def __init__(self, coords, quat, radiusPar, offset, sOfst, lengthPar, parBone): @@ -88,39 +97,39 @@ class childPoint: # This function calculates the shape ratio as defined in the paper def shapeRatio(shape, ratio, pruneWidthPeak=0.0, prunePowerHigh=0.0, prunePowerLow=0.0, custom=None): if shape == 0: - return 0.05 + 0.95*ratio #0.2 + 0.8*ratio + return 0.05 + 0.95 * ratio # 0.2 + 0.8 * ratio elif shape == 1: - return 0.2 + 0.8*sin(pi*ratio) + return 0.2 + 0.8 * sin(pi * ratio) elif shape == 2: - return 0.2 + 0.8*sin(0.5*pi*ratio) + return 0.2 + 0.8 * sin(0.5 * pi * ratio) elif shape == 3: return 1.0 elif shape == 4: - return 0.5 + 0.5*ratio + return 0.5 + 0.5 * ratio elif shape == 5: if ratio <= 0.7: - return 0.05 + 0.95 * ratio/0.7 + return 0.05 + 0.95 * ratio / 0.7 else: - return 0.05 + 0.95 * (1.0 - ratio)/0.3 + return 0.05 + 0.95 * (1.0 - ratio) / 0.3 elif shape == 6: - return 1.0 - 0.8*ratio + return 1.0 - 0.8 * ratio elif shape == 7: if ratio <= 0.7: - return 0.5 + 0.5*ratio/0.7 + return 0.5 + 0.5 * ratio / 0.7 else: - return 0.5 + 0.5*(1.0 - ratio)/0.3 + return 0.5 + 0.5 * (1.0 - ratio) / 0.3 elif shape == 8: r = 1 - ratio if r == 1: v = custom[3] elif r >= custom[2]: pos = (r - custom[2]) / (1 - custom[2]) - #if (custom[0] >= custom[1] <= custom[3]) or (custom[0] <= custom[1] >= custom[3]): + # if (custom[0] >= custom[1] <= custom[3]) or (custom[0] <= custom[1] >= custom[3]): pos = pos * pos v = (pos * (custom[3] - custom[1])) + custom[1] else: pos = r / custom[2] - #if (custom[0] >= custom[1] <= custom[3]) or (custom[0] <= custom[1] >= custom[3]): + # if (custom[0] >= custom[1] <= custom[3]) or (custom[0] <= custom[1] >= custom[3]): pos = 1 - (1 - pos) * (1 - pos) v = (pos * (custom[1] - custom[0])) + custom[0] @@ -128,15 +137,16 @@ def shapeRatio(shape, ratio, pruneWidthPeak=0.0, prunePowerHigh=0.0, prunePowerL elif shape == 9: if (ratio < (1 - pruneWidthPeak)) and (ratio > 0.0): - return ((ratio/(1 - pruneWidthPeak))**prunePowerHigh) + return ((ratio / (1 - pruneWidthPeak))**prunePowerHigh) elif (ratio >= (1 - pruneWidthPeak)) and (ratio < 1.0): - return (((1 - ratio)/pruneWidthPeak)**prunePowerLow) + return (((1 - ratio) / pruneWidthPeak)**prunePowerLow) else: return 0.0 elif shape == 10: return 0.5 + 0.5 * (1 - ratio) + # This function determines the actual number of splits at a given point using the global error def splits(n): global splitError @@ -144,6 +154,7 @@ def splits(n): splitError -= (nEff - n) return int(nEff) + def splits2(n): r = random() if r < n: @@ -151,6 +162,7 @@ def splits2(n): else: return 0 + def splits3(n): ni = int(n) nf = n - int(n) @@ -160,6 +172,7 @@ def splits3(n): else: return ni + 0 + # Determine the declination from a given quaternion def declination(quat): tempVec = zAxis.copy() @@ -167,6 +180,7 @@ def declination(quat): tempVec.normalize() return degrees(acos(tempVec.z)) + # Determines the angle of upward rotation of a segment due to attractUp def curveUp(attractUp, quat, curveRes): tempVec = yAxis.copy() @@ -174,32 +188,40 @@ def curveUp(attractUp, quat, curveRes): tempVec.normalize() dec = radians(declination(quat)) - curveUpAng = attractUp*dec*abs(tempVec.z)/curveRes + curveUpAng = attractUp * dec * abs(tempVec.z) / curveRes if (-dec + curveUpAng) < -pi: curveUpAng = -pi + dec if (dec - curveUpAng) < 0: curveUpAng = dec return curveUpAng + # Evaluate a bezier curve for the parameter 0<=t<=1 along its length def evalBez(p1, h1, h2, p2, t): - return ((1-t)**3)*p1 + (3*t*(1-t)**2)*h1 + (3*(t**2)*(1-t))*h2 + (t**3)*p2 + return ((1 - t)**3) * p1 + (3 * t * (1 - t)**2) * h1 + (3 * (t**2) * (1 - t)) * h2 + (t**3) * p2 + # Evaluate the unit tangent on a bezier curve for t def evalBezTan(p1, h1, h2, p2, t): - return ((-3*(1-t)**2)*p1 + (-6*t*(1-t) + 3*(1-t)**2)*h1 + (-3*(t**2) + 6*t*(1-t))*h2 + (3*t**2)*p2).normalized() + return ( + (-3 * (1 - t)**2) * p1 + (-6 * t * (1 - t) + 3 * (1 - t)**2) * h1 + + (-3 * (t**2) + 6 * t * (1 - t)) * h2 + (3 * t**2) * p2 + ).normalized() + # Determine the range of t values along a splines length where child stems are formed def findChildPoints(stemList, numChild): numPoints = sum([len(n.spline.bezier_points) for n in stemList]) numSplines = len(stemList) numSegs = numPoints - numSplines - numPerSeg = numChild/numSegs - numMain = round(numPerSeg*stemList[0].segMax, 0) - return [(a+1)/(numMain) for a in range(int(numMain))] + numPerSeg = numChild / numSegs + numMain = round(numPerSeg * stemList[0].segMax, 0) + return [(a + 1) / (numMain) for a in range(int(numMain))] + def findChildPoints2(stemList, numChild): - return [(a+1)/(numChild) for a in range(int(numChild))] + return [(a + 1) / (numChild) for a in range(int(numChild))] + # Find the coordinates, quaternion and radius for each t on the stem def interpStem1(stem, tVals, lPar, parRad): @@ -210,27 +232,42 @@ def interpStem1(stem, tVals, lPar, parRad): tempList = deque() for t in tVals: if t == 1.0: - index = numPoints-2 + index = numPoints - 2 coord = points[-1].co quat = (points[-1].handle_right - points[-1].co).to_track_quat('Z', 'Y') radius = points[-1].radius - tempList.append(childPoint(coord, quat, (parRad, radius), t, lPar, 'bone'+(str(stem.splN).rjust(3, '0'))+'.'+(str(index).rjust(3, '0')))) + tempList.append( + childPoint(coord, quat, (parRad, radius), t, lPar, 'bone' + + (str(stem.splN).rjust(3, '0')) + '.' + (str(index).rjust(3, '0'))) + ) elif (t >= checkVal) and (t < 1.0): scaledT = (t - checkVal) / ((1 - checkVal) + .0001) - length = (numPoints-1)*scaledT + length = (numPoints - 1) * scaledT index = int(length) tTemp = length - index - coord = evalBez(points[index].co, points[index].handle_right, points[index+1].handle_left, points[index+1].co, tTemp) - quat = (evalBezTan(points[index].co, points[index].handle_right, points[index+1].handle_left, points[index+1].co, tTemp)).to_track_quat('Z', 'Y') - radius = (1-tTemp)*points[index].radius + tTemp*points[index+1].radius # Not sure if this is the parent radius at the child point or parent start radius - - tempList.append(childPoint(coord, quat, (parRad, radius), t, lPar, 'bone'+(str(stem.splN).rjust(3, '0'))+'.'+(str(index).rjust(3, '0')))) - + coord = evalBez( + points[index].co, points[index].handle_right, + points[index + 1].handle_left, points[index + 1].co, tTemp + ) + quat = ( + evalBezTan( + points[index].co, points[index].handle_right, + points[index + 1].handle_left, points[index + 1].co, tTemp) + ).to_track_quat('Z', 'Y') + # Not sure if this is the parent radius at the child point or parent start radius + radius = (1 - tTemp) * points[index].radius + tTemp * points[index + 1].radius + + tempList.append( + childPoint( + coord, quat, (parRad, radius), t, lPar, 'bone' + + (str(stem.splN).rjust(3, '0')) + '.' + (str(index).rjust(3, '0'))) + ) return tempList + def interpStem(stem, tVals, lPar, parRad, maxOffset, baseSize): points = stem.spline.bezier_points numSegs = len(points) - 1 @@ -250,21 +287,40 @@ def interpStem(stem, tVals, lPar, parRad, maxOffset, baseSize): index = int(length) tTemp = length - index - coord = evalBez(points[index].co, points[index].handle_right, points[index+1].handle_left, points[index+1].co, tTemp) - quat = (evalBezTan(points[index].co, points[index].handle_right, points[index+1].handle_left, points[index+1].co, tTemp)).to_track_quat('Z', 'Y') - radius = (1-tTemp)*points[index].radius + tTemp*points[index+1].radius # Not sure if this is the parent radius at the child point or parent start radius - - tempList.append(childPoint(coord, quat, (parRad, radius), t, ofst, lPar, 'bone'+(str(stem.splN).rjust(3, '0'))+'.'+(str(index).rjust(3, '0')))) - - #add stem at tip - index = numSegs-1 + coord = evalBez( + points[index].co, points[index].handle_right, + points[index + 1].handle_left, points[index + 1].co, tTemp + ) + quat = ( + evalBezTan( + points[index].co, points[index].handle_right, + points[index + 1].handle_left, points[index + 1].co, tTemp + ) + ).to_track_quat('Z', 'Y') + # Not sure if this is the parent radius at the child point or parent start radius + radius = (1 - tTemp) * points[index].radius + tTemp * points[index + 1].radius + + tempList.append( + childPoint( + coord, quat, (parRad, radius), t, ofst, lPar, + 'bone' + (str(stem.splN).rjust(3, '0')) + '.' + (str(index).rjust(3, '0'))) + ) + + # add stem at tip + index = numSegs - 1 coord = points[-1].co quat = (points[-1].handle_right - points[-1].co).to_track_quat('Z', 'Y') radius = points[-1].radius - tempList.append(childPoint(coord, quat, (parRad, radius), 1, 1, lPar, 'bone'+(str(stem.splN).rjust(3, '0'))+'.'+(str(index).rjust(3, '0')))) + tempList.append( + childPoint( + coord, quat, (parRad, radius), 1, 1, lPar, + 'bone' + (str(stem.splN).rjust(3, '0')) + '.' + (str(index).rjust(3, '0')) + ) + ) return tempList + # round down bone number def roundBone(bone, step): bone_i = bone[:-3] @@ -272,10 +328,12 @@ def roundBone(bone, step): bone_n = int(bone_n / step) * step return bone_i + str(bone_n).rjust(3, '0') + # Convert a list of degrees to radians def toRad(list): return [radians(a) for a in list] + def anglemean(a1, a2, fac): x1 = sin(a1) y1 = cos(a1) @@ -287,16 +345,17 @@ def anglemean(a1, a2, fac): # This is the function which extends (or grows) a given stem. -def growSpline(n, stem, numSplit, splitAng, splitAngV, splineList, hType, splineToBone, closeTip, kp, splitHeight, outAtt, stemsegL, +def growSpline(n, stem, numSplit, splitAng, splitAngV, splineList, + hType, splineToBone, closeTip, kp, splitHeight, outAtt, stemsegL, lenVar, taperCrown, boneStep, rotate, rotateV): - #curv at base + # curv at base sCurv = stem.curv if (n == 0) and (kp <= splitHeight): sCurv = 0.0 - #curveangle = sCurv + (uniform(-stem.curvV, stem.curvV) * kp) - #curveVar = uniform(-stem.curvV, stem.curvV) * kp + # curveangle = sCurv + (uniform(-stem.curvV, stem.curvV) * kp) + # curveVar = uniform(-stem.curvV, stem.curvV) * kp curveangle = sCurv + (uniform(0, stem.curvV) * kp * stem.curvSignx) curveVar = uniform(0, stem.curvV) * kp * stem.curvSigny stem.curvSignx *= -1 @@ -317,7 +376,7 @@ def growSpline(n, stem, numSplit, splitAng, splitAngV, splineList, hType, spline dir = Euler((-rx, ry, 0), 'XYZ') - #length taperCrown + # length taperCrown if n == 0: dec = declination(dir) / 180 dec = dec ** 2 @@ -326,7 +385,7 @@ def growSpline(n, stem, numSplit, splitAng, splitAngV, splineList, hType, spline else: tf = 1.0 - #outward attraction + # outward attraction if (n > 0) and (kp > 0) and (outAtt > 0): p = stem.p.co.copy() d = atan2(p[0], -p[1]) + tau @@ -334,23 +393,24 @@ def growSpline(n, stem, numSplit, splitAng, splitAngV, splineList, hType, spline d = anglemean(edir[2], d, (kp * outAtt)) dirv = Euler((edir[0], edir[1], d), 'XYZ') dir = dirv.to_quaternion() - - #parent weight -# parWeight = kp * degrees(stem.curvV) * pi -# #parWeight = parWeight * kp -# #parWeight = kp -# if (n > 1) and (parWeight != 0): -# d1 = zAxis.copy() -# d2 = zAxis.copy() -# d1.rotate(dir) -# d2.rotate(stem.patentQuat) -# -# x = d1[0] + ((d2[0] - d1[0]) * parWeight) -# y = d1[1] + ((d2[1] - d1[1]) * parWeight) -# z = d1[2] + ((d2[2] - d1[2]) * parWeight) -# -# d3 = Vector((x, y, z)) -# dir = d3.to_track_quat('Z', 'Y') + """ + # parent weight + parWeight = kp * degrees(stem.curvV) * pi + parWeight = parWeight * kp + parWeight = kp + if (n > 1) and (parWeight != 0): + d1 = zAxis.copy() + d2 = zAxis.copy() + d1.rotate(dir) + d2.rotate(stem.patentQuat) + + x = d1[0] + ((d2[0] - d1[0]) * parWeight) + y = d1[1] + ((d2[1] - d1[1]) * parWeight) + z = d1[2] + ((d2[2] - d1[2]) * parWeight) + + d3 = Vector((x, y, z)) + dir = d3.to_track_quat('Z', 'Y') + """ # If the stem splits, we need to add new splines etc if numSplit > 0: @@ -358,14 +418,14 @@ def growSpline(n, stem, numSplit, splitAng, splitAngV, splineList, hType, spline cuData = stem.spline.id_data.name cu = bpy.data.curves[cuData] - #calc split angles + # calc split angles angle = choice([-1, 1]) * (splitAng + uniform(-splitAngV, splitAngV)) if n > 0: - #make branches flatter + # make branches flatter angle *= max(1 - declination(dir) / 90, 0) * .67 + .33 spreadangle = choice([-1, 1]) * (splitAng + uniform(-splitAngV, splitAngV)) - #branchRotMat = Matrix.Rotation(radians(uniform(0, 360)), 3, 'Z') + # branchRotMat = Matrix.Rotation(radians(uniform(0, 360)), 3, 'Z') if not hasattr(stem, 'rLast'): stem.rLast = radians(uniform(0, 360)) @@ -376,31 +436,33 @@ def growSpline(n, stem, numSplit, splitAng, splitAngV, splineList, hType, spline # Now for each split add the new spline and adjust the growth direction for i in range(numSplit): - #find split scale + # find split scale lenV = uniform(1 - lenVar, 1 + lenVar) bScale = min(lenV * tf, 1) newSpline = cu.splines.new('BEZIER') newPoint = newSpline.bezier_points[-1] (newPoint.co, newPoint.handle_left_type, newPoint.handle_right_type) = (stem.p.co, 'VECTOR', 'VECTOR') - newPoint.radius = (stem.radS*(1 - stem.seg/stem.segMax) + stem.radE*(stem.seg/stem.segMax)) * bScale + newPoint.radius = ( + stem.radS * (1 - stem.seg / stem.segMax) + stem.radE * (stem.seg / stem.segMax) + ) * bScale # Here we make the new "sprouting" stems diverge from the current direction divRotMat = Matrix.Rotation(angle + curveangle, 3, 'X') dirVec = zAxis.copy() dirVec.rotate(divRotMat) - #horizontal curvature variation + # horizontal curvature variation dirVec.rotate(curveVarMat) - if n == 0: #Special case for trunk splits + if n == 0: # Special case for trunk splits dirVec.rotate(branchRotMat) - ang = pi - ((tau) / (numSplit + 1)) * (i+1) + ang = pi - ((tau) / (numSplit + 1)) * (i + 1) dirVec.rotate(Matrix.Rotation(ang, 3, 'Z')) # Spread the stem out in a random fashion spreadMat = Matrix.Rotation(spreadangle, 3, 'Y') - if n != 0: #Special case for trunk splits + if n != 0: # Special case for trunk splits dirVec.rotate(spreadMat) dirVec.rotate(dir) @@ -415,12 +477,12 @@ def growSpline(n, stem, numSplit, splitAng, splitAngV, splineList, hType, spline # Make the growth vec the length of a stem segment dirVec.normalize() - #split length variation + # split length variation stemL = stemsegL * lenV dirVec *= stemL * tf ofst = stem.offsetLen + (stem.segL * (len(stem.spline.bezier_points) - 1)) - ##dirVec *= stem.segL + # dirVec *= stem.segL # Get the end point position end_co = stem.p.co.copy() @@ -429,40 +491,48 @@ def growSpline(n, stem, numSplit, splitAng, splitAngV, splineList, hType, spline newSpline.bezier_points.add() newPoint = newSpline.bezier_points[-1] (newPoint.co, newPoint.handle_left_type, newPoint.handle_right_type) = (end_co + dirVec, hType, hType) - newPoint.radius = (stem.radS*(1 - (stem.seg + 1)/stem.segMax) + stem.radE*((stem.seg + 1)/stem.segMax)) * bScale - if (stem.seg == stem.segMax-1) and closeTip: + newPoint.radius = ( + stem.radS * (1 - (stem.seg + 1) / stem.segMax) + + stem.radE * ((stem.seg + 1) / stem.segMax) + ) * bScale + if (stem.seg == stem.segMax - 1) and closeTip: newPoint.radius = 0.0 - # If this isn't the last point on a stem, then we need to add it to the list of stems to continue growing - #print(stem.seg != stem.segMax, stem.seg, stem.segMax) - #if stem.seg != stem.segMax: # if probs not nessesary - nstem = stemSpline(newSpline, stem.curv, stem.curvV, stem.vertAtt, stem.seg+1, stem.segMax, stemL, stem.children, - stem.radS * bScale, stem.radE * bScale, len(cu.splines)-1, ofst, stem.quat()) - nstem.splitlast = 1#numSplit #keep track of numSplit for next stem + # If this isn't the last point on a stem, then we need to add it + # to the list of stems to continue growing + # print(stem.seg != stem.segMax, stem.seg, stem.segMax) + # if stem.seg != stem.segMax: # if probs not nessesary + nstem = stemSpline( + newSpline, stem.curv, stem.curvV, stem.vertAtt, stem.seg + 1, + stem.segMax, stemL, stem.children, + stem.radS * bScale, stem.radE * bScale, len(cu.splines) - 1, ofst, stem.quat() + ) + nstem.splitlast = 1 # numSplit # keep track of numSplit for next stem nstem.rLast = branchRot + pi splineList.append(nstem) - bone = 'bone'+(str(stem.splN)).rjust(3, '0')+'.'+(str(len(stem.spline.bezier_points)-2)).rjust(3, '0') + bone = 'bone' + (str(stem.splN)).rjust(3, '0') + '.' + \ + (str(len(stem.spline.bezier_points) - 2)).rjust(3, '0') bone = roundBone(bone, boneStep[n]) - splineToBone.append((bone, False, True, len(stem.spline.bezier_points)-2)) + splineToBone.append((bone, False, True, len(stem.spline.bezier_points) - 2)) # The original spline also needs to keep growing so adjust its direction too divRotMat = Matrix.Rotation(-angle + curveangle, 3, 'X') dirVec = zAxis.copy() dirVec.rotate(divRotMat) - #horizontal curvature variation + # horizontal curvature variation dirVec.rotate(curveVarMat) - if n == 0: #Special case for trunk splits + if n == 0: # Special case for trunk splits dirVec.rotate(branchRotMat) - #spread + # spread spreadMat = Matrix.Rotation(-spreadangle, 3, 'Y') - if n != 0: #Special case for trunk splits + if n != 0: # Special case for trunk splits dirVec.rotate(spreadMat) dirVec.rotate(dir) - stem.splitlast = 1#numSplit #keep track of numSplit for next stem + stem.splitlast = 1 # numSplit #keep track of numSplit for next stem else: # If there are no splits then generate the growth direction without accounting for spreading of stems @@ -470,12 +540,12 @@ def growSpline(n, stem, numSplit, splitAng, splitAngV, splineList, hType, spline divRotMat = Matrix.Rotation(curveangle, 3, 'X') dirVec.rotate(divRotMat) - #horizontal curvature variation + # horizontal curvature variation dirVec.rotate(curveVarMat) dirVec.rotate(dir) - stem.splitlast = 0#numSplit #keep track of numSplit for next stem + stem.splitlast = 0 # numSplit #keep track of numSplit for next stem # Introduce upward curvature upRotAxis = xAxis.copy() @@ -493,25 +563,32 @@ def growSpline(n, stem, numSplit, splitAng, splitAngV, splineList, hType, spline stem.spline.bezier_points.add() newPoint = stem.spline.bezier_points[-1] (newPoint.co, newPoint.handle_left_type, newPoint.handle_right_type) = (end_co + dirVec, hType, hType) - newPoint.radius = stem.radS*(1 - (stem.seg + 1)/stem.segMax) + stem.radE*((stem.seg + 1)/stem.segMax) - if (stem.seg == stem.segMax-1) and closeTip: + newPoint.radius = stem.radS * (1 - (stem.seg + 1) / stem.segMax) + \ + stem.radE * ((stem.seg + 1) / stem.segMax) + + if (stem.seg == stem.segMax - 1) and closeTip: newPoint.radius = 0.0 - # There are some cases where a point cannot have handles as VECTOR straight away, set these now. + # There are some cases where a point cannot have handles as VECTOR straight away, set these now if len(stem.spline.bezier_points) == 2: tempPoint = stem.spline.bezier_points[0] (tempPoint.handle_left_type, tempPoint.handle_right_type) = ('VECTOR', 'VECTOR') # Update the last point in the spline to be the newly added one stem.updateEnd() - #return splineList + # return splineList + -def genLeafMesh(leafScale, leafScaleX, leafScaleT, leafScaleV, loc, quat, offset, index, downAngle, downAngleV, rotate, rotateV, oldRot, +def genLeafMesh(leafScale, leafScaleX, leafScaleT, leafScaleV, loc, quat, + offset, index, downAngle, downAngleV, rotate, rotateV, oldRot, bend, leaves, leafShape, leafangle, horzLeaves): if leafShape == 'hex': - verts = [Vector((0, 0, 0)), Vector((0.5, 0, 1/3)), Vector((0.5, 0, 2/3)), Vector((0, 0, 1)), Vector((-0.5, 0, 2/3)), Vector((-0.5, 0, 1/3))] + verts = [ + Vector((0, 0, 0)), Vector((0.5, 0, 1 / 3)), Vector((0.5, 0, 2 / 3)), + Vector((0, 0, 1)), Vector((-0.5, 0, 2 / 3)), Vector((-0.5, 0, 1 / 3)) + ] edges = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 0], [0, 3]] faces = [[0, 1, 2, 3], [0, 3, 4, 5]] elif leafShape == 'rect': - #verts = [Vector((1, 0, 0)), Vector((1, 0, 1)), Vector((-1, 0, 1)), Vector((-1, 0, 0))] + # verts = [Vector((1, 0, 0)), Vector((1, 0, 1)), Vector((-1, 0, 1)), Vector((-1, 0, 0))] verts = [Vector((.5, 0, 0)), Vector((.5, 0, 1)), Vector((-.5, 0, 1)), Vector((-.5, 0, 0))] edges = [[0, 1], [1, 2], [2, 3], [3, 0]] faces = [[0, 1, 2, 3]] @@ -533,26 +610,27 @@ def genLeafMesh(leafScale, leafScaleX, leafScaleT, leafScaleV, loc, quat, offset else: rotMat = Matrix.Rotation(oldRot, 3, 'Z') - # If the -ve flag for rotate is used we need to find which side of the stem the last child point was and then grow in the opposite direction. + # If the -ve flag for rotate is used we need to find which side of the stem + # the last child point was and then grow in the opposite direction if rotate < 0.0: oldRot = -copysign(rotate + uniform(-rotateV, rotateV), oldRot) else: # If the special -ve flag for leaves is used we need a different rotation of the leaf geometry if leaves == -1: - #oldRot = 0 + # oldRot = 0 rotMat = Matrix.Rotation(0, 3, 'Y') elif leaves < -1: oldRot += rotate / (-leaves - 1) else: oldRot += rotate + uniform(-rotateV, rotateV) - -# if leaves < 0: -# rotMat = Matrix.Rotation(oldRot, 3, 'Y') -# else: -# rotMat = Matrix.Rotation(oldRot, 3, 'Z') - + """ + if leaves < 0: + rotMat = Matrix.Rotation(oldRot, 3, 'Y') + else: + rotMat = Matrix.Rotation(oldRot, 3, 'Z') + """ if leaves >= 0: - #downRotMat = Matrix.Rotation(downAngle+uniform(-downAngleV, downAngleV), 3, 'X') + # downRotMat = Matrix.Rotation(downAngle+uniform(-downAngleV, downAngleV), 3, 'X') if downAngleV > 0.0: downV = -downAngleV * offset @@ -560,7 +638,7 @@ def genLeafMesh(leafScale, leafScaleX, leafScaleT, leafScaleV, loc, quat, offset downV = uniform(-downAngleV, downAngleV) downRotMat = Matrix.Rotation(downAngle + downV, 3, 'X') - #leaf scale variation + # leaf scale variation if (leaves < -1) and (rotate != 0): f = 1 - abs((oldRot - (rotate / (-leaves - 1))) / (rotate / 2)) else: @@ -586,7 +664,7 @@ def genLeafMesh(leafScale, leafScaleX, leafScaleT, leafScaleV, loc, quat, offset thetaPos = atan2(loc.y, loc.x) thetaBend = thetaPos - atan2(normal.y, normal.x) - rotateZ = Matrix.Rotation(bend*thetaBend, 3, 'Z') + rotateZ = Matrix.Rotation(bend * thetaBend, 3, 'Z') normal.rotate(rotateZ) orientationVec.rotate(rotateZ) @@ -594,7 +672,7 @@ def genLeafMesh(leafScale, leafScaleX, leafScaleT, leafScaleV, loc, quat, offset orientation = atan2(orientationVec.y, orientationVec.x) rotateZOrien = Matrix.Rotation(orientation, 3, 'X') - rotateX = Matrix.Rotation(bend*phiBend, 3, 'Z') + rotateX = Matrix.Rotation(bend * phiBend, 3, 'Z') rotateZOrien2 = Matrix.Rotation(-orientation, 3, 'X') @@ -602,11 +680,11 @@ def genLeafMesh(leafScale, leafScaleX, leafScaleT, leafScaleV, loc, quat, offset for v in verts: v.z *= leafScale v.y *= leafScale - v.x *= leafScaleX*leafScale + v.x *= leafScaleX * leafScale v.rotate(Euler((0, 0, radians(180)))) - #leafangle + # leafangle v.rotate(Matrix.Rotation(radians(-leafangle), 3, 'X')) if rotate < 0: @@ -646,8 +724,9 @@ def genLeafMesh(leafScale, leafScaleX, leafScaleT, leafScaleV, loc, quat, offset return vertsList, facesList, normal, oldRot -def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSize, leaves, levelCount, splineToBone, - treeOb, wind, gust, gustF, af1, af2, af3, leafAnim, loopFrames, previewArm, armLevels, makeMesh, boneStep): +def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSize, leaves, + levelCount, splineToBone, treeOb, wind, gust, gustF, af1, af2, af3, + leafAnim, loopFrames, previewArm, armLevels, makeMesh, boneStep): arm = bpy.data.armatures.new('tree') armOb = bpy.data.objects.new('treeArm', arm) bpy.context.scene.objects.link(armOb) @@ -666,7 +745,7 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi armMod.use_apply_on_spline = True armMod.object = armOb armMod.use_bone_envelopes = True - armMod.use_vertex_groups = False # curves don't have vertex groups (yet) + armMod.use_vertex_groups = False # curves don't have vertex groups (yet) # If there are leaves then they need a modifier if leaves: armMod = leafObj.modifiers.new('windSway', 'ARMATURE') @@ -691,7 +770,7 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi # Get some data about the spline like length and number of points numPoints = len(s.bezier_points) - 1 - #find branching level + # find branching level level = 0 for l, c in enumerate(levelCount): if i < c: @@ -708,10 +787,11 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi bxOffset = uniform(0, tau) byOffset = uniform(0, tau) # Set the phase multiplier for the spline - #bMult_r = (s.bezier_points[0].radius / max(splineL, 1e-6)) * (1 / 15) * (1 / frameRate) - #bMult = degrees(bMult_r) # This shouldn't have to be in degrees but it looks much better in animation + # bMult_r = (s.bezier_points[0].radius / max(splineL, 1e-6)) * (1 / 15) * (1 / frameRate) + # This shouldn't have to be in degrees but it looks much better in animation + # bMult = degrees(bMult_r) bMult = (1 / max(splineL ** .5, 1e-6)) * (1 / 4) - #print((1 / bMult) * tau) #print wavelength in frames + # print((1 / bMult) * tau) #print wavelength in frames windFreq1 = bMult * animSpeed windFreq2 = 0.7 * bMult * animSpeed @@ -736,14 +816,14 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi b.head_radius = s.bezier_points[n].radius b.tail_radius = s.bezier_points[n + 1].radius b.envelope_distance = 0.001 - -# # If there are leaves then we need a new vertex group so they will attach to the bone -# if not leafAnim: -# if (len(levelCount) > 1) and (i >= levelCount[-2]) and leafObj: -# leafObj.vertex_groups.new(boneName) -# elif (len(levelCount) == 1) and leafObj: -# leafObj.vertex_groups.new(boneName) - + """ + # If there are leaves then we need a new vertex group so they will attach to the bone + if not leafAnim: + if (len(levelCount) > 1) and (i >= levelCount[-2]) and leafObj: + leafObj.vertex_groups.new(boneName) + elif (len(levelCount) == 1) and leafObj: + leafObj.vertex_groups.new(boneName) + """ # If this is first point of the spline then it must be parented to the level above it if n == 0: if parBone: @@ -759,12 +839,12 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi # Add the animation to the armature if required if armAnim: # Define all the required parameters of the wind sway by the dimension of the spline - #a0 = 4 * splineL * (1 - n / (numPoints + 1)) / max(s.bezier_points[n].radius, 1e-6) + # a0 = 4 * splineL * (1 - n / (numPoints + 1)) / max(s.bezier_points[n].radius, 1e-6) a0 = 2 * (splineL / numPoints) * (1 - n / (numPoints + 1)) / max(s.bezier_points[n].radius, 1e-6) a0 = a0 * min(step, numPoints) - #a0 = (splineL / numPoints) / max(s.bezier_points[n].radius, 1e-6) + # a0 = (splineL / numPoints) / max(s.bezier_points[n].radius, 1e-6) a1 = (wind / 50) * a0 - a2 = a1 * .65 #(windGust / 50) * a0 + a1 / 2 + a2 = a1 * .65 # (windGust / 50) * a0 + a1 / 2 p = s.bezier_points[nx].co - s.bezier_points[n].co p.normalize() @@ -777,9 +857,9 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi a3 = radians(a3) a4 = radians(a4) - #wind bending + # wind bending if loopFrames == 0: - swayFreq = gustF * (tau / fps) * frameRate #animSpeed # .075 # 0.02 + swayFreq = gustF * (tau / fps) * frameRate # animSpeed # .075 # 0.02 else: swayFreq = 1 / (loopFrames / tau) @@ -791,9 +871,12 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi a4 = 0 # Add new fcurves for each sway as well as the modifiers - swayX = armOb.animation_data.action.fcurves.new('pose.bones["' + boneName + '"].rotation_euler', 0) - swayY = armOb.animation_data.action.fcurves.new('pose.bones["' + boneName + '"].rotation_euler', 2) - + swayX = armOb.animation_data.action.fcurves.new( + 'pose.bones["' + boneName + '"].rotation_euler', 0 + ) + swayY = armOb.animation_data.action.fcurves.new( + 'pose.bones["' + boneName + '"].rotation_euler', 2 + ) swayXMod1 = swayX.modifiers.new(type='FNGENERATOR') swayXMod2 = swayX.modifiers.new(type='FNGENERATOR') @@ -819,7 +902,7 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi swayYMod2.phase_multiplier = windFreq2 swayYMod2.use_additive = True - #wind bending + # wind bending swayYMod3 = swayY.modifiers.new(type='FNGENERATOR') swayYMod3.amplitude = a3 swayYMod3.phase_multiplier = swayFreq @@ -840,7 +923,7 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi leafParent = roundBone(cp.parBone, boneStep[armLevels]) idx = int(leafParent[4:-4]) while leafParent not in bonelist: - #find parent bone of parent bone + # find parent bone of parent bone leafParent = splineToBone[idx] idx = int(leafParent[4:-4]) @@ -852,7 +935,10 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi b.envelope_distance = 0.0 b.parent = arm.edit_bones[leafParent] - vertexGroups[bname] = [v.index for v in leafMesh.vertices[leafVertSize * i:(leafVertSize * i + leafVertSize)]] + vertexGroups[bname] = [ + v.index for v in + leafMesh.vertices[leafVertSize * i:(leafVertSize * i + leafVertSize)] + ] if armAnim: # Define all the required parameters of the wind sway by the dimension of the spline @@ -867,9 +953,12 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi byOffset = uniform(-ofstRand, ofstRand) # Add new fcurves for each sway as well as the modifiers - swayX = armOb.animation_data.action.fcurves.new('pose.bones["' + bname + '"].rotation_euler', 0) - swayY = armOb.animation_data.action.fcurves.new('pose.bones["' + bname + '"].rotation_euler', 2) - + swayX = armOb.animation_data.action.fcurves.new( + 'pose.bones["' + bname + '"].rotation_euler', 0 + ) + swayY = armOb.animation_data.action.fcurves.new( + 'pose.bones["' + bname + '"].rotation_euler', 2 + ) # Add keyframe so noise works swayX.keyframe_points.add() swayY.keyframe_points.add() @@ -901,7 +990,10 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi else: if leafParent not in vertexGroups: vertexGroups[leafParent] = [] - vertexGroups[leafParent].extend([v.index for v in leafMesh.vertices[leafVertSize * i:(leafVertSize * i + leafVertSize)]]) + vertexGroups[leafParent].extend( + [v.index for v in + leafMesh.vertices[leafVertSize * i:(leafVertSize * i + leafVertSize)]] + ) for group in vertexGroups: leafObj.vertex_groups.new(group) @@ -914,8 +1006,9 @@ def create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSi treeOb.parent = armOb -def kickstart_trunk(addstem, levels, leaves, branches, cu, curve, curveRes, curveV, attractUp, length, lengthV, ratio, ratioPower, resU, scale0, scaleV0, - scaleVal, taper, minRadius, rootFlare): +def kickstart_trunk(addstem, levels, leaves, branches, cu, curve, curveRes, + curveV, attractUp, length, lengthV, ratio, ratioPower, + resU, scale0, scaleV0, scaleVal, taper, minRadius, rootFlare): newSpline = cu.splines.new('BEZIER') cu.resolution_u = resU newPoint = newSpline.bezier_points[-1] @@ -925,33 +1018,38 @@ def kickstart_trunk(addstem, levels, leaves, branches, cu, curve, curveRes, curv # (newPoint.handle_right_type, newPoint.handle_left_type) = ('VECTOR', 'VECTOR') branchL = scaleVal * length[0] curveVal = curve[0] / curveRes[0] - #curveVal = curveVal * (branchL / scaleVal) + # curveVal = curveVal * (branchL / scaleVal) if levels == 1: childStems = leaves else: childStems = branches[1] - startRad = scaleVal * ratio * scale0 * uniform(1-scaleV0, 1+scaleV0) ## * (scale0 + uniform(-scaleV0, scaleV0)) # + startRad = scaleVal * ratio * scale0 * uniform(1 - scaleV0, 1 + scaleV0) # * (scale0 + uniform(-scaleV0, scaleV0)) endRad = (startRad * (1 - taper[0])) ** ratioPower startRad = max(startRad, minRadius) endRad = max(endRad, minRadius) newPoint.radius = startRad * rootFlare addstem( - stemSpline(newSpline, curveVal, curveV[0] / curveRes[0], attractUp[0], 0, curveRes[0], branchL / curveRes[0], - childStems, startRad, endRad, 0, 0, None)) - - -def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, curve, curveBack, curveRes, curveV, attractUp, - downAngle, downAngleV, leafDist, leaves, length, lengthV, levels, n, ratioPower, resU, - rotate, rotateV, scaleVal, shape, storeN, taper, shapeS, minRadius, radiusTweak, customShape, rMode, segSplits, + stemSpline( + newSpline, curveVal, curveV[0] / curveRes[0], attractUp[0], + 0, curveRes[0], branchL / curveRes[0], + childStems, startRad, endRad, 0, 0, None + ) + ) + + +def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, curve, curveBack, + curveRes, curveV, attractUp, downAngle, downAngleV, leafDist, leaves, length, + lengthV, levels, n, ratioPower, resU, rotate, rotateV, scaleVal, shape, storeN, + taper, shapeS, minRadius, radiusTweak, customShape, rMode, segSplits, useOldDownAngle, useParentAngle, boneStep): - #prevent baseSize from going to 1.0 + # prevent baseSize from going to 1.0 baseSize = min(0.999, baseSize) # Store the old rotation to allow new stems to be rotated away from the previous one. oldRotate = 0 - #use fancy child point selection / rotation + # use fancy child point selection / rotation if (n == 1) and (rMode != "original"): childP_T = OrderedDict() childP_L = [] @@ -976,17 +1074,17 @@ def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, cu oldRotate += rotate[n] bRotate = oldRotate + uniform(-rotateV[n], rotateV[n]) - #choose start point whose angle is closest to the rotate angle + # choose start point whose angle is closest to the rotate angle a1 = bRotate % tau a_diff = [] for a in p: a2 = atan2(a.co[0], -a.co[1]) - d = min((a1-a2+tau)%tau, (a2-a1+tau)%tau) + d = min((a1 - a2 + tau) % tau, (a2 - a1 + tau) % tau) a_diff.append(d) idx = a_diff.index(min(a_diff)) - #find actual rotate angle from branch location + # find actual rotate angle from branch location br = p[idx] b = br.co vx = sin(bRotate) @@ -996,7 +1094,7 @@ def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, cu bD = ((b[0] * b[0] + b[1] * b[1]) ** .5) bL = br.lengthPar * length[1] * shapeRatio(shape, (1 - br.offset) / (1 - baseSize), custom=customShape) - #account for down angle + # account for down angle if downAngleV[1] > 0: downA = downAngle[n] + (-downAngleV[n] * (1 - (1 - br.offset) / (1 - baseSize)) ** 2) else: @@ -1011,27 +1109,27 @@ def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, cu bv = Vector((b[0], -b[1])) cv = v - bv a = atan2(cv[0], cv[1]) - #rot_a.append(a) - -# # add fill points at top #experimental -# fillHeight = 1 - degrees(rotateV[3])#0.8 -# if fillHeight < 1: -# w = (p[0].offset - fillHeight) / (1- fillHeight) -# prob_b = random() < w -# else: -# prob_b = False -# -# if (p[0].offset > fillHeight): #prob_b and (len(p) > 1): ##(p[0].offset > fillHeight) and -# childP.append(p[randint(0, len(p)-1)]) -# rot_a.append(bRotate)# + pi) + # rot_a.append(a) + """ + # add fill points at top #experimental + fillHeight = 1 - degrees(rotateV[3]) # 0.8 + if fillHeight < 1: + w = (p[0].offset - fillHeight) / (1- fillHeight) + prob_b = random() < w + else: + prob_b = False + if (p[0].offset > fillHeight): # prob_b and (len(p) > 1): ##(p[0].offset > fillHeight) and + childP.append(p[randint(0, len(p)-1)]) + rot_a.append(bRotate)# + pi) + """ childP.append(p[idx]) rot_a.append(a) else: - idx = randint(0, len(p)-1) + idx = randint(0, len(p) - 1) childP.append(p[idx]) - #childP.append(p[idx]) + # childP.append(p[idx]) childP.extend(childP_L) rot_a.extend([0] * len(childP_L)) @@ -1056,14 +1154,15 @@ def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, cu if downAngleV[n] < 0.0: downV = uniform(-downAngleV[n], downAngleV[n]) else: - downV = -downAngleV[n] * (1 - (1 - p.offset) / (1 - baseSize)) ** 2 #(110, 80) = (60, -50) + downV = -downAngleV[n] * (1 - (1 - p.offset) / (1 - baseSize)) ** 2 # (110, 80) = (60, -50) if p.offset == 1: downRotMat = Matrix.Rotation(0, 3, 'X') else: downRotMat = Matrix.Rotation(downAngle[n] + downV, 3, 'X') - # If the -ve flag for rotate is used we need to find which side of the stem the last child point was and then grow in the opposite direction. + # If the -ve flag for rotate is used we need to find which side of the stem + # the last child point was and then grow in the opposite direction if rotate[n] < 0.0: oldRotate = -copysign(rotate[n], oldRotate) # Otherwise just generate a random number in the specified range @@ -1080,7 +1179,7 @@ def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, cu tempPos.rotate(downRotMat) tempPos.rotate(rotMat) - #use quat angle + # use quat angle if (rMode == "rotate") and (n == 1) and (p.offset != 1): if useParentAngle: edir = p.quat.to_euler('XYZ', Euler((0, 0, bRotate), 'XYZ')) @@ -1101,13 +1200,13 @@ def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, cu newPoint.handle_right = p.co + tempPos # Make length variation inversely proportional to segSplits - #lenV = (1 - min(segSplits[n], 1)) * lengthV[n] + # lenV = (1 - min(segSplits[n], 1)) * lengthV[n] # Find branch length and the number of child stems. maxbL = scaleVal - for l in length[:n+1]: + for l in length[:n + 1]: maxbL *= l - lMax = length[n] # * uniform(1 - lenV, 1 + lenV) + lMax = length[n] # * uniform(1 - lenV, 1 + lenV) if n == 1: lShape = shapeRatio(shape, (1 - p.stemOffset) / (1 - baseSize), custom=customShape) else: @@ -1122,7 +1221,7 @@ def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, cu else: childStems = leaves * (0.1 + 0.9 * (branchL / maxbL)) * shapeRatio(leafDist, (1 - p.offset)) - #print("n=%d, levels=%d, n'=%d, childStems=%s"%(n, levels, storeN, childStems)) + # print("n=%d, levels=%d, n'=%d, childStems=%s"%(n, levels, storeN, childStems)) # Determine the starting and ending radii of the stem using the tapering of the stem startRad = min((p.radiusPar[0] * ((branchL / p.lengthPar) ** ratioPower)) * radiusTweak[n], p.radiusPar[1]) @@ -1137,14 +1236,18 @@ def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, cu curveVal = curve[n] / curveRes[n] curveVar = curveV[n] / curveRes[n] - #curveVal = curveVal * (branchL / scaleVal) + # curveVal = curveVal * (branchL / scaleVal) # Add the new stem to list of stems to grow and define which bone it will be parented to addstem( - stemSpline(newSpline, curveVal, curveVar, attractUp[n], 0, curveRes[n], branchL / curveRes[n], childStems, - startRad, endRad, len(cu.splines) - 1, 0, p.quat)) - - bone = roundBone(p.parBone, boneStep[n-1]) + stemSpline( + newSpline, curveVal, curveVar, attractUp[n], + 0, curveRes[n], branchL / curveRes[n], childStems, + startRad, endRad, len(cu.splines) - 1, 0, p.quat + ) + ) + + bone = roundBone(p.parBone, boneStep[n - 1]) if p.offset == 1: isend = True else: @@ -1152,23 +1255,26 @@ def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, cu addsplinetobone((bone, isend)) -def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, currentScale, curve, curveBack, curveRes, - deleteSpline, forceSprout, handles, n, oldMax, orginalSplineToBone, originalCo, originalCurv, - originalCurvV, originalHandleL, originalHandleR, originalLength, originalSeg, prune, prunePowerHigh, - prunePowerLow, pruneRatio, pruneWidth, pruneBase, pruneWidthPeak, randState, ratio, scaleVal, segSplits, - splineToBone, splitAngle, splitAngleV, st, startPrune, branchDist, length, splitByLen, closeTip, nrings, - splitBias, splitHeight, attractOut, rMode, lengthV, taperCrown, boneStep, rotate, rotateV): +def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, currentScale, curve, + curveBack, curveRes, deleteSpline, forceSprout, handles, n, oldMax, orginalSplineToBone, + originalCo, originalCurv, originalCurvV, originalHandleL, originalHandleR, originalLength, + originalSeg, prune, prunePowerHigh, prunePowerLow, pruneRatio, pruneWidth, pruneBase, + pruneWidthPeak, randState, ratio, scaleVal, segSplits, splineToBone, splitAngle, splitAngleV, + st, startPrune, branchDist, length, splitByLen, closeTip, nrings, splitBias, splitHeight, + attractOut, rMode, lengthV, taperCrown, boneStep, rotate, rotateV): while startPrune and ((currentMax - currentMin) > 0.005): setstate(randState) - # If the search will halt after this iteration, then set the adjustment of stem length to take into account the pruning ratio + # If the search will halt after this iteration, then set the adjustment of stem + # length to take into account the pruning ratio if (currentMax - currentMin) < 0.01: currentScale = (currentScale - 1) * pruneRatio + 1 startPrune = False forceSprout = True # Change the segment length of the stem by applying some scaling st.segL = originalLength * currentScale - # To prevent millions of splines being created we delete any old ones and replace them with only their first points to begin the spline again + # To prevent millions of splines being created we delete any old ones and + # replace them with only their first points to begin the spline again if deleteSpline: for x in splineList: cu.splines.remove(x.spline) @@ -1189,9 +1295,9 @@ def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, cu # Initialise the spline list for those contained in the current level of branching splineList = [st] - #split length variation - stemsegL = splineList[0].segL #initial segment length used for variation - splineList[0].segL = stemsegL * uniform(1 - lengthV[n], 1 + lengthV[n]) #variation for first stem + # split length variation + stemsegL = splineList[0].segL # initial segment length used for variation + splineList[0].segL = stemsegL * uniform(1 - lengthV[n], 1 + lengthV[n]) # variation for first stem # For each of the segments of the stem which must be grown we have to add to each spline in splineList for k in range(curveRes[n]): @@ -1199,13 +1305,13 @@ def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, cu tempList = splineList[:] # print('Leng: ', len(tempList)) - #for curve variation + # for curve variation if curveRes[n] > 1: - kp = (k / (curveRes[n] - 1)) # * 2 + kp = (k / (curveRes[n] - 1)) # * 2 else: kp = 1.0 - #split bias + # split bias splitValue = segSplits[n] if n == 0: splitValue = ((2 * splitBias) * (kp - .5) + 1) * splitValue @@ -1213,8 +1319,7 @@ def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, cu # For each of the splines in this list set the number of splits and then grow it for spl in tempList: - - #adjust numSplit + # adjust numSplit lastsplit = getattr(spl, 'splitlast', 0) splitVal = splitValue if lastsplit == 0: @@ -1224,17 +1329,18 @@ def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, cu if k == 0: numSplit = 0 - elif (n == 0) and (k < ((curveRes[n]-1) * splitHeight)) and (k != 1): + elif (n == 0) and (k < ((curveRes[n] - 1) * splitHeight)) and (k != 1): numSplit = 0 elif (k == 1) and (n == 0): numSplit = baseSplits - elif (n == 0) and (k == int((curveRes[n]-1) * splitHeight) + 1) and (splitVal > 0): #allways split at splitHeight + # allways split at splitHeight + elif (n == 0) and (k == int((curveRes[n] - 1) * splitHeight) + 1) and (splitVal > 0): numSplit = 1 else: if (n >= 1) and splitByLen: L = ((spl.segL * curveRes[n]) / scaleVal) lf = 1 - for l in length[:n+1]: + for l in length[:n + 1]: lf *= l L = L / lf numSplit = splits2(splitVal * L) @@ -1242,10 +1348,13 @@ def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, cu numSplit = splits2(splitVal) if (k == int(curveRes[n] / 2 + 0.5)) and (curveBack[n] != 0): - spl.curv += 2 * (curveBack[n] / curveRes[n]) #was -4 * + spl.curv += 2 * (curveBack[n] / curveRes[n]) # was -4 * - growSpline(n, spl, numSplit, splitAngle[n], splitAngleV[n], splineList, handles, splineToBone, - closeTip, kp, splitHeight, attractOut[n], stemsegL, lengthV[n], taperCrown, boneStep, rotate, rotateV) + growSpline( + n, spl, numSplit, splitAngle[n], splitAngleV[n], splineList, + handles, splineToBone, closeTip, kp, splitHeight, attractOut[n], + stemsegL, lengthV[n], taperCrown, boneStep, rotate, rotateV + ) # If pruning is enabled then we must to the check to see if the end of the spline is within the evelope if prune: @@ -1266,7 +1375,8 @@ def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, cu currentMax = currentScale currentScale = 0.5 * (currentMax + currentMin) break - # If the scale is the original size and the point is inside then we need to make sure it won't be pruned or extended to the edge of the envelope + # If the scale is the original size and the point is inside then + # we need to make sure it won't be pruned or extended to the edge of the envelope if insideBool and (currentScale != 1): currentMin = currentScale currentMax = oldMax @@ -1274,13 +1384,14 @@ def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, cu if insideBool and ((currentMax - currentMin) == 1): currentMin = 1 - # If the search will halt on the next iteration then we need to make sure we sprout child points to grow the next splines or leaves + # If the search will halt on the next iteration then we need + # to make sure we sprout child points to grow the next splines or leaves if (((currentMax - currentMin) < 0.005) or not prune) or forceSprout: if (n == 0) and (rMode != "original"): tVals = findChildPoints2(splineList, st.children) else: tVals = findChildPoints(splineList, st.children) - #print("debug tvals[%d] , splineList[%d], %s" % ( len(tVals), len(splineList), st.children)) + # print("debug tvals[%d] , splineList[%d], %s" % ( len(tVals), len(splineList), st.children)) # If leaves is -ve then we need to make sure the only point which sprouts is the end of the spline if not st.children: tVals = [1.0] @@ -1288,14 +1399,14 @@ def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, cu trimNum = int(baseSize * (len(tVals) + 1)) tVals = tVals[trimNum:] - #grow branches in rings + # grow branches in rings if (n == 0) and (nrings > 0): - #tVals = [(floor(t * nrings)) / nrings for t in tVals[:-1]] + # tVals = [(floor(t * nrings)) / nrings for t in tVals[:-1]] tVals = [(floor(t * nrings) / nrings) * uniform(.995, 1.005) for t in tVals[:-1]] tVals.append(1) tVals = [t for t in tVals if t > baseSize] - #branch distribution + # branch distribution if n == 0: tVals = [((t - baseSize) / (1 - baseSize)) for t in tVals] if branchDist < 1.0: @@ -1307,7 +1418,7 @@ def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, cu # For all the splines, we interpolate them and add the new points to the list of child points maxOffset = max([s.offsetLen + (len(s.spline.bezier_points) - 1) * s.segL for s in splineList]) for s in splineList: - #print(str(n)+'level: ', s.segMax*s.segL) + # print(str(n)+'level: ', s.segMax*s.segL) childP.extend(interpStem(s, tVals, s.segMax * s.segL, s.radS, maxOffset, baseSize)) # Force the splines to be deleted @@ -1317,7 +1428,8 @@ def perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, cu startPrune = False return ratio, splineToBone -#calculate taper automaticly + +# calculate taper automaticly def findtaper(length, taper, shape, shapeS, levels, customShape): taperS = [] for i, t in enumerate(length): @@ -1333,7 +1445,7 @@ def findtaper(length, taper, shape, shapeS, levels, customShape): taperP = [] for i, t in enumerate(taperS): pm = 1 - for x in range(i+1): + for x in range(i + 1): pm *= taperS[x] taperP.append(pm) @@ -1357,32 +1469,32 @@ def findtaper(length, taper, shape, shapeS, levels, customShape): def addTree(props): global splitError - #startTime = time.time() + # startTime = time.time() # Set the seed for repeatable results - seed(props.seed)# + seed(props.seed) # Set all other variables - levels = props.levels# - length = props.length# - lengthV = props.lengthV# + levels = props.levels + length = props.length + lengthV = props.lengthV taperCrown = props.taperCrown - branches = props.branches# - curveRes = props.curveRes# - curve = toRad(props.curve)# - curveV = toRad(props.curveV)# - curveBack = toRad(props.curveBack)# - baseSplits = props.baseSplits# - segSplits = props.segSplits# + branches = props.branches + curveRes = props.curveRes + curve = toRad(props.curve) + curveV = toRad(props.curveV) + curveBack = toRad(props.curveBack) + baseSplits = props.baseSplits + segSplits = props.segSplits splitByLen = props.splitByLen rMode = props.rMode - splitAngle = toRad(props.splitAngle)# - splitAngleV = toRad(props.splitAngleV)# - scale = props.scale# - scaleV = props.scaleV# - attractUp = props.attractUp# + splitAngle = toRad(props.splitAngle) + splitAngleV = toRad(props.splitAngleV) + scale = props.scale + scaleV = props.scaleV + attractUp = props.attractUp attractOut = props.attractOut - shape = int(props.shape)# - shapeS = int(props.shapeS)# + shape = int(props.shape) + shapeS = int(props.shapeS) customShape = props.customShape branchDist = props.branchDist nrings = props.nrings @@ -1395,38 +1507,38 @@ def addTree(props): closeTip = props.closeTip rootFlare = props.rootFlare autoTaper = props.autoTaper - taper = props.taper# + taper = props.taper radiusTweak = props.radiusTweak - ratioPower = props.ratioPower# - downAngle = toRad(props.downAngle)# - downAngleV = toRad(props.downAngleV)# - rotate = toRad(props.rotate)# - rotateV = toRad(props.rotateV)# - scale0 = props.scale0# - scaleV0 = props.scaleV0# - prune = props.prune# - pruneWidth = props.pruneWidth# + ratioPower = props.ratioPower + downAngle = toRad(props.downAngle) + downAngleV = toRad(props.downAngleV) + rotate = toRad(props.rotate) + rotateV = toRad(props.rotateV) + scale0 = props.scale0 + scaleV0 = props.scaleV0 + prune = props.prune + pruneWidth = props.pruneWidth pruneBase = props.pruneBase - pruneWidthPeak = props.pruneWidthPeak# - prunePowerLow = props.prunePowerLow# - prunePowerHigh = props.prunePowerHigh# - pruneRatio = props.pruneRatio# + pruneWidthPeak = props.pruneWidthPeak + prunePowerLow = props.prunePowerLow + prunePowerHigh = props.prunePowerHigh + pruneRatio = props.pruneRatio leafDownAngle = radians(props.leafDownAngle) leafDownAngleV = radians(props.leafDownAngleV) leafRotate = radians(props.leafRotate) leafRotateV = radians(props.leafRotateV) - leafScale = props.leafScale# - leafScaleX = props.leafScaleX# + leafScale = props.leafScale + leafScaleX = props.leafScaleX leafScaleT = props.leafScaleT leafScaleV = props.leafScaleV leafShape = props.leafShape leafDupliObj = props.leafDupliObj - bend = props.bend# + bend = props.bend leafangle = props.leafangle horzLeaves = props.horzLeaves - leafDist = int(props.leafDist)# - bevelRes = props.bevelRes# - resU = props.resU# + leafDist = int(props.leafDist) + bevelRes = props.bevelRes + resU = props.resU useArm = props.useArm previewArm = props.previewArm @@ -1435,8 +1547,8 @@ def addTree(props): frameRate = props.frameRate loopFrames = props.loopFrames - #windSpeed = props.windSpeed - #windGust = props.windGust + # windSpeed = props.windSpeed + # windGust = props.windGust wind = props.wind gust = props.gust @@ -1456,11 +1568,11 @@ def addTree(props): if not makeMesh: boneStep = [1, 1, 1, 1] - #taper + # taper if autoTaper: taper = findtaper(length, taper, shape, shapeS, levels, customShape) - #pLevels = branches[0] - #taper = findtaper(length, taper, shape, shapeS, pLevels, customShape) + # pLevels = branches[0] + # taper = findtaper(length, taper, shape, shapeS, pLevels, customShape) leafObj = None @@ -1488,7 +1600,7 @@ def addTree(props): treeOb = bpy.data.objects.new('tree', cu) bpy.context.scene.objects.link(treeOb) -# treeOb.location=bpy.context.scene.cursor_location attractUp + # treeOb.location=bpy.context.scene.cursor_location attractUp cu.dimensions = '3D' cu.fill_mode = 'FULL' @@ -1517,9 +1629,15 @@ def addTree(props): for c in range(enNum): newSpline.bezier_points.add() newPoint = newSpline.bezier_points[-1] - ratioVal = (c+1)/(enNum) - zVal = scaleVal - scaleVal*(1-pruneBase)*ratioVal - newPoint.co = Vector((scaleVal*pruneWidth*shapeRatio(9, ratioVal, pruneWidthPeak, prunePowerHigh, prunePowerLow), 0, zVal)) + ratioVal = (c + 1) / (enNum) + zVal = scaleVal - scaleVal * (1 - pruneBase) * ratioVal + newPoint.co = Vector( + ( + scaleVal * pruneWidth * + shapeRatio(9, ratioVal, pruneWidthPeak, prunePowerHigh, prunePowerLow), + 0, zVal + ) + ) (newPoint.handle_right_type, newPoint.handle_left_type) = (enHandle, enHandle) newSpline = enCu.splines.new('BEZIER') newPoint = newSpline.bezier_points[-1] @@ -1529,12 +1647,17 @@ def addTree(props): for c in range(enNum): newSpline.bezier_points.add() newPoint = newSpline.bezier_points[-1] - ratioVal = (c+1)/(enNum) - zVal = scaleVal - scaleVal*(1-pruneBase)*ratioVal - newPoint.co = Vector((0, scaleVal*pruneWidth*shapeRatio(9, ratioVal, pruneWidthPeak, prunePowerHigh, prunePowerLow), zVal)) + ratioVal = (c + 1) / (enNum) + zVal = scaleVal - scaleVal * (1 - pruneBase) * ratioVal + newPoint.co = Vector( + ( + 0, scaleVal * pruneWidth * + shapeRatio(9, ratioVal, pruneWidthPeak, prunePowerHigh, prunePowerLow), + zVal + ) + ) (newPoint.handle_right_type, newPoint.handle_left_type) = (enHandle, enHandle) - childP = [] stemList = [] @@ -1547,16 +1670,18 @@ def addTree(props): storeN = n stemList = deque() addstem = stemList.append - # If n is used as an index to access parameters for the tree it must be at most 3 or it will reference outside the array index + # If n is used as an index to access parameters for the tree + # it must be at most 3 or it will reference outside the array index n = min(3, n) splitError = 0.0 - #closeTip only on last level - closeTipp = all([(n == levels-1), closeTip]) + # closeTip only on last level + closeTipp = all([(n == levels - 1), closeTip]) # If this is the first level of growth (the trunk) then we need some special work to begin the tree if n == 0: - kickstart_trunk(addstem, levels, leaves, branches, cu, curve, curveRes, curveV, attractUp, length, lengthV, ratio, ratioPower, resU, + kickstart_trunk(addstem, levels, leaves, branches, cu, curve, curveRes, + curveV, attractUp, length, lengthV, ratio, ratioPower, resU, scale0, scaleV0, scaleVal, taper, minRadius, rootFlare) # If this isn't the trunk then we may have multiple stem to intialise else: @@ -1567,20 +1692,22 @@ def addTree(props): taper, shapeS, minRadius, radiusTweak, customShape, rMode, segSplits, useOldDownAngle, useParentAngle, boneStep) - #change base size for each level + # change base size for each level if n > 0: - baseSize *= baseSize_s #decrease at each level + baseSize *= baseSize_s # decrease at each level if (n == levels - 1): baseSize = 0 childP = [] # Now grow each of the stems in the list of those to be extended for st in stemList: - # When using pruning, we need to ensure that the random effects will be the same for each iteration to make sure the problem is linear. + # When using pruning, we need to ensure that the random effects + # will be the same for each iteration to make sure the problem is linear randState = getstate() startPrune = True lengthTest = 0.0 - # Store all the original values for the stem to make sure we have access after it has been modified by pruning + # Store all the original values for the stem to make sure + # we have access after it has been modified by pruning originalLength = st.segL originalCurv = st.curv originalCurvV = st.curvV @@ -1595,16 +1722,20 @@ def addTree(props): deleteSpline = False orginalSplineToBone = copy.copy(splineToBone) forceSprout = False - # Now do the iterative pruning, this uses a binary search and halts once the difference between upper and lower bounds of the search are less than 0.005 - ratio, splineToBone = perform_pruning(baseSize, baseSplits, childP, cu, currentMax, currentMin, - currentScale, curve, curveBack, curveRes, deleteSpline, forceSprout, - handles, n, oldMax, orginalSplineToBone, originalCo, originalCurv, - originalCurvV, originalHandleL, originalHandleR, originalLength, - originalSeg, prune, prunePowerHigh, prunePowerLow, pruneRatio, - pruneWidth, pruneBase, pruneWidthPeak, randState, ratio, scaleVal, segSplits, - splineToBone, splitAngle, splitAngleV, st, startPrune, - branchDist, length, splitByLen, closeTipp, nrings, splitBias, splitHeight, attractOut, rMode, lengthV, - taperCrown, boneStep, rotate, rotateV) + # Now do the iterative pruning, this uses a binary search and halts once the difference + # between upper and lower bounds of the search are less than 0.005 + ratio, splineToBone = perform_pruning( + baseSize, baseSplits, childP, cu, currentMax, currentMin, + currentScale, curve, curveBack, curveRes, deleteSpline, forceSprout, + handles, n, oldMax, orginalSplineToBone, originalCo, originalCurv, + originalCurvV, originalHandleL, originalHandleR, originalLength, + originalSeg, prune, prunePowerHigh, prunePowerLow, pruneRatio, + pruneWidth, pruneBase, pruneWidthPeak, randState, ratio, scaleVal, + segSplits, splineToBone, splitAngle, splitAngleV, st, startPrune, + branchDist, length, splitByLen, closeTipp, nrings, splitBias, + splitHeight, attractOut, rMode, lengthV, taperCrown, boneStep, + rotate, rotateV + ) levelCount.append(len(cu.splines)) @@ -1613,43 +1744,53 @@ def addTree(props): leafFaces = [] leafNormals = [] - leafMesh = None # in case we aren't creating leaves, we'll still have the variable + leafMesh = None # in case we aren't creating leaves, we'll still have the variable leafP = [] if leaves: oldRot = 0.0 - n = min(3, n+1) + n = min(3, n + 1) # For each of the child points we add leaves for cp in childP: # If the special flag is set then we need to add several leaves at the same location if leaves < 0: oldRot = -leafRotate / 2 for g in range(abs(leaves)): - (vertTemp, faceTemp, normal, oldRot) = genLeafMesh(leafScale, leafScaleX, leafScaleT, leafScaleV, cp.co, cp.quat, cp.offset, - len(leafVerts), leafDownAngle, leafDownAngleV, leafRotate, leafRotateV, - oldRot, bend, leaves, leafShape, leafangle, horzLeaves) + (vertTemp, faceTemp, normal, oldRot) = genLeafMesh( + leafScale, leafScaleX, leafScaleT, + leafScaleV, cp.co, cp.quat, cp.offset, + len(leafVerts), leafDownAngle, leafDownAngleV, + leafRotate, leafRotateV, + oldRot, bend, leaves, leafShape, + leafangle, horzLeaves + ) leafVerts.extend(vertTemp) leafFaces.extend(faceTemp) leafNormals.extend(normal) leafP.append(cp) - # Otherwise just add the leaves like splines. + # Otherwise just add the leaves like splines else: - (vertTemp, faceTemp, normal, oldRot) = genLeafMesh(leafScale, leafScaleX, leafScaleT, leafScaleV, cp.co, cp.quat, cp.offset, - len(leafVerts), leafDownAngle, leafDownAngleV, leafRotate, leafRotateV, - oldRot, bend, leaves, leafShape, leafangle, horzLeaves) + (vertTemp, faceTemp, normal, oldRot) = genLeafMesh( + leafScale, leafScaleX, leafScaleT, leafScaleV, + cp.co, cp.quat, cp.offset, len(leafVerts), + leafDownAngle, leafDownAngleV, leafRotate, + leafRotateV, oldRot, bend, leaves, leafShape, + leafangle, horzLeaves + ) leafVerts.extend(vertTemp) leafFaces.extend(faceTemp) leafNormals.extend(normal) leafP.append(cp) - # Create the leaf mesh and object, add geometry using from_pydata, edges are currently added by validating the mesh which isn't great + # Create the leaf mesh and object, add geometry using from_pydata, + # edges are currently added by validating the mesh which isn't great leafMesh = bpy.data.meshes.new('leaves') leafObj = bpy.data.objects.new('leaves', leafMesh) bpy.context.scene.objects.link(leafObj) leafObj.parent = treeOb leafMesh.from_pydata(leafVerts, (), leafFaces) - #set vertex normals for dupliVerts + # set vertex normals for dupliVerts if leafShape == 'dVert': leafMesh.vertices.foreach_set('normal', leafNormals) @@ -1659,18 +1800,20 @@ def addTree(props): leafObj.use_dupli_faces_scale = True leafObj.dupli_faces_scale = 10.0 try: - bpy.data.objects[leafDupliObj].parent = leafObj + if leafDupliObj not in "NONE": + bpy.data.objects[leafDupliObj].parent = leafObj except KeyError: pass elif leafShape == 'dVert': leafObj.dupli_type = "VERTS" leafObj.use_dupli_vertices_rotation = True try: - bpy.data.objects[leafDupliObj].parent = leafObj + if leafDupliObj not in "NONE": + bpy.data.objects[leafDupliObj].parent = leafObj except KeyError: pass - #add leaf UVs + # add leaf UVs if leafShape == 'rect': leafMesh.uv_textures.new("leafUV") uvlayer = leafMesh.uv_layers.active.data @@ -1679,10 +1822,10 @@ def addTree(props): u2 = 1 - u1 for i in range(0, len(leafFaces)): - uvlayer[i*4 + 0].uv = Vector((u2, 0)) - uvlayer[i*4 + 1].uv = Vector((u2, 1)) - uvlayer[i*4 + 2].uv = Vector((u1, 1)) - uvlayer[i*4 + 3].uv = Vector((u1, 0)) + uvlayer[i * 4 + 0].uv = Vector((u2, 0)) + uvlayer[i * 4 + 1].uv = Vector((u2, 1)) + uvlayer[i * 4 + 2].uv = Vector((u1, 1)) + uvlayer[i * 4 + 3].uv = Vector((u1, 0)) elif leafShape == 'hex': leafMesh.uv_textures.new("leafUV") @@ -1692,15 +1835,15 @@ def addTree(props): u2 = 1 - u1 for i in range(0, int(len(leafFaces) / 2)): - uvlayer[i*8 + 0].uv = Vector((.5, 0)) - uvlayer[i*8 + 1].uv = Vector((u1, 1/3)) - uvlayer[i*8 + 2].uv = Vector((u1, 2/3)) - uvlayer[i*8 + 3].uv = Vector((.5, 1)) + uvlayer[i * 8 + 0].uv = Vector((.5, 0)) + uvlayer[i * 8 + 1].uv = Vector((u1, 1 / 3)) + uvlayer[i * 8 + 2].uv = Vector((u1, 2 / 3)) + uvlayer[i * 8 + 3].uv = Vector((.5, 1)) - uvlayer[i*8 + 4].uv = Vector((.5, 0)) - uvlayer[i*8 + 5].uv = Vector((.5, 1)) - uvlayer[i*8 + 6].uv = Vector((u2, 2/3)) - uvlayer[i*8 + 7].uv = Vector((u2, 1/3)) + uvlayer[i * 8 + 4].uv = Vector((.5, 0)) + uvlayer[i * 8 + 5].uv = Vector((.5, 1)) + uvlayer[i * 8 + 6].uv = Vector((u2, 2 / 3)) + uvlayer[i * 8 + 7].uv = Vector((u2, 1 / 3)) leafMesh.validate() @@ -1719,13 +1862,15 @@ def addTree(props): # If we need an armature we add it if useArm: # Create the armature and objects - create_armature(armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSize, leaves, levelCount, splineToBone, - treeOb, wind, gust, gustF, af1, af2, af3, leafAnim, loopFrames, previewArm, armLevels, makeMesh, boneStep) - - #print(time.time()-startTime) + create_armature( + armAnim, leafP, cu, frameRate, leafMesh, leafObj, leafVertSize, + leaves, levelCount, splineToBone, treeOb, wind, gust, gustF, af1, + af2, af3, leafAnim, loopFrames, previewArm, armLevels, makeMesh, boneStep + ) + # print(time.time()-startTime) - #mesh branches + # mesh branches if makeMesh: t1 = time.time() @@ -1743,7 +1888,7 @@ def addTree(props): for i, curve in enumerate(cu.splines): points = curve.bezier_points - #find branching level + # find branching level level = 0 for l, c in enumerate(levelCount): if i < c: @@ -1756,46 +1901,46 @@ def addTree(props): p1 = points[0] - #add extra vertex for splits + # add extra vertex for splits if issplit[i]: pb = int(splineToBone[i][4:-4]) - pn = splitPidx[i] #int(splineToBone[i][-3:]) + pn = splitPidx[i] # int(splineToBone[i][-3:]) p_1 = cu.splines[pb].bezier_points[pn] - p_2 = cu.splines[pb].bezier_points[pn+1] - p = evalBez(p_1.co, p_1.handle_right, p_2.handle_left, p_2.co, 1 - 1/(resU + 1)) + p_2 = cu.splines[pb].bezier_points[pn + 1] + p = evalBez(p_1.co, p_1.handle_right, p_2.handle_left, p_2.co, 1 - 1 / (resU + 1)) treeVerts.append(p) root_vert.append(False) vert_radius.append((p1.radius * .75, p1.radius * .75)) - treeEdges.append([vindex,vindex+1]) + treeEdges.append([vindex, vindex + 1]) vindex += 1 if isend[i]: parent = lastVerts[int(splineToBone[i][4:-4])] vindex -= 1 else: - #add first point + # add first point treeVerts.append(p1.co) root_vert.append(True) vert_radius.append((p1.radius, p1.radius)) - -# #add extra vertex for splits -# if issplit[i]: -# p2 = points[1] -# p = evalBez(p1.co, p1.handle_right, p2.handle_left, p2.co, .001) -# treeVerts.append(p) -# root_vert.append(False) -# vert_radius.append((p1.radius, p1.radius)) #(p1.radius * .95, p1.radius * .95) -# treeEdges.append([vindex,vindex+1]) -# vindex += 1 - - #dont make vertex group if above armLevels + """ + # add extra vertex for splits + if issplit[i]: + p2 = points[1] + p = evalBez(p1.co, p1.handle_right, p2.handle_left, p2.co, .001) + treeVerts.append(p) + root_vert.append(False) + vert_radius.append((p1.radius, p1.radius)) #(p1.radius * .95, p1.radius * .95) + treeEdges.append([vindex,vindex+1]) + vindex += 1 + """ + # dont make vertex group if above armLevels if (i >= levelCount[armLevels]): idx = i groupName = splineToBone[idx] g = True while groupName not in vertexGroups: - #find parent bone of parent bone + # find parent bone of parent bone b = splineToBone[idx] idx = int(b[4:-4]) groupName = splineToBone[idx] @@ -1816,7 +1961,7 @@ def addTree(props): else: vertexGroups[splineToBone[i]].append(vindex - 1) - for f in range(1, resU+1): + for f in range(1, resU + 1): pos = f / resU p = evalBez(p1.co, p1.handle_right, p2.handle_left, p2.co, pos) radius = p1.radius + (p2.radius - p1.radius) * pos @@ -1829,7 +1974,7 @@ def addTree(props): edge = [parent, n * resU + f + vindex] else: edge = [n * resU + f + vindex - 1, n * resU + f + vindex] - #add vert to group + # add vert to group vertexGroups[groupName].append(n * resU + f + vindex - 1) treeEdges.append(edge) @@ -1837,7 +1982,7 @@ def addTree(props): p1 = p2 - lastVerts.append(len(treeVerts)-1) + lastVerts.append(len(treeVerts) - 1) treeMesh.from_pydata(treeVerts, treeEdges, ()) @@ -1845,7 +1990,7 @@ def addTree(props): treeObj.vertex_groups.new(group) treeObj.vertex_groups[group].add(vertexGroups[group], 1.0, 'ADD') - #add armature + # add armature if useArm: armMod = treeObj.modifiers.new('windSway', 'ARMATURE') if previewArm: @@ -1856,7 +2001,7 @@ def addTree(props): armMod.use_vertex_groups = True treeObj.parent = bpy.data.objects['treeArm'] - #add skin modifier and set data + # add skin modifier and set data skinMod = treeObj.modifiers.new('Skin', 'SKIN') skinMod.use_smooth_shade = True if previewArm: -- cgit v1.2.3