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 initialise it curve = bpy.data.curves.new("IVY", type='CURVE') curve.dimensions = '3D' curve.bevel_depth = 1 curve.fill_mode = 'FULL' curve.resolution_u = 4 if growLeaves: # Create the ivy leaves # Order location of the vertices signList = ( (-1.0, +1.0), (+1.0, +1.0), (+1.0, -1.0), (-1.0, -1.0), ) # 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.0 / (root.parents + 1) + 1.0 prevIvyLength = 1.0 / 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 normalize 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.0 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.0) + 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.collection.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.collection.objects.link(ob) me.uv_layers.new(name="Leaves") # Set the uv texture coords # TODO, this is non-functional, default uvs are ok? ''' for d in tex.data: uv1, uv2, uv3, uv4 = signList ''' ob.parent = newCurve
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 curve.resolution_u = 4 if growLeaves: # Create the ivy leaves # Order location of the vertices signList = ((-1.0, +1.0), (+1.0, +1.0), (+1.0, -1.0), (-1.0, -1.0), ) # 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.0 / (root.parents + 1) + 1.0 prevIvyLength = 1.0 / 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.0 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.0) + 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 # TODO, this is non-functional, default uvs are ok? ''' for d in tex.data: uv1, uv2, uv3, uv4 = signList ''' ob.parent = newCurve
def grow(self, ob, bvhtree): # 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 normalize 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, bvhtree, 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, newPos = collision(bvhtree, 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 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