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:
authorBrendon Murphy <meta.androcto1@gmail.com>2014-08-04 22:22:08 +0400
committerBrendon Murphy <meta.androcto1@gmail.com>2014-08-04 22:22:08 +0400
commit0e536cd1b7225ef7b6c9edd982b2d9d5c527ce92 (patch)
treef7084adcc8be74512fe19360e94e7bd60e381ed2 /add_curve_sapling
parent9c46a10d07e8ab0cea3734c509c54d21205ea1e2 (diff)
fixes for T41099 and T38495 by purplefrog in irc, added warning "Armature Mode buggy"
Diffstat (limited to 'add_curve_sapling')
-rw-r--r--add_curve_sapling/__init__.py6
-rw-r--r--add_curve_sapling/utils.py633
2 files changed, 344 insertions, 295 deletions
diff --git a/add_curve_sapling/__init__.py b/add_curve_sapling/__init__.py
index 78f2ebb6..a5739cbd 100644
--- a/add_curve_sapling/__init__.py
+++ b/add_curve_sapling/__init__.py
@@ -25,7 +25,7 @@ bl_info = {
"description": ("Adds a parametric tree. The method is presented by "
"Jason Weber & Joseph Penn in their paper 'Creation and Rendering of "
"Realistic Trees'."),
- "warning": "",
+ "warning": "Armature Mode buggy",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
"Scripts/Curve/Sapling_Tree",
"category": "Add Curve",
@@ -323,8 +323,10 @@ class AddTree(bpy.types.Operator):
min=0.0,
max=1.0,
default=1.0, update=update_tree)
- leaves = IntProperty(name='Leaves',
+ leaves = FloatProperty(name='Leaves',
description='Maximum number of leaves per branch (Leaves)',
+ min=0,
+ max=50,
default=25, update=update_tree)
leafScale = FloatProperty(name='Leaf Scale',
description='The scaling applied to the whole leaf (LeafScale)',
diff --git a/add_curve_sapling/utils.py b/add_curve_sapling/utils.py
index 2ff86424..8f49eeb5 100644
--- a/add_curve_sapling/utils.py
+++ b/add_curve_sapling/utils.py
@@ -338,7 +338,7 @@ def genLeafMesh(leafScale,leafScaleX,loc,quat,index,downAngle,downAngleV,rotate,
# If the special -ve flag is used we need a different rotation of the leaf geometry
if leaves < 0:
rotMat = Matrix.Rotation(oldRot,3,'Y')
- oldRot += rotate/(abs(leaves)-1)
+ oldRot += rotate/abs(leaves)
else:
oldRot += rotate+uniform(-rotateV,rotateV)
downRotMat = Matrix.Rotation(downAngle+uniform(-downAngleV,downAngleV),3,'X')
@@ -401,6 +401,330 @@ def genLeafMesh(leafScale,leafScaleX,loc,quat,index,downAngle,downAngleV,rotate,
facesList.append([f[0] + index,f[1] + index,f[2] + index,f[3] + index])
return vertsList,facesList,oldRot
+
+def create_armature(armAnim, childP, cu, frameRate, leafMesh, leafObj, leafShape, leaves, levelCount, splineToBone,
+ treeOb, windGust, windSpeed):
+ arm = bpy.data.armatures.new('tree')
+ armOb = bpy.data.objects.new('treeArm', arm)
+ bpy.context.scene.objects.link(armOb)
+ # Create a new action to store all animation
+ newAction = bpy.data.actions.new(name='windAction')
+ armOb.animation_data_create()
+ armOb.animation_data.action = newAction
+ arm.draw_type = 'STICK'
+ arm.use_deform_delay = True
+ # Add the armature modifier to the curve
+ armMod = treeOb.modifiers.new('windSway', 'ARMATURE')
+ # armMod.use_apply_on_spline = True
+ armMod.object = armOb
+ # If there are leaves then they need a modifier
+ if leaves:
+ armMod = leafObj.modifiers.new('windSway', 'ARMATURE')
+ armMod.object = armOb
+
+ # Make sure all objects are deselected (may not be required?)
+ for ob in bpy.data.objects:
+ ob.select = False
+
+ # Set the armature as active and go to edit mode to add bones
+ bpy.context.scene.objects.active = armOb
+ bpy.ops.object.mode_set(mode='EDIT')
+ masterBones = []
+ offsetVal = 0
+ # For all the splines in the curve we need to add bones at each bezier point
+ for i, parBone in enumerate(splineToBone):
+ s = cu.splines[i]
+ b = None
+ # Get some data about the spline like length and number of points
+ numPoints = len(s.bezier_points) - 1
+ splineL = numPoints * ((s.bezier_points[0].co - s.bezier_points[1].co).length)
+ # Set the random phase difference of the animation
+ bxOffset = uniform(0, 2 * pi)
+ byOffset = uniform(0, 2 * pi)
+ # Set the phase multiplier for the spline
+ bMult = (s.bezier_points[0].radius / splineL) * (1 / 15) * (1 / frameRate)
+ # For all the points in the curve (less the last) add a bone and name it by the spline it will affect
+ for n in range(numPoints):
+ oldBone = b
+ boneName = 'bone' + (str(i)).rjust(3, '0') + '.' + (str(n)).rjust(3, '0')
+ b = arm.edit_bones.new(boneName)
+ b.head = s.bezier_points[n].co
+ b.tail = s.bezier_points[n + 1].co
+
+ b.head_radius = s.bezier_points[n].radius
+ b.tail_radius = s.bezier_points[n + 1].radius
+ b.envelope_distance = 0.001 #0.001
+
+ # If there are leaves then we need a new vertex group so they will attach to the bone
+ 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:
+ b.parent = arm.edit_bones[parBone]
+ # if len(parBone) > 11:
+ # b.use_connect = True
+ # Otherwise, we need to attach it to the previous bone in the spline
+ else:
+ b.parent = oldBone
+ b.use_connect = True
+ # If there isn't a previous bone then it shouldn't be attached
+ if not oldBone:
+ b.use_connect = False
+ #tempList.append(b)
+
+ # 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)) / s.bezier_points[n].radius
+ a1 = (windSpeed / 50) * a0
+ a2 = (windGust / 50) * a0 + a1 / 2
+
+ # 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)
+
+ swayXMod1 = swayX.modifiers.new(type='FNGENERATOR')
+ swayXMod2 = swayX.modifiers.new(type='FNGENERATOR')
+
+ swayYMod1 = swayY.modifiers.new(type='FNGENERATOR')
+ swayYMod2 = swayY.modifiers.new(type='FNGENERATOR')
+
+ # Set the parameters for each modifier
+ swayXMod1.amplitude = radians(a1) / numPoints
+ swayXMod1.phase_offset = bxOffset
+ swayXMod1.phase_multiplier = degrees(bMult)
+
+ swayXMod2.amplitude = radians(a2) / numPoints
+ swayXMod2.phase_offset = 0.7 * bxOffset
+ swayXMod2.phase_multiplier = 0.7 * degrees(
+ bMult) # This shouldn't have to be in degrees but it looks much better in animation
+ swayXMod2.use_additive = True
+
+ swayYMod1.amplitude = radians(a1) / numPoints
+ swayYMod1.phase_offset = byOffset
+ swayYMod1.phase_multiplier = degrees(
+ bMult) # This shouldn't have to be in degrees but it looks much better in animation
+
+ swayYMod2.amplitude = radians(a2) / numPoints
+ swayYMod2.phase_offset = 0.7 * byOffset
+ swayYMod2.phase_multiplier = 0.7 * degrees(
+ bMult) # This shouldn't have to be in degrees but it looks much better in animation
+ swayYMod2.use_additive = True
+
+ # If there are leaves we need to assign vertices to their vertex groups
+ if leaves:
+ offsetVal = 0
+ leafVertSize = 6
+ if leafShape == 'rect':
+ leafVertSize = 4
+ for i, cp in enumerate(childP):
+ for v in leafMesh.vertices[leafVertSize * i:(leafVertSize * i + leafVertSize)]:
+ leafObj.vertex_groups[cp.parBone].add([v.index], 1.0, 'ADD')
+
+ # Now we need the rotation mode to be 'XYZ' to ensure correct rotation
+ bpy.ops.object.mode_set(mode='OBJECT')
+ for p in armOb.pose.bones:
+ p.rotation_mode = 'XYZ'
+ treeOb.parent = armOb
+
+
+def kickstart_trunk(addstem, branches, cu, curve, curveRes, curveV, length, lengthV, ratio, resU, scale0, scaleV0,
+ scaleVal, taper, vertAtt):
+ vertAtt = 0.0
+ newSpline = cu.splines.new('BEZIER')
+ cu.resolution_u = resU
+ newPoint = newSpline.bezier_points[-1]
+ newPoint.co = Vector((0, 0, 0))
+ newPoint.handle_right = Vector((0, 0, 1))
+ newPoint.handle_left = Vector((0, 0, -1))
+ # (newPoint.handle_right_type,newPoint.handle_left_type) = ('VECTOR','VECTOR')
+ branchL = (scaleVal) * (length[0] + uniform(-lengthV[0], lengthV[0]))
+ childStems = branches[1]
+ startRad = branchL * ratio * (scale0 + uniform(-scaleV0, scaleV0))
+ endRad = startRad * (1 - taper[0])
+ newPoint.radius = startRad
+ addstem(
+ stemSpline(newSpline, curve[0] / curveRes[0], curveV[0] / curveRes[0], 0, curveRes[0], branchL / curveRes[0],
+ childStems, startRad, endRad, 0))
+ return vertAtt
+
+
+def fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, curve, curveBack, curveRes, curveV,
+ downAngle, downAngleV, leafDist, leaves, length, lengthV, levels, n, oldRotate, ratioPower, resU,
+ rotate, rotateV, scaleVal, shape, storeN, taper, vertAtt):
+ for p in childP:
+ # Add a spline and set the coordinate of the first point.
+ newSpline = cu.splines.new('BEZIER')
+ cu.resolution_u = resU
+ newPoint = newSpline.bezier_points[-1]
+ newPoint.co = p.co
+ tempPos = zAxis.copy()
+ # If the -ve flag for downAngle is used we need a special formula to find it
+ if downAngleV[n] < 0.0:
+ downV = downAngleV[n] * (
+ 1 - 2 * shapeRatio(0, (p.lengthPar - p.offset) / (p.lengthPar - baseSize * scaleVal)))
+ random()
+ # Otherwise just find a random value
+ else:
+ downV = uniform(-downAngleV[n], downAngleV[n])
+ downRotMat = Matrix.Rotation(downAngle[n] + downV, 3, 'X')
+ tempPos.rotate(downRotMat)
+ # 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] + uniform(-rotateV[n], rotateV[n]), oldRotate)
+ # Otherwise just generate a random number in the specified range
+ else:
+ oldRotate += rotate[n] + uniform(-rotateV[n], rotateV[n])
+ # Rotate the direction of growth and set the new point coordinates
+ rotMat = Matrix.Rotation(oldRotate, 3, 'Z')
+ tempPos.rotate(rotMat)
+ tempPos.rotate(p.quat)
+ newPoint.handle_right = p.co + tempPos
+ if (storeN>= levels-1):
+ # If this is the last level before leaves then we need to generate the child points differently
+ branchL = (length[n] + uniform(-lengthV[n], lengthV[n])) * (p.lengthPar - 0.6 * p.offset)
+ if leaves < 0:
+ childStems = False
+ else:
+ childStems = leaves * shapeRatio(leafDist, p.offset / p.lengthPar)
+ elif n == 1:
+ # If this is the first level of branching then upward attraction has no effect and a special formula is used to find branch length and the number of child stems
+ vertAtt = 0.0
+ lMax = length[1] + uniform(-lengthV[1], lengthV[1])
+ branchL = p.lengthPar * lMax * shapeRatio(shape,
+ (p.lengthPar - p.offset) / (p.lengthPar - baseSize * scaleVal))
+ childStems = branches[2] * (0.2 + 0.8 * (branchL / p.lengthPar) / lMax)
+ else:
+ branchL = (length[n] + uniform(-lengthV[n], lengthV[n])) * (p.lengthPar - 0.6 * p.offset)
+ childStems = branches[min(3, n + 1)] * (1.0 - 0.5 * p.offset / p.lengthPar)
+
+ #print("n=%d, levels=%d, n'=%d, childStems=%s"%(n, levels, storeN, childStems))
+ branchL = max(branchL, 0.0)
+ # Determine the starting and ending radii of the stem using the tapering of the stem
+ startRad = min(p.radiusPar[0] * ((branchL / p.lengthPar) ** ratioPower), p.radiusPar[1])
+ endRad = startRad * (1 - taper[n])
+ newPoint.radius = startRad
+ # If curveBack is used then the curviness of the stem is different for the first half
+ if curveBack[n] == 0:
+ curveVal = curve[n] / curveRes[n]
+ else:
+ curveVal = 2 * curve[n] / curveRes[n]
+ # Add the new stem to list of stems to grow and define which bone it will be parented to
+ addstem(
+ stemSpline(newSpline, curveVal, curveV[n] / curveRes[n], 0, curveRes[n], branchL / curveRes[n], childStems,
+ startRad, endRad, len(cu.splines) - 1))
+ addsplinetobone(p.parBone)
+ return vertAtt
+
+
+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, pruneWidthPeak, randState, ratio, scaleVal, segSplits,
+ splineToBone, splitAngle, splitAngleV, st, startPrune, vertAtt):
+ 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 (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
+ if deleteSpline:
+ for x in splineList:
+ cu.splines.remove(x.spline)
+ newSpline = cu.splines.new('BEZIER')
+ newPoint = newSpline.bezier_points[-1]
+ newPoint.co = originalCo
+ newPoint.handle_right = originalHandleR
+ newPoint.handle_left = originalHandleL
+ (newPoint.handle_left_type, newPoint.handle_right_type) = ('VECTOR', 'VECTOR')
+ st.spline = newSpline
+ st.curv = originalCurv
+ st.curvV = originalCurvV
+ st.seg = originalSeg
+ st.p = newPoint
+ newPoint.radius = st.radS
+ splineToBone = orginalSplineToBone
+
+ # Initialise the spline list for those contained in the current level of branching
+ splineList = [st]
+ # 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]):
+ # Make a copy of the current list to avoid continually adding to the list we're iterating over
+ tempList = splineList[:]
+ # print('Leng: ',len(tempList))
+ # For each of the splines in this list set the number of splits and then grow it
+ for spl in tempList:
+ if k == 0:
+ numSplit = 0
+ elif (k == 1) and (n == 0):
+ numSplit = baseSplits
+ else:
+ numSplit = splits(segSplits[n])
+ if (k == int(curveRes[n] / 2)) and (curveBack[n] != 0):
+ spl.curvAdd(-2 * curve[n] / curveRes[n] + 2 * curveBack[n] / curveRes[n])
+ growSpline(spl, numSplit, splitAngle[n], splitAngleV[n], splineList, vertAtt, handles,
+ splineToBone) # Add proper refs for radius and attractUp
+
+ # If pruning is enabled then we must to the check to see if the end of the spline is within the evelope
+ if prune:
+ # Check each endpoint to see if it is inside
+ for s in splineList:
+ coordMag = (s.spline.bezier_points[-1].co.xy).length
+ ratio = (scaleVal - s.spline.bezier_points[-1].co.z) / (scaleVal * (1 - baseSize))
+ # Don't think this if part is needed
+ if (n == 0) and (s.spline.bezier_points[-1].co.z < baseSize * scaleVal):
+ pass # insideBool = True
+ else:
+ insideBool = (
+ (coordMag / scaleVal) < pruneWidth * shapeRatio(8, ratio, pruneWidthPeak, prunePowerHigh,
+ prunePowerLow))
+ # If the point is not inside then we adjust the scale and current search bounds
+ if not insideBool:
+ oldMax = currentMax
+ 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 insideBool and (currentScale != 1):
+ currentMin = currentScale
+ currentMax = oldMax
+ currentScale = 0.5 * (currentMax + currentMin)
+ 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 (((currentMax - currentMin) < 0.005) or not prune) or forceSprout:
+ tVals = findChildPoints(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:
+ if not st.children:
+ tVals = [0.9]
+ # If this is the trunk then we need to remove some of the points because of baseSize
+ if n == 0:
+ trimNum = int(baseSize * (len(tVals) + 1))
+ tVals = tVals[trimNum:]
+
+ # For all the splines, we interpolate them and add the new points to the list of child points
+ for s in splineList:
+ #print(str(n)+'level: ',s.segMax*s.segL)
+ childP.extend(interpStem(s, tVals, s.segMax * s.segL, s.radS))
+
+ # Force the splines to be deleted
+ deleteSpline = True
+ # If pruning isn't enabled then make sure it doesn't loop
+ if not prune:
+ startPrune = False
+ return ratio, splineToBone
+
+
def addTree(props):
global splitError
#startTime = time.time()
@@ -544,81 +868,17 @@ def addTree(props):
splitError = 0.0
# If this is the first level of growth (the trunk) then we need some special work to begin the tree
if n == 0:
- vertAtt = 0.0
- newSpline = cu.splines.new('BEZIER')
- cu.resolution_u = resU
- newPoint = newSpline.bezier_points[-1]
- newPoint.co = Vector((0,0,0))
- newPoint.handle_right = Vector((0,0,1))
- newPoint.handle_left = Vector((0,0,-1))
- #(newPoint.handle_right_type,newPoint.handle_left_type) = ('VECTOR','VECTOR')
- branchL = (scaleVal)*(length[0] + uniform(-lengthV[0],lengthV[0]))
- childStems = branches[1]
- startRad = branchL*ratio*(scale0 + uniform(-scaleV0,scaleV0))
- endRad = startRad*(1 - taper[0])
- newPoint.radius = startRad
- addstem(stemSpline(newSpline,curve[0]/curveRes[0],curveV[0]/curveRes[0],0,curveRes[0],branchL/curveRes[0],childStems,startRad,endRad,0))
+ vertAtt = kickstart_trunk(addstem, branches, cu, curve, curveRes, curveV, length, lengthV, ratio, resU,
+ scale0, scaleV0, scaleVal, taper, vertAtt)
# If this isn't the trunk then we may have multiple stem to intialise
else:
# Store the old rotation to allow new stems to be rotated away from the previous one.
oldRotate = 0
# For each of the points defined in the list of stem starting points we need to grow a stem.
- for p in childP:
- # Add a spline and set the coordinate of the first point.
- newSpline = cu.splines.new('BEZIER')
- cu.resolution_u = resU
- newPoint = newSpline.bezier_points[-1]
- newPoint.co = p.co
- tempPos = zAxis.copy()
- # If the -ve flag for downAngle is used we need a special formula to find it
- if downAngleV[n] < 0.0:
- downV = downAngleV[n]*(1 - 2*shapeRatio(0,(p.lengthPar - p.offset)/(p.lengthPar - baseSize*scaleVal)))
- random()
- # Otherwise just find a random value
- else:
- downV = uniform(-downAngleV[n],downAngleV[n])
- downRotMat = Matrix.Rotation(downAngle[n]+downV,3,'X')
- tempPos.rotate(downRotMat)
- # 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] + uniform(-rotateV[n],rotateV[n]),oldRotate)
- # Otherwise just generate a random number in the specified range
- else:
- oldRotate += rotate[n]+uniform(-rotateV[n],rotateV[n])
- # Rotate the direction of growth and set the new point coordinates
- rotMat = Matrix.Rotation(oldRotate,3,'Z')
- tempPos.rotate(rotMat)
- tempPos.rotate(p.quat)
- newPoint.handle_right = p.co + tempPos
- # If this is the first level of branching then upward attraction has no effect and a special formula is used to find branch length and the number of child stems
- if n == 1:
- vertAtt = 0.0
- lMax = length[1] + uniform(-lengthV[1],lengthV[1])
- branchL = p.lengthPar*lMax*shapeRatio(shape,(p.lengthPar - p.offset)/(p.lengthPar - baseSize*scaleVal))
- childStems = branches[2]*(0.2 + 0.8*(branchL/p.lengthPar)/lMax)
- elif storeN <= levels - 2:
- branchL = (length[n] + uniform(-lengthV[n],lengthV[n]))*(p.lengthPar - 0.6*p.offset)
- childStems = branches[min(3,n+1)]*(1.0 - 0.5*p.offset/p.lengthPar)
- # If this is the last level before leaves then we need to generate the child points differently
- else:
- branchL = (length[n] + uniform(-lengthV[n],lengthV[n]))*(p.lengthPar - 0.6*p.offset)
- if leaves < 0:
- childStems = False
- else:
- childStems = leaves*shapeRatio(leafDist,p.offset/p.lengthPar)
- branchL = max(branchL, 0.0)
- # Determine the starting and ending radii of the stem using the tapering of the stem
- startRad = min(p.radiusPar[0]*((branchL/p.lengthPar)**ratioPower), p.radiusPar[1])
- endRad = startRad*(1 - taper[n])
- newPoint.radius = startRad
- # If curveBack is used then the curviness of the stem is different for the first half
- if curveBack[n] == 0:
- curveVal = curve[n]/curveRes[n]
- else:
- curveVal = 2*curve[n]/curveRes[n]
- # Add the new stem to list of stems to grow and define which bone it will be parented to
- addstem(stemSpline(newSpline,curveVal,curveV[n]/curveRes[n],0,curveRes[n],branchL/curveRes[n],childStems,startRad,endRad,len(cu.splines)-1))
- addsplinetobone(p.parBone)
+ vertAtt = fabricate_stems(addsplinetobone, addstem, baseSize, branches, childP, cu, curve, curveBack,
+ curveRes, curveV, downAngle, downAngleV, leafDist, leaves, length, lengthV,
+ levels, n, oldRotate, ratioPower, resU, rotate, rotateV, scaleVal, shape, storeN,
+ taper, vertAtt)
childP = []
# Now grow each of the stems in the list of those to be extended
@@ -643,99 +903,13 @@ def addTree(props):
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
- 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 (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
- if deleteSpline:
- for x in splineList:
- cu.splines.remove(x.spline)
- newSpline = cu.splines.new('BEZIER')
- newPoint = newSpline.bezier_points[-1]
- newPoint.co = originalCo
- newPoint.handle_right = originalHandleR
- newPoint.handle_left = originalHandleL
- (newPoint.handle_left_type,newPoint.handle_right_type) = ('VECTOR','VECTOR')
- st.spline = newSpline
- st.curv = originalCurv
- st.curvV = originalCurvV
- st.seg = originalSeg
- st.p = newPoint
- newPoint.radius = st.radS
- splineToBone = orginalSplineToBone
-
- # Initialise the spline list for those contained in the current level of branching
- splineList = [st]
- # 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]):
- # Make a copy of the current list to avoid continually adding to the list we're iterating over
- tempList = splineList[:]
- #print('Leng: ',len(tempList))
- # For each of the splines in this list set the number of splits and then grow it
- for spl in tempList:
- if k == 0:
- numSplit = 0
- elif (k == 1) and (n == 0):
- numSplit = baseSplits
- else:
- numSplit = splits(segSplits[n])
- if (k == int(curveRes[n]/2)) and (curveBack[n] != 0):
- spl.curvAdd(-2*curve[n]/curveRes[n] + 2*curveBack[n]/curveRes[n])
- growSpline(spl,numSplit,splitAngle[n],splitAngleV[n],splineList,vertAtt,handles,splineToBone)# Add proper refs for radius and attractUp
-
- # If pruning is enabled then we must to the check to see if the end of the spline is within the evelope
- if prune:
- # Check each endpoint to see if it is inside
- for s in splineList:
- coordMag = (s.spline.bezier_points[-1].co.xy).length
- ratio = (scaleVal - s.spline.bezier_points[-1].co.z)/(scaleVal*(1 - baseSize))
- # Don't think this if part is needed
- if (n == 0) and (s.spline.bezier_points[-1].co.z < baseSize*scaleVal):
- pass#insideBool = True
- else:
- insideBool = ((coordMag/scaleVal) < pruneWidth*shapeRatio(8,ratio,pruneWidthPeak,prunePowerHigh,prunePowerLow))
- # If the point is not inside then we adjust the scale and current search bounds
- if not insideBool:
- oldMax = currentMax
- 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 insideBool and (currentScale != 1):
- currentMin = currentScale
- currentMax = oldMax
- currentScale = 0.5*(currentMax + currentMin)
- 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 (((currentMax - currentMin) < 0.005) or not prune) or forceSprout:
- tVals = findChildPoints(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:
- if not st.children:
- tVals = [0.9]
- # If this is the trunk then we need to remove some of the points because of baseSize
- if n == 0:
- trimNum = int(baseSize*(len(tVals)+1))
- tVals = tVals[trimNum:]
-
- # For all the splines, we interpolate them and add the new points to the list of child points
- for s in splineList:
- #print(str(n)+'level: ',s.segMax*s.segL)
- childP.extend(interpStem(s,tVals,s.segMax*s.segL,s.radS))
-
- # Force the splines to be deleted
- deleteSpline = True
- # If pruning isn't enabled then make sure it doesn't loop
- if not prune:
- startPrune = False
+ 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, pruneWidthPeak, randState, ratio, scaleVal, segSplits,
+ splineToBone, splitAngle, splitAngleV, st, startPrune, vertAtt)
levelCount.append(len(cu.splines))
# If we need to add leaves, we do it here
@@ -805,133 +979,6 @@ def addTree(props):
# If we need and armature we add it
if useArm:
# Create the armature and objects
- arm = bpy.data.armatures.new('tree')
- armOb = bpy.data.objects.new('treeArm',arm)
- bpy.context.scene.objects.link(armOb)
-
- # Create a new action to store all animation
- newAction = bpy.data.actions.new(name='windAction')
- armOb.animation_data_create()
- armOb.animation_data.action = newAction
-
- arm.draw_type = 'STICK'
- arm.use_deform_delay = True
-
- # Add the armature modifier to the curve
- armMod = treeOb.modifiers.new('windSway','ARMATURE')
- #armMod.use_apply_on_spline = True
- armMod.object = armOb
-
- # If there are leaves then they need a modifier
- if leaves:
- armMod = leafObj.modifiers.new('windSway','ARMATURE')
- armMod.object = armOb
-
- # Make sure all objects are deselected (may not be required?)
- for ob in bpy.data.objects:
- ob.select = False
-
- # Set the armature as active and go to edit mode to add bones
- bpy.context.scene.objects.active = armOb
- bpy.ops.object.mode_set(mode='EDIT')
-
- masterBones = []
-
- offsetVal = 0
-
- # For all the splines in the curve we need to add bones at each bezier point
- for i,parBone in enumerate(splineToBone):
- s = cu.splines[i]
- b = None
- # Get some data about the spline like length and number of points
- numPoints = len(s.bezier_points)-1
- splineL = numPoints*((s.bezier_points[0].co-s.bezier_points[1].co).length)
- # Set the random phase difference of the animation
- bxOffset = uniform(0,2*pi)
- byOffset = uniform(0,2*pi)
- # Set the phase multiplier for the spline
- bMult = (s.bezier_points[0].radius/splineL)*(1/15)*(1/frameRate)
- # For all the points in the curve (less the last) add a bone and name it by the spline it will affect
- for n in range(numPoints):
- oldBone = b
- boneName = 'bone'+(str(i)).rjust(3,'0')+'.'+(str(n)).rjust(3,'0')
- b = arm.edit_bones.new(boneName)
- b.head = s.bezier_points[n].co
- b.tail = s.bezier_points[n+1].co
-
- b.head_radius = s.bezier_points[n].radius
- b.tail_radius = s.bezier_points[n+1].radius
- b.envelope_distance = 0.001#0.001
-
- # If there are leaves then we need a new vertex group so they will attach to the bone
- 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:
- b.parent = arm.edit_bones[parBone]
-# if len(parBone) > 11:
-# b.use_connect = True
- # Otherwise, we need to attach it to the previous bone in the spline
- else:
- b.parent = oldBone
- b.use_connect = True
- # If there isn't a previous bone then it shouldn't be attached
- if not oldBone:
- b.use_connect = False
- #tempList.append(b)
-
- # 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))/s.bezier_points[n].radius
- a1 = (windSpeed/50)*a0
- a2 = (windGust/50)*a0 + a1/2
-
- # 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)
-
- swayXMod1 = swayX.modifiers.new(type='FNGENERATOR')
- swayXMod2 = swayX.modifiers.new(type='FNGENERATOR')
-
- swayYMod1 = swayY.modifiers.new(type='FNGENERATOR')
- swayYMod2 = swayY.modifiers.new(type='FNGENERATOR')
-
- # Set the parameters for each modifier
- swayXMod1.amplitude = radians(a1)/numPoints
- swayXMod1.phase_offset = bxOffset
- swayXMod1.phase_multiplier = degrees(bMult)
-
- swayXMod2.amplitude = radians(a2)/numPoints
- swayXMod2.phase_offset = 0.7*bxOffset
- swayXMod2.phase_multiplier = 0.7*degrees(bMult) # This shouldn't have to be in degrees but it looks much better in animation
- swayXMod2.use_additive = True
-
- swayYMod1.amplitude = radians(a1)/numPoints
- swayYMod1.phase_offset = byOffset
- swayYMod1.phase_multiplier = degrees(bMult) # This shouldn't have to be in degrees but it looks much better in animation
-
- swayYMod2.amplitude = radians(a2)/numPoints
- swayYMod2.phase_offset = 0.7*byOffset
- swayYMod2.phase_multiplier = 0.7*degrees(bMult) # This shouldn't have to be in degrees but it looks much better in animation
- swayYMod2.use_additive = True
-
- # If there are leaves we need to assign vertices to their vertex groups
- if leaves:
- offsetVal = 0
- leafVertSize = 6
- if leafShape == 'rect':
- leafVertSize = 4
- for i,cp in enumerate(childP):
- for v in leafMesh.vertices[leafVertSize*i:(leafVertSize*i+leafVertSize)]:
- leafObj.vertex_groups[cp.parBone].add([v.index],1.0,'ADD')
-
- # Now we need the rotation mode to be 'XYZ' to ensure correct rotation
- bpy.ops.object.mode_set(mode='OBJECT')
- for p in armOb.pose.bones:
- p.rotation_mode = 'XYZ'
- treeOb.parent = armOb
+ create_armature(armAnim, childP, cu, frameRate, leafMesh, leafObj, leafShape, leaves, levelCount, splineToBone,
+ treeOb, windGust, windSpeed)
#print(time.time()-startTime)