~ubuntu-branches/ubuntu/gutsy/blender/gutsy-security

« back to all changes in this revision

Viewing changes to release/scripts/bvh_export.py

  • Committer: Bazaar Package Importer
  • Author(s): Florian Ernst
  • Date: 2005-11-06 12:40:03 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051106124003-3pgs7tcg5rox96xg
Tags: 2.37a-1.1
* Non-maintainer upload.
* Split out parts of 01_SConstruct_debian.dpatch again: root_build_dir
  really needs to get adjusted before the clean target runs - closes: #333958,
  see #288882 for reference

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!BPY
 
2
 
 
3
"""
 
4
Name: 'Motion Capture (.bvh)...'
 
5
Blender: 232
 
6
Group: 'Export'
 
7
Tip: 'Export a (.bvh) motion capture file'
 
8
"""
 
9
 
 
10
__author__ = "Campbell Barton"
 
11
__url__ = ("blender", "elysiun")
 
12
__version__ = "1.0 03/30/04"
 
13
 
 
14
__bpydoc__ = """\
 
15
This script exports animation data to BVH motion capture file format.
 
16
 
 
17
Supported:<br>
 
18
 
 
19
Missing:<br>
 
20
 
 
21
Known issues:<br>
 
22
 
 
23
Notes:<br>
 
24
 
 
25
"""
 
26
 
 
27
# $Id: bvh_export.py,v 1.5 2004/11/07 16:31:13 ianwill Exp $
 
28
#
 
29
#===============================================#
 
30
# BVH Export script 1.0 by Campbell Barton      #
 
31
# Copyright MetaVR 30/03/2004,                  #
 
32
# if you have any questions about this script   #
 
33
# email me ideasman@linuxmail.org               #
 
34
#                                               #
 
35
#===============================================#
 
36
 
 
37
# -------------------------------------------------------------------------- 
 
38
# BVH Export v0.9 by Campbell Barton (AKA Ideasman) 
 
39
# -------------------------------------------------------------------------- 
 
40
# ***** BEGIN GPL LICENSE BLOCK ***** 
 
41
 
42
# This program is free software; you can redistribute it and/or 
 
43
# modify it under the terms of the GNU General Public License 
 
44
# as published by the Free Software Foundation; either version 2 
 
45
# of the License, or (at your option) any later version. 
 
46
 
47
# This program is distributed in the hope that it will be useful, 
 
48
# but WITHOUT ANY WARRANTY; without even the implied warranty of 
 
49
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 
50
# GNU General Public License for more details. 
 
51
 
52
# You should have received a copy of the GNU General Public License 
 
53
# along with this program; if not, write to the Free Software Foundation, 
 
54
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
 
55
 
56
# ***** END GPL LICENCE BLOCK ***** 
 
57
# -------------------------------------------------------------------------- 
 
58
 
 
59
import Blender
 
60
from Blender import Scene, Object
 
61
import math
 
62
from math import *
 
63
 
 
64
# Get the current scene.
 
65
scn = Scene.GetCurrent()
 
66
context = scn.getRenderingContext()
 
67
 
 
68
frameRate = 0.3333 # 0.04 = 25fps
 
69
scale = 1
 
70
 
 
71
indent = '  ' # 2 space indent per object
 
72
prefixDelimiter = '_'
 
73
 
 
74
# Vars used in eular rotation funtcion
 
75
RAD_TO_DEG = 180.0/3.14159265359
 
76
 
 
77
 
 
78
 
 
79
#====================================================#
 
80
# Search for children of this object and return them #
 
81
#====================================================#
 
82
def getChildren(parent):
 
83
  children = [] # We'll assume none.
 
84
  for child in Object.Get():
 
85
    if child.getParent() == Object.Get(parent):
 
86
      children.append( child.getName() )
 
87
  return children
 
88
 
 
89
#====================================================#
 
90
# MESSY BUT WORKS: Make a string that shows the      #
 
91
# hierarchy as a list and then eval it               #
 
92
#====================================================#
 
93
def getHierarchy(root, hierarchy):
 
94
  hierarchy = hierarchy + '["' + root + '",'
 
95
  for child in getChildren(root):
 
96
    hierarchy = getHierarchy(child, hierarchy)
 
97
  hierarchy += '],' 
 
98
  return hierarchy
 
99
 
 
100
 
 
101
#====================================================#
 
102
# Strips the prefix off the name before writing      #
 
103
#====================================================#
 
104
def stripName(name): # name is a string
 
105
  
 
106
  # WARNING!!! Special case for a custom RIG for output
 
107
  # for MetaVR's HPX compatable RIG.
 
108
  print 'stripname', name[0:10]
 
