[Bf-extensions-cvs] [fefc9c4e] master: io_anim_c3d: moved to contrib: T63750

meta-androcto noreply at git.blender.org
Fri May 24 03:12:38 CEST 2019


Commit: fefc9c4eb8405185c7df115861d71ef2af94bbb2
Author: meta-androcto
Date:   Fri May 24 11:12:15 2019 +1000
Branches: master
https://developer.blender.org/rBACfefc9c4eb8405185c7df115861d71ef2af94bbb2

io_anim_c3d: moved to contrib: T63750

===================================================================

A	io_anim_c3d/__init__.py
A	io_anim_c3d/import_c3d.py

===================================================================

diff --git a/io_anim_c3d/__init__.py b/io_anim_c3d/__init__.py
new file mode 100644
index 00000000..88ff974b
--- /dev/null
+++ b/io_anim_c3d/__init__.py
@@ -0,0 +1,366 @@
+# ##### 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": "C3D Graphics Lab Motion Capture file (.c3d)",
+    "author": "Daniel Monteiro Basso <daniel at basso.inf.br>",
+    "version": (2015, 5, 5, 1),
+    "blender": (2, 74, 1),
+    "location": "File > Import",
+    "description": "Imports C3D Graphics Lab Motion Capture files",
+    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
+                "Scripts/Import-Export/C3D_Importer",
+    "category": 'Import-Export',
+}
+
+
+import bpy
+from bpy.props import (
+    StringProperty,
+    BoolProperty,
+    FloatProperty,
+    IntProperty,
+)
+
+import os
+import math
+from mathutils import Vector
+from . import import_c3d
+
+
+class C3DAnimateCloud(bpy.types.Operator):
+    """
+        Animate the Marker Cloud
+    """
+    bl_idname = "import_anim.c3danim"
+    bl_label = "Animate C3D"
+
+    is_armature = False
+    markerset = None
+    uname = None
+    curframe = 0
+    fskip = 0
+    scale = 0
+    timer = None
+    Y_up = False
+
+    def update_empty(self, fno, ml, m):
+        name = self.unames[self.prefix + ml]
+        o = bpy.context.scene.objects[name]
+        p = Vector(m.position) * self.scale
+        o.location = Vector((p[0], -p[2], p[1])) if self.Y_up else p
+        o.keyframe_insert('location', frame=fno)
+
+    def update_bone(self, fno, ml, m, bones):
+        name = self.prefix + ml
+        if name not in bones:
+            return
+        b = bones[name]
+        p = Vector(m.position) * self.scale
+        b.matrix.translation = Vector((p[0], -p[2], p[1])) if self.Y_up else p
+        b.keyframe_insert('location', -1, fno, name)
+
+    def update_frame(self):
+        fno = self.curframe
+        if not self.use_frame_no:
+            fno = (self.curframe - self.markerset.startFrame) / self.fskip
+        for i in range(self.fskip):
+            self.markerset.readNextFrameData()
+        if self.is_armature:
+            bones = bpy.context.active_object.pose.bones
+        for ml in self.markerset.markerLabels:
+            m = self.markerset.getMarker(ml, self.curframe)
+            if m.confidence < self.confidence:
+                continue
+            if self.is_armature:
+                self.update_bone(fno, ml, m, bones)
+            else:
+                self.update_empty(fno, ml, m)
+
+    def modal(self, context, event):
+        if event.type == 'ESC':
+            return self.cancel(context)
+        if event.type == 'TIMER':
+            if self.curframe > self.markerset.endFrame:
+                return self.cancel(context)
+            self.update_frame()
+            self.curframe += self.fskip
+        return {'PASS_THROUGH'}
+
+    def execute(self, context):
+        self.timer = context.window_manager.\
+            event_timer_add(0.001, context.window)
+        context.window_manager.modal_handler_add(self)
+        return {'RUNNING_MODAL'}
+
+    def cancel(self, context):
+        bpy.context.scene.frame_set(bpy.context.scene.frame_current)
+        context.window_manager.event_timer_remove(self.timer)
+        return {'FINISHED'}
+
+
+class C3DImporter(bpy.types.Operator):
+    """
+        Load a C3D Marker Cloud
+    """
+    bl_idname = "import_anim.c3d"
+    bl_label = "Import C3D"
+
+    filepath: StringProperty(
+        subtype='FILE_PATH',
+    )
+    Y_up: BoolProperty(
+        name="Up vector is Y axis",
+        default=False,
+        description="Check when the data uses Y-up, uncheck when it uses Z-up",
+    )
+    from_inches: BoolProperty(
+        name="Convert from inches to meters",
+        default=False,
+        description="Scale by 2.54/100",
+    )
+    scale: FloatProperty(
+        name="Scale",
+        default=1.0,
+        description="Scale the positions by this value",
+        min=0.0000001, max=1000000.0,
+        soft_min=0.001, soft_max=100.0,
+    )
+    auto_scale: BoolProperty(
+        name="Adjust scale automatically",
+        default=False,
+        description="Guess correct scale factor",
+    )
+    auto_magnitude: BoolProperty(
+        name="Adjust scale magnitude",
+        default=True,
+        description="Automatically adjust scale magnitude",
+    )
+    create_armature: BoolProperty(
+        name="Create an armature",
+        default=True,
+        description="Import the markers as bones instead of empties",
+    )
+    size: FloatProperty(
+        name="Empty or bone size",
+        default=.03,
+        description="The size of each empty or bone",
+        min=0.0001, max=1000000.0,
+        soft_min=0.001, soft_max=100.0,
+    )
+    x_ray: BoolProperty(
+        name="Use X-Ray",
+        default=True,
+        description="Show the empties or armature over other objects",
+    )
+    frame_skip: IntProperty(
+        name="Fps divisor",
+        default=1,
+        description="Frame supersampling factor",
+        min=1,
+    )
+    use_frame_no: BoolProperty(
+        name="Use frame numbers",
+        default=False,
+        description="Offset start of animation according to the source",
+    )
+    show_names: BoolProperty(
+        name="Show Names", default=False,
+        description="Show the markers' name",
+    )
+    prefix: StringProperty(
+        name="Name Prefix", maxlen=32,
+        description="Prefix object names with this",
+    )
+    use_existing: BoolProperty(
+        name="Use existing empties or armature",
+        default=False,
+        description="Use previously created homonymous empties or bones",
+    )
+    confidence: FloatProperty(
+        name="Minimum Confidence Level", default=0,
+        description="Only consider markers with at least "
+                    "this confidence level",
+        min=-1., max=1000000.0,
+        soft_min=-1., soft_max=100.0,
+    )
+
+    filter_glob: StringProperty(default="*.c3d;*.csv", options={'HIDDEN'})
+
+    def find_height(self, ms):
+        """
+            Heuristic to find the height of the subject in the markerset
+            (only works for standing poses and you must have correct data
+            on the first frame)
+        """
+        zmin, zmax = None, None
+        hidx = 1 if self.properties.Y_up else 2
+        for ml in ms.markerLabels:
+            # check if LTOE is a substring of this marker label
+            if 'LTOE' in ml:
+                # substitute the substring to get the head marker
+                hd = ml.replace('LTOE', 'LFHD')
+                if hd not in ms.markerLabels:
+                    break
+                pmin_idx = ms.markerLabels.index(ml)
+                pmax_idx = ms.markerLabels.index(hd)
+                zmin = ms.frames[0][pmin_idx].position[hidx]
+                zmax = ms.frames[0][pmax_idx].position[hidx]
+                break
+        if zmin is None:  # could not find named markers, get extremes
+            allz = [m.position[hidx] for m in ms.frames[0]]
+            zmin, zmax = min(allz), max(allz)
+        return abs(zmax - zmin) or 1
+
+    def adjust_scale_magnitude(self, height, scale):
+        mag = math.log10(height * scale)
+        return scale * math.pow(10, -int(mag))
+
+    def adjust_scale(self, height, scale):
+        """
+            Try to find the correct scale for some common configurations
+            found in CMU's c3d files.
+        """
+        factor = height * scale / 1.75  # normalize
+        if factor < 0.5:
+            scale /= 10.0
+            factor *= 10.0
+        cmu_factors = [(1.0, 1.0), (1.1, 1.45), (1.6, 1.6), (2.54, 2.54)]
+        sqerr, fix = min(
+            ((cf[0] - factor) ** 2.0, 1.0 / cf[1])
+            for cf in cmu_factors
+        )
+        return scale * fix
+
+    def create_empties(self, ms):
+        """
+            Create the empties and get their collision-free names
+        """
+        unames = {}
+        use_existing = self.properties.use_existing
+        s = self.properties.size
+        empty_size = (s, s, s)
+        for ml in ms.markerLabels:
+            name = self.properties.prefix + ml
+            if use_existing and name in bpy.context.scene.objects:
+                o = bpy.context.scene.objects[name]
+            else:
+                bpy.ops.object.add()
+                o = bpy.context.active_object
+                o.name = name
+            unames[name] = o.name
+            bpy.ops.transform.resize(value=empty_size)
+            o.show_name = self.properties.show_names
+            o.show_in_front = self.properties.x_ray
+        for name in unames.values():
+            bpy.context.scene.objects[name].select_set(True)
+        return unames
+
+    def create_armature_obj(self, ms, scale):
+        """
+            Create or use existing armature, return a bone dict,
+            leave the armature in POSE mode
+        """
+        head_dir = Vector((0, 0, self.properties.size))
+        ao = bpy.context.active_object
+        # when using an existing armature we restrict importing
+        # the markers only for existing bones
+        if not self.properties.use_existing or not ao or ao.type != 'ARMATURE':
+         

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list