[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