bool slopkeepTest(FbxAnimCurve* curve, FbxAnimCurveKey prevkey, FbxAnimCurveKey currkey, FbxAnimCurveKey nextkey) { FbxTime prevt = prevkey.GetTime(); FbxTime currt = currkey.GetTime(); FbxTime nextt = nextkey.GetTime(); float slope1 = (currkey.GetValue() - prevkey.GetValue()) / (currt.GetSecondDouble() - prevt.GetSecondDouble()); float slope2 = (nextkey.GetValue() - currkey.GetValue()) / (nextt.GetSecondDouble() - currt.GetSecondDouble()); output2 << setw(20) << "slope : " << setw(10) << setprecision(3) << slope1 << "," << setw(10) << slope2; if (abs(slope1 - slope2) > 0.005) { output2 << " keepinSlope" << endl; return true; } output2 << endl; float deriv1, deriv2, deriv3, deriv4; deriv1 = prevkey.GetDataFloat(FbxAnimCurveDef::EDataIndex::eRightSlope); deriv2 = prevkey.GetDataFloat(FbxAnimCurveDef::EDataIndex::eNextLeftSlope); deriv3 = currkey.GetDataFloat(FbxAnimCurveDef::EDataIndex::eRightSlope); deriv4 = currkey.GetDataFloat(FbxAnimCurveDef::EDataIndex::eNextLeftSlope); FbxTime mili; mili.SetMilliSeconds(1); output3 << "deriv1 : " << deriv1 << ", val : " << prevkey.GetValue() << ", +1mili value : " << curve->EvaluateRightDerivative(prevt + mili) << endl; float derivl11, derivl12, derivl21, derivl22; float derivr11, derivr12, derivr21, derivr22; FbxTime term1, term2; term1.SetSecondDouble((currt.GetSecondDouble() - prevt.GetSecondDouble()) / 3); term2.SetSecondDouble((nextt.GetSecondDouble() - currt.GetSecondDouble()) / 3); derivl11 = curve->EvaluateLeftDerivative(prevt + term1); derivl12 = curve->EvaluateLeftDerivative(prevt + term1 + term1); derivl21 = curve->EvaluateLeftDerivative(currt + term2); derivl22 = curve->EvaluateLeftDerivative(currt + term2 + term2); derivr11 = curve->EvaluateRightDerivative(prevt + term1); derivr12 = curve->EvaluateRightDerivative(prevt + term1 + term1); derivr21 = curve->EvaluateRightDerivative(currt + term2); derivr22 = curve->EvaluateRightDerivative(currt + term2 + term2); output2 << setw(20) << "deriv : " << setprecision(3) << deriv1 <<"," << deriv2 <<"," << deriv3 <<"," << deriv4 <<"," << derivl11<<"," << derivl12<<"," << derivl21<<"," << derivl22<<"," << derivr11<<"," << derivr12<<"," << derivr21<<"," << derivr22<<"," ; if ( prevkey.GetInterpolation() == FbxAnimCurveDef::eInterpolationConstant && currkey.GetInterpolation() == FbxAnimCurveDef::eInterpolationConstant && nextkey.GetInterpolation() == FbxAnimCurveDef::eInterpolationConstant ) { if ( abs(prevkey.GetValue() - currkey.GetValue()) < comp_level_horizon && abs(currkey.GetValue() - nextkey.GetValue()) < comp_level_horizon ) return false; } else if ( prevkey.GetInterpolation() == FbxAnimCurveDef::eInterpolationCubic && currkey.GetInterpolation() == FbxAnimCurveDef::eInterpolationCubic && nextkey.GetInterpolation() == FbxAnimCurveDef::eInterpolationCubic ) { if ( abs(deriv1 - deriv2) < comp_level_deriv && abs(deriv2 - deriv3) < comp_level_deriv && abs(deriv3 - deriv4) < comp_level_deriv ) { float nearCurr = (deriv1*(currt.GetMilliSeconds() - prevt.GetMilliSeconds())) + prevkey.GetValue(); float nearNext = (deriv3*(nextt.GetMilliSeconds() - currt.GetMilliSeconds())) + currkey.GetValue(); if ( abs(nearCurr - currkey.GetValue()) < comp_level_integError && abs(nearNext - nextkey.GetValue()) < comp_level_integError ) return false; } } return true; /* if ( abs(deriv1 - deriv2) < 0.005 && abs(deriv2 - deriv3) < 0.005 && abs(deriv3 - deriv4) < 0.005 && abs(deriv4 - derivl11) < 0.005 && abs(derivl11 - derivr11) < 0.005 && abs(derivr11 - derivl12) < 0.005 && abs(derivl12 - derivr12) < 0.005 && abs(derivr12 - derivl21) < 0.005 && abs(derivl21 - derivr21) < 0.005 && abs(derivr21 - derivl22) < 0.005 && abs(derivl22 - derivr22) < 0.005 ) { } else { output2 << "keepinDeriv" << endl; return true; } output2 << "removable key" << endl; */ return false; }
bool UnFbx::FFbxImporter::ImportCurve(const FbxAnimCurve* FbxCurve, FFloatCurve * Curve, const FbxTimeSpan &AnimTimeSpan, const float ValueScale/*=1.f*/) const { static float DefaultCurveWeight = FbxAnimCurveDef::sDEFAULT_WEIGHT; if ( FbxCurve && Curve ) { for ( int32 KeyIndex=0; KeyIndex<FbxCurve->KeyGetCount(); ++KeyIndex ) { FbxAnimCurveKey Key = FbxCurve->KeyGet(KeyIndex); FbxTime KeyTime = Key.GetTime() - AnimTimeSpan.GetStart(); float Value = Key.GetValue() * ValueScale; FKeyHandle NewKeyHandle = Curve->FloatCurve.AddKey(KeyTime.GetSecondDouble(), Value, true); FbxAnimCurveDef::ETangentMode KeyTangentMode = Key.GetTangentMode(); FbxAnimCurveDef::EInterpolationType KeyInterpMode = Key.GetInterpolation(); FbxAnimCurveDef::EWeightedMode KeyTangentWeightMode = Key.GetTangentWeightMode(); ERichCurveInterpMode NewInterpMode = RCIM_Linear; ERichCurveTangentMode NewTangentMode = RCTM_Auto; ERichCurveTangentWeightMode NewTangentWeightMode = RCTWM_WeightedNone; float LeaveTangent = 0.f; float ArriveTangent = 0.f; float LeaveTangentWeight = 0.f; float ArriveTangentWeight = 0.f; switch (KeyInterpMode) { case FbxAnimCurveDef::eInterpolationConstant://! Constant value until next key. NewInterpMode = RCIM_Constant; break; case FbxAnimCurveDef::eInterpolationLinear://! Linear progression to next key. NewInterpMode = RCIM_Linear; break; case FbxAnimCurveDef::eInterpolationCubic://! Cubic progression to next key. NewInterpMode = RCIM_Cubic; // get tangents { LeaveTangent = Key.GetDataFloat(FbxAnimCurveDef::eRightSlope); if ( KeyIndex > 0 ) { FbxAnimCurveKey PrevKey = FbxCurve->KeyGet(KeyIndex-1); ArriveTangent = PrevKey.GetDataFloat(FbxAnimCurveDef::eNextLeftSlope); } else { ArriveTangent = 0.f; } } break; } // when we import tangent, we only support break or user // since it's modified by DCC and we only assume these two are valid // auto does our own stuff, which doesn't work with what you see in DCC if (KeyTangentMode & FbxAnimCurveDef::eTangentBreak) { NewTangentMode = RCTM_Break; } else { NewTangentMode = RCTM_User; } // @fix me : weight of tangent is not used, but we'll just save this for future where we might use it. switch (KeyTangentWeightMode) { case FbxAnimCurveDef::eWeightedNone://! Tangent has default weights of 0.333; we define this state as not weighted. LeaveTangentWeight = ArriveTangentWeight = DefaultCurveWeight; NewTangentWeightMode = RCTWM_WeightedNone; break; case FbxAnimCurveDef::eWeightedRight: //! Right tangent is weighted. NewTangentWeightMode = RCTWM_WeightedLeave; LeaveTangentWeight = Key.GetDataFloat(FbxAnimCurveDef::eRightWeight); ArriveTangentWeight = DefaultCurveWeight; break; case FbxAnimCurveDef::eWeightedNextLeft://! Left tangent is weighted. NewTangentWeightMode = RCTWM_WeightedArrive; LeaveTangentWeight = DefaultCurveWeight; if ( KeyIndex > 0 ) { FbxAnimCurveKey PrevKey = FbxCurve->KeyGet(KeyIndex-1); ArriveTangentWeight = PrevKey.GetDataFloat(FbxAnimCurveDef::eNextLeftWeight); } else { ArriveTangentWeight = 0.f; } break; case FbxAnimCurveDef::eWeightedAll://! Both left and right tangents are weighted. NewTangentWeightMode = RCTWM_WeightedBoth; LeaveTangentWeight = Key.GetDataFloat(FbxAnimCurveDef::eRightWeight); if ( KeyIndex > 0 ) { FbxAnimCurveKey PrevKey = FbxCurve->KeyGet(KeyIndex-1); ArriveTangentWeight = PrevKey.GetDataFloat(FbxAnimCurveDef::eNextLeftWeight); } else { ArriveTangentWeight = 0.f; } break; } Curve->FloatCurve.SetKeyInterpMode(NewKeyHandle, NewInterpMode); Curve->FloatCurve.SetKeyTangentMode(NewKeyHandle, NewTangentMode); Curve->FloatCurve.SetKeyTangentWeightMode(NewKeyHandle, NewTangentWeightMode); FRichCurveKey& NewKey = Curve->FloatCurve.GetKey(NewKeyHandle); // apply 1/100 - that seems like the tangent unit difference with FBX NewKey.ArriveTangent = ArriveTangent * 0.01f; NewKey.LeaveTangent = LeaveTangent * 0.01f; NewKey.ArriveTangentWeight = ArriveTangentWeight; NewKey.LeaveTangentWeight = LeaveTangentWeight; } return true; } return false; }