Skip to content

Commit 84fd116

Browse files
committed
+ Update v2.1: add "optimize bone frames" feature
1 parent bb8ccbc commit 84fd116

File tree

4 files changed

+243
-117
lines changed

4 files changed

+243
-117
lines changed

source/W3MayaAnimUtil.cpp

Lines changed: 147 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,12 @@ void W3MayaAnimUtil::applyEdits() {
243243
hasChanges = true;
244244
}
245245
if (ui->checkEditAddRootMotion->isChecked()) {
246-
246+
QJsonObject animBuff = animObj.value("animBuffer").toObject();
247+
QJsonArray animBones = animBuff.value("bones").toArray();
248+
editAddEmptyBoneFrames(animBones, "RootMotion");
249+
animBuff["bones"] = animBones;
250+
animObj["animBuffer"] = animBuff;
251+
hasChanges = true;
247252
}
248253
if (ui->groupEditBake->isChecked()) {
249254
editBakeBones(animObj, ui->checkEditBakePos->isChecked(), ui->checkEditBakeRot->isChecked(), ui->checkEditBakeScale->isChecked());
@@ -258,6 +263,11 @@ void W3MayaAnimUtil::applyEdits() {
258263
hasChanges = true;
259264
}
260265

266+
if (ui->groupEditOptimize->isChecked()) {
267+
int boneOptimized = editOptimizeBones(animObj, ui->checkEditOptimizePos->isChecked(), ui->checkEditOptimizeRot->isChecked(), ui->checkEditOptimizeScale->isChecked());
268+
hasChanges = hasChanges || (boneOptimized > 0);
269+
}
270+
261271
if (ui->checkEditSortEvents->isChecked()) {
262272
editSortEvents(eventsArray);
263273
hasChanges = true;
@@ -397,7 +407,7 @@ void W3MayaAnimUtil::editCropAnim(QJsonObject& animObj, QJsonArray& eventsArray,
397407
.arg( framesToSec(durationFrames - 1) ));
398408
}
399409

400-
void W3MayaAnimUtil::editAddEmptyBone(QJsonArray& bonesArr, QString boneName) {
410+
void W3MayaAnimUtil::editAddEmptyBoneFrames(QJsonArray& bonesArr, QString boneName, int numFrames) {
401411
int last_index = 0;
402412
if (!bonesArr.isEmpty()) {
403413
last_index = bonesArr.last().toObject().value("index").toInt();
@@ -411,14 +421,16 @@ void W3MayaAnimUtil::editAddEmptyBone(QJsonArray& bonesArr, QString boneName) {
411421
double dt = 0.033333333;
412422
QString attrNames[3] = { "position", "rotation", "scale" };
413423
upn(j, 0, 2) {
414-
newBoneObj.insert(QString("%1_numFrames").arg(attrNames[j]), 1);
424+
newBoneObj.insert(QString("%1_numFrames").arg(attrNames[j]), numFrames);
415425
QJsonArray attrArray = QJsonArray();
416-
if (attrNames[j] == "rotation")
417-
attrArray.append(objXYZW(0,0,0,1));
418-
else if (attrNames[j] == "position")
419-
attrArray.append(objXYZ(0,0,0));
420-
else
421-
attrArray.append(objXYZ(1,1,1));
426+
upn(jj, 1, numFrames) {
427+
if (attrNames[j] == "rotation")
428+
attrArray.append(objXYZW(0,0,0,1));
429+
else if (attrNames[j] == "position")
430+
attrArray.append(objXYZ(0,0,0));
431+
else
432+
attrArray.append(objXYZ(1,1,1));
433+
}
422434
newBoneObj.insert(QString("%1Frames").arg(attrNames[j]), attrArray);
423435
newBoneObj.insert(QString("%1_dt").arg(attrNames[j]), dt);
424436
}
@@ -471,6 +483,94 @@ void W3MayaAnimUtil::editBakeBones(QJsonObject& animObj, bool bakePos, bool bake
471483
animBuff["bones"] = animBones;
472484
animObj["animBuffer"] = animBuff;
473485
}
486+
487+
bool W3MayaAnimUtil::editOptimizeBone(QJsonObject& boneObj, bool optimizePos, bool optimizeRot, bool optimizeScale) {
488+
int posNum = boneObj["position_numFrames"].toInt();
489+
int rotNum = boneObj["rotation_numFrames"].toInt();
490+
int scaleNum = boneObj["scale_numFrames"].toInt();
491+
492+
optimizePos = posNum > 1;
493+
optimizeRot = rotNum > 1;
494+
optimizeScale = scaleNum > 1;
495+
QJsonArray posArray = boneObj["positionFrames"].toArray();
496+
QJsonArray rotArray = boneObj["rotationFrames"].toArray();
497+
QJsonArray scaleArray = boneObj["scaleFrames"].toArray();
498+
499+
upn(frame, 1, posNum - 1) {
500+
double diffX = posArray[frame].toObject().value("x").toDouble() - posArray[frame - 1].toObject().value("x").toDouble();
501+
double diffY = posArray[frame].toObject().value("y").toDouble() - posArray[frame - 1].toObject().value("y").toDouble();
502+
double diffZ = posArray[frame].toObject().value("z").toDouble() - posArray[frame - 1].toObject().value("z").toDouble();
503+
double diffTotal = qAbs(diffX) + qAbs(diffY) + qAbs(diffZ);
504+
if (diffTotal > mReductionSensitivity()) {
505+
optimizePos = false;
506+
break;
507+
}
508+
}
509+
upn(frame, 1, rotNum - 1) {
510+
double diffX = rotArray[frame].toObject().value("X").toDouble() - rotArray[frame - 1].toObject().value("X").toDouble();
511+
double diffY = rotArray[frame].toObject().value("Y").toDouble() - rotArray[frame - 1].toObject().value("Y").toDouble();
512+
double diffZ = rotArray[frame].toObject().value("Z").toDouble() - rotArray[frame - 1].toObject().value("Z").toDouble();
513+
double diffW = rotArray[frame].toObject().value("W").toDouble() - rotArray[frame - 1].toObject().value("W").toDouble();
514+
double diffTotal = qAbs(diffX) + qAbs(diffY) + qAbs(diffZ) + qAbs(diffW);
515+
if (diffTotal > mReductionSensitivity()) {
516+
optimizeRot = false;
517+
break;
518+
}
519+
}
520+
upn(frame, 1, scaleNum - 1) {
521+
double diffX = scaleArray[frame].toObject().value("x").toDouble() - scaleArray[frame - 1].toObject().value("x").toDouble();
522+
double diffY = scaleArray[frame].toObject().value("y").toDouble() - scaleArray[frame - 1].toObject().value("y").toDouble();
523+
double diffZ = scaleArray[frame].toObject().value("z").toDouble() - scaleArray[frame - 1].toObject().value("z").toDouble();
524+
double diffTotal = qAbs(diffX) + qAbs(diffY) + qAbs(diffZ);
525+
if (diffTotal > mReductionSensitivity()) {
526+
optimizeScale = false;
527+
break;
528+
}
529+
}
530+
if (optimizePos) {
531+
QJsonArray newPosArray;
532+
newPosArray.append( posArray.first() );
533+
boneObj["positionFrames"] = newPosArray;
534+
boneObj["position_numFrames"] = 1;
535+
}
536+
if (optimizeRot) {
537+
QJsonArray newRotArray;
538+
newRotArray.append( rotArray.first() );
539+
boneObj["rotationFrames"] = newRotArray;
540+
boneObj["rotation_numFrames"] = 1;
541+
}
542+
if (optimizeScale) {
543+
QJsonArray newScaleArray;
544+
newScaleArray.append( scaleArray.first() );
545+
boneObj["scaleFrames"] = newScaleArray;
546+
boneObj["scale_numFrames"] = 1;
547+
}
548+
return (optimizePos || optimizeRot || optimizeScale);
549+
}
550+
551+
int W3MayaAnimUtil::editOptimizeBones(QJsonObject& animObj, bool optimizePos, bool optimizeRot, bool optimizeScale) {
552+
QJsonObject bufferObj = animObj["animBuffer"].toObject();
553+
QJsonArray bonesArray = bufferObj["bones"].toArray();
554+
int optimized = 0;
555+
int numBones = bonesArray.count();
556+
557+
upn(i, 0, numBones - 1) {
558+
QJsonObject boneObj = bonesArray.at(i).toObject();
559+
bool boneOptimized = editOptimizeBone(boneObj, optimizePos, optimizeRot, optimizeScale);
560+
if (boneOptimized) {
561+
optimized += 1;
562+
bonesArray[i] = boneObj;
563+
}
564+
}
565+
566+
if (optimized > 0) {
567+
bufferObj["bones"] = bonesArray;
568+
animObj["animBuffer"] = bufferObj;
569+
}
570+
addLog(QString("\t[EDIT] Optimized %1 bones of %2.").arg(optimized).arg(numBones));
571+
return optimized;
572+
}
573+
474574
void W3MayaAnimUtil::onChecked_EditCut(bool checked) {
475575
if (checked) {
476576
if (!ui->groupEditBake->isChecked())
@@ -483,6 +583,13 @@ void W3MayaAnimUtil::onChecked_EditCut(bool checked) {
483583
ui->groupEditBake->setEnabled(true);
484584
}
485585
}
586+
void W3MayaAnimUtil::onClicked_EditGroupOptimize(bool checked) {
587+
if (checked) {
588+
ui->checkEditOptimizePos->setChecked(true);
589+
ui->checkEditOptimizeRot->setChecked(true);
590+
ui->checkEditOptimizeScale->setChecked(true);
591+
}
592+
}
486593
void W3MayaAnimUtil::onClicked_EditApply() {
487594
applyEdits();
488595
}
@@ -1320,6 +1427,11 @@ bool W3MayaAnimUtil::extractMotionFromBone(QJsonValueRef ref) {
13201427
m_animNames.push_back(animName);
13211428
m_animDurations.push_back(animDuration);
13221429

1430+
int bonesOptimized = 0;
1431+
if ( ui->checkOptimizeEqual->isChecked() ) {
1432+
bonesOptimized = editOptimizeBones(animObj, true, true, true);
1433+
}
1434+
13231435
QJsonObject bufferObj = animObj["animBuffer"].toObject();
13241436
QJsonArray bonesArray = bufferObj["bones"].toArray();
13251437
if ( bonesArray.isEmpty() ) {
@@ -1330,133 +1442,66 @@ bool W3MayaAnimUtil::extractMotionFromBone(QJsonValueRef ref) {
13301442
int animFrames = bufferObj["numFrames"].toInt();
13311443
int mBoneIdx = -1;
13321444
QStringList brokenBones;
1333-
int bonesOptimized = 0;
1334-
int bonesBaked = 0;
1445+
13351446

13361447
upn(i, 0, bonesArray.size() - 1) {
1337-
QJsonObject tempObj = bonesArray[i].toObject();
1338-
QString boneName = tempObj.value("BoneName").toString();
1448+
QJsonObject boneObj = bonesArray[i].toObject();
1449+
QString boneName = boneObj.value("BoneName").toString();
13391450

13401451
if (boneName == mBoneName) {
13411452
mBoneIdx = i;
13421453
}
1343-
int posNum = tempObj["position_numFrames"].toInt();
1344-
int rotNum = tempObj["rotation_numFrames"].toInt();
1345-
int scaleNum = tempObj["scale_numFrames"].toInt();
1346-
1347-
if ( ui->checkOptimizeEqual->isChecked() ) {
1348-
bool optimizeTranslation = posNum > 1;
1349-
bool optimizeRotation = rotNum > 1;
1350-
bool optimizeScale = scaleNum > 1;
1351-
QJsonArray posArray = tempObj["positionFrames"].toArray();
1352-
QJsonArray rotArray = tempObj["rotationFrames"].toArray();
1353-
QJsonArray scaleArray = tempObj["scaleFrames"].toArray();
1354-
1355-
upn(frame, 1, posNum - 1) {
1356-
double diffX = posArray[frame].toObject().value("x").toDouble() - posArray[frame - 1].toObject().value("x").toDouble();
1357-
double diffY = posArray[frame].toObject().value("y").toDouble() - posArray[frame - 1].toObject().value("y").toDouble();
1358-
double diffZ = posArray[frame].toObject().value("z").toDouble() - posArray[frame - 1].toObject().value("z").toDouble();
1359-
double diffTotal = qAbs(diffX) + qAbs(diffY) + qAbs(diffZ);
1360-
if (diffTotal > mReductionSensitivity()) {
1361-
optimizeTranslation = false;
1362-
break;
1363-
}
1364-
}
1365-
upn(frame, 1, rotNum - 1) {
1366-
double diffX = rotArray[frame].toObject().value("X").toDouble() - rotArray[frame - 1].toObject().value("X").toDouble();
1367-
double diffY = rotArray[frame].toObject().value("Y").toDouble() - rotArray[frame - 1].toObject().value("Y").toDouble();
1368-
double diffZ = rotArray[frame].toObject().value("Z").toDouble() - rotArray[frame - 1].toObject().value("Z").toDouble();
1369-
double diffW = rotArray[frame].toObject().value("W").toDouble() - rotArray[frame - 1].toObject().value("W").toDouble();
1370-
double diffTotal = qAbs(diffX) + qAbs(diffY) + qAbs(diffZ) + qAbs(diffW);
1371-
if (diffTotal > mReductionSensitivity()) {
1372-
optimizeRotation = false;
1373-
break;
1374-
}
1375-
}
1376-
upn(frame, 1, scaleNum - 1) {
1377-
double diffX = scaleArray[frame].toObject().value("x").toDouble() - scaleArray[frame - 1].toObject().value("x").toDouble();
1378-
double diffY = scaleArray[frame].toObject().value("y").toDouble() - scaleArray[frame - 1].toObject().value("y").toDouble();
1379-
double diffZ = scaleArray[frame].toObject().value("z").toDouble() - scaleArray[frame - 1].toObject().value("z").toDouble();
1380-
double diffTotal = qAbs(diffX) + qAbs(diffY) + qAbs(diffZ);
1381-
if (diffTotal > mReductionSensitivity()) {
1382-
optimizeScale = false;
1383-
break;
1384-
}
1385-
}
1386-
if (optimizeTranslation) {
1387-
QJsonArray nposArray;
1388-
nposArray.append( posArray.first() );
1389-
tempObj["positionFrames"] = nposArray;
1390-
tempObj["position_numFrames"] = 1;
1391-
posNum = 1;
1392-
}
1393-
if (optimizeRotation) {
1394-
QJsonArray nrotArray;
1395-
nrotArray.append( rotArray.first() );
1396-
tempObj["rotationFrames"] = nrotArray;
1397-
tempObj["rotation_numFrames"] = 1;
1398-
rotNum = 1;
1399-
}
1400-
if (optimizeScale) {
1401-
QJsonArray nscaleArray;
1402-
nscaleArray.append( scaleArray.first() );
1403-
tempObj["scaleFrames"] = nscaleArray;
1404-
tempObj["scale_numFrames"] = 1;
1405-
scaleNum = 1;
1406-
}
1407-
if (optimizeTranslation || optimizeRotation || optimizeScale) {
1408-
bonesArray[i] = tempObj;
1409-
bonesOptimized += 1;
1410-
}
1411-
}
1454+
/*int posNum = boneObj["position_numFrames"].toInt();
1455+
int rotNum = boneObj["rotation_numFrames"].toInt();
1456+
int scaleNum = boneObj["scale_numFrames"].toInt();
14121457
14131458
QString error;
14141459
if (posNum != animFrames && posNum != 1) {
14151460
if (ui->checkAutoBakeIncomplete->isChecked()) {
1416-
QJsonArray posArray = tempObj["positionFrames"].toArray();
1461+
QJsonArray posArray = boneObj["positionFrames"].toArray();
14171462
while (posArray.count() != animFrames) {
14181463
posArray.append( posArray.last() );
14191464
}
1420-
tempObj["positionFrames"] = posArray;
1421-
tempObj["position_numFrames"] = animFrames;
1465+
boneObj["positionFrames"] = posArray;
1466+
boneObj["position_numFrames"] = animFrames;
14221467
}
14231468
error += QString(" [translation = %1];").arg(posNum);
14241469
}
14251470
14261471
if (rotNum != animFrames && rotNum != 1) {
14271472
if (ui->checkAutoBakeIncomplete->isChecked()) {
1428-
QJsonArray rotArray = tempObj["rotationFrames"].toArray();
1473+
QJsonArray rotArray = boneObj["rotationFrames"].toArray();
14291474
while (rotArray.count() != animFrames) {
14301475
rotArray.append( rotArray.last() );
14311476
}
1432-
tempObj["rotationFrames"] = rotArray;
1433-
tempObj["rotation_numFrames"] = animFrames;
1477+
boneObj["rotationFrames"] = rotArray;
1478+
boneObj["rotation_numFrames"] = animFrames;
14341479
}
14351480
error += QString(" [rotation = %1];").arg(rotNum);
14361481
}
14371482
14381483
if (scaleNum != animFrames && scaleNum != 1) {
14391484
if (ui->checkAutoBakeIncomplete->isChecked()) {
1440-
QJsonArray scaleArray = tempObj["scaleFrames"].toArray();
1485+
QJsonArray scaleArray = boneObj["scaleFrames"].toArray();
14411486
while (scaleArray.count() != animFrames) {
14421487
scaleArray.append( scaleArray.last() );
14431488
}
1444-
tempObj["scaleFrames"] = scaleArray;
1445-
tempObj["scale_numFrames"] = animFrames;
1489+
boneObj["scaleFrames"] = scaleArray;
1490+
boneObj["scale_numFrames"] = animFrames;
14461491
}
14471492
error += QString(" [scale = %1];").arg(scaleNum);
14481493
}
14491494
14501495
if (!error.isEmpty()) {
14511496
if (ui->checkAutoBakeIncomplete->isChecked()) {
1452-
bonesArray[i] = tempObj;
1497+
bonesArray[i] = boneObj;
14531498
++bonesBaked;
14541499
}
14551500
if (boneName.endsWith("_roll") || boneName.startsWith("IK_"))
14561501
brokenBones.append( boneName + ":" + error );
14571502
else
14581503
brokenBones.append( "!!! " + boneName + ":" + error );
1459-
}
1504+
}*/
14601505
}
14611506

14621507
bool isAdditive = isAdditiveAnim(animObj);
@@ -1515,7 +1560,7 @@ bool W3MayaAnimUtil::extractMotionFromBone(QJsonValueRef ref) {
15151560
QMessageBox::information(this, "Warning!", QString("Detected bones with incorrect numFrames in anim [%1] (numFrames = %2)\nIt may break the game!\nBones: %3").arg(animName).arg(animFrames).arg(brokenBones.join("\n")));
15161561
}
15171562
if (mBoneIdx == -1) {
1518-
if (bonesOptimized || bonesBaked) {
1563+
if (bonesOptimized) {
15191564
bufferObj["bones"] = bonesArray;
15201565
animObj["animBuffer"] = bufferObj;
15211566
}
@@ -2521,11 +2566,11 @@ void W3MayaAnimUtil::onClicked_MergeProcess() {
25212566
boneByNameF[boneNameF] = animBonesF[i].toObject();
25222567
}
25232568
if (!boneByNameF.contains("RootMotion")) {
2524-
editAddEmptyBone(animBonesF, "RootMotion");
2569+
editAddEmptyBoneFrames(animBonesF, "RootMotion", framesF);
25252570
boneByNameF["RootMotion"] = animBonesF.last().toObject();
25262571
}
25272572
if (!boneByNameS.contains("RootMotion")) {
2528-
editAddEmptyBone(animBonesS, "RootMotion");
2573+
editAddEmptyBoneFrames(animBonesS, "RootMotion", framesS);
25292574
boneByNameS["RootMotion"] = animBonesS.last().toObject();
25302575
}
25312576

@@ -2540,8 +2585,6 @@ void W3MayaAnimUtil::onClicked_MergeProcess() {
25402585
// for every bone
25412586
for (int j = 0; j < animBonesF.count(); j += 1) {
25422587
QString boneNameF = animBonesF[j].toObject().value("BoneName").toString();
2543-
if ( !isBlend && boneNameF == "RootMotion" )
2544-
continue;
25452588

25462589
QJsonObject boneF = animBonesF[j].toObject();
25472590
QJsonObject boneS = boneByNameS[boneNameF];
@@ -2651,7 +2694,7 @@ void W3MayaAnimUtil::onClicked_MergeProcess() {
26512694
rotArrF[frame - 1] = objXYZW(sumQ.x(), sumQ.y(), sumQ.z(), sumQ.scalar());
26522695
}
26532696
if (ui->checkMergeCropToSecond->isChecked()) {
2654-
addLog(QString("\t[MERGE] Cropping anim from %1 to %2 frames.").arg(posArrF.count()).arg(framesS));
2697+
addLog(QString("\t[MERGE] Cropping bone %1 from %2 to %3 frames.").arg(boneNameF).arg(posArrF.count()).arg(framesS));
26552698
while (posArrF.count() > framesS) {
26562699
posArrF.pop_back();
26572700
}
@@ -2751,6 +2794,11 @@ void W3MayaAnimUtil::onClicked_MergeProcess() {
27512794
animObjF["duration"] = framesToSec(framesTotal - 1);
27522795
animObjF["animBuffer"] = animBuffF;
27532796

2797+
/* optimize */
2798+
if (ui->checkMergeOptimize->isChecked()) {
2799+
editOptimizeBones(animObjF, true, true, true);
2800+
}
2801+
27542802
QJsonObject mergedJsonRoot = QJsonObject();
27552803
mergedJsonRoot.insert("animation", animObjF);
27562804
mergedJsonRoot.insert("entries", eventsArrayF);

0 commit comments

Comments
 (0)