Implemented BlendShape export

This commit is contained in:
Perfare 2019-07-28 16:41:23 +08:00
parent b1ea8dd346
commit 0b462754a5
4 changed files with 138 additions and 8 deletions

View File

@ -292,7 +292,7 @@ namespace AssetStudio
public AnimationCurve<float> curve;
public string attribute;
public string path;
public int classID;
public ClassIDType classID;
public PPtr<MonoScript> script;
@ -301,7 +301,7 @@ namespace AssetStudio
curve = new AnimationCurve<float>(reader, reader.ReadSingle);
attribute = reader.ReadAlignedString();
path = reader.ReadAlignedString();
classID = reader.ReadInt32();
classID = (ClassIDType)reader.ReadInt32();
script = new PPtr<MonoScript>(reader);
}
}

View File

@ -227,6 +227,7 @@ namespace AssetStudio
public List<ImportedKeyframe<Vector3>> Scalings = new List<ImportedKeyframe<Vector3>>();
public List<ImportedKeyframe<Vector3>> Rotations = new List<ImportedKeyframe<Vector3>>();
public List<ImportedKeyframe<Vector3>> Translations = new List<ImportedKeyframe<Vector3>>();
public ImportedBlendShape BlendShape;
}
public class ImportedKeyframe<T>
@ -243,6 +244,12 @@ namespace AssetStudio
}
}
public class ImportedBlendShape
{
public string ChannelName;
public List<ImportedKeyframe<float>> Keyframes = new List<ImportedKeyframe<float>>();
}
public class ImportedMorph
{
public string Path { get; set; }

View File

@ -96,7 +96,7 @@ namespace AssetStudio
}
pBindPose = FbxPose::Create(pScene, "BindPose");
pBindPose->SetIsBindPose(true);
pScene->AddPose(pBindPose);
frameToNode = gcnew Dictionary<ImportedFrame^, size_t>();
meshFrames = imported->MeshList != nullptr ? gcnew List<ImportedFrame^>() : nullptr;
@ -173,13 +173,25 @@ namespace AssetStudio
if (frameToNode->TryGetValue(frame, pointer))
{
auto pNode = (FbxNode*)pointer;
if (allBones || bonePaths->Contains(frame->Path))
if (allBones)
{
FbxSkeleton* pJoint = FbxSkeleton::Create(pScene, "");
pJoint->Size.Set(FbxDouble(boneSize));
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
pNode->SetNodeAttribute(pJoint);
}
else if (bonePaths->Contains(frame->Path))
{
FbxSkeleton* pJoint = FbxSkeleton::Create(pScene, "");
pJoint->Size.Set(FbxDouble(boneSize));
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
pNode->SetNodeAttribute(pJoint);
pJoint = FbxSkeleton::Create(pScene, "");
pJoint->Size.Set(FbxDouble(boneSize));
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
pNode->GetParent()->SetNodeAttribute(pJoint);
}
else
{
FbxNull* pNull = FbxNull::Create(pScene, "");
@ -344,7 +356,7 @@ namespace AssetStudio
}
}
FbxMesh* pMesh = FbxMesh::Create(pScene, "");
FbxMesh* pMesh = FbxMesh::Create(pScene, pFrameNode->GetName());
pFrameNode->SetNodeAttribute(pMesh);
int vertexCount = 0;
@ -755,6 +767,42 @@ namespace AssetStudio
eulerFilter->SetQualityTolerance(filterPrecision);
eulerFilter->Apply(lCurve, 3);
}
//BlendShape
if (keyframeList->BlendShape != nullptr)
{
FbxString channelName;
WITH_MARSHALLED_STRING
(
pClipName,
keyframeList->BlendShape->ChannelName,
channelName = FbxString(pClipName);
);
auto lGeometry = (FbxGeometry*)pNode->GetNodeAttribute();
FbxBlendShape* lBlendShape = (FbxBlendShape*)lGeometry->GetDeformer(0, FbxDeformer::eBlendShape);
int lBlendShapeChannelCount = lBlendShape->GetBlendShapeChannelCount();
for (int lChannelIndex = 0; lChannelIndex < lBlendShapeChannelCount; ++lChannelIndex)
{
FbxBlendShapeChannel* lChannel = lBlendShape->GetBlendShapeChannel(lChannelIndex);
FbxString lChannelName = lChannel->GetNameOnly();
if (lChannelName == channelName)
{
FbxAnimCurve* lAnimCurve = lGeometry->GetShapeChannel(0, lChannelIndex, lAnimLayer, true);
lAnimCurve->KeyModifyBegin();
for each (auto keyframe in keyframeList->BlendShape->Keyframes)
{
lTime.SetSecondDouble(keyframe->time);
int lKeyIndex = lAnimCurve->KeyAdd(lTime);
lAnimCurve->KeySetValue(lKeyIndex, keyframe->value);
lAnimCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);
}
lAnimCurve->KeyModifyEnd();
}
}
}
}
}
}
@ -773,7 +821,7 @@ namespace AssetStudio
FbxNode* pNode = (FbxNode*)frameToNode[frame];
FbxMesh* pMesh = pNode->GetMesh();
FbxBlendShape* lBlendShape = FbxBlendShape::Create(pScene, pNode->GetName());
FbxBlendShape* lBlendShape = FbxBlendShape::Create(pScene, pMesh->GetNameOnly() + FbxString("BlendShape"));
pMesh->AddDeformer(lBlendShape);
for (int i = 0; i < morph->Channels->Count; i++)
@ -791,7 +839,7 @@ namespace AssetStudio
for each(ImportedMorphKeyframe^ keyframe in channel->KeyframeList)
{
FbxShape* lShape = FbxShape::Create(pScene, "");
FbxShape* lShape = FbxShape::Create(pScene, FbxString(keyframe->Weight));
lBlendShapeChannel->AddTargetShape(lShape, keyframe->Weight);
auto vectorCount = pMesh->GetControlPointsCount();

View File

@ -21,6 +21,7 @@ namespace AssetStudio
private Dictionary<uint, string> bonePathHash = new Dictionary<uint, string>();
private Dictionary<Texture2D, string> textureNameDictionary = new Dictionary<Texture2D, string>();
private Dictionary<Transform, ImportedFrame> transformDictionary = new Dictionary<Transform, ImportedFrame>();
Dictionary<uint, string> morphChannelNames = new Dictionary<uint, string>();
public ModelConverter(GameObject m_GameObject, AnimationClip[] animationList = null)
{
@ -444,6 +445,9 @@ namespace AssetStudio
var channel = new ImportedMorphChannel();
morph.Channels.Add(channel);
var shapeChannel = mesh.m_Shapes.channels[i];
morphChannelNames.Add(shapeChannel.nameHash, shapeChannel.name);
channel.Name = shapeChannel.name;
channel.KeyframeList = new List<ImportedMorphKeyframe>(shapeChannel.frameCount);
var frameEnd = shapeChannel.frameIndex + shapeChannel.frameCount;
@ -773,6 +777,31 @@ namespace AssetStudio
}
}
}
foreach (var m_FloatCurve in animationClip.m_FloatCurves)
{
if (m_FloatCurve.classID == ClassIDType.SkinnedMeshRenderer) //BlendShape
{
var channelName = m_FloatCurve.attribute;
int dotPos = channelName.IndexOf('.');
if (dotPos >= 0)
{
channelName = channelName.Substring(dotPos + 1);
}
var path = FixBonePath(m_FloatCurve.path);
if (string.IsNullOrEmpty(path))
{
path = GetPathByChannelName(channelName);
}
var track = iAnim.FindTrack(path);
track.BlendShape = new ImportedBlendShape();
track.BlendShape.ChannelName = channelName;
foreach (var m_Curve in m_FloatCurve.curve.m_Curve)
{
track.BlendShape.Keyframes.Add(new ImportedKeyframe<float>(m_Curve.time, m_Curve.value));
}
}
}
}
else
{
@ -822,6 +851,26 @@ namespace AssetStudio
private void ReadCurveData(ImportedKeyframedAnimation iAnim, AnimationClipBindingConstant m_ClipBindingConstant, int index, float time, float[] data, int offset, ref int curveIndex)
{
var binding = m_ClipBindingConstant.FindBinding(index);
if (binding.typeID == ClassIDType.SkinnedMeshRenderer) //BlendShape
{
var channelName = GetChannelNameFromHash(binding.attribute);
int dotPos = channelName.IndexOf('.');
if (dotPos >= 0)
{
channelName = channelName.Substring(dotPos + 1);
}
var bPath = FixBonePath(GetPathFromHash(binding.path));
if (string.IsNullOrEmpty(bPath))
{
bPath = GetPathByChannelName(channelName);
}
var bTrack = iAnim.FindTrack(bPath);
bTrack.BlendShape = new ImportedBlendShape();
bTrack.BlendShape.ChannelName = channelName;
bTrack.BlendShape.Keyframes.Add(new ImportedKeyframe<float>(time, data[curveIndex++ + offset]));
return;
}
if (binding.path == 0)
{
curveIndex++;
@ -868,7 +917,6 @@ namespace AssetStudio
)));
break;
default:
//track.Curve.Add(new ImportedKeyframe<float>(time, data[curveIndex++]));
curveIndex++;
break;
}
@ -974,5 +1022,32 @@ namespace AssetStudio
}
}
}
private string GetPathByChannelName(string channelName)
{
foreach (var morph in MorphList)
{
foreach (var channel in morph.Channels)
{
if (channel.Name == channelName)
{
return morph.Path;
}
}
}
return null;
}
private string GetChannelNameFromHash(uint attribute)
{
if (morphChannelNames.TryGetValue(attribute, out var name))
{
return name;
}
else
{
return null;
}
}
}
}