summaryrefslogtreecommitdiff
path: root/Runtime/Animation/AnimatorGenericBindings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Animation/AnimatorGenericBindings.cpp')
-rw-r--r--Runtime/Animation/AnimatorGenericBindings.cpp1100
1 files changed, 1100 insertions, 0 deletions
diff --git a/Runtime/Animation/AnimatorGenericBindings.cpp b/Runtime/Animation/AnimatorGenericBindings.cpp
new file mode 100644
index 0000000..78d884f
--- /dev/null
+++ b/Runtime/Animation/AnimatorGenericBindings.cpp
@@ -0,0 +1,1100 @@
+#include "UnityPrefix.h"
+#include "AnimatorGenericBindings.h"
+#include "AnimationClipBindings.h"
+#include "AnimationSetBinding.h"
+#include "Runtime/mecanim/generic/crc32.h"
+#include "Runtime/mecanim/skeleton/skeleton.h"
+#include "Runtime/Animation/MecanimUtility.h"
+#include "Runtime/Animation/AnimationUtility.h"
+#include "Runtime/Filters/Deformation/SkinnedMeshFilter.h"
+#include "Runtime/Filters/Mesh/LodMesh.h"
+#include "GenericAnimationBindingCache.h"
+#include "Runtime/Misc/BuildSettings.h"
+#include "Runtime/BaseClasses/EventIDs.h"
+
+namespace UnityEngine { namespace Animation
+{
+ static void InitializeDefaultValues (const UnityEngine::Animation::AnimatorGenericBindingConstant& genericBinding, const mecanim::animation::AvatarConstant* avatar, bool hasTransformHierarchy, mecanim::animation::ControllerBindingConstant& controllerBindingConstant);
+
+ struct BoundTransform
+ {
+ BindingHash pathHash;
+
+ Transform* transform;
+ int bindIndexForSkeleton;
+ };
+
+ #define IS_DEPRECATED_NAME_BASED_BINDING (!IS_CONTENT_NEWER_OR_SAME(kUnityVersion4_3_a1))
+
+ mecanim::int32_t SkeletonFindNodeIndexByNameID(const mecanim::animation::AvatarConstant* avatar, mecanim::uint32_t aNameID)
+ {
+ mecanim::int32_t ret = -1;
+
+ mecanim::int32_t i;
+ for(i = 0; ret == -1 && i < avatar->m_SkeletonNameIDCount; i++)
+ {
+ if(avatar->m_SkeletonNameIDArray[i] == aNameID)
+ {
+ ret = i;
+ }
+ }
+
+ return ret;
+ }
+
+
+
+ void GenerateTransformBindingMapRecursive (Transform& transform, const mecanim::crc32& nameHash, dynamic_array<BoundTransform>& bindings, const mecanim::animation::AvatarConstant* avatar, bool hasTransformHierarchy)
+ {
+ const mecanim::skeleton::Skeleton* skeleton = avatar->m_AvatarSkeleton.Get();
+
+ BoundTransform& binding = bindings.push_back();
+ binding.pathHash = nameHash.checksum();
+ binding.transform = &transform;
+
+ if (IS_DEPRECATED_NAME_BASED_BINDING)
+ {
+ binding.pathHash = mecanim::processCRC32(transform.GetName());
+ }
+
+ if (hasTransformHierarchy)
+ {
+ // binding.pathHash : full path
+ binding.bindIndexForSkeleton = skeleton ? mecanim::skeleton::SkeletonFindNode(skeleton, binding.pathHash) : -1;
+ }
+ else
+ {
+ // binding.pathHash : flattened path
+ binding.bindIndexForSkeleton = SkeletonFindNodeIndexByNameID(avatar, binding.pathHash);
+ }
+
+ Transform::iterator end=transform.end();
+ for (Transform::iterator i=transform.begin();i != end;++i)
+ {
+ Transform* child = *i;
+ const char* name = child->GetName();
+
+ mecanim::crc32 childNameHash = AppendPathToHash(nameHash, name);
+ GenerateTransformBindingMapRecursive(*child, childNameHash, bindings, avatar, hasTransformHierarchy);
+ }
+ }
+
+ int FindTransformBindingIndexByBindingHash (const dynamic_array<BoundTransform>& bindings, BindingHash pathHash)
+ {
+ for (int i=0;i<bindings.size();++i)
+ {
+ if (bindings[i].pathHash == pathHash)
+ return i;
+ }
+
+ return -1;
+ }
+
+ int FindTransformBindingIndexBySkeletonIndex (const dynamic_array<BoundTransform>& bindings, int skeletonIndex)
+ {
+ for (int i=0;i<bindings.size();++i)
+ {
+ if (bindings[i].bindIndexForSkeleton == skeletonIndex)
+ return i;
+ }
+
+ return -1;
+ }
+
+ static void BindControllerRootMotionMask(const mecanim::animation::AvatarConstant &avatar,const mecanim::animation::ControllerConstant &controller, bool *rootMotionLayerMask)
+ {
+ mecanim::uint32_t rootMotionNodePathHash = 0;
+
+ if(avatar.m_RootMotionBoneIndex != -1)
+ {
+ rootMotionNodePathHash = avatar.m_AvatarSkeleton->m_ID[avatar.m_RootMotionBoneIndex];
+ }
+
+ for(int layerIter = 0; layerIter < controller.m_LayerCount; layerIter++)
+ {
+ bool mask = false;
+ bool found = false;
+
+ for(int maskIter = 0; !found && maskIter < controller.m_LayerArray[layerIter]->m_SkeletonMask->m_Count; maskIter++)
+ {
+ found = controller.m_LayerArray[layerIter]->m_SkeletonMask->m_Data[maskIter].m_PathHash == rootMotionNodePathHash;
+
+ if(found)
+ {
+ mask = controller.m_LayerArray[layerIter]->m_SkeletonMask->m_Data[maskIter].m_Weight > 0;
+ }
+ }
+
+ rootMotionLayerMask[layerIter] = mask;
+ }
+ }
+
+ mecanim::animation::ControllerBindingConstant *CreateControllerBindingConstant(const mecanim::animation::ControllerConstant* controller, const mecanim::animation::AnimationSet* animationSet, mecanim::ValueArrayConstant* valueArrayConstant, mecanim::uint32_t valueArrayConstantSize, const mecanim::animation::AvatarConstant* avatar, mecanim::memory::Allocator& alloc)
+ {
+ SETPROFILERLABEL(ControllerBindingConstant);
+
+ mecanim::animation::ControllerBindingConstant* controllerBindingConstant = alloc.Construct<mecanim::animation::ControllerBindingConstant>();
+ controllerBindingConstant->m_Avatar = avatar;
+ controllerBindingConstant->m_Controller = controller;
+ controllerBindingConstant->m_AnimationSet = animationSet;
+
+ int skeletonCount = !avatar->m_AvatarSkeleton.IsNull() ? avatar->m_AvatarSkeleton->m_Count : 0;
+ if (skeletonCount > 0)
+ controllerBindingConstant->m_SkeletonTQSMap = alloc.ConstructArray<mecanim::animation::SkeletonTQSMap> (avatar->m_AvatarSkeleton->m_Count);
+
+ controllerBindingConstant->m_DynamicValuesConstant = CreateValueArrayConstantCopy (valueArrayConstant, valueArrayConstantSize, alloc);
+ controllerBindingConstant->m_DynamicValuesDefault = CreateValueArray(controllerBindingConstant->m_DynamicValuesConstant, alloc);
+
+ controllerBindingConstant->m_RootMotionLayerMask = alloc.ConstructArray<bool>(controller->m_LayerCount);
+ BindControllerRootMotionMask(*avatar,*controller,controllerBindingConstant->m_RootMotionLayerMask);
+
+ return controllerBindingConstant;
+ }
+
+ void DestroyControllerBindingConstant(mecanim::animation::ControllerBindingConstant* controllerBindingConstant, mecanim::memory::Allocator& alloc)
+ {
+ if(controllerBindingConstant)
+ {
+ DestroyValueArray (controllerBindingConstant->m_DynamicValuesDefault, alloc);
+ DestroyValueArrayConstant (controllerBindingConstant->m_DynamicValuesConstant, alloc);
+ alloc.Deallocate (controllerBindingConstant->m_SkeletonTQSMap);
+ alloc.Deallocate (controllerBindingConstant->m_RootMotionLayerMask);
+ alloc.Deallocate (controllerBindingConstant);
+ }
+ }
+
+ static void BindControllerTQSMap(const AnimationSetBindings& animationSetBindings,
+ const mecanim::skeleton::Skeleton& skeleton,
+ int nonConstantTransformBindingCount,
+ const int* genericTransformBindingToBindingCache,
+ const BoundTransform* bindingCache,
+ bool hasTransformHierarchy,
+ mecanim::animation::ControllerBindingConstant *binding,
+ mecanim::memory::Allocator& alloc)
+ {
+ if (binding->m_SkeletonTQSMap == NULL)
+ return;
+
+ int rotationCount = -1;
+ int positionCount = -1;
+ int scaleCount = -1;
+
+ for (int transformIter = 0; transformIter < nonConstantTransformBindingCount; transformIter++)
+ {
+ const TransformBinding& transformBinding = animationSetBindings.transformBindings[transformIter];
+ int targetType = transformBinding.bindType;
+
+ if (targetType == kBindTransformScale)
+ scaleCount++;
+ else if (targetType == kBindTransformRotation)
+ rotationCount++;
+ else if (targetType == kBindTransformPosition)
+ positionCount++;
+
+ int skIndex = -1;
+ if (hasTransformHierarchy)
+ {
+ int transformIndex = genericTransformBindingToBindingCache[transformIter];
+ if (transformIndex == -1)
+ continue;
+ skIndex = bindingCache[transformIndex].bindIndexForSkeleton;
+ }
+ else
+ skIndex = SkeletonFindNode(&skeleton, transformBinding.path);
+
+ if (skIndex == -1)
+ continue;
+
+ if(targetType == kBindTransformScale)
+ binding->m_SkeletonTQSMap[skIndex].m_SIndex = scaleCount;
+ else if(targetType == kBindTransformRotation)
+ binding->m_SkeletonTQSMap[skIndex].m_QIndex = rotationCount;
+ else if(targetType == kBindTransformPosition)
+ binding->m_SkeletonTQSMap[skIndex].m_TIndex = positionCount;
+ }
+ }
+
+ static void GetDefaultTransformValues (Transform& targetTransform, int bindType, float* defaults)
+ {
+ if (bindType == kBindTransformPosition)
+ {
+ Vector3f pos = targetTransform.GetLocalPosition();
+ memcpy(defaults, &pos, sizeof(pos));
+ }
+ else if (bindType == kBindTransformRotation)
+ {
+ Quaternionf rot = targetTransform.GetLocalRotation();
+ memcpy(defaults, &rot, sizeof(rot));
+ }
+ else if (bindType == kBindTransformScale)
+ {
+ Vector3f scale = targetTransform.GetLocalScale();
+ memcpy(defaults, &scale, sizeof(scale));
+ }
+ else
+ {
+ AssertString("Bad");
+ }
+ }
+
+ static void GetDefaultSkeletonPoseValues (const math::xform& x, int bindType, float* defaults)
+ {
+ if (bindType == kBindTransformPosition)
+ math::store(x.t, defaults);
+ else if (bindType == kBindTransformRotation)
+ math::store(x.q, defaults);
+ else if (bindType == kBindTransformScale)
+ math::store(x.s, defaults);
+ else
+ {
+ AssertString("Bad");
+ }
+ }
+
+ static int CalculateTransformBindingSizeBasedOnConstantOptimization (const AnimationSetBindings& animationSet, dynamic_array<BoundTransform> const& transformBindingCache, const int* genericTransformBindingToBindingCache, const mecanim::animation::AvatarConstant* avatar, bool hasTransformHierarchy)
+ {
+ // Generate Constant Default values
+ ATTRIBUTE_ALIGN(ALIGN4F) float values[4];
+ const mecanim::skeleton::Skeleton* skeleton = hasTransformHierarchy ? NULL : avatar->m_AvatarSkeleton.Get();
+ const mecanim::skeleton::SkeletonPose* defaultPose = hasTransformHierarchy ? NULL : avatar->m_AvatarSkeletonPose.Get();
+
+ int highestMismatch = animationSet.transformBindingsNonConstantSize;
+
+ int constantDefaultValueIndex = 0;
+ for (int i=animationSet.transformBindingsNonConstantSize;i<animationSet.transformBindingsSize;i++)
+ {
+ const TransformBinding& transformBinding = animationSet.transformBindings[i];
+ int count = GetCurveCountForBindingType (transformBinding.bindType);
+
+ if (hasTransformHierarchy)
+ {
+ // If we can't write the value, then we don't need it to be sampled either...
+ // Thus we can simply assume it matches.
+ int transformIndex = genericTransformBindingToBindingCache[i];
+ if (transformIndex == -1)
+ {
+ constantDefaultValueIndex += count;
+ continue;
+ }
+ Transform* targetTransform = transformBindingCache[transformIndex].transform;
+ GetDefaultTransformValues(*targetTransform, transformBinding.bindType, values);
+ }
+ else
+ {
+ // get the default value from skeleton
+ int skeletonIndex = SkeletonFindNode(skeleton, transformBinding.path);
+ if (skeletonIndex == -1)
+ {
+ constantDefaultValueIndex += count;
+ continue;
+ }
+ GetDefaultSkeletonPoseValues(defaultPose->m_X[skeletonIndex], transformBinding.bindType, values);
+ }
+
+ for (int k=0;k<count;k++)
+ {
+ float clipConstant = animationSet.constantCurveValues[constantDefaultValueIndex];
+
+ if (!CompareApproximately(clipConstant, values[k], 0.00001F))
+ {
+ // printf_console("mismatch index: %d type: %d clipconstant/instance: %f vs %f.\n", i, bindType, animationSet.constantCurveValues[constantDefaultValueIndex], values[k]);
+ highestMismatch = i + 1;
+ }
+
+ constantDefaultValueIndex++;
+ }
+ }
+
+ Assert(constantDefaultValueIndex == animationSet.constantCurveValueCount);
+ return highestMismatch;
+ }
+
+ static void InvalidateBoundCurveArray(BoundCurve *boundCurveArray, int boundCurveCount, Object *object)
+ {
+ for(int iter = 0; iter < boundCurveCount; iter++)
+ {
+ if(boundCurveArray[iter].targetObject == object)
+ {
+ boundCurveArray[iter] = BoundCurve();
+ }
+ }
+ }
+
+ static void InvalidateTransformArray(Transform **transformArray, int transformCount, Object *object)
+ {
+ for(int iter = 0; iter < transformCount; iter++)
+ {
+ if(transformArray[iter] == object)
+ {
+ transformArray[iter] = 0;
+ }
+ }
+ }
+
+ void InvalidateAvatarBindingObject(AvatarBindingConstant* bindingConstant, Object *object)
+ {
+ InvalidateTransformArray(bindingConstant->skeletonBindings,bindingConstant->skeletonBindingsCount,object);
+ for (int i = 0; i < bindingConstant->exposedTransformCount; i++)
+ {
+ if (bindingConstant->exposedTransforms[i].transform == object)
+ bindingConstant->exposedTransforms[i].transform = NULL;
+ }
+ }
+
+
+ static void InvalidateGenericBindingObject(AnimatorGenericBindingConstant* bindingConstant, Object *object)
+ {
+ InvalidateBoundCurveArray(bindingConstant->transformBindings,bindingConstant->transformBindingsCount,object);
+ InvalidateBoundCurveArray(bindingConstant->genericBindings,bindingConstant->genericBindingsCount,object);
+ InvalidateBoundCurveArray(bindingConstant->genericPPtrBindings,bindingConstant->genericPPtrBindingsCount,object);
+ }
+
+ static void GenericBindingCallback(void *userData, void *sender,int eventType)
+ {
+ if(eventType == kWillDestroyEvent)
+ {
+ InvalidateGenericBindingObject(reinterpret_cast<AnimatorGenericBindingConstant *>(userData),reinterpret_cast<Object *>(sender));
+ }
+ }
+
+ void AvatarBindingCallback(void *userData, void *sender,int eventType)
+ {
+ if(eventType == kWillDestroyEvent)
+ {
+ InvalidateAvatarBindingObject(reinterpret_cast<AvatarBindingConstant *>(userData),reinterpret_cast<Object *>(sender));
+ }
+ }
+
+ static void RegisterBoundCurveArray(BoundCurve *boundCurveArray, int boundCurveCount, AnimatorGenericBindingConstant* bindingConstant)
+ {
+ for(int iter = 0; iter < boundCurveCount; iter++)
+ {
+ if(boundCurveArray[iter].targetObject != 0)
+ {
+ if(!boundCurveArray[iter].targetObject->HasEvent(GenericBindingCallback,bindingConstant))
+ {
+ boundCurveArray[iter].targetObject->AddEvent(GenericBindingCallback,bindingConstant);
+ }
+ }
+ }
+ }
+
+ template <typename TYPE> static void RegisterTransformArray(Transform **transformArray, int transformCount, TYPE* bindingConstant, Object::EventCallback* callback)
+ {
+ for(int iter = 0; iter < transformCount; iter++)
+ {
+ if(transformArray[iter] != 0)
+ {
+ if(!transformArray[iter]->HasEvent(callback, bindingConstant))
+ {
+ transformArray[iter]->AddEvent(callback, bindingConstant);
+ }
+ }
+ }
+ }
+
+ void RegisterAvatarBindingObjects(AvatarBindingConstant* bindingConstant)
+ {
+ RegisterTransformArray(bindingConstant->skeletonBindings,bindingConstant->skeletonBindingsCount,bindingConstant, AvatarBindingCallback);
+ for (int i = 0; i < bindingConstant->exposedTransformCount; i++)
+ {
+ if (bindingConstant->exposedTransforms[i].transform &&
+ !bindingConstant->exposedTransforms[i].transform->HasEvent(AvatarBindingCallback, bindingConstant))
+ bindingConstant->exposedTransforms[i].transform->AddEvent(AvatarBindingCallback, bindingConstant);
+ }
+ }
+
+ static void RegisterGenericBindingObjects(AnimatorGenericBindingConstant* bindingConstant)
+ {
+ RegisterBoundCurveArray(bindingConstant->transformBindings,bindingConstant->transformBindingsCount,bindingConstant);
+ RegisterBoundCurveArray(bindingConstant->genericBindings,bindingConstant->genericBindingsCount,bindingConstant);
+ RegisterBoundCurveArray(bindingConstant->genericPPtrBindings,bindingConstant->genericPPtrBindingsCount,bindingConstant);
+ }
+
+ static void UnregisterBoundCurveArray(BoundCurve *boundCurveArray, int boundCurveCount, AnimatorGenericBindingConstant* bindingConstant)
+ {
+ for(int iter = 0; iter < boundCurveCount; iter++)
+ {
+ if(boundCurveArray[iter].targetObject != 0)
+ {
+ boundCurveArray[iter].targetObject->RemoveEvent(GenericBindingCallback,bindingConstant);
+ }
+ }
+ }
+
+ template<typename TYPE> static void UnregisterTransformArray(Transform **transformArray, int transformCount, TYPE* bindingConstant, Object::EventCallback* callback)
+ {
+ for(int iter = 0; iter < transformCount; iter++)
+ {
+ if(transformArray[iter] != 0)
+ {
+ transformArray[iter]->RemoveEvent(callback,bindingConstant);
+ }
+ }
+ }
+
+ void UnregisterAvatarBindingObjects(AvatarBindingConstant* bindingConstant)
+ {
+ UnregisterTransformArray(bindingConstant->skeletonBindings,bindingConstant->skeletonBindingsCount,bindingConstant, AvatarBindingCallback);
+ for (int i = 0; i < bindingConstant->exposedTransformCount; i++)
+ {
+ if (bindingConstant->exposedTransforms[i].transform != NULL)
+ bindingConstant->exposedTransforms[i].transform->RemoveEvent(AvatarBindingCallback, bindingConstant);
+ }
+ }
+
+ void UnregisterGenericBindingObjects(AnimatorGenericBindingConstant* bindingConstant)
+ {
+ UnregisterBoundCurveArray(bindingConstant->transformBindings,bindingConstant->transformBindingsCount,bindingConstant);
+ UnregisterBoundCurveArray(bindingConstant->genericBindings,bindingConstant->genericBindingsCount,bindingConstant);
+ UnregisterBoundCurveArray(bindingConstant->genericPPtrBindings,bindingConstant->genericPPtrBindingsCount,bindingConstant);
+ }
+
+ static Transform *humanMark = reinterpret_cast<Transform *>(std::numeric_limits<size_t>::max());
+
+ static void humanMarkUp(mecanim::skeleton::Skeleton const &sk, int nodeIndex, Transform** bindings)
+ {
+ if(nodeIndex != -1)
+ {
+ bindings[nodeIndex] = humanMark;
+
+ humanMarkUp(sk,sk.m_Node[nodeIndex].m_ParentId,bindings);
+ }
+ }
+
+ AvatarBindingConstant* CreateAvatarBindingConstant (Transform& root, mecanim::animation::AvatarConstant const* avatar, mecanim::memory::Allocator& allocator)
+ {
+ SETPROFILERLABEL(AvatarBindingConstant);
+
+ // Generate binding cache
+ dynamic_array<BoundTransform> transformBindingCache (kMemTempAlloc);
+
+ const mecanim::skeleton::Skeleton* skeleton = avatar->m_AvatarSkeleton.Get();
+
+ GenerateTransformBindingMapRecursive(root, mecanim::crc32(), transformBindingCache, avatar, true);
+
+ AvatarBindingConstant* constant = allocator.Construct<AvatarBindingConstant> ();
+ constant->exposedTransformCount = 0;
+ constant->exposedTransforms = NULL;
+
+ constant->skeletonBindingsCount = skeleton ? skeleton->m_Count : 0;
+ constant->skeletonBindings = allocator.ConstructArray<Transform*> (constant->skeletonBindingsCount);
+
+ int transformChangedMask = 0;
+
+ // just bind what human will effectively affect
+
+ if(IS_CONTENT_NEWER_OR_SAME (kUnityVersion4_3_a1))
+ {
+ if (constant->skeletonBindingsCount != 0)
+ {
+ memset(constant->skeletonBindings, 0, sizeof(Transform*) * constant->skeletonBindingsCount);
+
+ if(avatar->m_HumanSkeletonIndexCount > 0)
+ {
+ humanMarkUp(*skeleton,avatar->m_HumanSkeletonIndexArray[0],constant->skeletonBindings);
+
+ for(int humanSkIndexIter = 0; humanSkIndexIter < avatar->m_HumanSkeletonIndexCount; humanSkIndexIter++)
+ {
+ int humanSkIndex = avatar->m_HumanSkeletonIndexArray[humanSkIndexIter];
+
+ if(humanSkIndex != -1)
+ {
+ constant->skeletonBindings[humanSkIndex] = humanMark;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for(int i = 0 ; i < constant->skeletonBindingsCount; ++i)
+ constant->skeletonBindings[i] = humanMark;
+ }
+
+ for (int i=0;i<transformBindingCache.size();i++)
+ {
+ int skeletonIndex = transformBindingCache[i].bindIndexForSkeleton;
+
+ if (skeletonIndex != -1)
+ {
+ if(constant->skeletonBindings[skeletonIndex] == humanMark)
+ {
+ constant->skeletonBindings[skeletonIndex] = transformBindingCache[i].transform;
+ transformChangedMask |= Transform::kPositionChanged | Transform::kRotationChanged;
+ }
+ }
+ }
+
+ for(int i = 0 ; i < constant->skeletonBindingsCount; ++i)
+ {
+ if(constant->skeletonBindings[i] == humanMark)
+ constant->skeletonBindings[i] = 0;
+ }
+
+ constant->transformChangedMask = transformChangedMask;
+
+ RegisterAvatarBindingObjects(constant);
+
+ return constant;
+ }
+
+ AvatarBindingConstant* CreateAvatarBindingConstantOpt (Transform& root, mecanim::animation::AvatarConstant const* avatar, mecanim::memory::Allocator& allocator)
+ {
+ SETPROFILERLABEL(AvatarBindingConstant);
+
+ // Generate binding cache
+ dynamic_array<BoundTransform> transformBindingCache (kMemTempAlloc);
+
+ GenerateTransformBindingMapRecursive(root, mecanim::crc32(), transformBindingCache, avatar, false);
+
+ mecanim::skeleton::Skeleton const* skeleton = avatar->m_AvatarSkeleton.Get();
+
+ AvatarBindingConstant* constant = allocator.Construct<AvatarBindingConstant> ();
+ constant->skeletonBindingsCount = 0;
+ constant->skeletonBindings = NULL;
+ constant->transformChangedMask = 0;
+
+ // For the flattened transform, it's impossible to tell if the transform will be modified just by the curve which
+ // is binded to it, because all its parent transforms will also affect it.
+ // Since normally, there are only a few exposed transforms, the performance penalty will not be huge
+ // if we don't care which exact properties of the transform are modified.
+ int exposedCount = 0;
+ int maxExposeCount = transformBindingCache.size();
+ dynamic_array<ExposedTransform> exposedTransforms(maxExposeCount, kMemTempAlloc);
+ for (int i = 0; i < maxExposeCount; ++i)
+ {
+ BoundTransform& boundTransform = transformBindingCache[i];
+ bool isChildOfRoot = (boundTransform.transform->GetParent() == &root);
+ if (!isChildOfRoot)
+ continue;
+
+ ExposedTransform& exposedTransform = exposedTransforms[exposedCount];
+ exposedTransform.transform = boundTransform.transform;
+ exposedTransform.skeletonIndex = -1;
+ exposedTransform.skeletonIndexForUpdateTransform = -1;
+
+ if (boundTransform.bindIndexForSkeleton != -1)
+ {
+ exposedTransform.skeletonIndex = boundTransform.bindIndexForSkeleton;
+ exposedTransform.skeletonIndexForUpdateTransform = boundTransform.bindIndexForSkeleton;
+ }
+
+ // Handle special case: SkinnedMeshRenderer
+ // We directly update the root bone to the Transform of the SkinnedMeshRenderer.
+ SkinnedMeshRenderer* skin = boundTransform.transform->QueryComponent(SkinnedMeshRenderer);
+ if (skin)
+ {
+ const Mesh* mesh = skin->GetMesh();
+ if (mesh && mesh->GetRootBonePathHash() != 0)
+ {
+ int skinRootIndex = skeleton ? mecanim::skeleton::SkeletonFindNode(
+ skeleton, mesh->GetRootBonePathHash()) : -1;
+ if (skinRootIndex != -1)
+ exposedTransform.skeletonIndexForUpdateTransform = skinRootIndex;
+ }
+ }
+ if (exposedTransform.skeletonIndexForUpdateTransform != -1)
+ exposedCount++;
+ }
+
+ constant->exposedTransformCount = exposedCount;
+ constant->exposedTransforms = allocator.ConstructArray<ExposedTransform> (constant->exposedTransformCount);
+ for (int i=0; i<exposedCount; i++)
+ constant->exposedTransforms[i] = exposedTransforms[i];
+
+ RegisterAvatarBindingObjects(constant);
+
+ return constant;
+ }
+
+ void DestroyAvatarBindingConstant (AvatarBindingConstant* bindingConstant, mecanim::memory::Allocator& allocator)
+ {
+ if (bindingConstant != NULL)
+ {
+ UnregisterAvatarBindingObjects(bindingConstant);
+
+ allocator.Deallocate(bindingConstant->skeletonBindings);
+ allocator.Deallocate(bindingConstant->exposedTransforms);
+ allocator.Deallocate(bindingConstant);
+ }
+ }
+
+ AnimatorGenericBindingConstant* CreateAnimatorGenericBindings (const AnimationSetBindings& animationSet, Transform& root, const mecanim::animation::AvatarConstant* avatar, const mecanim::animation::ControllerConstant* controller, mecanim::memory::Allocator& allocator)
+ {
+ SETPROFILERLABEL(AnimatorGenericBindingConstant);
+
+ GenericAnimationBindingCache& bindingCache = GetGenericAnimationBindingCache ();
+
+ const mecanim::skeleton::Skeleton* skeleton = avatar->m_AvatarSkeleton.Get();
+
+ // Generate binding cache
+ dynamic_array<BoundTransform> transformBindingCache (kMemTempAlloc);
+ dynamic_array<int> genericTransformBindingToBindingCache (kMemTempAlloc);
+
+ GenerateTransformBindingMapRecursive(root, mecanim::crc32(), transformBindingCache, avatar, true);
+
+ // Map from animation set to binding cache index
+ genericTransformBindingToBindingCache.resize_uninitialized(animationSet.transformBindingsSize);
+ for (int i=0;i<animationSet.transformBindingsSize;i++)
+ genericTransformBindingToBindingCache[i] = FindTransformBindingIndexByBindingHash (transformBindingCache, animationSet.transformBindings[i].path);
+
+ // Calculate Transform bindings that are actually animating (Constant curve values can be removed if they match the default values)
+ // Generate new reduced ValueArrayCount from it.
+ int nonConstantTransformBindingCount = CalculateTransformBindingSizeBasedOnConstantOptimization (animationSet, transformBindingCache, genericTransformBindingToBindingCache.begin(), avatar, true);
+ int optimizedValueArrayConstantCount = animationSet.animationSet->m_DynamicFullValuesConstant->m_Count - (animationSet.transformBindingsSize - nonConstantTransformBindingCount);
+ bool allowConstantClipSamplingOptimization = nonConstantTransformBindingCount == animationSet.transformBindingsNonConstantSize;
+
+ AnimatorGenericBindingConstant* constant = allocator.Construct<AnimatorGenericBindingConstant> ();
+
+ constant->transformBindingsCount = nonConstantTransformBindingCount;
+ constant->transformBindings = allocator.ConstructArray<BoundCurve> (constant->transformBindingsCount);
+
+ constant->genericBindingsCount = animationSet.genericBindingsSize;
+ constant->genericBindings = allocator.ConstructArray<BoundCurve> (constant->genericBindingsCount);
+
+ constant->genericPPtrBindingsCount = animationSet.genericPPtrBindingsSize;
+ constant->genericPPtrBindings = allocator.ConstructArray<BoundCurve> (constant->genericPPtrBindingsCount);
+
+ constant->allowConstantClipSamplingOptimization = allowConstantClipSamplingOptimization;
+
+ int transformChangedMask = 0;
+
+ // Bind Transforms
+ for (int i=0;i<constant->transformBindingsCount;i++)
+ {
+ int transformIndex = genericTransformBindingToBindingCache[i];
+ constant->transformBindings[i].targetType = animationSet.transformBindings[i].bindType;
+ if (transformIndex != -1)
+ {
+ constant->transformBindings[i].targetObject = transformBindingCache[transformIndex].transform;
+
+ transformChangedMask |= Transform::kPositionChanged | Transform::kRotationChanged;
+ if (animationSet.transformBindings[i].bindType == kBindTransformScale)
+ transformChangedMask |= Transform::kScaleChanged;
+ }
+ else
+ {
+ constant->transformBindings[i].targetObject = NULL;
+ }
+ }
+
+ constant->transformChangedMask = transformChangedMask;
+
+ // Bind Generic properties
+ for (int i=0;i<constant->genericBindingsCount;i++)
+ {
+ constant->genericBindings[i].targetObject = NULL;
+ constant->genericBindings[i].targetType = kUnbound;
+
+ int index = FindTransformBindingIndexByBindingHash (transformBindingCache, animationSet.genericBindings[i].path);
+ if (index != -1)
+ bindingCache.BindGeneric(animationSet.genericBindings[i], *transformBindingCache[index].transform, constant->genericBindings[i]);
+ }
+
+ // Bind Generic PPtr properties
+ for (int i=0;i<constant->genericPPtrBindingsCount;i++)
+ {
+ constant->genericPPtrBindings[i].targetObject = NULL;
+ constant->genericPPtrBindings[i].targetType = kUnbound;
+
+ int index = FindTransformBindingIndexByBindingHash (transformBindingCache, animationSet.genericPPtrBindings[i].path);
+ if (index != -1)
+ bindingCache.BindPPtrGeneric(animationSet.genericPPtrBindings[i], *transformBindingCache[index].transform, constant->genericPPtrBindings[i]);
+ }
+
+ constant->controllerBindingConstant = CreateControllerBindingConstant (controller, animationSet.animationSet, animationSet.animationSet->m_DynamicFullValuesConstant, optimizedValueArrayConstantCount, avatar, allocator);
+
+ // Gravity weight should must be in both optimized and non-optimized ValueArray
+ Assert(animationSet.animationSet->m_GravityWeightIndex == -1 || animationSet.animationSet->m_GravityWeightIndex < constant->controllerBindingConstant->m_DynamicValuesDefault->m_FloatCount);
+
+ // Bind Controller skeleton to dynamic value array
+ BindControllerTQSMap(animationSet, *skeleton, nonConstantTransformBindingCount, genericTransformBindingToBindingCache.begin(), transformBindingCache.begin(), true, constant->controllerBindingConstant, allocator);
+
+ RegisterGenericBindingObjects(constant);
+
+ InitializeDefaultValues (*constant, avatar, true, *constant->controllerBindingConstant);
+
+ return constant;
+ }
+
+ AnimatorGenericBindingConstant* CreateAnimatorGenericBindingsOpt ( const AnimationSetBindings& animationSet, Transform& root, const mecanim::animation::AvatarConstant* avatar, const mecanim::animation::ControllerConstant* controller, mecanim::memory::Allocator& allocator)
+ {
+ GenericAnimationBindingCache& bindingCache = GetGenericAnimationBindingCache ();
+ const mecanim::skeleton::Skeleton* skeleton = avatar->m_AvatarSkeleton.Get();
+
+ dynamic_array<BoundTransform> transformBindingCache (kMemTempAlloc);
+ // BoundTransform.pathHash: hash of flattened path
+ // BoundTransform.bindIndexForSkeleton: corresponding skeleton index
+ GenerateTransformBindingMapRecursive(root, mecanim::crc32(), transformBindingCache, avatar, false);
+
+ // Calculate Transform bindings that are actually animating (Constant curve values can be removed if they match the default values)
+ // Generate new reduced ValueArrayCount from it.
+ int nonConstantTransformBindingCount = CalculateTransformBindingSizeBasedOnConstantOptimization (animationSet, transformBindingCache, NULL, avatar, false);
+ int optimizedValueArrayConstantCount = animationSet.animationSet->m_DynamicFullValuesConstant->m_Count - (animationSet.transformBindingsSize - nonConstantTransformBindingCount);
+ bool allowConstantClipSamplingOptimization = nonConstantTransformBindingCount == animationSet.transformBindingsNonConstantSize;
+
+ AnimatorGenericBindingConstant* constant = allocator.Construct<AnimatorGenericBindingConstant> ();
+
+ constant->transformBindingsCount = 0;
+ constant->transformBindings = NULL;
+
+ constant->genericBindingsCount = animationSet.genericBindingsSize;
+ constant->genericBindings = allocator.ConstructArray<BoundCurve> (constant->genericBindingsCount);
+
+ constant->genericPPtrBindingsCount = animationSet.genericPPtrBindingsSize;
+ constant->genericPPtrBindings = allocator.ConstructArray<BoundCurve> (constant->genericPPtrBindingsCount);
+
+ constant->allowConstantClipSamplingOptimization = allowConstantClipSamplingOptimization;
+
+
+ // Bind Generic properties
+ for (int i=0; i<constant->genericBindingsCount; i++)
+ {
+ constant->genericBindings[i].targetObject = NULL;
+ constant->genericBindings[i].targetType = kUnbound;
+
+ BindingHash fullPath = animationSet.genericBindings[i].path;
+ int skeletonIndex = mecanim::skeleton::SkeletonFindNode(skeleton, fullPath);
+
+ int transformIndex = FindTransformBindingIndexBySkeletonIndex (transformBindingCache, skeletonIndex);
+ if (transformIndex != -1)
+ bindingCache.BindGeneric(animationSet.genericBindings[i], *transformBindingCache[transformIndex].transform, constant->genericBindings[i]);
+ }
+
+ // Bind Generic PPtr properties
+ for (int i=0; i<constant->genericPPtrBindingsCount; i++)
+ {
+ constant->genericPPtrBindings[i].targetObject = NULL;
+ constant->genericPPtrBindings[i].targetType = kUnbound;
+
+ BindingHash fullPath = animationSet.genericPPtrBindings[i].path;
+ int skeletonIndex = mecanim::skeleton::SkeletonFindNode(skeleton, fullPath);
+
+ int transformIndex = FindTransformBindingIndexBySkeletonIndex (transformBindingCache, skeletonIndex);
+ if (transformIndex != -1)
+ bindingCache.BindPPtrGeneric(animationSet.genericPPtrBindings[i], *transformBindingCache[transformIndex].transform, constant->genericPPtrBindings[i]);
+ }
+
+ constant->controllerBindingConstant = CreateControllerBindingConstant (controller, animationSet.animationSet, animationSet.animationSet->m_DynamicFullValuesConstant, optimizedValueArrayConstantCount, avatar, allocator);
+
+ // Gravity weight should must be in both optimized and non-optimized ValueArray
+ Assert(animationSet.animationSet->m_GravityWeightIndex == -1 || animationSet.animationSet->m_GravityWeightIndex < constant->controllerBindingConstant->m_DynamicValuesDefault->m_FloatCount);
+
+ // Bind Controller skeleton to dynamic value array
+ BindControllerTQSMap(animationSet, *skeleton, nonConstantTransformBindingCount, NULL, transformBindingCache.begin(), false, constant->controllerBindingConstant, allocator);
+
+ RegisterGenericBindingObjects(constant);
+
+ InitializeDefaultValues (*constant, avatar, false, *constant->controllerBindingConstant);
+
+ return constant;
+ }
+
+ void DestroyAnimatorGenericBindings (AnimatorGenericBindingConstant* bindingConstant, mecanim::memory::Allocator& allocator)
+ {
+ if (bindingConstant != NULL)
+ {
+ UnregisterGenericBindingObjects(bindingConstant);
+
+ DestroyControllerBindingConstant(bindingConstant->controllerBindingConstant, allocator);
+ allocator.Deallocate(bindingConstant->transformBindings);
+ allocator.Deallocate(bindingConstant->genericBindings);
+ allocator.Deallocate(bindingConstant);
+ }
+ }
+
+ ////// Get & Set Values
+ void SetGenericPPtrPropertyValues (const AnimatorGenericBindingConstant& bindings, const mecanim::ValueArray &values)
+ {
+ for (int bindIndex = 0;bindIndex != bindings.genericPPtrBindingsCount;bindIndex++)
+ {
+ const BoundCurve& binding = bindings.genericPPtrBindings[bindIndex];
+ int targetType = binding.targetType;
+
+ if (targetType == kUnbound)
+ continue;
+
+ Assert (targetType >= kMinSinglePropertyBinding);
+
+ mecanim::int32_t value = 0;
+ values.ReadData(value, bindIndex);
+ SetBoundCurveIntValue (binding, value);
+ }
+ }
+
+ void SetGenericFloatPropertyValues (const AnimatorGenericBindingConstant& bindings, const mecanim::ValueArray &values)
+ {
+ Object* lastAwakeFromLoadObject = NULL;
+ for (int bindIndex = 0;bindIndex != bindings.genericBindingsCount;bindIndex++)
+ {
+ const BoundCurve& binding = bindings.genericBindings[bindIndex];
+ int targetType = binding.targetType;
+
+ if (targetType == kUnbound)
+ continue;
+
+ // When applying multiple properties to the same object in a row.
+ // Call AwakeFromLoad / SetDirty only once.
+ if (ShouldAwakeGeneric(binding))
+ {
+ if (lastAwakeFromLoadObject != binding.targetObject)
+ {
+ if (lastAwakeFromLoadObject != NULL)
+ BoundCurveValueAwakeGeneric(*lastAwakeFromLoadObject);
+ lastAwakeFromLoadObject = binding.targetObject;
+ }
+ }
+
+ Assert (targetType >= kMinSinglePropertyBinding);
+
+ float value = 0.0F;
+ values.ReadData(value, bindIndex);
+
+ SetBoundCurveFloatValue (binding, value);
+ }
+
+ if (lastAwakeFromLoadObject != NULL)
+ BoundCurveValueAwakeGeneric(*lastAwakeFromLoadObject);
+ }
+
+
+ void SetTransformPropertyApplyMainThread (Transform& root, const AvatarBindingConstant& avatarBindings, bool skipRoot, int mask)
+ {
+ // Send TransformChanged message
+ int transformChangedMask = avatarBindings.transformChangedMask & mask;
+ if (transformChangedMask != 0)
+ {
+ if(skipRoot)
+ {
+ for(int childIter = 0; childIter < root.m_Children.size(); childIter++)
+ {
+ root.m_Children[childIter]->SendTransformChanged(transformChangedMask);
+ }
+ }
+ else
+ {
+ root.SendTransformChanged(transformChangedMask);
+ }
+ }
+
+ // In The editor we set dirty so the inspector UI is always up to date
+ #if UNITY_EDITOR
+ for (int bindIndex = 0;bindIndex != avatarBindings.skeletonBindingsCount;bindIndex++)
+ {
+ Transform* targetTransform = avatarBindings.skeletonBindings[bindIndex];
+ if (targetTransform)
+ targetTransform->SetDirty();
+ }
+ #endif
+ }
+
+ void SetTransformPropertyApplyMainThread (Transform& root, const AnimatorGenericBindingConstant& bindings, const AvatarBindingConstant& avatarBindings, bool skipRoot)
+ {
+ // Send TransformChanged message
+ if (bindings.transformChangedMask != 0)
+ {
+ if(skipRoot)
+ {
+ for(int childIter = 0; childIter < root.m_Children.size(); childIter++)
+ {
+ root.m_Children[childIter]->SendTransformChanged(bindings.transformChangedMask);
+ }
+ }
+ else
+ {
+ root.SendTransformChanged(bindings.transformChangedMask);
+ }
+ }
+
+ SetTransformPropertyApplyMainThread(root, avatarBindings, skipRoot, ~bindings.transformChangedMask);
+
+ // In The editor we set dirty so the inspector UI is always up to date
+ #if UNITY_EDITOR
+ for (int bindIndex = 0;bindIndex != bindings.transformBindingsCount;bindIndex++)
+ {
+ const BoundCurve& binding = bindings.transformBindings[bindIndex];
+ Transform* targetTransform = reinterpret_cast<Transform*> (binding.targetObject);
+ if (targetTransform)
+ targetTransform->SetDirty();
+ }
+ #endif
+ }
+
+
+ void SetHumanTransformPropertyValues (const AvatarBindingConstant& bindings, const mecanim::skeleton::SkeletonPose& pose)
+ {
+ int transformCount = bindings.skeletonBindingsCount;
+ Assert(pose.m_Count == transformCount);
+
+ // skip root node i = 1
+ for(int i = 1; i < transformCount; i++)
+ {
+ Transform* transform = bindings.skeletonBindings[i];
+ if (transform != NULL)
+ {
+ Vector3f t = float4ToVector3f(pose.m_X[i].t);
+ transform->SetLocalPositionWithoutNotification(t);
+
+ Quaternionf q = float4ToQuaternionf(pose.m_X[i].q);
+ transform->SetLocalRotationWithoutNotification(q);
+ }
+ }
+ }
+
+ void SetFlattenedSkeletonTransformsMainThread (const AvatarBindingConstant& bindings, const mecanim::skeleton::SkeletonPose& globalSpacePose, const mecanim::animation::AvatarConstant& avatar)
+ {
+ for (size_t i=0;i < bindings.exposedTransformCount;i++)
+ {
+ ExposedTransform& exposedTransform = bindings.exposedTransforms[i];
+ if (exposedTransform.transform)
+ {
+ const math::xform& globalXForm = globalSpacePose.m_X[exposedTransform.skeletonIndexForUpdateTransform];
+ exposedTransform.transform->SetPositionAndRotation(float4ToVector3f(globalXForm.t), float4ToQuaternionf(globalXForm.q));
+ }
+ }
+ }
+
+ void SetGenericTransformPropertyValues (const AnimatorGenericBindingConstant& bindings, const mecanim::ValueArray &values, Transform *skipTransform)
+ {
+ int rotationIndex = 0;
+ int positionIndex = 0;
+ int scaleIndex = 0;
+
+ for (int bindIndex = 0;bindIndex != bindings.transformBindingsCount;bindIndex++)
+ {
+ const BoundCurve& binding = bindings.transformBindings[bindIndex];
+ int targetType = binding.targetType;
+
+ Transform* targetTransform = reinterpret_cast<Transform*> (binding.targetObject);
+
+ if (targetType == kBindTransformRotation)
+ {
+ if(targetTransform && (targetTransform != skipTransform ))
+ {
+ math::float4 value = values.ReadQuaternion(rotationIndex);
+ targetTransform->SetLocalRotationWithoutNotification(float4ToQuaternionf(value));
+ }
+ rotationIndex++;
+ }
+ else if (targetType == kBindTransformPosition)
+ {
+ if(targetTransform && (targetTransform != skipTransform ))
+ {
+ math::float4 value = values.ReadPosition(positionIndex);
+ targetTransform->SetLocalPositionWithoutNotification(float4ToVector3f(value));
+ }
+
+ positionIndex++;
+ }
+ else if (targetType == kBindTransformScale)
+ {
+ if(targetTransform && (targetTransform != skipTransform ))
+ {
+ math::float4 value = values.ReadScale(scaleIndex);
+ targetTransform->SetLocalScaleWithoutNotification(float4ToVector3f(value));
+ }
+
+ scaleIndex++;
+ }
+ }
+ }
+
+
+ static void GetDefaultTransformValues (const BoundCurve* transformBindings, size_t transformBindingsCount, mecanim::ValueArray &values)
+ {
+ int positionIndex = 0;
+ int rotationIndex = 0;
+ int scaleIndex = 0;
+
+ for (int bindIndex = 0; bindIndex < transformBindingsCount; bindIndex++)
+ {
+ const BoundCurve& binding = transformBindings[bindIndex];
+
+ Transform* targetTransform = reinterpret_cast<Transform*> (binding.targetObject);
+ if (binding.targetType == kBindTransformPosition)
+ {
+ if(targetTransform)
+ values.WritePosition(Vector3fTofloat4(targetTransform->GetLocalPosition()), positionIndex);
+
+ positionIndex++;
+ }
+ else if (binding.targetType == kBindTransformRotation)
+ {
+ if(targetTransform)
+ values.WriteQuaternion(QuaternionfTofloat4(targetTransform->GetLocalRotation()), rotationIndex);
+
+ rotationIndex++;
+ }
+ else if (binding.targetType == kBindTransformScale)
+ {
+ if(targetTransform)
+ values.WriteScale(Vector3fTofloat4(targetTransform->GetLocalScale()), scaleIndex);
+
+ scaleIndex++;
+ }
+ }
+ }
+
+ static void GetDefaultGenericFloatValues (const AnimatorGenericBindingConstant& bindings, mecanim::ValueArray &values)
+ {
+ for (int bindIndex = 0; bindIndex < bindings.genericBindingsCount; bindIndex++)
+ {
+ const BoundCurve& binding = bindings.genericBindings[bindIndex];
+ int targetType = binding.targetType;
+ if (targetType == kUnbound)
+ continue;
+
+ Assert (targetType >= kMinSinglePropertyBinding);
+
+ float value = GetBoundCurveFloatValue (binding);
+
+ values.WriteData(value, bindIndex);
+ }
+ }
+
+ static void GetDefaultGenericPPtrValues (const AnimatorGenericBindingConstant& bindings, mecanim::ValueArray &values)
+ {
+ for (int bindIndex = 0; bindIndex < bindings.genericPPtrBindingsCount; bindIndex++)
+ {
+ const BoundCurve& binding = bindings.genericPPtrBindings[bindIndex];
+ int targetType = binding.targetType;
+ if (targetType == kUnbound)
+ continue;
+
+ Assert (targetType >= kMinSinglePropertyBinding);
+
+ mecanim::int32_t value = GetBoundCurveIntValue (binding);
+
+ values.WriteData(value, bindIndex);
+ }
+ }
+
+ static void InitializeDefaultValues (const UnityEngine::Animation::AnimatorGenericBindingConstant& genericBinding, const mecanim::animation::AvatarConstant* avatar, bool hasTransformHierarchy, mecanim::animation::ControllerBindingConstant& controllerBindingConstant)
+ {
+ const mecanim::skeleton::Skeleton* skeleton = avatar->m_AvatarSkeleton.Get();
+ const mecanim::skeleton::SkeletonPose* skeletonPose = avatar->m_AvatarSkeletonPose.Get();
+ const mecanim::animation::AnimationSet& animSet = *controllerBindingConstant.m_AnimationSet;
+
+ if (hasTransformHierarchy)
+ {
+ // Get default values from transform
+ GetDefaultTransformValues (genericBinding.transformBindings, genericBinding.transformBindingsCount, *controllerBindingConstant.m_DynamicValuesDefault);
+ }
+ else
+ {
+ // When there is no transform & game object hierarchy, get it from the skeleton.
+ if (skeleton != NULL && skeletonPose != NULL)
+ ValueFromSkeletonPose (*skeleton, *skeletonPose, controllerBindingConstant.m_SkeletonTQSMap, *controllerBindingConstant.m_DynamicValuesDefault);
+ }
+
+ // Get default values from generic bindings
+ GetDefaultGenericFloatValues (genericBinding, *controllerBindingConstant.m_DynamicValuesDefault);
+ GetDefaultGenericPPtrValues (genericBinding, *controllerBindingConstant.m_DynamicValuesDefault);
+
+ // Copy default parameters from controller defaults to m_DynamicValuesDefault
+ const mecanim::animation::ControllerConstant* controller = controllerBindingConstant.m_Controller;
+ mecanim::ValueArrayReverseCopy(controller->m_Values.Get(), controller->m_DefaultValues.Get(), controllerBindingConstant.m_DynamicValuesConstant, controllerBindingConstant.m_DynamicValuesDefault, animSet.m_AdditionalIndexArray);
+ }
+
+} }