#include "NiVMDTool.h" using namespace jbxl; using namespace jbxwl; static std::string _VMDJointName[] = // VMD_JOINT_NUM { // SJIS "全ての親", "センター", "下半身", "上半身", "上半身2", "首", "頭", "頭先", "両目", "左目", "右目", "左胸", "右胸", "左肩", "左腕", "左腕捩", "左ひじ", "左手捩", "左手首", "左手先", "右肩", "右腕", "右腕捩", "右ひじ", "右手捩", "右手首", "右手先", "左足", "左ひざ", "左足IK", "左足首", "左つま先", "左つま先IK", "右足", "右ひざ", "右足IK", "右足首", "右つま先", "右つま先IK" }; // static std::string _VMDJointName_eng[] = // VMD_JOINT_NUM { "parent", "center", "lower body", "upper body", "upper body2", "neck", "head", "skull", "eyes", "eye_L", "eye_R", "bust_L", "bust_R", "shoulder_L", "arm_L", "arm twist_L", "elbow_L", "wrist twist_L", "wrist_L", "c wrist l", "shoulder_R", "arm_R", "arm twist_R", "elbow_R", "wrist twist_R", "wrist_R", "c wrist r", "leg_L", "knee_L", "leg_IK_L", "ankle_L", "toe_L", "toe_IK_L", "leg_R", "knee_R", "leg_IK_R", "ankle_R", "toe_R", "toe_IK_R" }; /** std::string jbxwl::VMDJointName(int n) VMDのジョイント番号から,MMDのジョイント名を得る */ std::string jbxwl::VMDJointName(int n) { std::string str = ""; if (n>=0 && n none VMD_CENTER ( 1) => NI_PELVIS ( 0) VMD_LOWER ( 2) => NI_WAIST ( 1) VMD_UPPER ( 3) => NI_TORSO ( 2) VMD_UPPER2 ( 4) => NI_CHEST ( 3) VMD_NECK ( 5) => NI_NECK ( 4) VMD_HEAD ( 6) => NI_HEAD ( 5) VMD_SKULL ( 7) => NI_SKULL ( 6) VMD_EYES ( 8) => none VMD_L_EYE ( 9) => NI_L_EYE ( 7) VMD_R_EYE (10) => NI_R_EYE ( 8) VMD_L_BUST (11) => NI_L_BUST ( 9) VMD_R_BUST (12) => NI_R_BUST (10) VMD_L_SHLDR (13) => NI_L_COLLAR(11) VMD_L_ARM (14) => NI_L_SHLDR (12) VMD_L_ARM_TW (15) => none VMD_L_ELBOW (16) => NI_R_ELBOW (13) VMD_L_WRIST_TW (17) => none VMD_L_WRIST (18) => NI_L_WRIST (14) VMD_L_HAND (19) => NI_R_HAND (15) VMD_R_SHLDR (20) => NI_R_COLLAR(17) VMD_R_ARM (21) => NI_R_SHLDR (18) VMD_R_ARM_TW (22) => none VMD_R_ELBOW (23) => NI_R_ELBOW (19) VMD_R_WRIST_TW (24) => none VMD_R_WRIST (25) => NI_R_WRIST (20) VMD_R_HAND (26) => NI_R_HAND (21) VMD_L_HIP (27) => NI_L_HIP (23) VMD_L_KNEE (28) => NI_L_KNEE (24) VMD_L_ANKLE_IK (29) => NI_L_ANKLE (25) VMD_L_ANKLE (30) => NI_L_FOOT (26) VMD_L_TOE (31) => NI_L_TOE (27) VMD_L_TOE_IK (32) => none VMD_R_HIP (33) => NI_R_HIP (28) VMD_R_KNEE (34) => NI_R_KNEE (29) VMD_R_ANKLE_IK (35) => NI_R_ANKLE (30) VMD_R_ANKLE (36) => NI_R_FOOT (31) VMD_R_TOE (37) => NI_R_TOE (32) VMD_R_TOE_IK (38) => none */ // // VMDのジョイント番号から,共通ジョイントの番号を得る // static int _VMD2NiJointNum[] = // VMD_JOINT_NUM (37) { -1, 0, 1, 2, 3, 4, 5, 6, -1, 7, 8, 9, 10, 11, 12, -1, 13, -1, 14, 15, 17, 18, -1, 19, -1, 20, 21, 23, 24, 25, 26, 27, -1, 28, 29, 30, 31, 32, -1 }; /** VMDのジョイント番号から,共通ジョイントの番号を得る */ int jbxwl::VMD2NiJointNum(int joint) { if (joint<0 || joint>=VMD_JOINT_NUM) return -1; return _VMD2NiJointNum[joint]; } ////////////////////////////////////////////////////////////////////////////////////////////////////// // CNiVMDTool Class CNiVMDTool::CNiVMDTool(void) { memset(&vmd_header, 0, sizeof(VMDFileHeader)); vmd_frames = NULL; vmd_datnum = 0; dmy_frames = NULL; dmy_frmnum = 0; joints_num = VMD_JOINT_NUM; rate_frame = VMD_FARME_RATE/30.0; A2TPose.setRotation(37.0/180.0*PI, 1.0, 0.0, 0.0, 1.0); posVect = (Vector*)malloc(sizeof(Vector)*VMD_JOINT_NUM); rotQuat = (Quaternion*)malloc(sizeof(Quaternion)*VMD_JOINT_NUM); } CNiVMDTool::~CNiVMDTool(void) { DEBUG_INFO("DESTRUCTOR: CNiVMDTool\n"); free_data(); } void CNiVMDTool::free_data(void) { if (dmy_frames!=NULL) ::freeFramesData(dmy_frames, dmy_frmnum); if (vmd_frames!=NULL) ::free(vmd_frames); vmd_frames = NULL; vmd_datnum = 0; dmy_frames = NULL; dmy_frmnum = 0; clear_data(); } void CNiVMDTool::clear_data(void) { CBaseFrameTool::free_data(); } //////////////////////////////////////////////////////////////////////////////////////////////////// // /** BOOL CNiVMDTool::readFile(FILE* fp) VMDファイルを読み込む */ BOOL CNiVMDTool::readFile(FILE* fp) { if (fp==NULL) return FALSE; clear_data(); vmd_datnum = 0; vmd_header = readFileHeader(fp); // ヘッダ部 if (vmd_header.data_num==0) return FALSE; vmd_frames = readJointsData(fp, vmd_header.data_num); // 全フレームのデータ if (vmd_frames==NULL) return FALSE; vmd_datnum = vmd_header.data_num; // joints_num = VMD_JOINT_NUM; if (jointsData!=NULL) ::free(jointsData); jointsData = (NiJointData*)malloc(sizeof(NiJointData)*joints_num); if (jointsData==NULL) { clear_data(); return FALSE; } clearJointsData(joints_num); if (posVect==NULL) posVect = (Vector*)malloc(sizeof(Vector)*VMD_JOINT_NUM); if (rotQuat==NULL) rotQuat = (Quaternion*)malloc(sizeof(Quaternion)*VMD_JOINT_NUM); if (posVect==NULL || rotQuat==NULL) { clear_data(); return FALSE; } clearVectorData(VMD_JOINT_NUM); return TRUE; } /** VMDFileHeader CNiVMDTool::readFileHeader(FILE* fp) VMDファイルのヘッダ部を読み込む */ VMDFileHeader CNiVMDTool::readFileHeader(FILE* fp) { VMDFileHeader fhd; fread(fhd.header, 30, 1, fp); fread(fhd.name, 20, 1, fp); fread(&fhd.data_num, 4, 1, fp); if (strcmp(VMD_FILE_HD_ID2, fhd.header)) { fhd.data_num = 0; } return fhd; } /** VMDJointData CNiVMDTool::readJointData(FILE* fp) VMDファイルから 1フレーム(ジョイント)の VMDJointDataを読み込む.@n sizeof(VMDJointData)==15 + (4+4x7+64) */ VMDJointData CNiVMDTool::readJointData(FILE* fp) { VMDJointData frame; fread(frame.name, 15, 1, fp); fread(&frame.frm_num, 96, 1, fp); // 4 + 4x7 + 64 return frame; } /** VMDJointData* CNiVMDTool::readJointsData(FILE* fp, unsigned int& frmnum) 全フレーム&ジョイントの VMDJointDataを読み込む.@n ジョイント間でフレームの同期は取られていない. */ VMDJointData* CNiVMDTool::readJointsData(FILE* fp, unsigned int& frmnum) { VMDJointData* motion_data = (VMDJointData*)malloc(frmnum*sizeof(VMDJointData)); if (motion_data==NULL) return NULL; memset(motion_data, 0, frmnum*sizeof(VMDJointData)); // unsigned int num = 0; while(num0) { unsigned int j = 0; for (unsigned int i=0; imotion_data[i+1].frm_num) { swap_motion = motion_data[i]; motion_data[i] = motion_data[i+1]; motion_data[i+1] = swap_motion; j = i; } } k = j; } // 一意的なフレーム数を数える unsigned int uniq_frame = 1; unsigned int frm_num = motion_data[0].frm_num; for (unsigned int i=1; i=0) { NiJointData* jdat = &(ni_joints[i].jdat[joint]); jdat->joint = joint; jdat->index = i; jdat->vect.x = -motion_data[datacnt].posz*(double)VMD_GRID_UNIT; jdat->vect.y = motion_data[datacnt].posx*(double)VMD_GRID_UNIT; jdat->vect.z = motion_data[datacnt].posy*(double)VMD_GRID_UNIT; jdat->quat.x = motion_data[datacnt].qutz; jdat->quat.y = -motion_data[datacnt].qutx; jdat->quat.z = -motion_data[datacnt].quty; jdat->quat.s = motion_data[datacnt].qutw; if (jdat->quat.s<0.0) jdat->quat = - jdat->quat; jdat->quat.normalize(); // if (jdat->vect.x!=0.0 || jdat->vect.y!=0.0 || jdat->vect.z!=0.0) { jdat->vect.c = 1.0; } if (jdat->quat.x!=0.0 || jdat->quat.y!=0.0 || jdat->quat.z!=0.0 || jdat->quat.s!=0.0) { jdat->quat.c = 1.0; } } datacnt++; if (datacnt==datanum) break; } } // return ni_joints; } /** void CNiVMDTool::calcJointRotation(void) 全ジョイントのクオータニオンを計算し直す. */ void CNiVMDTool::calcJointRotation(void) { if (framesData==NULL || frames_num<=0) return; if (posVect==NULL) posVect = (Vector*)malloc(sizeof(Vector)*VMD_JOINT_NUM); if (rotQuat==NULL) rotQuat = (Quaternion*)malloc(sizeof(Quaternion)*VMD_JOINT_NUM); if (posVect==NULL || rotQuat==NULL) return; clearVectorData(VMD_JOINT_NUM); NiJointData prevJoint[VMD_JOINT_NUM]; // joints_num = VMD_JOINT_NUM for (int j=0; j=0) { posVect[j] = jdata[j].vect; rotQuat[j] = jdata[j].quat; if (posVect[j].c<0.0) posVect[j] = prevJoint[j].vect; if (rotQuat[j].c<0.0) rotQuat[j] = prevJoint[j].quat; } // else { posVect[j] = prevJoint[j].vect; rotQuat[j] = prevJoint[j].quat; } } /////////////////////////////////////////////// calcJointIK(i); // IK /////////////////////////////////////////////// // for (int j=0; j=0) { prevJoint[j] = jdata[j]; } } // rotQuat[VMD_L_WRIST] = rotQuat[VMD_L_WRIST]*rotQuat[VMD_L_WRIST_TW]; rotQuat[VMD_L_ELBOW] = rotQuat[VMD_L_ELBOW]*rotQuat[VMD_L_ARM_TW]; rotQuat[VMD_R_WRIST] = rotQuat[VMD_R_WRIST]*rotQuat[VMD_R_WRIST_TW]; rotQuat[VMD_R_ELBOW] = rotQuat[VMD_R_ELBOW]*rotQuat[VMD_R_ARM_TW]; rotQuat[VMD_L_EYE] = rotQuat[VMD_L_EYE]*rotQuat[VMD_EYES]; rotQuat[VMD_R_EYE] = rotQuat[VMD_R_EYE]*rotQuat[VMD_EYES]; /////// A -> T rotQuat[VMD_L_WRIST] = A2TPose*rotQuat[VMD_L_WRIST]*~A2TPose; rotQuat[VMD_L_ELBOW] = A2TPose*rotQuat[VMD_L_ELBOW]*~A2TPose; rotQuat[VMD_L_ARM] = rotQuat[VMD_L_ARM]*~A2TPose; rotQuat[VMD_R_WRIST] = ~A2TPose*rotQuat[VMD_R_WRIST]*A2TPose; rotQuat[VMD_R_ELBOW] = ~A2TPose*rotQuat[VMD_R_ELBOW]*A2TPose; rotQuat[VMD_R_ARM] = rotQuat[VMD_R_ARM]*A2TPose; // 足首の回転は省略 rotQuat[VMD_L_ANKLE_IK].set(1.0, 0.0, 0.0, 0.0, 1.0); rotQuat[VMD_R_ANKLE_IK].set(1.0, 0.0, 0.0, 0.0, 1.0); //rotQuat[VMD_CENTER] = rotQuat[VMD_CENTER]*~rotQuat[VMD_PARENT]; //posVect[VMD_CENTER] = posVect[VMD_CENTER] + posVect[VMD_PARENT]; // for (int j=0; j vect_Y(0.0, 1.0, 0.0, 1.0); Vector vect_Z(0.0, 0.0,-1.0, 1.0); Vector cnt_vect_Y = VectorRotation(vect_Y, rotQuat[VMD_CENTER]); Vector cnt_vect_Z = VectorRotation(vect_Z, rotQuat[VMD_CENTER]); // 足の方向 Vector l_leg_vect = VectorRotation(cnt_vect_Z, rotQuat[VMD_L_HIP]); Vector r_leg_vect = VectorRotation(cnt_vect_Z, rotQuat[VMD_R_HIP]); // エフェクタ: センターからの初期相対位置 Vector l_ank_vect = vect_Y*0.10 + vect_Z*0.83; Vector r_ank_vect = -vect_Y*0.10 + vect_Z*0.83; // エフェクタ: 移動後のセンターからの相対位置 Vector l_end_vect = cnt_vect_Y*0.10 + l_leg_vect*0.83; Vector r_end_vect = -cnt_vect_Y*0.10 + r_leg_vect*0.83; // 到達目標 Vector l_ik_vect = l_ank_vect + posVect[VMD_L_ANKLE_IK] - posVect[VMD_CENTER] - l_end_vect; Vector r_ik_vect = r_ank_vect + posVect[VMD_R_ANKLE_IK] - posVect[VMD_CENTER] - r_end_vect; // 到達目標(ローカル座標系) l_ik_vect = VectorRotation(l_ik_vect, ~rotQuat[VMD_CENTER]); r_ik_vect = VectorRotation(r_ik_vect, ~rotQuat[VMD_CENTER]); // Vector l_vect[3], r_vect[3]; Quaternion l_quat[3], r_quat[3]; // 膝,腰の相対位置 l_vect[0].set(0.0, 0.0, 0.0); r_vect[0].set(0.0, 0.0, 0.0); l_vect[1] = -l_leg_vect*0.58; r_vect[1] = -r_leg_vect*0.58; l_vect[2] = -l_leg_vect*1.18; r_vect[2] = -r_leg_vect*1.18; // ローカル座標系 l_vect[1] = VectorRotation(l_vect[1], ~rotQuat[VMD_CENTER]); r_vect[1] = VectorRotation(r_vect[1], ~rotQuat[VMD_CENTER]); l_vect[2] = VectorRotation(l_vect[2], ~rotQuat[VMD_CENTER]); r_vect[2] = VectorRotation(r_vect[2], ~rotQuat[VMD_CENTER]); /////////////////////////////////////////////////////////////////// calcLegIK_CCD(l_vect, l_ik_vect, l_quat, 50); calcLegIK_CCD(r_vect, r_ik_vect, r_quat, 50); /////////////////////////////////////////////////////////////////// // HIP if (rotQuat[VMD_L_HIP].c>0.0) rotQuat[VMD_L_HIP] = l_quat[2]*rotQuat[VMD_L_HIP]; else rotQuat[VMD_L_HIP] = l_quat[2]; if (rotQuat[VMD_R_HIP].c>0.0) rotQuat[VMD_R_HIP] = r_quat[2]*rotQuat[VMD_R_HIP]; else rotQuat[VMD_R_HIP] = r_quat[2]; framesData[fnum].jdat[VMD_L_HIP].joint = VMD_L_HIP; framesData[fnum].jdat[VMD_R_HIP].joint = VMD_R_HIP; framesData[fnum].jdat[VMD_L_HIP].index = fnum; framesData[fnum].jdat[VMD_R_HIP].index = fnum; // KNEE rotQuat[VMD_L_KNEE] = l_quat[1]; rotQuat[VMD_R_KNEE] = r_quat[1]; // double dot = vect_Y*rotQuat[VMD_L_KNEE].getVector(); if (dot>=0.0) { framesData[fnum].jdat[VMD_L_KNEE].joint = VMD_L_KNEE; framesData[fnum].jdat[VMD_L_KNEE].index = fnum; } else { framesData[fnum].jdat[VMD_L_KNEE].joint = -1; framesData[fnum].jdat[VMD_L_KNEE].index = -1; } dot = vect_Y*rotQuat[VMD_R_KNEE].getVector(); if (dot>=0.0) { framesData[fnum].jdat[VMD_R_KNEE].joint = VMD_R_KNEE; framesData[fnum].jdat[VMD_R_KNEE].index = fnum; } else { framesData[fnum].jdat[VMD_R_KNEE].joint = -1; framesData[fnum].jdat[VMD_R_KNEE].index = -1; } return; } /** HIP(2) -> KNEE(1) -> ANKLE(0) の IK をCCDで解く. */ void CNiVMDTool::calcLegIK_CCD(Vector* vect, Vector ik_vect, Quaternion* quat, int rpmax) { Vector vect_Y(0.0, 1.0, 0.0, 1.0); Vector effect, target; Quaternion rot; for (int j=0; j<3; j++) quat[j].init(); for (int i=0; i0.0) { rot.normalize(); if (rot.s<1.00-Zero_Eps) { //if (rot.s<1.00) { quat[j] = quat[j]*rot; for (int k=0; k=0) { unsigned int st_index = 0; unsigned int en_index = 0; while (en_index