I have two files one .bvh
and the other is .c3d
and I want to convert them to .bvh
files if anyone could please advise how to do this as I need to work on bvh only.
2 Answers
You can import .c3d
file in blender like this:
https://stackoverflow.com/questions/20499320/how-to-import-c3d-files-into-blender
The problem is it won't be an armature, but animated locations of points:
Some points will be dead in the center (marked).
- Adjust the frame range to fit the mocap data
- Delete the dead markers
Re-build the armature - add armature to scene
looks like we have markers from both sides for each leg - that means the bones will be somewhere in between markers
Building the armature:
- select a marker (or two if I want position in between) and align 3D cursor with 'Shift-S > Cursor to Selected'
- then enter edit-mode of armature and select a joint and 'Shift-S > Selection to Cursor'
this way I can place all the bones (joints) precisely
also recalculate the Roll of the bones with 'Ctrl+N > Cursor' with 3D cursor on some reference marker
Name the bones properly
Constraining location of root bones:
- use
copy_location
constraint - or two of them with second on 50% influence to get in-between position of two markers
- similar for center of 3 markers, you get the idea
- use
Constraining bones direction
- use
damped_track
constraint also multiple of them with adjusted influence for center of group of markers
- use
Bake the animation to Action with Pose > Animation
Bake Action: visual_keying_ON, clear_constraints_ON
Export armature as
.bvh
from the blender main menu (you might need to enable BVH addon).
These steps will result in having a .c3d
file converted to a .bvh
file.
A sample .blend
file with rigged markers here:
-
$\begingroup$ Is it possible to share with me a file with the modified steps so that I can go through them and have a reference? $\endgroup$– TakCommented May 15, 2015 at 1:37
-
$\begingroup$ @shepherd yep, I'll rig one leg or something and give the .blend. I suspect this is a dog am I right? (for anatomy reference) $\endgroup$ Commented May 15, 2015 at 5:27
-
$\begingroup$ @shepherd, yep, you only add 1 armature object to the scene and then you add bones to it in edit-mode (Tab). You can extrude a bone from a joint with E or add a new bone to 3D cursor location with Shift-A. This way you end only with 1 object with multiple bones inside.) If you have multiple armatures you can fix it with selecting them and joining them into one with Ctrl-J $\endgroup$ Commented May 16, 2015 at 18:37
-
$\begingroup$ Thank you very much again. I've been using these steps manually but now I need a script as I have many files. I've followed the answer below given by batFINGER and constructed the armature found here dropbox.com/s/nx8xsk4z0pavaxx/ArmatureToTpose.blend?dl=0 then I try to put the armature in Tpose to parent to my mesh with automatic weighting using the batFINGER's answer found here blender.stackexchange.com/a/53981/2517 you will find that the mesh is doesn't look good, kinda twisted and during the animation it get's ugly, I'm not sure why? is it because of the bone roll value? $\endgroup$– TakCommented Nov 19, 2016 at 9:31
-
$\begingroup$ so as you suggested, I've used
DAMPED_TRACK
instead ofTRACK_TO
used by batFINGER. And the mesh still looks bad usingcon = pb.constraints.new('DAMPED_TRACK')
con.target = bpy.data.objects.get(pb.name)
con.track_axis = 'TRACK_Y'
con.influence = 1
$\endgroup$– TakCommented Nov 19, 2016 at 9:33
Created a script to create a hierarchal armature and add constraints to animate.
Firstly import the c3d with a prefix, I've chosen "GT_", this makes it easier to clean up.
import bpy
context = bpy.context
scene = context.scene
prefix = "GT_"
# select all imported with prefix GT_
obs = [o for o in scene.objects if o.name.startswith(prefix)]
root = "RootDog"
# clean up unwanted objects could look for flat action sum.
text = bpy.data.texts.get("C3D_bones")
if not text:
text = bpy.data.texts.new("C3D_bones")
text.clear()
bones = {}
for o in obs:
if o.location.length < 0.0000001:
scene.objects.unlink(o)
bpy.data.objects.remove(o)
else:
name = o.name[3:]
print(bones)
bones[name] = {"parent":None,
"tail":root}
names = sorted(bones.keys())
text.write("%s\n" % root)
for name in names:
if name == root:
continue
text.write("\t%s\n" % name)
It creates a text object with a simple structure. Tabs must be used to indent. Like
RootDog
LBackElbow
LBackLeg
LBackPaw
Which was quite simple to edit into, and I renamed to "C3DBones.txt" to avoid overwriting with previous script.
RootDog
RFrontWaistDog
RBackWaistDog
RBackElbow
RBackLeg
RBackPaw
LFrontWaistDog
LBackWaistDog
LBackElbow
LBackLeg
LBackPaw
LowBackDog
MidbackDog
TopSpineDog
RFShoulderDog
RElbowDog
RForeLeg
RPaw
LFhoulderDog
LElbowDog
LForeLeg
LPaw
MidDoghead
LeftDogHead
RightDogHead
Lastly, the hierarchy is used to create a rig and add constraints.
import bpy
from mathutils import Vector
context = bpy.context
scene = context.scene
text = bpy.data.texts.get("C3D_bones.txt")
prefix = "GT_"
parent_level = 0
parents = [None] * 16
arm = bpy.data.armatures.new("Armature")
rig = bpy.data.objects.new("C3DRig", arm)
scene.objects.link(rig)
scene.objects.active = rig
scene.update()
bpy.ops.object.mode_set(mode='EDIT')
for l in text.lines:
body = l.body
level = 0
while body.startswith("\t"):
body = body[1:]
level += 1
print(l.body, level)
body = "%s%s" % (prefix, body)
bone = arm.edit_bones.new(body)
o = scene.objects.get(body)
if not o:
print("No %s" % body)
continue
bone.tail = o.location
parent_level = max(level-1, 0)
parents[level] = o
parent = parents[parent_level]
bone.parent = arm.edit_bones.get(parent.name)
if bone.parent:
bone.head = bone.parent.tail
bone = arm.edit_bones.get(parents[0].name)
if bone:
bone.head = bone.tail + Vector([0, 0, 1])
bpy.ops.object.mode_set(mode='OBJECT')
else:
print("no root bone")
# do something with pose bones
for pb in rig.pose.bones:
con = pb.constraints.new('COPY_LOCATION')
if not pb.parent:
con.target = bpy.data.objects.get(pb.name)
continue
con.target = bpy.data.objects.get(pb.parent.name)
con = pb.constraints.new('TRACK_TO')
con.target = bpy.data.objects.get(pb.name)
-
$\begingroup$ Thanks for that. Could you send me a link of the blend file please? $\endgroup$– TakCommented Mar 23, 2016 at 2:25
-
1$\begingroup$ Done, note it only creates a rig and animates it off the c3d empties. Connect bones where desired and add limit rot constraints etc to fix bone roll, or use the methods suggested by @Jerryno. Also the root bone loc is kinda crap. Might need to add a constrained empty half way between the waists and use that instead of RootDog. Once that is done I'd pose into a rest position, and change to this rest pos. (currently has the rest pose of the pose of the frame on which the 2nd script is run) $\endgroup$ Commented Mar 23, 2016 at 3:52
-
1$\begingroup$ Sample with tween waist empty as root. pasteall.org/blend/41189 $\endgroup$ Commented Mar 23, 2016 at 5:59
-
$\begingroup$ Is it possible to make the constructed root bone very small so it's not visible? I've tried doing this from the 3d view and it looks like this can be done by going to editmode then selecting the tail of it and then translating it by -1 along the Z-axis. $\endgroup$– TakCommented Nov 14, 2016 at 11:58
-
$\begingroup$ I was able to solve it using
context.object.data.edit_bones[0].select_head = True
thenbpy.ops.transform.translate(value=(0, 0, -0.99), constraint_axis=(False, False, True), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1) {'FINISHED'}
$\endgroup$– TakCommented Nov 14, 2016 at 12:42
.c3d
file into blender (which I already did), my problem is how to convert it into.bvh
$\endgroup$