"""The curvepulator, for generating manipulable & animatable curves. Version 0.1 Features: * creates new curves based on the shape of an existing one with random variation * ability to adjust the amount of created curves - also after restarts (they are gotten from scene based on parenting) * adding tapering (& modifying) curves to the generated ones - poweful for animation - only works with current cvs Todo: - use the geometry of the target object to guide positioning - animation features Bugs: - the randomly variated bez. handles are not in possible positions for the aligned mode they are in To think: - merge with beast? * add curve support * modifications to generated things """ from __future__ import division import Blender from Blender import Curve, Object, Scene, BezTriple from Blender import Noise from Blender.Mathutils import Vector from Blender import Registry #only for getting previous guiding curve for default import ScriptUI em = ScriptUI.EventManager() AMOUNT = 5 BEVRESOL = 10 W = 0.1 DENSITY = 5 #target = Blender.Object.Get('shapetarget') #targetmesh = NMesh.GetRawFromObject('target') #bbox = target.getBoundBox() #start = bbox[2] #up-left-behind .. at least in def cube #end = bbox[4] #down-right-front #trmat = target.getMatrix() scene = Scene.getCurrent() print "----------------" def trans(vecnum): #to be fixed #print "Trans: %s -> %s" % (gc[0].vec[1], start) return Vector(vecnum) #* trmat def variate(f): return (f/2) + (f/2 * Noise.random()) #probably different things needed in diff. places def make_btris(gc, mod): btris = [] for gp in gc: hnd1 = trans(gp.vec[0]) knot = trans(gp.vec[1]) hnd2 = trans(gp.vec[2]) hnd1.z += variate(mod) knot.z += variate(mod) hnd2.z += variate(mod) btri = BezTriple.New((hnd1.x, hnd1.y, hnd1.z, knot.x, knot.y, knot.z, hnd2.x, hnd2.y, hnd2.z)) btris.append(btri) return btris def create_curve(btris): ob = Object.New('Curve') #the Blender Object this wraps cob = Curve.New() #the Blender Curve object bez = cob.appendNurb(btris[0]) for btri in btris[1:]: bez.append(btri) cob.setExt2(variate(W)) cob.setBevresol(BEVRESOL) ob.link(cob) return ob def same(a, b): """Normal Python identity comparison does not work in bpython. This little function implements it 'the Blender way', for now.""" if not None in (a,b): try: return (a.getType() == b.getType()) and (a.name == b.name) except AttributeError: raise ValueError, "Non-Blender objects in BObject comparison" else: return False #means None != None. how bad is that? class Curvefill: def __init__(self, guide=None): self.curves = [] #the Blender objects wrapped self.guide = guide self.assign_guide(guide) self.update_curves() def update_curves(self): def owned(ob): if self.guide is not None: return same(ob.parent, self.guide) else: return False self.curves = [c for c in scene.getChildren() if owned(c)] self.curves.reverse() def assign_guide(self, guide=None): if guide is None: #the GUI calls like this try: self.guide = Blender.Object.GetSelected()[0] except IndexError: pass if self.guide is not None: self.gc = self.guide.getData()[0] #cur'nurb' self.update_curves() print "guide:", self.guide def _add(self): #print 'adding' mod = self.amount / DENSITY btris1 = make_btris(self.gc, mod) btris2 = make_btris(self.gc, -mod) ob1 = create_curve(btris1) ob2 = create_curve(btris2) self.curves.append(ob1) self.curves.append(ob2) scene.link(ob1) scene.link(ob2) self.guide.makeParent([ob1, ob2]) #could be given 'fast' option def _remove(self): #print 'removing' c = self.curves.pop() scene.unlink(c) c = self.curves.pop() scene.unlink(c) def set_amount(self, num): #self.update_curves() #something/-one may have changed them changed = False while num > self.amount: self._add() if not changed: changed = True while num < self.amount: self._remove() if not changed: changed = True return changed def get_amount(self): return len(self.curves) amount = property(get_amount, set_amount) def __str__(self): return 'curvatures purvatures', str(self.curves) d = Blender.Registry.GetKey('machina', True) if d: try: guide = d['prevguide'] except: print "could not get data" print d guide = None else: print "got:", guide else: print "first run, right?" d = {} guide = None c = Curvefill(guide) def quit(): print "O" d['prevguide'] = c.guide #to get in next run Blender.Registry.SetKey('machina', d, True) print "saved:", d em.exit() exitbtn = em.PushButton("Exit", x=300, bevent=quit) assignbtn = em.PushButton("Assign guiding curve", bevent=c.assign_guide) def slideamount(): try: if c.set_amount(amountsld.value): Blender.Redraw() except AttributeError: print "." pass amount = c.amount or AMOUNT amountsld = em.Slider("amount", initvalue=amount, x=100, max=20, bevent=slideamount) #taperer = Object.Get('taperer') #c.taperob = taperer #c.setTaperOb(taperer) #print "taperer", c.taperob em.run()