[Bf-extensions-cvs] [eab84e27] master: io_anim_acclaim: moved to contrin: T63750
meta-androcto
noreply at git.blender.org
Fri May 24 03:02:46 CEST 2019
Commit: eab84e27ef577198d1ee686fe13e8b15d1a97ed7
Author: meta-androcto
Date: Fri May 24 11:01:36 2019 +1000
Branches: master
https://developer.blender.org/rBACeab84e27ef577198d1ee686fe13e8b15d1a97ed7
io_anim_acclaim: moved to contrin: T63750
===================================================================
A io_anim_acclaim/__init__.py
===================================================================
diff --git a/io_anim_acclaim/__init__.py b/io_anim_acclaim/__init__.py
new file mode 100644
index 00000000..5aaaa5ad
--- /dev/null
+++ b/io_anim_acclaim/__init__.py
@@ -0,0 +1,546 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 3
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8-80 compliant>
+
+# This script was developed with financial support from the Foundation for
+# Science and Technology of Portugal, under the grant SFRH/BD/66452/2009.
+
+
+bl_info = {
+ "name": "Acclaim Motion Capture Files (.asf, .amc)",
+ "author": "Daniel Monteiro Basso <daniel at basso.inf.br>",
+ "version": (2013, 1, 26, 1),
+ "blender": (2, 65, 9),
+ "location": "File > Import-Export",
+ "description": "Imports Acclaim Skeleton and Motion Capture Files",
+ "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
+ "Scripts/Import-Export/Acclaim_Importer",
+ "category": "Import-Export",
+}
+
+
+import re
+import bpy
+from mathutils import Vector, Matrix
+from math import radians, degrees
+from bpy.props import (
+ StringProperty,
+ BoolProperty,
+ FloatProperty,
+ IntProperty,
+ )
+
+
+class DataStructure:
+ """
+ Parse the Skeleton and Motion Files to an internal data structure.
+ """
+ doc = re.compile(r"(?ms):(\w+)\s+([^:]+)")
+ block = re.compile(r"(?ms)begin\s+(.*?)\s+end")
+ bonedata = re.compile(r"(?ms)(name|direction|length|axis|dof)\s+(.*?)\s*$"
+ "|limits(\s.*)")
+
+ def __init__(self, file_path, scale=1.):
+ self.scale = scale
+ source = open(file_path, encoding="utf-8", errors="replace").read()
+ sections = dict(DataStructure.doc.findall(source))
+ if not sections:
+ raise ValueError("Wrong file structure.")
+
+ if 'units' in sections:
+ units = dict(u.strip().split()
+ for u in sections['units'].splitlines()
+ if u.strip())
+ if 'length' in units:
+ self.scale /= float(units['length'])
+
+ if 'bonedata' not in sections:
+ raise ValueError("Bone data section not found.")
+ bm = DataStructure.block.findall(sections['bonedata'])
+ if not bm:
+ raise ValueError("Bone data section malformed.")
+ self.bones = {'root': {
+ 'dof': ['X', 'Y', 'Z'],
+ 'direction': Vector(), # should be orientation of root sector
+ 'length': 1,
+ 'axis': Matrix(),
+ 'axis_inv': Matrix(),
+ }}
+ for b in bm:
+ bd = dict((i[0] or 'limits', i[0] and i[1] or i[2])
+ for i in DataStructure.bonedata.findall(b))
+ for k in bd:
+ s = [t for t in re.split(r"[^a-zA-Z0-9-+.]", bd[k]) if t]
+ if k == 'axis':
+ rot = Matrix()
+ for ang, basis in zip(s[:3], s[3].upper()):
+ rot = Matrix.Rotation(radians(float(ang)),
+ 4, basis) * rot
+ bd['axis'] = rot
+ elif k == 'direction':
+ bd[k] = Vector([float(n) for n in s])
+ elif k == 'length':
+ bd[k] = float(s[0]) * self.scale
+ elif k == 'dof':
+ bd[k] = [a[1].upper() for a in s] # only rotations
+ elif k == 'limits':
+ bd[k] = s
+ if 'axis' in bd:
+ bd['axis_inv'] = bd['axis'].inverted()
+ self.bones[bd['name']] = bd
+
+ if 'hierarchy' not in sections:
+ raise ValueError("Hierarchy section not found.")
+ hm = DataStructure.block.search(sections['hierarchy'])
+ if not hm:
+ raise ValueError("Hierarchy section malformed.")
+ self.hierarchy = {}
+ for l in hm.group(1).splitlines():
+ t = l.strip().split()
+ self.hierarchy[t[0]] = t[1:]
+
+ def scan_motion_capture(self, filename, skip=5):
+ """
+ Parse an Acclaim Motion Capture file and iterates over the data
+ """
+ amc = open(filename, encoding="utf-8", errors="replace")
+ l = ' '
+ while l and not l[0].isdigit():
+ l = amc.readline().strip()
+ while l:
+ frame = int(l)
+ bdefs = []
+ while True:
+ l = amc.readline().strip()
+ if not l or l[0].isdigit():
+ break
+ bdefs.append(l.split())
+ if (frame - 1) % skip != 0:
+ continue
+ self.pose_def = {}
+ for b in bdefs:
+ vs = [float(v) for v in b[1:]]
+ if b[0] == 'root':
+ loc = Vector(vs[:3]) * self.scale
+ vs = vs[3:]
+ rot = Matrix()
+ if 'dof' not in self.bones[b[0]]:
+ # If 'dof' isn't defined it probably means the AMC comes
+ # from a different origin than the ASF, such as the
+ # AMC exporter in this package. Assume XYZ order.
+ self.bones[b[0]]['dof'] = ['X', 'Y', 'Z']
+ for dof, ang in zip(self.bones[b[0]]['dof'], vs):
+ rot = Matrix.Rotation(radians(ang), 4, dof) * rot
+ self.pose_def[b[0]] = rot
+ pose = self.calculate_pose(Matrix.Translation(loc))
+ yield(frame / skip + 1, pose)
+ amc.close()
+
+ def calculate_pose(self, parent, bone='root'):
+ """
+ Calculate each bone transform iteratively
+ """
+ bd = self.bones[bone]
+ tail = Matrix.Translation(bd['direction'] * bd['length'])
+ if bone in self.pose_def:
+ tail = bd['axis'] * self.pose_def[bone] * bd['axis_inv'] * tail
+ world = parent * tail
+ local = tail
+ yield(bone, world, local)
+ if bone in self.hierarchy:
+ for child in self.hierarchy[bone]:
+ for b, w, l in self.calculate_pose(world, child):
+ yield(b, w, l)
+
+
+class StructureBuilder(DataStructure):
+ def __init__(self, file_path, name="Skel", scale=1.):
+ """
+ Setup instance data and load the skeleton
+ """
+ self.file_path = file_path
+ self.name = name
+ self.user_def_scale = scale
+ DataStructure.__init__(self, file_path, scale)
+
+ def create_armature(self):
+ """
+ Create the armature and leave it in edit mode
+ """
+ bpy.context.view_layer.objects.active = None
+ bpy.ops.object.add(type='ARMATURE', enter_editmode=True)
+ self.object = bpy.context.view_layer.objects.active
+ self.armature = self.object.data
+ self.object.name = self.name
+ self.armature.name = self.name
+ self.armature.display_type = 'STICK'
+ self.object['source_file_path'] = self.file_path
+ self.object['source_scale'] = self.user_def_scale
+ self.object['MhxArmature'] = 'Daz'
+
+ def load_armature(self, obj):
+ """
+ Assign the armature object to be used for loading motion
+ """
+ self.object = obj
+
+ def build_structure(self, use_limits=False):
+ """
+ Create the root bone and start the recursion, exit edit mode
+ """
+ self.use_limits = use_limits
+ bpy.ops.armature.bone_primitive_add(name='root')
+ root_dir = Vector((0, 0.1 * self.scale, 0))
+ bpy.ops.transform.translate(value=root_dir + Vector((.0, .0, -1.0)))
+ self.recursive_add_bones()
+ bpy.ops.armature.select_all(action='DESELECT')
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ def recursive_add_bones(self, parent_name='root'):
+ """
+ Traverse the hierarchy creating bones and constraints
+ """
+ if parent_name not in self.hierarchy:
+ return
+ for name in self.hierarchy[parent_name]:
+ self.add_bone(name, parent_name)
+ if self.use_limits:
+ self.add_limit_constraint(name)
+ self.recursive_add_bones(name)
+
+ def add_bone(self, name, parent_name):
+ """
+ Extrude a bone from the specified parent, and configure it
+ """
+ bone_def = self.bones[name]
+ bpy.ops.armature.select_all(action='DESELECT')
+ # select tail of parent bone
+ self.armature.edit_bones[parent_name].select_tail = True
+ # extrude and name the new bone
+ bpy.ops.armature.extrude()
+ self.armature.edit_bones[-1].name = name
+ # translate the tail of the new bone
+ tail = bone_def['direction'] * bone_def['length']
+ bpy.ops.transform.translate(value=tail)
+ # align the bone to the rotation axis
+ axis = bone_def['axis'].to_3x3()
+ vec = axis * Vector((.0, .0, -1.0))
+ self.armature.edit_bones[-1].align_roll(vector=vec)
+
+ def add_limit_constraint(self, name):
+ """
+ Create the limit rotation constraint of the specified bone
+ """
+ bpy.ops.object.mode_set(mode='POSE')
+ bone_def = self.bones[name]
+ dof = bone_def['dof'] if 'dof' in bone_def else ''
+ pb = self.object.pose.bones[name]
+ self.armature.bones.active = self.armature.bones[name]
+ bpy.ops.pose.constraint_add
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list