[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [2158] branches/ivygen/truman_ivy/ add_curve_ivygen.py: - Added maximum growing time property

Andrew Hale TrumanBlending at gmail.com
Fri Jul 22 06:03:46 CEST 2011


Revision: 2158
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=2158
Author:   trumanblending
Date:     2011-07-22 04:03:44 +0000 (Fri, 22 Jul 2011)
Log Message:
-----------
- Added maximum growing time property
- Increase speed of leaf generation
- Added property group to store properties
- Added panel to reveal properties

Modified Paths:
--------------
    branches/ivygen/truman_ivy/add_curve_ivygen.py

Modified: branches/ivygen/truman_ivy/add_curve_ivygen.py
===================================================================
--- branches/ivygen/truman_ivy/add_curve_ivygen.py	2011-07-21 15:42:09 UTC (rev 2157)
+++ branches/ivygen/truman_ivy/add_curve_ivygen.py	2011-07-22 04:03:44 UTC (rev 2158)
@@ -16,7 +16,7 @@
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 bl_info = {
     "name": "IvyGen",
@@ -33,11 +33,12 @@
 
 
 import bpy
-from bpy.props import FloatProperty, IntProperty
+from bpy.props import FloatProperty, IntProperty, BoolProperty, PointerProperty
 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 createIvyLeaves(IVY, radius):
@@ -65,27 +66,27 @@
         for i in range(10):
             for node in root.ivyNodes:
                 # Find the weight and normalise the smooth adhesion vector
-                weight = pow(node.length * prevIvyLength, 0.7)
+                weight = pow(node.length / prevIvyLength, 0.7)
                 normalAd = node.smoothAdhesionVector.normalized()
 
                 # Calculate the ground ivy and the new weight
-                groundIvy = max(0.0, -normalAd.dot(Vector((0, 0, 1))))
-                weight += groundIvy * pow(1 - node.length * prevIvyLength, 2)
+                groundIvy = max(0.0, -normalAd.z)
+                weight += groundIvy * pow(1 - node.length / prevIvyLength, 2)
 
                 # Generate the probability
                 probability = rand_val()
 
                 # If we need to grow a leaf, do so
-                if ((probability * weight) > IVY.leafProbability and
-                                      node.smoothAdhesionVector.length != 0.0):
+                if (probability * weight) > IVY.leafProbability:
                     # Find the alignment weight
                     alignmentWeight = node.smoothAdhesionVector.length
 
                     # Calculate the needed angles
                     phi = atan2(node.smoothAdhesionVector.y,
                                           node.smoothAdhesionVector.x) - pi / 2
+
                     theta = (0.5 *
-                           node.smoothAdhesionVector.angle(Vector((0, 0, -1))))
+                        node.smoothAdhesionVector.angle(Vector((0, 0, -1)), 0))
 
                     # Generate the random vector
                     randomVector = Vector((rand_val() - 0.5, rand_val() - 0.5,
@@ -105,18 +106,30 @@
                     leafSize = local_ivyLeafSize * sizeWeight
                     currentVert = len(vertList)
 
-                    faceList.append((currentVert, currentVert + 1,
+                    addF((currentVert, currentVert + 1,
                                              currentVert + 2, currentVert + 3))
 
                     # For each of the verts in the list 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 *= local_ivyLeafSize * sizeWeight
+                    basisVecY *= local_ivyLeafSize * sizeWeight
+
+                    randomVector = Vector((rand_val() - 0.5,
+                                           rand_val() - 0.5, rand_val() - 0.5))
+
                     for k1, k2 in signList:
-                        randomVector = Vector((rand_val() - 0.5,
-                                           rand_val() - 0.5, rand_val() - 0.5))
-                        tmpPos = Vector((k1 * leafSize, k2 * leafSize, 0.0))
-                        horiRot = rotMat(theta, 3, 'X')
-                        tmpPos.rotate(horiRot)
-                        vertRot = rotMat(phi, 3, 'Z')
-                        tmpPos.rotate(vertRot)
+                        tmpPos = k1 * basisVecX + k2 * basisVecY
                         tmpPos += (randomVector * local_ivyLeafSize *
                                                      sizeWeight * 0.5 + center)
                         addV(tmpPos)
@@ -250,14 +263,17 @@
                  ivyLeafSize=1.5,
                  ivyBranchSize=0.15,
                  maxFloatLength=0.1,
-                 maxAdhesionDistance=0.1):
+                 maxAdhesionDistance=0.1,
+                 randomSeed=1,
+                 maxIvyLength=0.0,
+                 maxTime=0.0):
 
         self.ivyRoots = deque()
         self.primaryWeight = primaryWeight
         self.randomWeight = randomWeight
         self.gravityWeight = gravityWeight
         self.adhesionWeight = adhesionWeight
-        self.branchingProbability = 1 - branchingProbability
+        self.branchingProbability = branchingProbability
         self.leafProbability = leafProbability
         self.ivySize = ivySize
         self.ivyLeafSize = ivyLeafSize
@@ -398,6 +414,7 @@
             adhesion_vector = nearest_result[0] - loc
             adhesion_vector.normalize()
             adhesion_vector *= 1.0 - distance / max_l
+            #adhesion_vector *= getFaceWeight(ob.data, nearest_result[2])
     return adhesion_vector
 
 
@@ -422,6 +439,83 @@
     bl_label = "IvyGen"
     bl_options = {'REGISTER', 'UNDO'}
 
+    @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):
+        # Get the properties
+        ivyProps = context.window_manager.ivy_props
+
+        # Get the selected object
+        ob = context.active_object
+
+        # Compute bounding sphere radius
+        radius = computeBoundingSphere(ob)
+
+        # Get the seeding point
+        seedPoint = context.scene.cursor_location
+
+        # Find the distance to the closest point
+        dist = (ob.closest_point_on_mesh(seedPoint)[0] - seedPoint).length
+
+        # If the distance is too far, cancel the operator
+        if dist > (radius * ivyProps.maxFloatLength / 2):
+            print("Invalid Root Location")
+            return {'CANCELLED'}
+
+        # If the point is on the surface move it outward slightly
+        if dist == 0.0:
+            seedPoint += (radius * ivyProps.maxFloatLength / 10 *
+                                        ob.closest_point_on_mesh(seedPoint)[1])
+
+        # Fix the random seed
+        rand_seed(ivyProps.randomSeed)
+
+        # Make the new ivy
+        IVY = Ivy(**dict(ivyProps.items()))
+
+        # Generate first root and node
+        IVY.seed(seedPoint)
+
+        checkAlive = True
+        checkTime = False
+        maxLength = radius * ivyProps.maxIvyLength
+
+        # If we need to check time set the flag
+        if ivyProps.maxTime != 0.0:
+            checkTime = True
+
+        t = time.time()
+
+        # Grow until 200 roots is reached or backup counter exceeds limit
+        while checkAlive and\
+              (IVY.maxLength < maxLength) and\
+              (not checkTime or (time.time() - t < ivyProps.maxTime)):
+            IVY.grow(radius, ob)
+            checkAliveIter = (r.alive for r in IVY.ivyRoots)
+            checkAlive = False
+            if True in checkAliveIter:
+                checkAlive = True
+
+        # Create the curve and leaf geometry
+        curveOb = createIvyCurves(IVY, radius)
+        leafOb = createIvyLeaves(IVY, radius)
+
+        # Parent the leave to the curve
+        leafOb.parent = curveOb
+
+        print("Ivy generated in %0.2f s" % (time.time() - t))
+        return {'FINISHED'}
+
+
+class IvyProps(bpy.types.PropertyGroup):
     maxIvyLength = FloatProperty(name="Max Ivy Length",
                     description="Maximum ivy length as a proportion"\
                                 "of bounding sphere radius",
@@ -451,12 +545,12 @@
                     soft_max=1.0)
     branchingProbability = FloatProperty(name="Branching Probability",
                     description="Probability of a new branch forming.",
-                    default=0.05,
+                    default=0.95,
                     min=0.0,
                     soft_max=1.0)
     leafProbability = FloatProperty(name="Leaf Probability",
                     description="Probability of a leaf forming.",
-                    default=0.7,
+                    default=0.95,
                     min=0.0,
                     soft_max=1.0,)
     ivySize = FloatProperty(name="Ivy Size",
@@ -496,7 +590,20 @@
                     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)
 
+
+class VIEW3D_PT_tools_ivygen(bpy.types.Panel):
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'TOOLS'
+    bl_context = "objectmode"
+    bl_label = "IvyGen"
+
     @classmethod
     def poll(self, context):
         # Check if there's an object and whether it's a mesh
@@ -507,75 +614,71 @@
             return True
         return False
 
-    def execute(self, context):
-        # Get the selected object
-        ob = context.active_object
+    def draw(self, context):
+        ivyProps = context.window_manager.ivy_props
+        layout = self.layout
+        row = layout.row()
+        row.alignment = 'EXPAND'
+        row.operator('curve.ivy_gen', text="Generate Ivy")
+        box = layout.box()
+        box.label("Generation Settings")
+        row = box.row()
+        row.prop(ivyProps, 'randomSeed')
+        row = box.row()
+        row.prop(ivyProps, 'maxTime')
+        box = layout.box()
+        box.label("Size Settings")
+        row = box.row()
+        row.prop(ivyProps, 'maxIvyLength')
+        row = box.row()
+        row.prop(ivyProps, 'ivySize')
+        row = box.row()
+        row.prop(ivyProps, 'maxFloatLength')
+        row = box.row()
+        row.prop(ivyProps, 'maxAdhesionDistance')

@@ Diff output truncated at 10240 characters. @@


More information about the Bf-extensions-cvs mailing list