Blender 3D: Blending Into Python/OrphanScripts
Appearance
Orphan Scripts
[edit | edit source]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()