I have made a very quick and simple way of getting data captured from Kinect into blender. It’s perhaps not the best of solutions out there and I coded it all in one morning so it could definitely do with some more work. But if you are interested in doing something similar it might be of interest.
I used this guide to set up the drivers and software.
Using the NITE “Stick Figure” sample, I added the source below to write each bone’s location and orientation to a text file along with a frame number in the file name (i.e. test_0.txt, test_1.txt, test_2.txt…)
//in StickFigure.cpp
#define AnimName "H:/mocap/kinect/test" //location to write data to
void OPBoneInfo(XnUserID user, xn::UserGenerator userGenerator, XnSkeletonJoint joint, std::ofstream& fs)
{
XnSkeletonJointPosition pos;
XnSkeletonJointOrientation rot;
userGenerator.GetSkeletonCap().GetSkeletonJointPosition(user, joint, pos);
userGenerator.GetSkeletonCap().GetSkeletonJointOrientation(user, joint, rot);
fs << pos.position.X << " " << pos.position.Y << " " << pos.position.Z << " ";
fs << rot.orientation.elements[0] << " " << rot.orientation.elements[1] << " " << rot.orientation.elements[2] << " "
<< rot.orientation.elements[3] << " "<< rot.orientation.elements[4] << " " << rot.orientation.elements[5] << " "
<< rot.orientation.elements[6] << " "<< rot.orientation.elements[7] << " " << rot.orientation.elements[8] << " ";
}
//in DrawSingleUser add
void DrawSingleUser(XnUserID user, xn::UserGenerator g_UserGenerator, const XnPoint3D& corner)
{
//existing source...
{
static int frame = 0;
std::ofstream fs;
std::string location(AnimName);
std::string extension(".txt");
std::stringstream oss;
oss << location << "_" << frame << extension;
fs.open (oss.str());
OPBoneInfo(user, g_UserGenerator, XN_SKEL_LEFT_HAND, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_LEFT_ELBOW, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_LEFT_SHOULDER, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_TORSO, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_RIGHT_SHOULDER, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_RIGHT_ELBOW, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_RIGHT_HAND, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_NECK, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_HEAD, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_LEFT_HIP, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_RIGHT_HIP, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_LEFT_KNEE, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_RIGHT_KNEE, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_LEFT_FOOT, fs);
OPBoneInfo(user, g_UserGenerator, XN_SKEL_RIGHT_FOOT, fs);
fs.close();
frame++;
}
//existing source...
}
Using the program as you would normally it will output the data for 15 bones to the location you specify.
In Blender, I created this script
import bpy
import os, codecs, time
import mathutils
gBoneName = "KinectArma"
gRootName = ["LEFT_HAND","LEFT_ELBOW","LEFT_SHOULDER","TORSO","RIGHT_SHOULDER","RIGHT_ELBOW", "RIGHT_HAND","NECK","HEAD","LEFT_HIP","RIGHT_HIP", "LEFT_KNEE","RIGHT_KNEE","LEFT_FOOT","RIGHT_FOOT"]
gBoneStream = "H:/mocap/kinect/test"
def AddKinectArma(scene):
armaData = bpy.data.armatures.new(gBoneName)
arma = bpy.data.objects.new(gBoneName, armaData)
scene.objects.link(arma)
return arma
#enddef
def CheckSceneForArma(scene):
if gBoneName in scene.objects:
return scene.objects[gBoneName]
return AddKinectArma(scene)
#endddef
def CheckArmaForBones(arma):
armaObj = bpy.data.objects[gBoneName]
armaDat = armaObj.data
bpy.context.scene.objects.active = armaObj
bpy.ops.object.mode_set(mode='EDIT')
for bone in gRootName:
if bone in armaDat.bones:
print("Bone Present\n")
else:
bone = bpy.ops.armature.bone_primitive_add(name=bone)
#endif
#endfor
bpy.ops.object.mode_set(mode='OBJECT')
#endddef
def MainLoop():
armaObj = bpy.data.objects[gBoneName]
armaDat = armaObj.data
scale = 0.01
fileIdx = 0
bpy.context.scene.frame_current = 0
bpy.ops.object.mode_set(mode='POSE')
mocapFile = gBoneStream + "_" + str(fileIdx) + ".txt"
while(os.access(mocapFile, os.F_OK)):
fs = open(mocapFile,"r")
pos = [float(x)*scale for x in fs.read().split()]
fs.close()
idx = 0
for bone in gRootName:
if idx + 12 <= len(pos):
armaObj.pose.bones[bone].location.x = pos[idx+0]
armaObj.pose.bones[bone].location.y = pos[idx+1]
armaObj.pose.bones[bone].location.z = pos[idx+2]
#create matrix, chnage it to a quat
mtx = mathutils.Matrix((pos[idx+3],pos[idx+4],pos[idx+5],0),(pos[idx+6],pos[idx+7],pos[idx+8],0),(pos[idx+9],pos[idx+10],pos[idx+11],0),(0,0,0,1))
armaObj.pose.bones[bone].rotation_mode = 'QUATERNION'
mtx = mtx.rotation_part()
#mtx = mtx.transpose()
armaObj.pose.bones[bone].rotation_quaternion = mtx.to_quat()
else:
print("numbers are wrong : " + str(idx) + ", " + str(len(pos)) + armaObj.pose.bones[bone].name)
#endif
idx = idx + 12
#endfor
#select all bones
for bone in gRootName:
armaObj.pose.bones[bone].bone.select = True
#add a keyframe
bpy.ops.anim.keyframe_insert(type='LocRotScale')
#update the anim counter
bpy.context.scene.frame_current = bpy.context.scene.frame_current+1
#get next file
fileIdx = fileIdx + 1
mocapFile = gBoneStream + "_" + str(fileIdx) + ".txt"
if fileIdx > 1000: #JUST IN CASE
break;
#endwhile
bpy.ops.object.mode_set(mode='OBJECT')
print("finished")
#endwhile
#endddef
arma = CheckSceneForArma(bpy.context.scene)
CheckArmaForBones(arma)
MainLoop()
Which creates an Armature with the correct amount of bones, and then reads in the source files sequentially creating keyframes as it goes along. Here’s one I made earlier
It’s a bit of hack, and it’s not very user friendly but it’s a start :)