109
  if name[0:10] == 'Transform(':
 
110
    name = name[10:]
 
111
    while name[-1] != ')':
 
112
      name = name[0:-1]
 
113
      print name
 
114
    name = name[:-1]
 
115
  
 
116
  
 
117
  return name[1+name.find(prefixDelimiter): ]
 
118
  
 
119
 
 
120
#====================================================#
 
121
# Return a 6 deciaml point floating point value      #
 
122
# as a string that dosent have any python chars      #
 
123
#====================================================#  
 
124
def saneFloat(float):
 
125
  #return '%(float)b' % vars()  # 6 fp as house.hqx
 
126
  return str('%f' % float) + ' '
 
127
 
 
128
 
 
129
 
 
130
#====================================================#
 
131
# Recieves an object name, gets all the data for that#
 
132
# node from blender and returns it for formatting    #
 
133
# and writing to a file.                             #
 
134
#====================================================#
 
135
def getNodeData(nodeName):  
 
136
  Object.Get(nodeName)
 
137
  # Get real location  
 
138
  offset = Object.Get(nodeName).getLocation()
 
139
  offset = (offset[0]*scale, offset[1]*scale, offset[2]*scale,)
 
140
  
 
141
  #=========================#
 
142
  # Test for X/Y/Z IPO's    #
 
143
  #=========================#
 
144
  obipo = Object.Get(nodeName).getIpo()
 
145
  
 
146
  # IF we dont have an IPO then dont check the curves.
 
147
  # This was added to catch end nodes that never have an IPO, only an offset.
 
148
  if obipo == None: 
 
149
    xloc=yloc=zloc=xrot=yrot=zrot = 0
 
150
  
 
151
  else: # Do have an IPO, checkout which curves are in use.
 
152
    # Assume the rot's/loc's exist until proven they dont
 
153
    xloc=yloc=zloc=xrot=yrot=zrot = 1
 
154
    if obipo.getCurve('LocX') == None:
 
155
      xloc = 0
 
156
    if obipo.getCurve('LocY') == None:
 
157
      yloc = 0
 
158
    if obipo.getCurve('LocZ') == None:
 
159
      zloc = 0
 
160
      
 
161
    # Now for the rotations, Because of the conversion of rotation coords
 
162
    # if there is one rotation er need to store all 3
 
163
    if obipo.getCurve('RotX') == None and \
 
164
    obipo.getCurve('RotY') == None and \
 
165
    obipo.getCurve('RotZ') == None:
 
166
      xrot=yrot=zrot = 0
 
167
  
 
168
  # DUMMY channels xloc, yloc, zloc, xrot, yrot, zrot
 
169
  # [<bool>, <bool>, <bool>, <bool>, <bool>, <bool>]
 
170
  channels = [xloc, yloc, zloc, xrot, yrot, zrot]
 
171
  
 
172
  return offset, channels
 
173
 
 
174
 
 
175
#====================================================#
 
176
# Return the BVH hierarchy to a file from a list     #
 
177
# hierarchy: is a list of the empty hierarcht        #
 
178
# bvhHierarchy: a string, in the bvh format to write #
 
179
# level: how many levels we are down the tree,       #
 
180
# ...used for indenting                              #
 
181
# Also gathers channelList , so we know the order to #
 
182
# write  the motiondata in                           #
 
183
#====================================================#
 
184
def hierarchy2bvh(hierarchy, bvhHierarchy, level, channelList, nodeObjectList):
 
185
  nodeName = hierarchy[0]
 
186
  
 
187
  # Add object to nodeObjectList
 
188
  nodeObjectList.append(Object.Get(nodeName))
 
189
  
 
190
  #============#
 
191
  # JOINT NAME #
 
192
  #============# 
 
193
  bvhHierarchy += level * indent
 
194
  if level == 0:
 
195
    # Add object to nodeObjectList
 
196
    nodeObjectList.append(Object.Get(nodeName))
 
197
    bvhHierarchy+= 'ROOT '
 
198
    bvhHierarchy += stripName(nodeName) + '\n'
 
199
  # If this is the last object in the list then we
 
200
  # dont bother withwriting its real name, use "End Site" instead
 
201
  elif len(hierarchy) == 1:
 
202
    bvhHierarchy+= 'End Site\n'
 
203
  # Ok This is a normal joint
 
204
  else:
 
205
    # Add object to nodeObjectList
 
206
    nodeObjectList.append(Object.Get(nodeName))
 
207
    bvhHierarchy+= 'JOINT '
 
208
    bvhHierarchy += stripName(nodeName) + '\n'
 
209
  #================#
 
210
  # END JOINT NAME #
 
211
  #================# 
 
