void Editor::Right() { if (mode == ROTATE_VIEW) addRot(0, 1.5F, 0); if (mode == MOVE_OBJECT) { if (Object3DS::selected != NULL) Object3DS::selected->transform.position.x += moveStep; } if (mode == ROTATE_OBJECT) { if (Object3DS::selected != NULL) Object3DS::selected->transform.rotation.z += rotStep; } }
void Editor::Backward() { if (mode == ROTATE_VIEW) addRot(-1.5F, 0, 0); if (mode == MOVE_VIEW) addPos(0, 0, 0.8f); if (mode == MOVE_OBJECT) { if (Object3DS::selected != NULL) Object3DS::selected->transform.position.z += moveStep; } if (mode == ROTATE_OBJECT) { if (Object3DS::selected != NULL) Object3DS::selected->transform.rotation.x += rotStep; } }
bool UAnimExporterITP::ExportText(const FExportObjectInnerContext* Context, UObject* Object, const TCHAR* Type, FOutputDevice& Ar, FFeedbackContext* Warn, uint32 PortFlags /*= 0*/) { UAnimSequence* AnimSeq = CastChecked<UAnimSequence>(Object); USkeleton* Skeleton = AnimSeq->GetSkeleton(); const FReferenceSkeleton& RefSkeleton = Skeleton->GetReferenceSkeleton(); USkeletalMesh* SkelMesh = Skeleton->GetPreviewMesh(); if (AnimSeq->SequenceLength == 0.f) { // something is wrong return false; } const float FrameRate = AnimSeq->NumFrames / AnimSeq->SequenceLength; // Open another archive FArchive* File = IFileManager::Get().CreateFileWriter(*UExporter::CurrentFilename); // Let's try the header... File->Logf(TEXT("{")); File->Logf(TEXT("\t\"metadata\":{")); File->Logf(TEXT("\t\t\"type\":\"itpanim\",")); File->Logf(TEXT("\t\t\"version\":2")); File->Logf(TEXT("\t},")); File->Logf(TEXT("\t\"sequence\":{")); File->Logf(TEXT("\t\t\"frames\":%d,"), AnimSeq->NumFrames); File->Logf(TEXT("\t\t\"length\":%f,"), AnimSeq->SequenceLength); File->Logf(TEXT("\t\t\"bonecount\":%d,"), RefSkeleton.GetNum()); File->Logf(TEXT("\t\t\"tracks\":[")); bool firstOutput = false; for (int32 BoneIndex = 0; BoneIndex < RefSkeleton.GetNum(); ++BoneIndex) { //int32 BoneTreeIndex = Skeleton->GetSkeletonBoneIndexFromMeshBoneIndex(SkelMesh, BoneIndex); int32 BoneTrackIndex = Skeleton->GetAnimationTrackIndex(BoneIndex, AnimSeq); if (BoneTrackIndex == INDEX_NONE) { // If this sequence does not have a track for the current bone, then skip it continue; } if (firstOutput) { File->Logf(TEXT("\t\t\t},")); } firstOutput = true; File->Logf(TEXT("\t\t\t{")); File->Logf(TEXT("\t\t\t\t\"bone\":%d,"), BoneIndex); File->Logf(TEXT("\t\t\t\t\"transforms\":[")); float AnimTime = 0.0f; float AnimEndTime = AnimSeq->SequenceLength; // Subtracts 1 because NumFrames includes an initial pose for 0.0 second double TimePerKey = (AnimSeq->SequenceLength / (AnimSeq->NumFrames - 1)); const float AnimTimeIncrement = TimePerKey; bool bLastKey = false; // Step through each frame and add the bone's transformation data while (!bLastKey) { const TArray<FBoneNode>& BoneTree = Skeleton->GetBoneTree(); FTransform BoneAtom; AnimSeq->GetBoneTransform(BoneAtom, BoneTrackIndex, AnimTime, true); bLastKey = AnimTime >= AnimEndTime; File->Logf(TEXT("\t\t\t\t\t{")); FQuat rot = BoneAtom.GetRotation(); // For the root bone, we need to fix-up the rotation because Unreal exports // animations with Y-forward for some reason (maybe because Maya?) if (BoneIndex == 0) { FQuat addRot(FVector(0.0f, 0.0f, 1.0f), -1.57f); rot = addRot * rot; } File->Logf(TEXT("\t\t\t\t\t\t\"rot\":[%f,%f,%f,%f],"), rot.X, rot.Y, rot.Z, rot.W); FVector trans = BoneAtom.GetTranslation(); // Sanjay: If it's skeleton retargeting, change the translation to be from the ref pose skeleton if (BoneTree[BoneIndex].TranslationRetargetingMode == EBoneTranslationRetargetingMode::Skeleton) { const FTransform& BoneTransform = RefSkeleton.GetRefBonePose()[BoneIndex]; trans = BoneTransform.GetTranslation(); } File->Logf(TEXT("\t\t\t\t\t\t\"trans\":[%f,%f,%f]"), trans.X, trans.Y, trans.Z); if (!bLastKey) { File->Logf(TEXT("\t\t\t\t\t},")); } else { File->Logf(TEXT("\t\t\t\t\t}")); } AnimTime += AnimTimeIncrement; } File->Logf(TEXT("\t\t\t\t]"), BoneIndex); } File->Logf(TEXT("\t\t\t}")); File->Logf(TEXT("\t\t]")); File->Logf(TEXT("\t}")); File->Logf(TEXT("}")); delete File; return true; }
/************************************************************************ CMinPack minimzation: *************************************************************************/ void SkeletonFitting::updateCMP(Joint* joint) { // TODO: use same minimization method also with MT_CMINPACK_CCD, just exchange the function if (!joint) { WARN << "joint invalid" << ENDL; // should never happen return; } // TODO: implement simple steepest descent method using the same functions const int i = 0; // if this is the root joint, also update the position if (!joint->getPrevJoint()) { const double tol = 0.000001; const double factor = 0.01; const double eps = 0.00001; const int iterFac = 50; cv::Point3d addPos(0, 0, 0); double addSize = 0; if (i == 0) { minimize(&Payload(joint, 0), funcPos, 1, 1, &addPos.x, tol, iterFac, factor, eps); minimize(&Payload(joint, 1), funcPos, 1, 1, &addPos.y, tol, iterFac, factor, eps); minimize(&Payload(joint, 2), funcPos, 1, 1, &addPos.z, tol, iterFac, factor, eps); if (m_minimizeSize) minimize(&Payload(joint, 2), funcSize, 1, 1, &addSize, tol, iterFac, factor, eps); } else { /*minimizeSteepestDesc(&Payload(joint, 0), funcPos, 1, 1, &addPos.x); minimizeSteepestDesc(&Payload(joint, 1), funcPos, 1, 1, &addPos.y); minimizeSteepestDesc(&Payload(joint, 2), funcPos, 1, 1, &addPos.z); if (m_minimizeSize) minimizeSteepestDesc(&Payload(joint, 2), funcSize, 1, 1, &addSize);*/ } joint->addPos3d(addPos); joint->addBoneSize(addSize); joint->updateForward(false); // changing position doesn't need constraint checking } // update joint angles const double tol = 0.001; const int iterFac = 50; double factor = 100; double eps = 0.001; switch (joint->getClass()) { case JC_BALLANDSOCKET: { // update ball and socket joints JointBallAndSocket* jointBAS = (JointBallAndSocket*)joint; // update angles cv::Point3d addRot(0, 0, 0); if (i == 0) { minimize(&Payload(joint, 0), funcBAS, 1, 1, &addRot.x, tol, iterFac, factor, eps); minimize(&Payload(joint, 1), funcBAS, 1, 1, &addRot.y, tol, iterFac, factor, eps); minimize(&Payload(joint, 2), funcBAS, 1, 1, &addRot.z, tol, iterFac, factor, eps); } else { //minimizeSteepestDesc(&Payload(joint, 0), funcBAS, 1, 1, &addRot.x); //minimizeSteepestDesc(&Payload(joint, 1), funcBAS, 1, 1, &addRot.y); //minimizeSteepestDesc(&Payload(joint, 2), funcBAS, 1, 1, &addRot.z); } jointBAS->addOrientation(addRot); jointBAS->updateForward(true); break; } case JC_HINGE: { // update hinge joints JointHinge* jointHinge = (JointHinge*)joint; // update angles double addAngle = 0; if (i == 0) { minimize(&Payload(joint, 0), funcHinge, 1, 1, &addAngle, tol, iterFac, factor, eps); } else { //minimizeSteepestDesc(&Payload(joint, 0), funcHinge, 1, 1, &addAngle); } jointHinge->addAngle(addAngle); jointHinge->updateForward(true); break; } case JC_ENDCONNECTOR: // no need to update end connector joints, their position is only // affected by their subordinate joints break; case JC_CONNECTOR: // does also not need to be updated break; default: WARN << "unknown joint type: " << (int)joint->getClass() << ENDL; break; } // if this is not the root joint, update the next previous joint if (joint->getPrevJoint()) updateCMP(joint->getPrevJoint()); }