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:
authorAndrew Hale <TrumanBlending@gmail.com>2011-07-30 13:59:19 +0400
committerAndrew Hale <TrumanBlending@gmail.com>2011-07-30 13:59:19 +0400
commit09e37c1f7048648952f3445b2e2e12445a653c8b (patch)
tree368538f4564f06c63b99146aab4606a0c9437539 /add_curve_ivygen.py
parentcad685e25dcd418efc308150d421204f0ab9bb12 (diff)
Moved to Trunk
[[Split portion of a mixed commit.]]
Diffstat (limited to 'add_curve_ivygen.py')
-rw-r--r--add_curve_ivygen.py687
1 files changed, 687 insertions, 0 deletions
diff --git a/add_curve_ivygen.py b/add_curve_ivygen.py
new file mode 100644
index 00000000..d46503b1
--- /dev/null
+++ b/add_curve_ivygen.py
@@ -0,0 +1,687 @@
+# ##### 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
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# 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 #####
+
+# <pep8-80 compliant>
+
+bl_info = {
+ "name": "IvyGen",
+ "author": "testscreenings, PKHG, TrumanBlending",
+ "version": (0, 1, 0),
+ "blender": (2, 5, 8),
+ "api": 38479,
+ "location": "View3D > Add > Curve",
+ "description": "Adds generated ivy to a mesh object starting at the 3D"\
+ " cursor.",
+ "warning": "",
+ "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
+ "Scripts/Curve/Ivy_Gen",
+ "tracker_url": "http://projects.blender.org/tracker/index.php?"\
+ "func=detail&aid=27234",
+ "category": "Add Curve"}
+
+
+import bpy
+from bpy.props import FloatProperty, IntProperty, BoolProperty
+from mathutils import Vector, Matrix
+from collections import deque
+from math import pow, cos, pi, atan2
+from random import random as rand_val, seed as rand_seed
+import time
+
+
+def createIvyGeometry(IVY, growLeaves):
+ '''Create the curve geometry for IVY'''
+ # Compute the local size and the gauss weight filter
+ #local_ivyBranchSize = IVY.ivyBranchSize # * radius * IVY.ivySize
+ gaussWeight = [1.0, 2.0, 4.0, 7.0, 9.0, 10.0, 9.0, 7.0, 4.0, 2.0, 1.0]
+
+ # Create a new curve and intialise it
+ curve = bpy.data.curves.new("IVY", type='CURVE')
+ curve.dimensions = '3D'
+ curve.bevel_depth = 1
+ curve.use_fill_front = curve.use_fill_back = False
+
+ if growLeaves:
+ # Create the ivy leaves
+ # Order location of the vertices
+ signList = [(-1, 1), (1, 1), (1, -1), (-1, -1)]
+
+ # Get the local size
+ #local_ivyLeafSize = IVY.ivyLeafSize # * radius * IVY.ivySize
+
+ # Initialise the vertex and face lists
+ vertList = deque()
+
+ # Store the methods for faster calling
+ addV = vertList.extend
+ rotMat = Matrix.Rotation
+
+ # Loop over all roots to generate its nodes
+ for root in IVY.ivyRoots:
+ # Only grow if more than one node
+ numNodes = len(root.ivyNodes)
+ if numNodes > 1:
+ # Calculate the local radius
+ local_ivyBranchRadius = 1 / (root.parents + 1) + 1
+ prevIvyLength = 1 / root.ivyNodes[-1].length
+ splineVerts = [ax for n in root.ivyNodes for ax in n.pos.to_4d()]
+
+ radiusConstant = local_ivyBranchRadius * IVY.ivyBranchSize
+ splineRadii = [radiusConstant * (1.3 - n.length * prevIvyLength)
+ for n in root.ivyNodes]
+
+ # Add the poly curve and set coords and radii
+ newSpline = curve.splines.new(type='POLY')
+ newSpline.points.add(len(splineVerts) // 4 - 1)
+ newSpline.points.foreach_set('co', splineVerts)
+ newSpline.points.foreach_set('radius', splineRadii)
+
+ # Loop over all nodes in the root
+ for i, n in enumerate(root.ivyNodes):
+ for k in range(len(gaussWeight)):
+ idx = max(0, min(i + k - 5, numNodes - 1))
+ n.smoothAdhesionVector += (gaussWeight[k] *
+ root.ivyNodes[idx].adhesionVector)
+ n.smoothAdhesionVector /= 56.0
+ n.adhesionLength = n.smoothAdhesionVector.length
+ n.smoothAdhesionVector.normalize()
+
+ if growLeaves and (i < numNodes - 1):
+ node = root.ivyNodes[i]
+ nodeNext = root.ivyNodes[i + 1]
+
+ # Find the weight and normalise the smooth adhesion vector
+ weight = pow(node.length * prevIvyLength, 0.7)
+
+ # Calculate the ground ivy and the new weight
+ groundIvy = max(0.0, -node.smoothAdhesionVector.z)
+ weight += groundIvy * pow(1 - node.length *
+ prevIvyLength, 2)
+
+ # Find the alignment weight
+ alignmentWeight = node.adhesionLength
+
+ # Calculate the needed angles
+ phi = atan2(node.smoothAdhesionVector.y,
+ node.smoothAdhesionVector.x) - pi / 2
+
+ theta = (0.5 *
+ node.smoothAdhesionVector.angle(Vector((0, 0, -1)), 0))
+
+ # Find the size weight
+ sizeWeight = 1.5 - (cos(2 * pi * weight) * 0.5 + 0.5)
+
+ # Randomise the angles
+ phi += (rand_val() - 0.5) * (1.3 - alignmentWeight)
+ theta += (rand_val() - 0.5) * (1.1 - alignmentWeight)
+
+ # Calculate the leaf size an append the face to the list
+ leafSize = IVY.ivyLeafSize * sizeWeight
+
+ for j in range(10):
+ # Generate the probability
+ probability = rand_val()
+
+ # If we need to grow a leaf, do so
+ if (probability * weight) > IVY.leafProbability:
+
+ # Generate the random vector
+ randomVector = Vector((rand_val() - 0.5,
+ rand_val() - 0.5, rand_val() - 0.5))
+
+ # Find the leaf center
+ center = node.pos.lerp(nodeNext.pos, j / 10) +\
+ IVY.ivyLeafSize * randomVector
+
+ # For each of the verts, rotate/scale and append
+ basisVecX = Vector((1, 0, 0))
+ basisVecY = Vector((0, 1, 0))
+
+ horiRot = rotMat(theta, 3, 'X')
+ vertRot = rotMat(phi, 3, 'Z')
+
+ basisVecX.rotate(horiRot)
+ basisVecY.rotate(horiRot)
+
+ basisVecX.rotate(vertRot)
+ basisVecY.rotate(vertRot)
+
+ basisVecX *= leafSize
+ basisVecY *= leafSize
+
+ addV([k1 * basisVecX + k2 * basisVecY + center for
+ k1, k2 in signList])
+
+ # Add the object and link to scene
+ newCurve = bpy.data.objects.new("IVY_Curve", curve)
+ bpy.context.scene.objects.link(newCurve)
+
+ if growLeaves:
+ faceList = [[4 * i + l for l in range(4)] for i in
+ range(len(vertList) // 4)]
+
+ # Generate the new leaf mesh and link
+ me = bpy.data.meshes.new('IvyLeaf')
+ me.from_pydata(vertList, [], faceList)
+ me.update(calc_edges=True)
+ ob = bpy.data.objects.new('IvyLeaf', me)
+ bpy.context.scene.objects.link(ob)
+
+ tex = me.uv_textures.new("Leaves")
+
+ # Set the uv texture coords
+ for d in tex.data:
+ uv1, uv2, uv3, uv4 = signList
+
+ ob.parent = newCurve
+
+
+def computeBoundingSphere(ob):
+ # Get the mesh data
+ me = ob.data
+ # Intialise the center
+ center = Vector((0, 0, 0))
+ # Add all vertex coords
+ for v in me.vertices:
+ center += v.co
+ # Average over all verts
+ center /= len(me.vertices)
+ # Create the iterator and find its max
+ length_iter = ((center - v.co).length for v in me.vertices)
+ radius = max(length_iter)
+ return radius
+
+
+class IvyNode:
+ """ The basic class used for each point on the ivy which is grown."""
+ __slots__ = ('pos', 'primaryDir', 'adhesionVector', 'adhesionLength',
+ 'smoothAdhesionVector', 'length', 'floatingLength', 'climb')
+
+ def __init__(self):
+ self.pos = Vector((0, 0, 0))
+ self.primaryDir = Vector((0, 0, 1))
+ self.adhesionVector = Vector((0, 0, 0))
+ self.smoothAdhesionVector = Vector((0, 0, 0))
+ self.length = 0.0001
+ self.floatingLength = 0.0
+ self.climb = True
+
+
+class IvyRoot:
+ """ The class used to hold all ivy nodes growing from this root point."""
+ __slots__ = ('ivyNodes', 'alive', 'parents')
+
+ def __init__(self):
+ self.ivyNodes = deque()
+ self.alive = True
+ self.parents = 0
+
+
+class Ivy:
+ """ The class holding all parameters and ivy roots."""
+ __slots__ = ('ivyRoots', 'primaryWeight', 'randomWeight',
+ 'gravityWeight', 'adhesionWeight', 'branchingProbability',
+ 'leafProbability', 'ivySize', 'ivyLeafSize', 'ivyBranchSize',
+ 'maxFloatLength', 'maxAdhesionDistance', 'maxLength')
+
+ def __init__(self,
+ primaryWeight=0.5,
+ randomWeight=0.2,
+ gravityWeight=1.0,
+ adhesionWeight=0.1,
+ branchingProbability=0.05,
+ leafProbability=0.35,
+ ivySize=0.02,
+ ivyLeafSize=0.02,
+ ivyBranchSize=0.001,
+ maxFloatLength=0.5,
+ maxAdhesionDistance=1.0):
+
+ self.ivyRoots = deque()
+ self.primaryWeight = primaryWeight
+ self.randomWeight = randomWeight
+ self.gravityWeight = gravityWeight
+ self.adhesionWeight = adhesionWeight
+ self.branchingProbability = 1 - branchingProbability
+ self.leafProbability = 1 - leafProbability
+ self.ivySize = ivySize
+ self.ivyLeafSize = ivyLeafSize
+ self.ivyBranchSize = ivyBranchSize
+ self.maxFloatLength = maxFloatLength
+ self.maxAdhesionDistance = maxAdhesionDistance
+ self.maxLength = 0.0
+
+ # Normalise all the weights only on intialisation
+ sum = self.primaryWeight + self.randomWeight + self.adhesionWeight
+ self.primaryWeight /= sum
+ self.randomWeight /= sum
+ self.adhesionWeight /= sum
+
+ def seed(self, seedPos):
+ # Seed the Ivy by making a new root and first node
+ tmpRoot = IvyRoot()
+ tmpIvy = IvyNode()
+ tmpIvy.pos = seedPos
+
+ tmpRoot.ivyNodes.append(tmpIvy)
+ self.ivyRoots.append(tmpRoot)
+
+ def grow(self, ob):
+ # Determine the local sizes
+ #local_ivySize = self.ivySize # * radius
+ #local_maxFloatLength = self.maxFloatLength # * radius
+ #local_maxAdhesionDistance = self.maxAdhesionDistance # * radius
+
+ for root in self.ivyRoots:
+ # Make sure the root is alive, if not, skip
+ if not root.alive:
+ continue
+
+ # Get the last node in the current root
+ prevIvy = root.ivyNodes[-1]
+
+ # If the node is floating for too long, kill the root
+ if prevIvy.floatingLength > self.maxFloatLength:
+ root.alive = False
+
+ # Set the primary direction from the last node
+ primaryVector = prevIvy.primaryDir
+
+ # Make the random vector and normalise
+ randomVector = Vector((rand_val() - 0.5, rand_val() - 0.5,
+ rand_val() - 0.5)) + Vector((0, 0, 0.2))
+ randomVector.normalize()
+
+ # Calculate the adhesion vector
+ adhesionVector = adhesion(prevIvy.pos, ob,
+ self.maxAdhesionDistance)
+
+ # Calculate the growing vector
+ growVector = self.ivySize * (primaryVector * self.primaryWeight +
+ randomVector * self.randomWeight +
+ adhesionVector * self.adhesionWeight)
+
+ # Find the gravity vector
+ gravityVector = (self.ivySize * self.gravityWeight *
+ Vector((0, 0, -1)))
+ gravityVector *= pow(prevIvy.floatingLength / self.maxFloatLength,
+ 0.7)
+
+ # Determine the new position vector
+ newPos = prevIvy.pos + growVector + gravityVector
+
+ # Check for collisions with the object
+ climbing = collision(ob, prevIvy.pos, newPos)
+
+ # Update the growing vector for any collisions
+ growVector = newPos - prevIvy.pos - gravityVector
+ growVector.normalize()
+
+ # Create a new IvyNode and set its properties
+ tmpNode = IvyNode()
+ tmpNode.climb = climbing
+ tmpNode.pos = newPos
+ tmpNode.primaryDir = prevIvy.primaryDir.lerp(growVector, 0.5)
+ tmpNode.primaryDir.normalize()
+ tmpNode.adhesionVector = adhesionVector
+ tmpNode.length = prevIvy.length + (newPos - prevIvy.pos).length
+
+ if tmpNode.length > self.maxLength:
+ self.maxLength = tmpNode.length
+
+ # If the node isn't climbing, update it's floating length
+ # Otherwise set it to 0
+ if not climbing:
+ tmpNode.floatingLength = prevIvy.floatingLength + (newPos -
+ prevIvy.pos).length
+ else:
+ tmpNode.floatingLength = 0.0
+
+ root.ivyNodes.append(tmpNode)
+
+ # Loop through all roots to check if a new root is generated
+ for root in self.ivyRoots:
+ # Check the root is alive and isn't at high level of recursion
+ if (root.parents > 3) or (not root.alive):
+ continue
+
+ # Check to make sure there's more than 1 node
+ if len(root.ivyNodes) > 1:
+ # Loop through all nodes in root to check if new root is grown
+ for node in root.ivyNodes:
+ # Set the last node of the root and find the weighting
+ prevIvy = root.ivyNodes[-1]
+ weight = 1.0 - (cos(2.0 * pi * node.length /
+ prevIvy.length) * 0.5 + 0.5)
+
+ probability = rand_val()
+
+ # Check if a new root is grown and if so, set its values
+ if (probability * weight > self.branchingProbability):
+ tmpNode = IvyNode()
+ tmpNode.pos = node.pos
+ tmpNode.floatingLength = node.floatingLength
+
+ tmpRoot = IvyRoot()
+ tmpRoot.parents = root.parents + 1
+
+ tmpRoot.ivyNodes.append(tmpNode)
+ self.ivyRoots.append(tmpRoot)
+ return
+
+
+def adhesion(loc, ob, max_l):
+ # Get transfor vector and transformed loc
+ tran_mat = ob.matrix_world.inverted()
+ tran_loc = tran_mat * loc
+
+ # Compute the adhesion vector by finding the nearest point
+ nearest_result = ob.closest_point_on_mesh(tran_loc, max_l)
+ adhesion_vector = Vector((0, 0, 0))
+ if nearest_result[2] != -1:
+ # Compute the distance to the nearest point
+ adhesion_vector = ob.matrix_world * nearest_result[0] - loc
+ distance = adhesion_vector.length
+ # If it's less than the maximum allowed and not 0, continue
+ if distance:
+ # Compute the direction vector between the closest point and loc
+ adhesion_vector.normalize()
+ adhesion_vector *= 1.0 - distance / max_l
+ #adhesion_vector *= getFaceWeight(ob.data, nearest_result[2])
+ return adhesion_vector
+
+
+def collision(ob, pos, new_pos):
+ # Check for collision with the object
+ climbing = False
+
+ # Transform vecs
+ tran_mat = ob.matrix_world.inverted()
+ tran_pos = tran_mat * pos
+ tran_new_pos = tran_mat * new_pos
+
+ ray_result = ob.ray_cast(tran_pos, tran_new_pos)
+ # If there's a collision we need to check it
+ if ray_result[2] != -1:
+ # Check whether the collision is going into the object
+ if (tran_new_pos - tran_pos).dot(ray_result[1]) < 0.0:
+ # Find projection of the piont onto the plane
+ p0 = tran_new_pos - (tran_new_pos -
+ ray_result[0]).project(ray_result[1])
+ # Reflect in the plane
+ tran_new_pos += 2 * (p0 - tran_new_pos)
+ new_pos *= 0
+ new_pos += ob.matrix_world * tran_new_pos
+ climbing = True
+ return climbing
+
+
+class IvyGen(bpy.types.Operator):
+ bl_idname = "curve.ivy_gen"
+ bl_label = "IvyGen"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ maxIvyLength = FloatProperty(name="Max Ivy Length",
+ description="Maximum ivy length in Blender Units.",
+ default=1.0,
+ min=0.0,
+ soft_max=3.0,
+ subtype='DISTANCE',
+ unit='LENGTH')
+ primaryWeight = FloatProperty(name="Primary Weight",
+ description="Weighting given to the current direction.",
+ default=0.5,
+ min=0.0,
+ soft_max=1.0)
+ randomWeight = FloatProperty(name="Random Weight",
+ description="Weighting given to the random direction.",
+ default=0.2,
+ min=0.0,
+ soft_max=1.0)
+ gravityWeight = FloatProperty(name="Gravity Weight",
+ description="Weighting given to the gravity direction.",
+ default=1.0,
+ min=0.0,
+ soft_max=1.0)
+ adhesionWeight = FloatProperty(name="Adhesion Weight",
+ description="Weighting given to the adhesion direction.",
+ default=0.1,
+ min=0.0,
+ soft_max=1.0)
+ branchingProbability = FloatProperty(name="Branching Probability",
+ description="Probability of a new branch forming.",
+ default=0.05,
+ min=0.0,
+ soft_max=1.0)
+ leafProbability = FloatProperty(name="Leaf Probability",
+ description="Probability of a leaf forming.",
+ default=0.35,
+ min=0.0,
+ soft_max=1.0)
+ ivySize = FloatProperty(name="Ivy Size",
+ description="The length of an ivy segment in Blender"\
+ " Units.",
+ default=0.02,
+ min=0.0,
+ soft_max=1.0,
+ precision=3)
+ ivyLeafSize = FloatProperty(name="Ivy Leaf Size",
+ description="The size of the ivy leaves",
+ default=0.02,
+ min=0.0,
+ soft_max=0.5,
+ precision=3)
+ ivyBranchSize = FloatProperty(name="Ivy Branch Size",
+ description="The size of the ivy branches",
+ default=0.001,
+ min=0.0,
+ soft_max=0.1,
+ precision=4)
+ maxFloatLength = FloatProperty(name="Max Float Length",
+ description="The maximum distance that a branch"\
+ "can live while floating.",
+ default=0.5,
+ min=0.0,
+ soft_max=1.0)
+ maxAdhesionDistance = FloatProperty(name="Max Adhesion Length",
+ description="The maximum distance that a branch"\
+ "will feel the effects of adhesion.",
+ default=1.0,
+ min=0.0,
+ soft_max=2.0,
+ precision=2)
+ randomSeed = FloatProperty(name="Random Seed",
+ description="The seed governing random generation.",
+ default=0,
+ min=0.0,
+ soft_max=10)
+ maxTime = FloatProperty(name="Maximum Time",
+ description="The maximum time to run the generation for"\
+ "in seconds generation (0.0 = Disabled)",
+ default=0.0,
+ min=0.0,
+ soft_max=10)
+ growLeaves = BoolProperty(name="Grow Leaves",
+ description="Grow leaves or not.",
+ default=True)
+ updateIvy = BoolProperty(name="Update Ivy", default=False)
+
+ @classmethod
+ def poll(self, context):
+ # Check if there's an object and whether it's a mesh
+ ob = context.active_object
+ if (ob is not None) and\
+ (ob.type == 'MESH') and\
+ (context.mode == 'OBJECT'):
+ return True
+ return False
+
+ def execute(self, context):
+ if self.updateIvy:
+ bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+ bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+
+ # Get the selected object
+ ob = context.active_object
+
+ # Compute bounding sphere radius
+ #radius = computeBoundingSphere(ob) # Not needed anymore
+
+ # Get the seeding point
+ seedPoint = context.scene.cursor_location
+
+ # Fix the random seed
+ rand_seed(int(self.randomSeed))
+
+ # Make the new ivy
+ IVY = Ivy(**self.as_keywords(ignore=('randomSeed', 'growLeaves',
+ 'maxIvyLength', 'maxTime', 'updateIvy')))
+
+ # Generate first root and node
+ IVY.seed(seedPoint)
+
+ checkAlive = True
+ checkTime = False
+ maxLength = self.maxIvyLength # * radius
+
+ # If we need to check time set the flag
+ if self.maxTime != 0.0:
+ checkTime = True
+
+ t = time.time()
+ startPercent = 0.0
+ checkAliveIter = [True, ]
+
+ # Grow until 200 roots is reached or backup counter exceeds limit
+ while any(checkAliveIter) and\
+ (IVY.maxLength < maxLength) and\
+ (not checkTime or (time.time() - t < self.maxTime)):
+ # Grow the ivy for this iteration
+ IVY.grow(ob)
+
+ # Print the proportion of ivy growth to console
+ if (IVY.maxLength / maxLength * 100) > 10 * startPercent // 10:
+ print('%0.2f%% of Ivy nodes have grown' %\
+ (IVY.maxLength / maxLength * 100))
+ startPercent += 10
+ if IVY.maxLength / maxLength > 1:
+ print("Halting Growth")
+
+ # Make an iterator to check if all are alive
+ checkAliveIter = (r.alive for r in IVY.ivyRoots)
+
+ # Create the curve and leaf geometry
+ createIvyGeometry(IVY, self.growLeaves)
+ print("Geometry Generation Complete")
+
+ print("Ivy generated in %0.2f s" % (time.time() - t))
+
+ self.updateIvy = False
+
+ return {'FINISHED'}
+
+ return {'PASS_THROUGH'}
+
+ def draw(self, context):
+ layout = self.layout
+ row = layout.row()
+ row.alignment = 'EXPAND'
+ row.prop(self, 'updateIvy', icon='CURVE_DATA')
+
+ row = layout.row()
+ properties = row.operator('curve.ivy_gen', text="Add New Ivy")
+ properties.randomSeed = self.randomSeed
+ properties.maxTime = self.maxTime
+ properties.maxIvyLength = self.maxIvyLength
+ properties.ivySize = self.ivySize
+ properties.maxFloatLength = self.maxFloatLength
+ properties.maxAdhesionDistance = self.maxAdhesionDistance
+ properties.primaryWeight = self.primaryWeight
+ properties.randomWeight = self.randomWeight
+ properties.gravityWeight = self.gravityWeight
+ properties.adhesionWeight = self.adhesionWeight
+ properties.branchingProbability = self.branchingProbability
+ properties.leafProbability = self.leafProbability
+ properties.ivyBranchSize = self.ivyBranchSize
+ properties.ivyLeafSize = self.ivyLeafSize
+
+ row = layout.row()
+ row.operator('curve.ivy_gen', text="Add New Default Ivy")
+
+ row = layout.row()
+ row.prop(self, 'growLeaves')
+
+ box = layout.box()
+ box.label("Generation Settings")
+ row = box.row()
+ row.prop(self, 'randomSeed')
+ row = box.row()
+ row.prop(self, 'maxTime')
+ box = layout.box()
+ box.label("Size Settings")
+ row = box.row()
+ row.prop(self, 'maxIvyLength')
+ row = box.row()
+ row.prop(self, 'ivySize')
+ row = box.row()
+ row.prop(self, 'maxFloatLength')
+ row = box.row()
+ row.prop(self, 'maxAdhesionDistance')
+ box = layout.box()
+ box.label("Weight Settings")
+ row = box.row()
+ row.prop(self, 'primaryWeight')
+ row = box.row()
+ row.prop(self, 'randomWeight')
+ row = box.row()
+ row.prop(self, 'gravityWeight')
+ row = box.row()
+ row.prop(self, 'adhesionWeight')
+ box = layout.box()
+ box.label("Branch Settings")
+ row = box.row()
+ row.prop(self, 'branchingProbability')
+ row = box.row()
+ row.prop(self, 'ivyBranchSize')
+
+ if self.growLeaves:
+ box = layout.box()
+ box.label("Leaf Settings")
+ row = box.row()
+ row.prop(self, 'ivyLeafSize')
+ row = box.row()
+ row.prop(self, 'leafProbability')
+
+
+def menu_func(self, context):
+ self.layout.operator(IvyGen.bl_idname, text="Add Ivy to Mesh",
+ icon='PLUGIN').updateIvy = True
+
+
+def register():
+ bpy.utils.register_module(__name__)
+ bpy.types.INFO_MT_curve_add.append(menu_func)
+
+
+def unregister():
+ bpy.types.INFO_MT_curve_add.remove(menu_func)
+ bpy.utils.unregister_module(__name__)
+
+
+if __name__ == "__main__":
+ register()