212
 
 
213
  # Indent again, this line is just for the brackets
 
214
  bvhHierarchy += level * indent + '{' + '\n'
 
215
 
 
216
  # Indent
 
217
  level += 1   
 
218
  
 
219
  #================================================#
 
220
  # Data for writing to a file offset and channels #
 
221
  #================================================#
 
222
  offset, channels = getNodeData(nodeName)
 
223
  
 
224
  #============#
 
225
  # Offset     #
 
226
  #============# 
 
227
  bvhHierarchy += level * indent + 'OFFSET ' + saneFloat(scale * offset[0]) + ' '  + saneFloat(scale * offset[1]) + ' ' + saneFloat(scale * offset[2]) + '\n'
 
228
  
 
229
  #============#
 
230
  # Channels   #
 
231
  #============# 
 
232
  if len(hierarchy) != 1:
 
233
    # Channels, remember who is where so when we write motiondata
 
234
    bvhHierarchy += level * indent + 'CHANNELS '
 
235
    # Count the channels
 
236
    chCount = 0
 
237
    for chn in channels:
 
238
      chCount += chn
 
239
    bvhHierarchy += str(chCount) + ' '
 
240
    if channels[0]:
 
241
      bvhHierarchy += 'Xposition '
 
242
      channelList.append([len(nodeObjectList)-1, 0])
 
243
    if channels[1]:
 
244
      bvhHierarchy += 'Yposition '
 
245
      channelList.append([len(nodeObjectList)-1, 1])
 
246
    if channels[2]:
 
247
      bvhHierarchy += 'Zposition '
 
248
      channelList.append([len(nodeObjectList)-1, 2])
 
249
    if channels[5]:
 
250
      bvhHierarchy += 'Zrotation '
 
251
      channelList.append([len(nodeObjectList)-1, 5])
 
252
    if channels[3]:
 
253
      bvhHierarchy += 'Xrotation '
 
254
      channelList.append([len(nodeObjectList)-1, 3])
 
255
    if channels[4]:
 
256
      bvhHierarchy += 'Yrotation '
 
257
      channelList.append([len(nodeObjectList)-1, 4])
 
258
    
 
259
    bvhHierarchy += '\n'
 
260
 
 
261
  # Loop through children if any and run this function (recursively)
 
262
  for hierarchyIdx in range(len(hierarchy)-1):
 
263
    bvhHierarchy, level, channelList, nodeObjectList = hierarchy2bvh(hierarchy[hierarchyIdx+1], bvhHierarchy, level, channelList, nodeObjectList)
 
264
  # Unindent
 
265
  level -= 1
 
266
  bvhHierarchy += level * indent + '}' + '\n'
 
267
  
 
268
  return bvhHierarchy, level, channelList, nodeObjectList
 
269
 
 
270
# added by Ben Batt 30/3/2004 to make the exported rotations correct
 
271
def ZYXToZXY(x, y, z):
 
272
  '''
 
273
  Converts a set of Euler rotations (x, y, z) (which are intended to be
 
274
  applied in z, y, x order) into a set which are intended to be applied in
 
275
  z, x, y order (the order expected by .bvh files)
 
276
  '''
 
277
  A,B = cos(x),sin(x)
 
278
  C,D = cos(y),sin(y)
 
279
  E,F = cos(z),sin(z)
 
280
 
 
281
  x = asin(-B*C)
 
282
  y = atan2(D, A*C)
 
283
  z = atan2(-B*D*E + A*F, B*D*F + A*E)
 
284
 
 
285
  # this seems to be necessary - not sure why (right/left-handed coordinates?)
 
286
  x = -x
 
287
  return x*RAD_TO_DEG, y*RAD_TO_DEG, z*RAD_TO_DEG
 
288
 
 
289
 
 
290
 
 
291
def getIpoLocation(object, frame):
 
292
  x =  y = z = 0 
 
293
  obipo = object.getIpo()
 
294
  for i in range(object.getIpo().getNcurves()):
 
295
    if obipo.getCurves()[i].getName() =='LocX':
 
296
      x = object.getIpo().EvaluateCurveOn(i,frame)
 
297
    elif obipo.getCurves()[i].getName() =='LocY':
 
298
      y = object.getIpo().EvaluateCurveOn(i,frame)
 
299
    elif obipo.getCurves()[i].getName() =='LocZ':
 
300
      z = object.getIpo().EvaluateCurveOn(i,frame)
 
301
  return x, y, z
 
302
 
 
303
 
 
304
#====================================================#
 
305
# Return the BVH motion for the spesified frame      #
 
306
# hierarchy: is a list of the empty hierarcht        #
 
307
# bvhHierarchy: a string, in the bvh format to write #
 
