1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
#include "UnityPrefix.h"
#include "Runtime/Animation/GenericAnimationBindingCache.h"
#include "Runtime/Animation/BoundCurve.h"
#include "SkinnedMeshFilter.h"
#include "Runtime/Filters/Mesh/MeshBlendShape.h"
#include "Runtime/Filters/Mesh/LodMesh.h"
#include "Runtime/Interfaces/IAnimationBinding.h"
#include "Runtime/mecanim/generic/crc32.h"
const char* kBlendShapePrefix = "blendShape.";
const char* kBlendShapeSerializedPropertyPath = "m_BlendShapeWeights.Array.data[";
static int BlendShapeNameToIndex (SkinnedMeshRenderer& renderer, BindingHash hash)
{
const Mesh* mesh = renderer.GetMesh();
if (mesh == NULL)
return -1;
const BlendShapeData& blendShapes = mesh->GetBlendShapeData();
int index = GetChannelIndex (blendShapes, hash);
return index;
}
static std::string BlendShapeIndexToName (Object& targetObject, int index)
{
SkinnedMeshRenderer* renderer = dynamic_pptr_cast<SkinnedMeshRenderer*> (&targetObject);
if (renderer == NULL)
return std::string();
const Mesh* mesh = renderer->GetMesh();
if (mesh == NULL)
return std::string();
const BlendShapeData& blendShapeData = mesh->GetBlendShapeData();
if (index < mesh->GetBlendShapeChannelCount ())
return std::string(kBlendShapePrefix) + GetChannelName (blendShapeData, index);
else
return std::string();
}
static bool CalculateBlendShapeHash (const char* name, BindingHash& hash)
{
// Special case support for blendshape weights. We have to call a function.
const char* shapeName = ParsePrefixedName (name, kBlendShapePrefix);
if (shapeName == NULL)
return false;
hash = mecanim::processCRC32(shapeName);
return true;
}
class BlendshapePropertyBinding : public IAnimationBinding
{
#if UNITY_EDITOR
virtual void GetAllAnimatableProperties (Object& targetObject, std::vector<EditorCurveBinding>& outProperties) const
{
SkinnedMeshRenderer& renderer = static_cast<SkinnedMeshRenderer&> (targetObject);
Mesh* mesh = renderer.GetMesh();
if (mesh == NULL)
return;
for (int i = 0; i < mesh->GetBlendShapeChannelCount (); ++i)
AddBinding (outProperties, ClassID(SkinnedMeshRenderer), BlendShapeIndexToName (targetObject, i));
}
#endif
virtual float GetFloatValue (const UnityEngine::Animation::BoundCurve& bind) const
{
SkinnedMeshRenderer* renderer = reinterpret_cast<SkinnedMeshRenderer*>(bind.targetObject);
const int shapeIndex = reinterpret_cast<int> (bind.targetPtr);
return renderer->GetBlendShapeWeight(shapeIndex);
}
virtual void SetFloatValue (const UnityEngine::Animation::BoundCurve& bind, float value) const
{
SkinnedMeshRenderer* renderer = reinterpret_cast<SkinnedMeshRenderer*>(bind.targetObject);
const int shapeIndex = reinterpret_cast<int> (bind.targetPtr);
renderer->SetBlendShapeWeight(shapeIndex, value);
}
virtual void SetPPtrValue (const UnityEngine::Animation::BoundCurve& bound, SInt32 value) const { }
virtual SInt32 GetPPtrValue (const UnityEngine::Animation::BoundCurve& bound) const { return 0;}
virtual bool GenerateBinding (const UnityStr& attribute, bool pptrCurve, UnityEngine::Animation::GenericBinding& outputBinding) const
{
BindingHash hash;
if (pptrCurve || !CalculateBlendShapeHash (attribute.c_str(), hash))
return false;
outputBinding.attribute = hash;
return true;
}
virtual ClassIDType BindValue (Object& target, const UnityEngine::Animation::GenericBinding& inputBinding, UnityEngine::Animation::BoundCurve& bound) const
{
int index = BlendShapeNameToIndex (static_cast<SkinnedMeshRenderer&> (target), inputBinding.attribute);
if (index == -1)
return ClassID(Undefined);
bound.targetPtr = (void*)index;
return ClassID(float);
}
virtual std::string SerializedPropertyPathToCurveAttribute (Object& target, const char* propertyPath) const
{
Assert (target.GetClassID () == ClassID(SkinnedMeshRenderer));
if (BeginsWith (propertyPath, kBlendShapeSerializedPropertyPath))
{
int index = StringToInt (propertyPath + strlen(kBlendShapeSerializedPropertyPath));
return BlendShapeIndexToName (target, index);
}
else
return string();
}
virtual std::string CurveAttributeToSerializedPath (const UnityEngine::Animation::BoundCurve& bound) const
{
const int shapeIndex = reinterpret_cast<int> (bound.targetPtr);
Assert (shapeIndex != -1);
return kBlendShapeSerializedPropertyPath + IntToString(shapeIndex) + ']';
}
};
static BlendshapePropertyBinding* gBinding = NULL;
void InitializeBlendShapeAnimationBindingInterface ()
{
gBinding = UNITY_NEW (BlendshapePropertyBinding, kMemAnimation);
UnityEngine::Animation::GetGenericAnimationBindingCache ().RegisterIAnimationBinding (ClassID(SkinnedMeshRenderer), UnityEngine::Animation::kBlendShapeWeightBinding, gBinding);
}
void CleanupBlendShapeAnimationBindingInterface ()
{
UNITY_DELETE (gBinding, kMemAnimation);
}
|