Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormeta-androcto <meta.androcto1@gmail.com>2016-04-28 05:36:09 +0300
committermeta-androcto <meta.androcto1@gmail.com>2016-04-28 05:36:09 +0300
commitc3a6d9132a44afd254fa120157c66e72b751e6f1 (patch)
treeace2279cc062a97a8f90bfd7aed27e21b10626bd /add_curve_sapling/__init__.py
parentfe34f82e7059bb6b89dfc88b55f030111f2d431f (diff)
Update sapling tree gen: T46559 major rewrite
Diffstat (limited to 'add_curve_sapling/__init__.py')
-rw-r--r--add_curve_sapling/__init__.py613
1 files changed, 481 insertions, 132 deletions
diff --git a/add_curve_sapling/__init__.py b/add_curve_sapling/__init__.py
index fa1b3267..4360fd37 100644
--- a/add_curve_sapling/__init__.py
+++ b/add_curve_sapling/__init__.py
@@ -17,20 +17,15 @@
#======================= END GPL LICENSE BLOCK ========================
bl_info = {
- "name": "Sapling",
- "author": "Andrew Hale (TrumanBlending)",
- "version": (0, 2, 6),
- "blender": (2, 73, 0),
+ "name": "Sapling Tree Gen",
+ "author": "Andrew Hale (TrumanBlending), Aaron Buchler",
+ "version": (0, 3, 2),
+ "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'."),
- "warning": "",
- "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
- "Scripts/Curve/Sapling_Tree",
- "category": "Add Curve",
-}
-
+ "category": "Add Curve"}
if "bpy" in locals():
import importlib
@@ -41,8 +36,10 @@ else:
import bpy
import time
import os
+import ast
+
+#import cProfile
-#from utils import *
from mathutils import *
from math import pi, sin, degrees, radians, atan2, copysign
from random import random, uniform, seed, choice, getstate, setstate
@@ -50,7 +47,6 @@ from bpy.props import *
from add_curve_sapling.utils import *
-#global splitError
useSet = False
shapeList = [('0', 'Conical (0)', 'Shape = 0'),
@@ -62,28 +58,74 @@ shapeList = [('0', 'Conical (0)', 'Shape = 0'),
('6', 'Inverse Conical (6)', 'Shape = 6'),
('7', 'Tend Flame (7)', 'Shape = 7')]
+shapeList3 = [('0', 'Conical', ''),
+ ('6', 'Inverse Conical', ''),
+ ('1', 'Spherical', ''),
+ ('2', 'Hemispherical', ''),
+ ('3', 'Cylindrical', ''),
+ ('4', 'Tapered Cylindrical', ''),
+ ('10', 'Inverse Tapered Cylindrical', ''),
+ ('5', 'Flame', ''),
+ ('7', 'Tend Flame', ''),
+ ('8', 'Custom Shape', '')]
+
+shapeList4 = [('0', 'Conical', ''),
+ ('6', 'Inverse Conical', ''),
+ ('1', 'Spherical', ''),
+ ('2', 'Hemispherical', ''),
+ ('3', 'Cylindrical', ''),
+ ('4', 'Tapered Cylindrical', ''),
+ ('10', 'Inverse Tapered Cylindrical', ''),
+ ('5', 'Flame', ''),
+ ('7', 'Tend Flame', '')]
+
handleList = [('0', 'Auto', 'Auto'),
('1', 'Vector', 'Vector')]
settings = [('0', 'Geometry', 'Geometry'),
- ('1', 'Branch Splitting', 'Branch Splitting'),
- ('2', 'Branch Growth', 'Branch Growth'),
- ('3', 'Pruning', 'Pruning'),
- ('4', 'Leaves', 'Leaves'),
- ('5', 'Armature', 'Armature')]
-
+ ('1', 'Branch Radius', 'Branch Radius'),
+ ('2', 'Branch Splitting', 'Branch Splitting'),
+ ('3', 'Branch Growth', 'Branch Growth'),
+ ('4', 'Pruning', 'Pruning'),
+ ('5', 'Leaves', 'Leaves'),
+ ('6', 'Armature', 'Armature'),
+ ('7', 'Animation', 'Animation')]
+
+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 = os.path.join(p, 'addons', 'add_curve_sapling', 'presets')
- if os.path.exists(presetpath):
- break
- return presetpath
-
+ #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
+
+ # why not just do this
+ script_file = os.path.realpath(__file__)
+ directory = os.path.dirname(script_file)
+ 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')
+
+ if os.path.isdir(userDir):
+ pass
+ else:
+ os.makedirs(userDir)
+
+ script_file = os.path.realpath(__file__)
+ directory = os.path.dirname(script_file)
+ localDir = os.path.join(directory, "presets")
+
+ return (localDir, userDir)
class ExportData(bpy.types.Operator):
"""This operator handles writing presets to file"""
@@ -94,24 +136,46 @@ class ExportData(bpy.types.Operator):
def execute(self, context):
# Unpack some data from the input
- data, filename = eval(self.data)
- try:
- # Check whether the file exists by trying to open it.
- f = open(os.path.join(getPresetpath(), filename + '.py'), 'r')
- f.close()
- # If it exists then report an error
- self.report({'ERROR_INVALID_INPUT'}, 'Preset Already Exists')
+ 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'}
+
+ fpath1 = os.path.join(getPresetpaths()[0], filename + '.py')
+ fpath2 = os.path.join(getPresetpaths()[1], filename + '.py')
+
+ if os.path.exists(fpath1):
+ # If it exists in built-in presets then report an error
+ self.report({'ERROR_INVALID_INPUT'}, 'Can\'t have same name as built-in preset')
return {'CANCELLED'}
- except IOError:
+ 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 data:
# If it doesn't exist, create the file with the required data
- f = open(os.path.join(getPresetpath(), filename + '.py'), 'w')
+ f = open(os.path.join(getPresetpaths()[1], filename + '.py'), 'w')
f.write(data)
f.close()
return {'FINISHED'}
else:
return {'CANCELLED'}
-
+ else:
+ # If it exists then report an error
+ self.report({'ERROR_INVALID_INPUT'}, 'Preset Already Exists')
+ return {'CANCELLED'}
class ImportData(bpy.types.Operator):
"""This operator handles importing existing presets"""
@@ -124,40 +188,78 @@ class ImportData(bpy.types.Operator):
# Make sure the operator knows about the global variables
global settings, useSet
# Read the preset data into the global settings
- f = open(os.path.join(getPresetpath(), self.filename), 'r')
+ try:
+ f = open(os.path.join(getPresetpaths()[0], self.filename), 'r')
+ except (FileNotFoundError, IOError):
+ f = open(os.path.join(getPresetpaths()[1], self.filename), 'r')
settings = f.readline()
f.close()
#print(settings)
- settings = eval(settings)
+ settings = ast.literal_eval(settings)
+
+ #use old attractup
+ if type(settings['attractUp']) == float:
+ atr = settings['attractUp']
+ settings['attractUp'] = [0, 0, atr, atr]
+
+ #use old leaf rotations
+ if 'leafDownAngle' not in settings:
+ l = settings['levels']
+ settings['leafDownAngle'] = settings['downAngle'][min(l, 3)]
+ settings['leafDownAngleV'] = settings['downAngleV'][min(l, 3)]
+ settings['leafRotate'] = settings['rotate'][min(l, 3)]
+ settings['leafRotateV'] = settings['rotateV'][min(l, 3)]
+
+ #zero leaf bend
+ settings['bend'] = 0
+
# Set the flag to use the settings
useSet = True
return {'FINISHED'}
-
class PresetMenu(bpy.types.Menu):
- """Create the preset menu by finding all preset files """ \
- """in the preset directory"""
+ """Create the preset menu by finding all preset files
+ in the preset directory"""
bl_idname = "sapling.presetmenu"
bl_label = "Presets"
def draw(self, context):
# Get all the sapling presets
- presets = [a for a in os.listdir(getPresetpath()) if a[-3:] == '.py']
+ presets = [a for a in os.listdir(getPresetpaths()[0]) if a[-3:] == '.py']
+ presets.extend([a for a in os.listdir(getPresetpaths()[1]) if a[-3:] == '.py'])
layout = self.layout
# Append all to the menu
for p in presets:
layout.operator("sapling.importdata", text=p[:-3]).filename = p
-
class AddTree(bpy.types.Operator):
bl_idname = "curve.tree_add"
bl_label = "Sapling: Add Tree"
bl_options = {'REGISTER', 'UNDO'}
+ 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
def update_tree(self, context):
self.do_update = True
+ def update_leaves(self, context):
+ if self.showLeaves:
+ self.do_update = True
+ else:
+ self.do_update = False
+
def no_update_tree(self, context):
self.do_update = False
@@ -189,20 +291,27 @@ class AddTree(bpy.types.Operator):
max=1,
default=0, update=update_tree)
levels = IntProperty(name='Levels',
- description='Number of recursive branches (Levels, note that last level is also used for generating leaves)',
+ description='Number of recursive branches (Levels)',
min=1,
max=6,
+ soft_max=4,
default=3, update=update_tree)
length = FloatVectorProperty(name='Length',
description='The relative lengths of each branch level (nLength)',
- min=1e-6,
+ min=0.000001,
default=[1, 0.3, 0.6, 0.45],
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',
+ description='Shorten trunk splits toward outside of tree',
+ min=0.0,
+ soft_max=1.0,
+ default=0, update=update_tree)
branches = IntVectorProperty(name='Branches',
description='The number of branches grown at each level (nBranches)',
min=0,
@@ -232,8 +341,16 @@ class AddTree(bpy.types.Operator):
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',
+ description='Split proportional to branch length',
+ 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',
description='Angle of branch splitting (nSplitAngle)',
default=[0, 0, 0, 0],
@@ -244,33 +361,94 @@ class AddTree(bpy.types.Operator):
size=4, update=update_tree)
scale = FloatProperty(name='Scale',
description='The tree scale (Scale)',
- min=0.001,
+ 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 = FloatProperty(name='Vertical Attraction',
+ attractUp = FloatVectorProperty(name='Vertical Attraction',
description='Branch upward attraction',
- default=0.0, update=update_tree)
+ default=[0, 0, 0, 0],
+ 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',
- description='The overall shape of the tree (Shape) - WARNING: at least three "Levels" of branching are needed',
- items=shapeList,
+ description='The overall shape of the tree (Shape)',
+ items=shapeList3,
default='7', update=update_tree)
- baseSize = FloatProperty(name='Base Size',
- description='Fraction of tree height with no branches (BaseSize)',
- min=0.001,
+ shapeS = EnumProperty(name='Secondary Branches Shape',
+ description='The shape of secondary splits',
+ items=shapeList4,
+ 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',
+ 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',
+ description='grow branches in rings',
+ min=0,
+ 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',
+ 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',
+ description='Fraction of tree height with no splits',
+ min=0.0,
+ max=1.0,
+ 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',
description='Base radius size (Ratio)',
min=0.0,
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',
+ description='Set radius at branch tips to zero',
+ 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',
+ description='Calculate taper automaticly based on branch lengths',
+ 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',
+ 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',
description=('Power which defines the radius of a branch compared to '
'the radius of the branch it grew from (RatioPower)'),
@@ -282,13 +460,17 @@ class AddTree(bpy.types.Operator):
default=[90, 60, 45, 45],
size=4, update=update_tree)
downAngleV = FloatVectorProperty(name='Down Angle Variation',
- description='Variation in the down angle (nDownAngleV)',
+ 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 '
- '(nRotate)'),
- default=[140, 140, 140, 77],
+ 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',
description='Variation in the rotate angle (nRotateV)',
@@ -300,11 +482,18 @@ class AddTree(bpy.types.Operator):
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',
description='The width of the envelope (PruneWidth)',
min=0.0,
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)'),
@@ -323,36 +512,71 @@ class AddTree(bpy.types.Operator):
min=0.0,
max=1.0,
default=1.0, update=update_tree)
- leaves = FloatProperty(name='Leaves',
- description='Maximum number of leaves per branch (Leaves)',
- min=0,
- max=50,
+ 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',
+ description='Variation in the rotate angle',
+ 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_tree)
+ 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_tree)
- leafShape = leafDist = EnumProperty(name='Leaf Shape',
- description='The shape of the leaves, rectangular are UV mapped',
- items=(('hex', 'Hexagonal', '0'), ('rect', 'Rectangular', '1')),
- default='hex', update=update_tree)
- 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_tree)
+ 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',
+ description='randomize leaf scale',
+ 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',
+ 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',
+ description='Leaf vertical attraction',
+ 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',
description='The way leaves are distributed on branches',
- items=shapeList,
- default='4', update=update_tree)
+ items=shapeList4,
+ 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',
description='The resolution along the curves',
@@ -361,21 +585,68 @@ class AddTree(bpy.types.Operator):
handleType = EnumProperty(name='Handle Type',
description='The type of handles used in the spline',
items=handleList,
- default='1', update=update_tree)
- frameRate = FloatProperty(name='Frame Rate',
- description=('The number of frames per second which can be used to '
- 'adjust the speed of animation'),
- min=0.001,
- default=1, update=update_tree)
- windSpeed = FloatProperty(name='Wind Speed',
- description='The wind speed to apply to the armature (WindSpeed)',
- default=2.0, update=update_tree)
- windGust = FloatProperty(name='Wind Gust',
- description='The greatest increase over Wind Speed (WindGust)',
- default=0.0, update=update_tree)
+ 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',
+ 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',
+ description='Whether animation is added to the leaves',
+ 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',
+ 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',
+ description='The intensity of the wind to apply to the armature',
+ 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',
+ description='The Fequency of directional movement',
+ 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',
+ description='Multiplier for noise fequency',
+ 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',
+ description='Convert curves to mesh, uses skin modifier, enables armature simplification',
+ 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',
+ description='Number of stem segments per bone',
+ min=1,
+ default=[1, 1, 1, 1],
+ size=4, update=update_tree)
presetName = StringProperty(name='Preset Name',
description='The name of the preset to be saved',
@@ -384,22 +655,21 @@ class AddTree(bpy.types.Operator):
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',
+ 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)
+# 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 check(self, context):
- # TODO, should check exact vars which require redraw
- return True
-
def draw(self, context):
layout = self.layout
@@ -419,25 +689,27 @@ class AddTree(bpy.types.Operator):
row.prop(self, 'resU')
box.prop(self, 'handleType')
- sub = box.row()
- sub.active = self.levels >= 3
- sub.prop(self, 'shape')
+ box.prop(self, 'shape')
+
+ col = box.column()
+ col.prop(self, 'customShape')
+
+ row = box.row()
+ box.prop(self, 'shapeS')
+ box.prop(self, 'branchDist')
+ box.prop(self, 'nrings')
box.prop(self, 'seed')
- box.prop(self, 'ratio')
+ box.label("Tree Scale:")
row = box.row()
row.prop(self, 'scale')
row.prop(self, 'scaleV')
- row = box.row()
- row.prop(self, 'scale0')
- row.prop(self, 'scaleV0')
-
# Here we create a dict of all the properties.
# 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"))).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)
@@ -451,94 +723,173 @@ class AddTree(bpy.types.Operator):
row = box.row()
row.prop(self, 'presetName')
# Send the data dict and the file name to the exporter
- row.operator('sapling.exportdata').data = repr([repr(data),
- self.presetName])
+ row.operator('sapling.exportdata').data = repr([repr(data), self.presetName, self.overwrite])
+ row = box.row()
+ row.label(" ")
+ row.prop(self, 'overwrite')
row = box.row()
row.menu('sapling.presetmenu', text='Load Preset')
row.prop(self, 'limitImport')
elif self.chooseSet == '1':
box = layout.box()
+ box.label("Branch Radius:")
+
+ row = box.row()
+ row.prop(self, 'bevel')
+ row.prop(self, 'bevelRes')
+
+ box.prop(self, 'ratio')
+ row = box.row()
+ row.prop(self, 'scale0')
+ row.prop(self, 'scaleV0')
+ box.prop(self, 'ratioPower')
+
+ box.prop(self, 'minRadius')
+ box.prop(self, 'closeTip')
+ box.prop(self, 'rootFlare')
+
+ box.prop(self, 'autoTaper')
+
+ split = box.split()
+ col = split.column()
+ col.prop(self, 'taper')
+ col = split.column()
+ col.prop(self, 'radiusTweak')
+
+ elif self.chooseSet == '2':
+ box = layout.box()
box.label("Branch Splitting:")
box.prop(self, 'levels')
box.prop(self, 'baseSplits')
- box.prop(self, 'baseSize')
+ row = box.row()
+ row.prop(self, 'baseSize')
+ row.prop(self, 'baseSize_s')
+ box.prop(self, 'splitHeight')
+ box.prop(self, 'splitBias')
+ box.prop(self, 'splitByLen')
split = box.split()
col = split.column()
col.prop(self, 'branches')
col.prop(self, 'splitAngle')
- col.prop(self, 'downAngle')
col.prop(self, 'rotate')
+ col.prop(self, 'attractOut')
col = split.column()
col.prop(self, 'segSplits')
col.prop(self, 'splitAngleV')
- col.prop(self, 'downAngleV')
col.prop(self, 'rotateV')
- box.prop(self, 'ratioPower')
+ col.label("Branching Mode:")
+ col.prop(self, 'rMode')
- elif self.chooseSet == '2':
+ box.column().prop(self, 'curveRes')
+
+ elif self.chooseSet == '3':
box = layout.box()
box.label("Branch Growth:")
- box.prop(self, 'startCurv')
- box.prop(self, 'attractUp')
+
+ box.prop(self, 'taperCrown')
split = box.split()
col = split.column()
col.prop(self, 'length')
+ col.prop(self, 'downAngle')
col.prop(self, 'curve')
col.prop(self, 'curveBack')
col = split.column()
col.prop(self, 'lengthV')
+ col.prop(self, 'downAngleV')
col.prop(self, 'curveV')
- col.prop(self, 'taper')
+ col.prop(self, 'attractUp')
- box.column().prop(self, 'curveRes')
+ box.prop(self, 'useOldDownAngle')
+ box.prop(self, 'useParentAngle')
- elif self.chooseSet == '3':
+ elif self.chooseSet == '4':
box = layout.box()
- box.label("Pruning:")
+ box.label("Prune:")
box.prop(self, 'prune')
box.prop(self, 'pruneRatio')
- box.prop(self, 'pruneWidth')
+ row = box.row()
+ row.prop(self, 'pruneWidth')
+ row.prop(self, 'pruneBase')
box.prop(self, 'pruneWidthPeak')
row = box.row()
row.prop(self, 'prunePowerHigh')
row.prop(self, 'prunePowerLow')
- elif self.chooseSet == '4':
+ elif self.chooseSet == '5':
box = layout.box()
box.label("Leaves:")
box.prop(self, 'showLeaves')
box.prop(self, 'leafShape')
+ box.prop(self, 'leafDupliObj')
box.prop(self, 'leaves')
box.prop(self, 'leafDist')
+ box.label("")
+ row = box.row()
+ row.prop(self, 'leafDownAngle')
+ row.prop(self, 'leafDownAngleV')
+
+ row = box.row()
+ row.prop(self, 'leafRotate')
+ row.prop(self, 'leafRotateV')
+ box.label("")
+
row = box.row()
row.prop(self, 'leafScale')
row.prop(self, 'leafScaleX')
- box.prop(self, 'bend')
+ row = box.row()
+ row.prop(self, 'leafScaleT')
+ row.prop(self, 'leafScaleV')
- elif self.chooseSet == '5':
- box = layout.box()
- box.label("Armature and Animation:")
+ box.prop(self, 'horzLeaves')
+ box.prop(self, 'leafangle')
+
+ #box.label(" ")
+ #box.prop(self, 'bend')
+ elif self.chooseSet == '6':
+ box = layout.box()
+ box.label("Armature:")
row = box.row()
row.prop(self, 'useArm')
- row.prop(self, 'armAnim')
+ box.prop(self, 'makeMesh')
+ box.label("Armature Simplification:")
+ box.prop(self, 'armLevels')
+ box.prop(self, 'boneStep')
+
+ elif self.chooseSet == '7':
+ box = layout.box()
+ box.label("Finalize All Other Settings First!")
+ box.prop(self, 'armAnim')
+ box.prop(self, 'leafAnim')
+ box.prop(self, 'previewArm')
+ box.prop(self, 'frameRate')
+ box.prop(self, 'loopFrames')
+
+ #row = box.row()
+ #row.prop(self, 'windSpeed')
+ #row.prop(self, 'windGust')
+ box.label('Wind Settings:')
+ box.prop(self, 'wind')
row = box.row()
- row.prop(self, 'windSpeed')
- row.prop(self, 'windGust')
+ row.prop(self, 'gust')
+ row.prop(self, 'gustF')
- box.prop(self, 'frameRate')
+ box.label('Leaf Wind Settings:')
+ box.prop(self, 'af1')
+ box.prop(self, 'af2')
+ box.prop(self, 'af3')
def execute(self, context):
# Ensure the use of the global variables
@@ -550,12 +901,13 @@ class AddTree(bpy.types.Operator):
for a, b in settings.items():
setattr(self, a, b)
if self.limitImport:
- setattr(self, 'levels', 2)
+ setattr(self, 'levels', min(settings['levels'], 2))
setattr(self, 'showLeaves', False)
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))
return {'FINISHED'}
@@ -565,17 +917,14 @@ class AddTree(bpy.types.Operator):
bpy.ops.sapling.importdata(filename = "quaking_aspen.py")
return self.execute(context)
-
def menu_func(self, context):
- self.layout.operator(AddTree.bl_idname, text="Add Tree", icon='PLUGIN')
-
+ 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__)