Skip to content

Instantly share code, notes, and snippets.

@batFINGER
Created December 13, 2016 01:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save batFINGER/41910e5208431d452d70db66466bf660 to your computer and use it in GitHub Desktop.
Save batFINGER/41910e5208431d452d70db66466bf660 to your computer and use it in GitHub Desktop.
C3D addon with modal "animation" operator removed
# ##### 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@basso.inf.br>",
"version": (2013, 12, 10, 1),
"blender": (2, 69, 5),
"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 math
import time
from mathutils import Vector
#from . import import_c3d
from io_anim_c3d import import_c3d
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",
)
size = FloatProperty(
name="Empty Size",
default=.03,
description="The size of each empty",
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 over other objects",
)
frame_skip = IntProperty(
name="Fps divisor",
default=4,
# usually the sample rate is 120, so the default 4 gives you 30fps
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",
default=False,
description="Use previously created homonymous empties",
)
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)
"""
zmin = None
hidx = 1 if self.properties.Y_up else 2
for ml in ms.markerLabels:
if 'LTOE' in ml:
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]
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)
#print('mag',mag, 'scale',scale)
return scale * math.pow(10, -int(mag))
def adjust_scale(self, height, scale):
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)
#print('height * scale: {:.2f}'.format(height * scale))
#print(factor, fix)
return scale * fix
def execute(self, context):
s = self.properties.size
empty_size = (s, s, s)
ms = import_c3d.read(self.properties.filepath, onlyHeader=True)
ms.readNextFrameData()
#print(ms.fileName)
# determine the final scale
height = self.find_height(ms)
#print('h', height)
scale = 1.0 if not self.properties.from_inches else 0.0254
scale *= ms.scale
if self.properties.auto_magnitude:
scale = self.adjust_scale_magnitude(height, scale)
#print('scale',scale)
if self.properties.auto_scale:
scale = self.adjust_scale(height, scale)
scale *= self.properties.scale
# create the empties and get their collision-free names
unames = {}
use_existing = self.properties.use_existing
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_x_ray = self.properties.x_ray
for name in unames.values():
bpy.context.scene.objects[name].select = True
Y_up = self.properties.Y_up
fskip = self.properties.frame_skip
prefix = self.properties.prefix
use_frame_no = self.properties.use_frame_no
confidence = self.properties.confidence
curframe = ms.startFrame
while curframe < ms.endFrame:
fno = curframe
if not use_frame_no:
fno = (curframe - ms.startFrame) / fskip
for i in range(fskip):
ms.readNextFrameData()
for ml in ms.markerLabels:
name = unames[prefix + ml]
o = context.scene.objects[name]
m = ms.getMarker(ml, curframe)
p = Vector(m.position) * scale
o.location = Vector((p[0], -p[2], p[1])) if Y_up else p
if m.confidence >= confidence:
o.keyframe_insert('location', frame=fno)
curframe += fskip
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
wm.fileselect_add(self)
return {'RUNNING_MODAL'}
def menu_func(self, context):
self.layout.operator(C3DImporter.bl_idname,
text="Graphics Lab Motion Capture (.c3d)")
def register():
bpy.utils.register_module(__name__)
bpy.types.INFO_MT_file_import.append(menu_func)
def unregister():
bpy.utils.unregister_module(__name__)
bpy.types.INFO_MT_file_import.remove(menu_func)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment