Procházet zdrojové kódy

Animation keyframe reduction

BearishSun před 9 roky
rodič
revize
1b134abf3a

+ 1 - 1
Source/BansheeCore/Source/BsAnimationCurve.cpp

@@ -296,7 +296,7 @@ namespace BansheeEngine
 		}
 		}
 		else
 		else
 		{
 		{
-			// Resize tangents since we're not evaluating the curve over unit range
+			// Scale from arbitrary range to [0, 1]
 			t = (time - leftKey.time) / length;
 			t = (time - leftKey.time) / length;
 			leftTangent = leftKey.outTangent * length;
 			leftTangent = leftKey.outTangent * length;
 			rightTangent = rightKey.inTangent * length;
 			rightTangent = rightKey.inTangent * length;

+ 1 - 0
Source/BansheeFBXImporter/Include/BsFBXImportData.h

@@ -26,6 +26,7 @@ namespace BansheeEngine
 		float importScale = 0.01f;
 		float importScale = 0.01f;
 		float animSampleRate = 1.0f / 60.0f;
 		float animSampleRate = 1.0f / 60.0f;
 		bool animResample = false;
 		bool animResample = false;
+		bool reduceKeyframes = true;
 	};
 	};
 
 
 	/**	Represents a single node in the FBX transform hierarchy. */
 	/**	Represents a single node in the FBX transform hierarchy. */

+ 6 - 0
Source/BansheeFBXImporter/Include/BsFBXImporter.h

@@ -104,6 +104,12 @@ namespace BansheeEngine
 		void convertAnimations(const Vector<FBXAnimationClip>& clips, const Vector<AnimationSplitInfo>& splits, 
 		void convertAnimations(const Vector<FBXAnimationClip>& clips, const Vector<AnimationSplitInfo>& splits, 
 			Vector<FBXAnimationClipData>& output);
 			Vector<FBXAnimationClipData>& output);
 
 
+		/** 
+		 * Removes identical sequential keyframes for the provided set of curves. The keyframe must be identical over all
+		 * the curves in order for it to be removed.
+		 */
+		void reduceKeyframes(FBXAnimationCurve(&curves)[3]);
+
 		/**	Converts a set of curves containing rotation in euler angles into a set of curves using	quaternion rotation. */
 		/**	Converts a set of curves containing rotation in euler angles into a set of curves using	quaternion rotation. */
 		void eulerToQuaternionCurves(FBXAnimationCurve(&eulerCurves)[3], FBXAnimationCurve(&quatCurves)[4]);
 		void eulerToQuaternionCurves(FBXAnimationCurve(&eulerCurves)[3], FBXAnimationCurve(&quatCurves)[4]);
 
 

+ 64 - 16
Source/BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -1540,6 +1540,13 @@ namespace BansheeEngine
 			importCurve(rotation[1], importOptions, tempCurveRotation[1], clip.start, clip.end);
 			importCurve(rotation[1], importOptions, tempCurveRotation[1], clip.start, clip.end);
 			importCurve(rotation[2], importOptions, tempCurveRotation[2], clip.start, clip.end);
 			importCurve(rotation[2], importOptions, tempCurveRotation[2], clip.start, clip.end);
 
 
+			if(importOptions.reduceKeyframes)
+			{
+				reduceKeyframes(boneAnim.translation);
+				reduceKeyframes(boneAnim.scale);
+				reduceKeyframes(tempCurveRotation);
+			}
+
 			eulerToQuaternionCurves(tempCurveRotation, boneAnim.rotation);
 			eulerToQuaternionCurves(tempCurveRotation, boneAnim.rotation);
 		}
 		}
 
 
@@ -1580,6 +1587,63 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
+	void FBXImporter::reduceKeyframes(FBXAnimationCurve(&curves)[3])
+	{
+		UINT32 keyCount = (UINT32)curves[0].keyframes.size();
+
+		assert((keyCount == (UINT32)curves[1].keyframes.size()) &&
+			(keyCount == (UINT32)curves[2].keyframes.size()));
+
+		Vector<FBXKeyFrame> newKeyframes[3];
+
+		bool lastWasEqual = false;
+		for (int i = 0; i < keyCount; i++)
+		{
+			bool isEqual = true;
+
+			if (i > 0)
+			{
+				for (int j = 0; j < 3; j++)
+				{
+					FBXKeyFrame& curKey = curves[j].keyframes[i];
+					FBXKeyFrame& prevKey = newKeyframes[j].back();
+
+					isEqual = Math::approxEquals(prevKey.value, curKey.value) &&
+						Math::approxEquals(prevKey.outTangent, curKey.inTangent) && isEqual;
+				}
+			}
+			else
+				isEqual = false;
+
+			for (int j = 0; j < 3; j++)
+			{
+				FBXKeyFrame& curKey = curves[j].keyframes[i];
+
+				// More than two keys in a row are equal, remove previous key by replacing it with this one
+				if (lastWasEqual && isEqual)
+				{
+					FBXKeyFrame& prevKey = newKeyframes[j].back();
+
+					// Other properties are guaranteed unchanged
+					prevKey.time = curKey.time;
+					prevKey.outTangent = curKey.outTangent;
+
+					continue;
+				}
+
+				newKeyframes[j].push_back(curKey);
+			}
+
+			lastWasEqual = isEqual;
+		}
+
+		for (int j = 0; j < 3; j++)
+		{
+			curves[j].keyframes.clear();
+			std::swap(curves[j].keyframes, newKeyframes[j]);
+		}
+	}
+
 	void FBXImporter::eulerToQuaternionCurves(FBXAnimationCurve(&eulerCurves)[3], FBXAnimationCurve(&quatCurves)[4])
 	void FBXImporter::eulerToQuaternionCurves(FBXAnimationCurve(&eulerCurves)[3], FBXAnimationCurve(&quatCurves)[4])
 	{
 	{
 		const float FIT_TIME = 0.33f;
 		const float FIT_TIME = 0.33f;
@@ -1784,22 +1848,6 @@ namespace BansheeEngine
 				keyFrame.value = fbxCurve->KeyGetValue(i);
 				keyFrame.value = fbxCurve->KeyGetValue(i);
 				keyFrame.inTangent = fbxCurve->KeyGetLeftDerivative(i);
 				keyFrame.inTangent = fbxCurve->KeyGetLeftDerivative(i);
 				keyFrame.outTangent = fbxCurve->KeyGetRightDerivative(i);
 				keyFrame.outTangent = fbxCurve->KeyGetRightDerivative(i);
-
-				// DEBUG VALUES
-				float leftAuto = fbxCurve->KeyGetLeftAuto(i);
-				float rightAuto = fbxCurve->KeyGetRightAuto(i);
-
-				float leftWeight = fbxCurve->KeyGetLeftTangentWeight(i);
-				float rightWeight = fbxCurve->KeyGetRightTangentWeight(i);
-
-				FbxAnimCurveTangentInfo leftInfo = fbxCurve->KeyGetLeftDerivativeInfo(i);
-				FbxAnimCurveTangentInfo rightInfo = fbxCurve->KeyGetRightDerivativeInfo(i);
-
-				FbxAnimCurveDef::EInterpolationType interpMode = fbxCurve->KeyGetInterpolation(i);
-				FbxAnimCurveDef::ETangentMode tangentMode = fbxCurve->KeyGetTangentMode(i);
-				//float tangent = Math::cubicHermiteD1(keyFrame.time)
-
-				int a = 5;
 			}
 			}
 		}
 		}
 	}
 	}