Blender 3D: Blending Into Python/OrphanScripts
From Wikibooks, open books for an open world
[edit] Orphan Scripts
Hi, post unmaintained scripts here.
Be wary of malicious code, especially the OS module, check in the history every so often for edits to see nobody's doing bad stuff.
Currently there are two scripts here in need of nice mothers or fathers.
This script is a simple L system that allows you to use pre-defined meshes. It DOES work in 2.43 and could possibly be a building generator (with some work).
# # ===================== # README # ===================== # # this is a simple L-system that uses pre-made mesh elemental blocks # # source blocks are in a different layer - press tilde (`) in 3d view # to see them all # # a new mesh is created every time; edge creases are carried over from # source meshes to allow subsurf work # # this system uses the turtle concept with pushable/poppable state, # just like most other L-systems # however, the "drawing" operation here is to place a pre-made mesh # instead the usual plant-oriented stuff # as a result, this should be pretty well suitable for Discombobulator # style work such as generating lots of small detail # # turtle instructions and any other tokens are XML-like tags # instead of single characters; they can also contain an arbitrary # argument string # rewriting rules are actually defined as functions to allow # procedural flexibility # # things left to do really depend on what the actual use is # some ideas include using lists instead of strings for arbitrary # argument data (may help with speed); supplying environment # info to the rule function (for queries, like in some advanced # L-systems out there) as well as the current model info # for true Discombobulator-style detail generation there has # to be a mode to populate the axiom (initial state) with # existing model faces # # of course, more code cleanup is in order # import sys import re import Blender from Blender import Mathutils from Blender import NMesh substrate = '<LimbArray>'#'<twist:90><turn:90><LimbArray>' # custom characters and their translations custom = [ \ ('<Stem>', '<add:Stem><offset:0.5,0,0>'), \ ('<Joint2>', '<add:Joint2Start><offset:0.2,0,0><pitch:-30_0><add:Joint2Middle><turn:-20_20><add:Joint2End><offset:0.2,0,0>') \ ] print "growing..." # force recompile of ruleset if 'ruleset' in sys.modules: del sys.modules['ruleset'] import ruleset rules = [ (re.compile('<' + name + '(?::([^>]+))?>'), getattr(ruleset, name)) for name in dir(ruleset) ] # do the matching for stage in range(20): curPos = 0 while True: newPos, newEnd = None, None newStr = None for regex, func in rules: match = regex.search(substrate, curPos) if match != None: if newPos == None or newPos > match.start(): newPos = match.start() newEnd = match.end() newStr = func(match.group(1)) if newPos == None: break substrate = substrate[:newPos] + newStr + substrate[newEnd:] curPos += len(newStr) # translate custom chars for char, repl in custom: substrate = re.sub(char, repl, substrate) print "interpreting..." # interpret the result class StackFrame: # prev is the parent frame def __init__(self, prev=None): self.prev = prev if prev != None: self.matrix = prev.matrix else: self.matrix = Mathutils.Matrix() self.matrix.identity() self.matrix.resize4x4() # modifications def rotate(self, axis, angle): rot = Mathutils.RotationMatrix(angle, 4, axis) self.matrix = rot * self.matrix def offset(self, xyz): tra = Mathutils.TranslationMatrix(Mathutils.Vector(xyz)) self.matrix = tra * self.matrix def scale(self, ratio): sca = Mathutils.Matrix( \ [ ratio, 0, 0, 0 ], \ [ 0, ratio, 0, 0 ], \ [ 0, 0, ratio, 0 ], \ [ 0, 0, 0, 1 ]) self.matrix = sca * self.matrix # raises exception if no parent def getPrev(self): if self.prev == None: raise Exception, "no parent frames" return self.prev # appends current mesh to given one # does NOT change position def addMesh(self, meshObj, dest): mesh = meshObj.getData() vertBase = len(dest.verts) for v in mesh.verts: vec = Mathutils.Vector(v.co[0], v.co[1], v.co[2], 1) vec = vec*self.matrix cv = NMesh.Vert(vec.x, vec.y, vec.z) dest.verts.append(cv) for f in mesh.faces: cf = NMesh.Face([ dest.verts[v.index + vertBase] for v in f.v ]) dest.addFace(cf) if mesh.edges != None: for e in mesh.edges: v1, v2 = e.v1, e.v2 nv1, nv2 = dest.verts[v1.index + vertBase], dest.verts[v2.index + vertBase] ne = dest.addEdge(nv1, nv2) ne.crease = e.crease #dest.update() # create result mesh mesh = NMesh.New() #mesh.addEdgesData() # for things like creases # do the dew frame = StackFrame() # parses and interprets a string of type # X:Y_Z (randomly choose either X or something between Y and Z) def number(str): import random choices = str.split(':') choice = random.choice(choices) limits = choice.split('_', 2) if len(limits) == 2: return random.uniform(float(limits[0]), float(limits[1])) return float(limits[0]) instrMatch = re.compile(r""" < (?P<instr1> \w+ ) (?: : (?P<arg> [^>]+ ) )? > | (?P<instr2> [\[\]] ) """, re.VERBOSE) curPos = 0 while True: match = instrMatch.search(substrate, curPos) if match == None: break curPos = match.end() # collect instruction instr = match.group('instr1') if instr == None: instr = match.group('instr2') arg = match.group('arg') # do the dew if instr == "[": frame = StackFrame(frame) elif instr == "]": frame = frame.getPrev() elif instr == "offset": frame.offset([ number(a) for a in arg.split(',', 3) ]) elif instr == "turn": frame.rotate("z", number(arg)) elif instr == "pitch": frame.rotate("y", number(arg)) elif instr == "twist": frame.rotate("x", number(arg)) elif instr == "scale": frame.scale(number(arg)) elif instr == "add": frame.addMesh(Blender.Object.Get(arg), mesh) NMesh.PutRaw(mesh, "Result", 1, 1)
This script apparently WONT work in blender 2.43, updates welcome.
# Jamesk's Walk-o-matic version 0.49.9 (MODIFIED) # for Blender 2.25 and a fully installed Python 2.0 [required] # CHANGES FOR BLENDER 2.36 GENERALLY MARKED '#MDR:' ... # Badly coded changes for Blender 2.43 by TwinStripe :) ! Appears to perform more passes but produces the same results!?! # SET/CHECK THE PARAMETERS BELOW BEFORE EXECUTING THE SCRIPT. # Make sure to select your proxy object, then run the script with ALT+P. # Please consult the documentation for a full description of the parameters. # ...Aaaaand check the console window for any messages. # GENERAL SETTINGS: FF = FIRST_FRAME = 1 # begin evaluating at this frame LF = LAST_FRAME = 850 # stop evaluating after this frame HS = HEEL_SEPARATION = 3.0 # desired distance between heel targets (in Blender Units) MT = MOVE_TIME = 8.0 # number of frames/cycle a foot is moving MSD = MOVE_STOP_DELAY = 0 # any value above zero will prolong the time a foot stays in the air. HEEL_TO_FLAT_DISTANCE = 1 # desired distance between a heel target and its associated foot look-at-target FLAT_TO_TLAT_DISTANCE = 0.5 # desired distance between a foot look-at-target and its associated toe look-at-target AL = ALWAYS_LIFT = 0 # set to zero to prevent feet moving up/down when proxy has speed 0 CTD = C_TARG_DISTANCE = 2.0 # how far above proxy to place center target LA = LIFT_AXIS = 'local' # lift feet along global Z or local proxy Z? CTDLA = CTD_LIFT_AXIS = 'global' # raise center target along global Z or local proxy Z? # NAMES FOR THE EMPTIES: HEEL_LEFT, HEEL_RIGHT = 'heel.ikt.left', 'heel.ikt.right' FLAT_LEFT, FLAT_RIGHT = 'foot.lat.left', 'foot.lat.right' TLAT_LEFT, TLAT_RIGHT = 'toe.lat.left', 'toe.lat.right' TARGET_CENTRE = 'target.centre' # LIFT ENVELOPE SETTINGS: LP = LIFT_PEAK = 0.5 # how far to lift above proxy initially FLATLP = FLAT_LIFT_PEAK = 0.2 # how far to lift foot look-at-target above proxy initially TLATLP = TLAT_LIFT_PEAK = 0.2 # how far to lift toe look-at-target above proxy initially LPT = LIFT_PEAK_TIME = 0.2 # time to reach lift-peak. (relative to movetime) MP = MID_PEAK = 0.4 # how far from proxy after lift-peak FLATMP = FLAT_MID_PEAK = 0.4 # how far to lift foot look-at-target TLATMP = TLAT_MID_PEAK = 0.4 # how far to lift toe look-at-target MPT = MID_PEAK_TIME = 0.5 # time to reach mid-peak (relative to movetime) FP = FINAL_PEAK = 0.5 # how far from proxy before setting down again FLATFP = FLAT_FINAL_PEAK = 0.7 # how far to lift foot look-at-target TLATFP = TLAT_FINAL_PEAK = 0.9 # how far to lift toe look-at-target FPT = FINAL_PEAK_TIME = 0.8 # time to reach final_peak (relative to - you guessed it - movetime) # # Concept and coding by James Kaufeldt a.k.a. Jamesk # Made in Sweden, november 2002 # Contact: james.k@home.se # # Special thanx to # - [d0pamine] and [theeth] for some hints regarding vector math. # - Martin [Strubi] Strubel from whom I borrowed the "normalize" function, # len3(x), dist3(x,y) and sub3(x,y) funcs found in his "vect.py" utility module. # - [eeshlo] for pointing out how simple it was to give names to the empties. # # --------------------------------------------------------------------------------------- # EDITABLE SECTION ENDS HERE! # # NO USER DEFINABLE VALUES BEYOND THIS POINT! # --------------------------------------------------------------------------------------- # # # # LT = MT CT = MT + LT from Blender import Object, Scene, Window, Ipo from Blender.Scene import Render from Blender.Window import Types import sys, math proxy = Object.GetSelected() status = 'UNDEFINED ERROR' Layer = 0 print print '----------------------------------' print 'W A L K - O - M A T I C V 0.49.9' print '----------------------------------' print # make sure that there's an actual walker proxy to use: if proxy == []: print 'No proxy indicated, terminating...' status = 'NO PROXY OBJECT SELECTED' if proxy != []: proxy = proxy[0] print 'Proxy in use: \t',proxy Layer = proxy.Layer print ' in Layer',Layer status = 'OK' sys.stdout.flush() scene = Scene.GetCurrent() # make sure there's a scene to use (should always be one, but wth...) if scene == []: print 'No scene available, terminating...' status = 'NO CURRENT SCENE AVAILABLE' if scene != []: print 'Target scene: \t',scene sys.stdout.flush() # some generally useful functions below: def normalize(v): r = math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) return (v[0]/r, v[1]/r, v[2]/r) def len3(x): return math.sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]) def sub3(x, y): return ((x[0] - y[0]), (x[1] - y[1]), (x[2] - y[2])) def dist3(x, y): return len3(sub3(x, y)) def moveAlong(origpos, distance, vector): newpos = [0,0,0] newpos[0] = origpos[0]+distance*vector[0] newpos[1] = origpos[1]+distance*vector[1] newpos[2] = origpos[2]+distance*vector[2] return newpos def invertVector(v): return (-v[0], -v[1], -v[2]) #MDR: def selectFrame(f): f = int(f) if scene.getRenderingContext().currentFrame() != f: scene.getRenderingContext().currentFrame(f) Window.Redraw(Window.Types.VIEW3D) # MDR: # Conversion routine: try to get an object, return None if it's not there. # Just like Blender used to do. The easiest way to accomplish this is to # allow the exception to occur, and catch it. def TryGetObject(v): try: return Object.Get(v) except: return None def getOffset(origin, frame, xdir, xdist, forward): # origin: the point to offset frame: framenumber # xdir: 1 = positive offset along X, -1 = negative offset # xdist: how much to offset selectFrame(frame) loc = origin.getMatrix()[3] loc = moveAlong(loc, forward, normalize(origin.getMatrix()[1])) direction = normalize(origin.getMatrix()[0]) if xdir == -1: direction = invertVector(direction) return moveAlong(loc, xdist, direction) def getLiftAxisOffset(origin, frame, liftaxis, liftdist): # origin: the point to offset frame: framenumber # liftaxis: 'global' or 'local' lifting liftdist: the amount of lift selectFrame(frame) loc = origin.getMatrix()[3] direction = normalize(origin.getMatrix()[2]) if liftaxis=='global': direction = [0,0,1.0] return moveAlong(loc, liftdist, direction) def getElevation(origin, frame, axis, zdist, xdir, xdist, forward): # origin: the point to offset frame: framenumber # axis: 'local' or 'global' zdist: how much to elevate # xdir: the X offset xdist: the distance to offset along X loc = getOffset(origin, frame, xdir, xdist, forward) if axis=='local': direction = normalize(origin.getMatrix()[2]) return moveAlong(loc, zdist, direction) if axis=='global': direction = [0, 0, 1.0] return moveAlong(loc, zdist, direction) def writeCurvePoint(ipo, frame, point): # ipo: the IPOblock to use frame: at what frame # point: the 3D coordinate to write xc = ipo.getCurve('LocX') yc = ipo.getCurve('LocY') zc = ipo.getCurve('LocZ') for idx, c in enumerate([xc,yc,zc]): c.addBezier((frame, point[idx])) c.update() def makeIPO(name, ipol, expol): # name: desired name for this IPOblock ipol: type of interpolation # expol: type of extrapolation ipo = Ipo.New('Object', name) xc = ipo.addCurve('LocX') yc = ipo.addCurve('LocY') zc = ipo.addCurve('LocZ') for curve in [xc, yc, zc]: curve.setInterpolation(ipol) curve.setExtrapolation(expol) return ipo def move(ipo, origin, destination, startframe, framespan, proxob, xdir, xdist, forward): # ipo - what ipo to write points to origin - the location (3Dpoint) to start at # destination - the location to end up at startframe - frame to set the first curvepoint at # framespan - total number of frames for the move proxob - the proxy/reference object # xdir - pos or neg offset along proxy X-axis xdist - how much to offset along proxy X-axis writeCurvePoint(ipo, startframe, origin) if AL==1 or origin!=destination: # Write curvepoints for LiftPeak and LiftPeakTime: # Pretty hackish formulae for proxyTime here... But they do work, so wtf... lpProxyTime = startframe + (LPT*framespan*2)-framespan*0.25 lpRealTime = startframe+(framespan+MSD)*LPT lpLocation = getElevation(proxob, lpProxyTime, LA, LP, xdir, xdist, forward) writeCurvePoint(ipo, lpRealTime, lpLocation) # Write curvepoints for MidPeak and MidPeakTime: mpProxyTime = startframe + (MPT*framespan*2)-framespan*0.25 mpRealTime = startframe+(framespan+MSD)*MPT mpLocation = getElevation(proxob, mpProxyTime, LA, MP, xdir, xdist, forward) writeCurvePoint(ipo, mpRealTime, mpLocation) # Write curvepoints for FinalPeak and FinalPeakTime: fpProxyTime = startframe + (FPT*framespan*2)-framespan*0.25 fpRealTime = startframe+(framespan+MSD)*FPT fpLocation = getElevation(proxob, fpProxyTime, LA, FP, xdir, xdist, forward) writeCurvePoint(ipo, fpRealTime, fpLocation) writeCurvePoint(ipo, startframe+framespan+MSD, destination) return (startframe+framespan, destination) def hold(ipo, location, startframe, framespan): # ipo - what ipo to write points to # location - the position (3Dpoint) to hold at # startframe - the first frame in the hold sequence # framespan - total number of frames to hold writeCurvePoint(ipo, startframe+MSD, location) writeCurvePoint(ipo, startframe+framespan, location) return (startframe+framespan, location) def recalculator(assignedTargets, targ1, targ2, basetarg): # rewrites some globals based on the current arrangement of the empties: loc1 = targ1.getLocation() loc2 = targ2.getLocation() loc3 = basetarg.getLocation() # HEEL_SEPARATION: if assignedTargets=='heels': print 'Default heel empties found. Recalculating:' global HS HS = dist3(loc1, loc2) print 'HEEL_SEPARATION set to',HS if assignedTargets=='flats': print 'Default foot look-at targets found. Reusing.' global HEEL_TO_FLAT_DISTANCE HEEL_TO_FLAT_DISTANCE = dist3(loc2, loc3) print 'HEEL_TO_FLAT_DISTANCE set to', HEEL_TO_FLAT_DISTANCE if assignedTargets=='tlats': print 'Default toe look-at targets found. Reusing.' global FLAT_TO_TLAT_DISTANCE FLAT_TO_TLAT_DISTANCE = dist3(loc2, loc3) print 'FLAT_TO_TLAT_DISTANCE set to',FLAT_TO_TLAT_DISTANCE def doIt(forwardOffset, addCenter, whatsUp, firstName, secondName): print print 'Currently processing:',whatsUp # Start building the IPO for the right foot: ffootipo = makeIPO('rfoot', 'Linear', 'Constant') cpf = currentProxyFrame = FF # make first step (only half as far as the others): ffootloc = getOffset(proxy, cpf, 1, HS/2, forwardOffset) ffootframe = cpf targetloc = getOffset(proxy, cpf+MT, 1, HS/2, forwardOffset) ffootframe, ffootloc = move(ffootipo, ffootloc, targetloc, ffootframe, MT/2,proxy, 1, HS/2, forwardOffset) ffootframe, ffootloc = hold(ffootipo, ffootloc, ffootframe, LT) # now make the rest of the steps (full length): while True: cpf += CT targetloc = getOffset(proxy, cpf+MT, 1, HS/2, forwardOffset) ffootframe, ffootloc = move(ffootipo, ffootloc, targetloc, ffootframe, MT,proxy, 1, HS/2, forwardOffset) ffootframe, ffootloc = hold(ffootipo, ffootloc, ffootframe, LT) if cpf>LF: break # Then we'll build the IPO for the left foot: sfootipo = makeIPO('lfoot', 'Linear', 'Constant') cpf = currentProxyFrame = FF # this one starts in hold-mode (waits for right foot to finish) sfootloc = getOffset(proxy, cpf, -1, HS/2, forwardOffset) sfootframe = cpf sfootframe, sfootloc = hold(sfootipo, sfootloc, cpf, MT/2) while True: cpf += CT targetloc = getOffset(proxy, cpf, -1, HS/2, forwardOffset) sfootframe, sfootloc = move(sfootipo, sfootloc, targetloc, sfootframe, MT,proxy, -1, HS/2, forwardOffset) sfootframe, sfootloc = hold(sfootipo, sfootloc, sfootframe, LT) if cpf>LF: break if addCenter: # And to finish it off, let's put something in the middle of this: # This will simply add a third target floating above the proxy. # It will respect the specified lift axis, hence useful as parent for an armature ctargetipo = makeIPO('center', 'Linear', 'Constant') for cframe in range(FF, LF): targetloc = getLiftAxisOffset(proxy, cframe, CTDLA, CTD) writeCurvePoint(ctargetipo, cframe, targetloc) # Finished. Add or reuse empties and link them to their respective IPOblocks. leftikt = TryGetObject(firstName) leftnew = False if leftikt==None: leftikt = Object.New('Empty') leftnew = True rightikt = TryGetObject(secondName) rightnew = False if rightikt==None: rightikt = Object.New('Empty') rightnew = True leftikt.name = firstName rightikt.name = secondName print 'Targets',leftikt,rightikt if addCenter: centertarget = TryGetObject(TARGET_CENTRE) centernew = False if centertarget==None: centertarget = Object.New('Empty') centernew = True centertarget.name = TARGET_CENTRE print 'Centertarget',centertarget centertarget.Layer = Layer if centernew: scene.link(centertarget) #MDR: 'SetIPO' was 'link'... centertarget.setIpo(ctargetipo) leftikt.Layer = Layer rightikt.Layer = Layer if leftnew: scene.link(leftikt) if rightnew: scene.link(rightikt) #MDR: Ditto... 'setIpo' was 'link'... leftikt.setIpo(sfootipo) rightikt.setIpo(ffootipo) print whatsUp,'IPO:s',sfootipo,ffootipo print '---------------------------------------------------------' sys.stdout.flush() ######################################### # if everything's OK, let's get to work # ######################################### if status=='OK': currentUserFrame = scene.getRenderingContext().currentFrame() # grab any walkomat empties left in the scene: oldleftheel =TryGetObject(HEEL_LEFT) oldrightheel =TryGetObject(HEEL_RIGHT) oldleftflat =TryGetObject(FLAT_LEFT) oldrightflat =TryGetObject(FLAT_RIGHT) oldlefttlat =TryGetObject(TLAT_LEFT) oldrighttlat=TryGetObject(TLAT_RIGHT) emptyipo = makeIPO('emptydummy', 'Linear', 'Constant') # recalculate if there were any such empties: if oldleftheel!=None and oldrightheel!=None: # assign an empty IPO first to clear any anim: # why isn't there some 'unlink' function somewhere??? # # MDR: These 'setIpo' calls were 'link' .... # oldleftheel.setIpo(emptyipo) oldrightheel.setIpo(emptyipo) recalculator('heels', oldleftheel, oldrightheel, oldrightheel) if oldleftflat!=None and oldrightflat!=None: oldleftflat.setIpo(emptyipo) oldrightflat.setIpo(emptyipo) recalculator('flats', oldleftflat, oldrightflat, oldrightheel) if oldlefttlat!=None and oldrighttlat!=None: oldlefttlat.setIpo(emptyipo) oldrighttlat.setIpo(emptyipo) recalculator('tlats', oldlefttlat, oldrighttlat, oldrightflat) # first pass, heel targets: doIt(0, 1, 'Heel targets', HEEL_LEFT, HEEL_RIGHT) #second pass, foot look-at targets: LP = FLATLP MP = FLATMP FP = FLATFP doIt(HEEL_TO_FLAT_DISTANCE, 0, 'Foot look-at targets', FLAT_LEFT, FLAT_RIGHT) #third pass, toe look-at targets: LP = TLATLP MP = TLATMP FP = TLATFP doIt(HEEL_TO_FLAT_DISTANCE+FLAT_TO_TLAT_DISTANCE, 0, 'Toe look-at targets', TLAT_LEFT, TLAT_RIGHT) # At last, as a friendly gesture, restore the frame to whatever the user # was looking at before running the script, and refresh the screens: scene.getRenderingContext().currentFrame(currentUserFrame) Window.RedrawAll() print 'Processing completed.' print 'Thank you for using Walk-O-Matic :D' sys.stdout.flush() ################################################### # if things are not right, print some dying words:# ################################################### if status!='OK': print '' print 'Walk-o-matic is sadly forced to report that' print 'it could not go to work properly.' print 'Cause of termination: ',status print 'Please consult the documentation regarding proper use.' sys.stdout.flush()
This page may need to be