308
# level: how many levels we are down the tree,       #
 
309
# ...used for indenting                              #
 
310
#====================================================#
 
311
def motion2bvh(frame, chennelList, nodeObjectList):
 
312
  
 
313
  motionData = '' # We'll append the frames to the string.
 
314
  
 
315
  for chIdx in chennelList:
 
316
    ob = nodeObjectList[chIdx[0]]
 
317
    chType = chIdx[1]
 
318
    
 
319
    # Get object rotation
 
320
    x, y, z = ob.getEuler()
 
321
    
 
322
    # Convert the rotation from ZYX order to ZXY order
 
323
    x, y, z = ZYXToZXY(x, y, z)
 
324
     
 
325
    
 
326
    # Using regular Locations stuffs upIPO locations stuffs up
 
327
    # Get IPO locations instead
 
328
    xloc, yloc, zloc = getIpoLocation(ob, frame)
 
329
 
 
330
    # WARNING non standard Location
 
331
    xloc, zloc, yloc = -xloc, yloc, zloc
 
332
    
 
333
 
 
334
    if chType == 0:
 
335
      motionData += saneFloat(scale * (xloc))
 
336
    if chType == 1:
 
337
      motionData += saneFloat(scale * (yloc))
 
338
    if chType == 2:
 
339
      motionData += saneFloat(scale * (zloc))      
 
340
    if chType == 3:
 
341
      motionData += saneFloat(x)
 
342
    if chType == 4:
 
343
      motionData += saneFloat(y)
 
344
    if chType == 5:
 
345
      motionData += saneFloat(z)
 
346
    
 
347
    motionData += ' '
 
348
     
 
349
  motionData += '\n'
 
350
  return motionData
 
351
 
 
352
def saveBVH(filename):
 
353
 
 
354
  if filename.find('.bvh', -4) <= 0: filename += '.bvh' # for safety
 
355
 
 
356
  # Here we store a serialized list of blender objects as they appier
 
357
  # in the hierarchy, this is refred to when writing motiondata
 
358
  nodeObjectList = []
 
359
  
 
360
  # In this list we store a 2 values for each node
 
361
  # 1) An index pointing to a blender object
 
362
  # in objectList
 
363
  # 2) The type if channel x/y/z rot:x/y/z - Use 0-5 to indicate this
 
364
  chennelList = []
 
365
  
 
366
  print ''
 
367
  print 'BVH  1.0 by Campbell Barton (Ideasman) - ideasman@linuxmail.org'
 
368
  
 
369
  # Get the active object and recursively traverse its kids to build
 
370
  # the BVH hierarchy, then eval the string to make a hierarchy list.
 
371
  hierarchy = eval(getHierarchy(Object.GetSelected()[0].getName(),''))[0] # somhow this returns a tuple with one list in it.
 
372
  
 
373
  # Put all data in the file we have selected file.
 
374
  file = open(filename, "w")
 
375
  file.write('HIERARCHY\n') # all bvh files have this on the first line
 
376
  
 
377
  # Write the whole hirarchy to a list
 
378
  bvhHierarchy, level, chennelList, nodeObjectList = hierarchy2bvh(hierarchy, '', 0, chennelList, nodeObjectList)
 
379
  file.write( bvhHierarchy ) # Rwite the var fileBlock to the output.
 
380
  bvhHierarchy = None # Save a tit bit of memory
 
381
  
 
382
  #====================================================#
 
383
  # MOTION: Loop through the frames ande write out     #
 
384
  # the motion data for each                           #
 
385
  #====================================================#
 
386
  # Do some basic motion file header stuff
 
387
  file.write('MOTION\n')
 
388
  file.write( 'Frames: ' + str(1 + context.endFrame() - context.startFrame()) + '\n'  )
 
389
  file.write( 'Frame Time: ' + saneFloat(frameRate) + '\n'  ) 
 
390
  
 
391
  #print 'WARNING- exact frames might be stuffed up- inclusive whatever, do some tests later on.'
 
392
  frames = range(context.startFrame(), context.endFrame()+1)
 
393
  print 'exporting ' + str(len(frames)) + ' of motion...'
 
394
  
 
395
  for frame in frames:
 
396
    context.currentFrame(frame)
 
397
    scn.update(1) # Update locations so we can write the new locations
 
398
    #Blender.Window.RedrawAll() # causes crash
 
399
    
 
400
    file.write(  motion2bvh(frame, chennelList, nodeObjectList)  )
 
401
     
 
402
  file.write('\n') # newline
 
403
  file.close()
 
404
  print 'done'
 
405
  
 
406
Blender.Window.FileSelector(saveBVH, 'Export BVH')