mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-06-03 00:58:13 -04:00
Prototype animation export
This commit is contained in:
parent
4bcbdbc57d
commit
0b111d5f79
@ -7,6 +7,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudio", "AssetStudio\
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudio-x86", "AssetStudio\AssetStudio-x86.csproj", "{F5E07FB2-95E4-417F-943F-D439D9A03BBA}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssetStudioFBX", "AssetStudioFBX\AssetStudioFBX.vcxproj", "{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudioUtility", "AssetStudioUtility\AssetStudioUtility.csproj", "{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssetStudioFBX-x86", "AssetStudioFBX\AssetStudioFBX-x86.vcxproj", "{276DE52E-3FFE-4C3D-9076-62BCB7A5B991}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -21,6 +27,18 @@ Global
|
||||
{F5E07FB2-95E4-417F-943F-D439D9A03BBA}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{F5E07FB2-95E4-417F-943F-D439D9A03BBA}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{F5E07FB2-95E4-417F-943F-D439D9A03BBA}.Release|Any CPU.Build.0 = Release|x86
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Release|Any CPU.Build.0 = Release|x64
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{276DE52E-3FFE-4C3D-9076-62BCB7A5B991}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{276DE52E-3FFE-4C3D-9076-62BCB7A5B991}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{276DE52E-3FFE-4C3D-9076-62BCB7A5B991}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{276DE52E-3FFE-4C3D-9076-62BCB7A5B991}.Release|Any CPU.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -167,6 +167,7 @@
|
||||
<Compile Include="StudioClasses\ClassStruct.cs" />
|
||||
<Compile Include="StudioClasses\FBXExporter.cs" />
|
||||
<Compile Include="StudioClasses\BuildTarget.cs" />
|
||||
<Compile Include="StudioClasses\ModelConverter.cs" />
|
||||
<Compile Include="StudioClasses\ShaderResource.Designer.cs">
|
||||
<DependentUpon>ShaderResource.resx</DependentUpon>
|
||||
<AutoGen>True</AutoGen>
|
||||
@ -264,6 +265,16 @@
|
||||
<ItemGroup>
|
||||
<None Include="Resources\preview.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudioFBX\AssetStudioFBX-x86.vcxproj">
|
||||
<Project>{276de52e-3ffe-4c3d-9076-62bcb7a5b991}</Project>
|
||||
<Name>AssetStudioFBX-x86</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj">
|
||||
<Project>{9131c403-7fe8-444d-9af5-5fe5df76ff24}</Project>
|
||||
<Name>AssetStudioUtility</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy /y "$(ProjectDir)Library" "$(TargetDir)"
|
||||
|
@ -205,6 +205,7 @@
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="StudioClasses\AssetsFile.cs" />
|
||||
<Compile Include="StudioClasses\ModelConverter.cs" />
|
||||
<Compile Include="StudioClasses\WebFile.cs" />
|
||||
<Compile Include="AssetStudioForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
@ -264,6 +265,16 @@
|
||||
<ItemGroup>
|
||||
<None Include="Resources\preview.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudioFBX\AssetStudioFBX.vcxproj">
|
||||
<Project>{4f8ef5ef-732b-49cf-9eb3-b23e19ae6267}</Project>
|
||||
<Name>AssetStudioFBX</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj">
|
||||
<Project>{9131c403-7fe8-444d-9af5-5fe5df76ff24}</Project>
|
||||
<Name>AssetStudioUtility</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy /y "$(ProjectDir)Library" "$(TargetDir)"
|
||||
|
20
AssetStudio/AssetStudioForm.Designer.cs
generated
20
AssetStudio/AssetStudioForm.Designer.cs
generated
@ -103,6 +103,8 @@
|
||||
this.treeTip = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.showOriginalFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.animatorWithAnimationClipToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.menuStrip1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
@ -317,7 +319,9 @@
|
||||
this.exportToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.exportAllAssetsMenuItem,
|
||||
this.exportSelectedAssetsMenuItem,
|
||||
this.exportFilteredAssetsMenuItem});
|
||||
this.exportFilteredAssetsMenuItem,
|
||||
this.toolStripSeparator1,
|
||||
this.animatorWithAnimationClipToolStripMenuItem});
|
||||
this.exportToolStripMenuItem.Name = "exportToolStripMenuItem";
|
||||
this.exportToolStripMenuItem.Size = new System.Drawing.Size(58, 21);
|
||||
this.exportToolStripMenuItem.Text = "Export";
|
||||
@ -837,6 +841,18 @@
|
||||
this.showOriginalFileToolStripMenuItem.Text = "show original file";
|
||||
this.showOriginalFileToolStripMenuItem.Click += new System.EventHandler(this.showOriginalFileToolStripMenuItem_Click);
|
||||
//
|
||||
// toolStripSeparator1
|
||||
//
|
||||
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
||||
this.toolStripSeparator1.Size = new System.Drawing.Size(162, 6);
|
||||
//
|
||||
// animatorWithAnimationClipToolStripMenuItem
|
||||
//
|
||||
this.animatorWithAnimationClipToolStripMenuItem.Name = "animatorWithAnimationClipToolStripMenuItem";
|
||||
this.animatorWithAnimationClipToolStripMenuItem.Size = new System.Drawing.Size(240, 22);
|
||||
this.animatorWithAnimationClipToolStripMenuItem.Text = "Export Animator with AnimationClip";
|
||||
this.animatorWithAnimationClipToolStripMenuItem.Click += new System.EventHandler(this.ExportAnimatorwithAnimationClip_Click);
|
||||
//
|
||||
// AssetStudioForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
@ -956,6 +972,8 @@
|
||||
private OpenTK.GLControl glControl1;
|
||||
private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
|
||||
private System.Windows.Forms.ToolStripMenuItem showOriginalFileToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
|
||||
private System.Windows.Forms.ToolStripMenuItem animatorWithAnimationClipToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1025,10 +1025,20 @@ namespace AssetStudio
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusStripUpdate("Unsupported sprite for preview");
|
||||
StatusStripUpdate("Unsupported sprite for preview.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ClassIDReference.Animator:
|
||||
{
|
||||
StatusStripUpdate("Can be exported as a FBX file.");
|
||||
break;
|
||||
}
|
||||
case ClassIDReference.AnimationClip:
|
||||
{
|
||||
StatusStripUpdate("Select AnimationClip with selecting Animator to export");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
var str = asset.ViewStruct();
|
||||
@ -1523,6 +1533,12 @@ namespace AssetStudio
|
||||
exportedCount++;
|
||||
}
|
||||
break;
|
||||
case ClassIDReference.Animator:
|
||||
if (ExportAnimator(asset, exportpath))
|
||||
{
|
||||
exportedCount++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ExportRawFile(asset, exportpath))
|
||||
{
|
||||
@ -1853,5 +1869,41 @@ namespace AssetStudio
|
||||
glControl1.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void ExportAnimatorwithAnimationClip_Click(object sender, EventArgs e)
|
||||
{
|
||||
AssetPreloadData animator = null;
|
||||
List<AssetPreloadData> animationList = new List<AssetPreloadData>();
|
||||
for (int i = 0; i < assetListView.SelectedIndices.Count; i++)
|
||||
{
|
||||
var index = assetListView.SelectedIndices[i];
|
||||
var asset = (AssetPreloadData)assetListView.Items[index];
|
||||
if (asset.Type2 == 95) //Animator
|
||||
{
|
||||
animator = asset;
|
||||
}
|
||||
else if (asset.Type2 == 74) //AnimationClip
|
||||
{
|
||||
animationList.Add(asset);
|
||||
}
|
||||
}
|
||||
|
||||
if (animator != null)
|
||||
{
|
||||
var saveFolderDialog1 = new OpenFolderDialog();
|
||||
if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
var savePath = saveFolderDialog1.Folder;
|
||||
string exportpath = savePath + "\\Animator\\";
|
||||
SetProgressBarValue(0);
|
||||
SetProgressBarMaximum(1);
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
StatusStripUpdate(ExportAnimator(animator, animationList, exportpath) ? "Successfully exported" : "Nothing exported.");
|
||||
ProgressBarPerformStep();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ namespace AssetStudio
|
||||
{
|
||||
public class GameObject : TreeNode
|
||||
{
|
||||
public AssetPreloadData asset;
|
||||
public List<PPtr> m_Components = new List<PPtr>();
|
||||
public PPtr m_Transform;
|
||||
public PPtr m_MeshRenderer;
|
||||
@ -24,6 +25,7 @@ namespace AssetStudio
|
||||
{
|
||||
if (preloadData != null)
|
||||
{
|
||||
asset = preloadData;
|
||||
var sourceFile = preloadData.sourceFile;
|
||||
var reader = preloadData.InitReader();
|
||||
|
||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using SharpDX;
|
||||
|
||||
/*Notes about handedness
|
||||
Converting from left-handed to right-handed and vice versa requires either:
|
||||
@ -122,6 +123,8 @@ namespace AssetStudio
|
||||
public float[] m_UV3;
|
||||
public float[] m_UV4;
|
||||
public float[] m_Tangents;
|
||||
public uint[] m_BoneNameHashes;
|
||||
public BlendShapeData m_Shapes;
|
||||
|
||||
public class SubMesh
|
||||
{
|
||||
@ -166,6 +169,100 @@ namespace AssetStudio
|
||||
public byte m_BitSize;
|
||||
}
|
||||
|
||||
public class BlendShapeData
|
||||
{
|
||||
public class BlendShapeVertex
|
||||
{
|
||||
public Vector3 vertex { get; set; }
|
||||
public Vector3 normal { get; set; }
|
||||
public Vector3 tangent { get; set; }
|
||||
public uint index { get; set; }
|
||||
|
||||
public BlendShapeVertex() { }
|
||||
|
||||
public BlendShapeVertex(EndianBinaryReader reader)
|
||||
{
|
||||
vertex = reader.ReadVector3();
|
||||
normal = reader.ReadVector3();
|
||||
tangent = reader.ReadVector3();
|
||||
index = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public class MeshBlendShape
|
||||
{
|
||||
public uint firstVertex { get; set; }
|
||||
public uint vertexCount { get; set; }
|
||||
public bool hasNormals { get; set; }
|
||||
public bool hasTangents { get; set; }
|
||||
|
||||
public MeshBlendShape() { }
|
||||
|
||||
public MeshBlendShape(EndianBinaryReader reader)
|
||||
{
|
||||
firstVertex = reader.ReadUInt32();
|
||||
vertexCount = reader.ReadUInt32();
|
||||
hasNormals = reader.ReadBoolean();
|
||||
hasTangents = reader.ReadBoolean();
|
||||
reader.ReadBytes(2);
|
||||
}
|
||||
}
|
||||
|
||||
public class MeshBlendShapeChannel
|
||||
{
|
||||
public string name { get; set; }
|
||||
public uint nameHash { get; set; }
|
||||
public int frameIndex { get; set; }
|
||||
public int frameCount { get; set; }
|
||||
|
||||
public MeshBlendShapeChannel() { }
|
||||
|
||||
public MeshBlendShapeChannel(EndianBinaryReader reader)
|
||||
{
|
||||
name = reader.ReadStringToNull();
|
||||
nameHash = reader.ReadUInt32();
|
||||
frameIndex = reader.ReadInt32();
|
||||
frameCount = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public List<BlendShapeVertex> vertices { get; set; }
|
||||
public List<MeshBlendShape> shapes { get; set; }
|
||||
public List<MeshBlendShapeChannel> channels { get; set; }
|
||||
public List<float> fullWeights { get; set; }
|
||||
|
||||
public BlendShapeData(EndianBinaryReader reader)
|
||||
{
|
||||
int numVerts = reader.ReadInt32();
|
||||
vertices = new List<BlendShapeVertex>(numVerts);
|
||||
for (int i = 0; i < numVerts; i++)
|
||||
{
|
||||
vertices.Add(new BlendShapeVertex(reader));
|
||||
}
|
||||
|
||||
int numShapes = reader.ReadInt32();
|
||||
shapes = new List<MeshBlendShape>(numShapes);
|
||||
for (int i = 0; i < numShapes; i++)
|
||||
{
|
||||
shapes.Add(new MeshBlendShape(reader));
|
||||
}
|
||||
|
||||
int numChannels = reader.ReadInt32();
|
||||
channels = new List<MeshBlendShapeChannel>(numChannels);
|
||||
for (int i = 0; i < numChannels; i++)
|
||||
{
|
||||
channels.Add(new MeshBlendShapeChannel(reader));
|
||||
}
|
||||
|
||||
int numWeights = reader.ReadInt32();
|
||||
fullWeights = new List<float>(numWeights);
|
||||
for (int i = 0; i < numWeights; i++)
|
||||
{
|
||||
fullWeights.Add(reader.ReadSingle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float bytesToFloat(byte[] inputBytes)
|
||||
{
|
||||
float result = 0;
|
||||
@ -177,7 +274,7 @@ namespace AssetStudio
|
||||
result = inputBytes[0] / 255.0f;
|
||||
break;
|
||||
case 2:
|
||||
result = Half.ToHalf(inputBytes, 0);
|
||||
result = System.Half.ToHalf(inputBytes, 0);
|
||||
break;
|
||||
case 4:
|
||||
result = BitConverter.ToSingle(inputBytes, 0);
|
||||
@ -420,25 +517,7 @@ namespace AssetStudio
|
||||
#region BlendShapeData and BindPose for 4.3.0 and later
|
||||
else if (version[0] >= 5 || (version[0] == 4 && version[1] >= 3))
|
||||
{
|
||||
int m_ShapeVertices_size = reader.ReadInt32();
|
||||
if (m_ShapeVertices_size > 0)
|
||||
{
|
||||
//bool stop = true;
|
||||
}
|
||||
reader.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index
|
||||
|
||||
int shapes_size = reader.ReadInt32();
|
||||
reader.Position += shapes_size * 12; //uint firstVertex, vertexCount; bool hasNormals, hasTangents
|
||||
|
||||
int channels_size = reader.ReadInt32();
|
||||
for (int c = 0; c < channels_size; c++)
|
||||
{
|
||||
string channel_name = reader.ReadAlignedString();
|
||||
reader.Position += 12; //uint nameHash; int frameIndex, frameCount
|
||||
}
|
||||
|
||||
int fullWeights_size = reader.ReadInt32();
|
||||
reader.Position += fullWeights_size * 4; //floats
|
||||
m_Shapes = new BlendShapeData(reader);//TODO 4.3 down
|
||||
|
||||
m_BindPose = new float[reader.ReadInt32()][,];
|
||||
for (int i = 0; i < m_BindPose.Length; i++)
|
||||
@ -451,7 +530,11 @@ namespace AssetStudio
|
||||
}
|
||||
|
||||
int m_BoneNameHashes_size = reader.ReadInt32();
|
||||
reader.Position += m_BoneNameHashes_size * 4; //uints
|
||||
m_BoneNameHashes = new uint[m_BoneNameHashes_size];
|
||||
for (int i = 0; i < m_BoneNameHashes_size; i++)
|
||||
{
|
||||
m_BoneNameHashes[i] = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
uint m_RootBoneNameHash = reader.ReadUInt32();
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
class MeshRenderer
|
||||
public class MeshRenderer
|
||||
{
|
||||
public PPtr m_GameObject;
|
||||
public bool m_Enabled;
|
||||
@ -15,6 +15,8 @@ namespace AssetStudio
|
||||
public ushort m_LightmapIndexDynamic;
|
||||
public PPtr[] m_Materials;
|
||||
|
||||
protected MeshRenderer() { }
|
||||
|
||||
public MeshRenderer(AssetPreloadData preloadData)
|
||||
{
|
||||
var sourceFile = preloadData.sourceFile;
|
||||
|
@ -5,17 +5,11 @@ using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class SkinnedMeshRenderer
|
||||
public class SkinnedMeshRenderer : MeshRenderer
|
||||
{
|
||||
public PPtr m_GameObject;
|
||||
public bool m_Enabled;
|
||||
public byte m_CastShadows;
|
||||
public bool m_ReceiveShadows;
|
||||
public ushort m_LightmapIndex;
|
||||
public ushort m_LightmapIndexDynamic;
|
||||
public PPtr[] m_Materials;
|
||||
public PPtr m_Mesh;
|
||||
public PPtr[] m_Bones;
|
||||
public List<float> m_BlendShapeWeights;
|
||||
|
||||
public SkinnedMeshRenderer(AssetPreloadData preloadData)
|
||||
{
|
||||
@ -126,13 +120,17 @@ namespace AssetStudio
|
||||
}
|
||||
else
|
||||
{
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3))
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3))//4.3 and up
|
||||
{
|
||||
int m_BlendShapeWeights = reader.ReadInt32();
|
||||
reader.Position += m_BlendShapeWeights * 4; //floats
|
||||
int numBSWeights = reader.ReadInt32();
|
||||
m_BlendShapeWeights = new List<float>(numBSWeights);
|
||||
for (int i = 0; i < numBSWeights; i++)
|
||||
{
|
||||
m_BlendShapeWeights.Add(reader.ReadSingle());
|
||||
}
|
||||
}
|
||||
|
||||
if (version[0] > 4 || (version[0] >= 3 && version[1] >= 5))
|
||||
/*if (version[0] > 4 || (version[0] >= 3 && version[1] >= 5))
|
||||
{
|
||||
PPtr m_RootBone = sourceFile.ReadPPtr();
|
||||
}
|
||||
@ -143,7 +141,7 @@ namespace AssetStudio
|
||||
float[] m_Center = { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() };
|
||||
float[] m_Extent = { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() };
|
||||
bool m_DirtyAABB = reader.ReadBoolean();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
177
AssetStudio/ExportOptions.Designer.cs
generated
177
AssetStudio/ExportOptions.Designer.cs
generated
@ -54,12 +54,26 @@
|
||||
this.topng = new System.Windows.Forms.RadioButton();
|
||||
this.tobmp = new System.Windows.Forms.RadioButton();
|
||||
this.converttexture = new System.Windows.Forms.CheckBox();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.compatibility = new System.Windows.Forms.CheckBox();
|
||||
this.flatInbetween = new System.Windows.Forms.CheckBox();
|
||||
this.boneSize = new System.Windows.Forms.NumericUpDown();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.skins = new System.Windows.Forms.CheckBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.filterPrecision = new System.Windows.Forms.NumericUpDown();
|
||||
this.allBones = new System.Windows.Forms.CheckBox();
|
||||
this.allFrames = new System.Windows.Forms.CheckBox();
|
||||
this.EulerFilter = new System.Windows.Forms.CheckBox();
|
||||
this.includeBox.SuspendLayout();
|
||||
this.geometryBox.SuspendLayout();
|
||||
this.advancedBox.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.scaleFactor)).BeginInit();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.boneSize)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.filterPrecision)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// includeBox
|
||||
@ -204,7 +218,7 @@
|
||||
this.advancedBox.Controls.Add(this.upAxis);
|
||||
this.advancedBox.Controls.Add(this.scaleFactor);
|
||||
this.advancedBox.Controls.Add(this.scaleLabel);
|
||||
this.advancedBox.Location = new System.Drawing.Point(12, 284);
|
||||
this.advancedBox.Location = new System.Drawing.Point(12, 285);
|
||||
this.advancedBox.Name = "advancedBox";
|
||||
this.advancedBox.Size = new System.Drawing.Size(249, 78);
|
||||
this.advancedBox.TabIndex = 5;
|
||||
@ -260,7 +274,7 @@
|
||||
//
|
||||
// fbxOKbutton
|
||||
//
|
||||
this.fbxOKbutton.Location = new System.Drawing.Point(332, 364);
|
||||
this.fbxOKbutton.Location = new System.Drawing.Point(339, 369);
|
||||
this.fbxOKbutton.Name = "fbxOKbutton";
|
||||
this.fbxOKbutton.Size = new System.Drawing.Size(75, 21);
|
||||
this.fbxOKbutton.TabIndex = 6;
|
||||
@ -271,7 +285,7 @@
|
||||
// fbxCancel
|
||||
//
|
||||
this.fbxCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.fbxCancel.Location = new System.Drawing.Point(420, 364);
|
||||
this.fbxCancel.Location = new System.Drawing.Point(420, 369);
|
||||
this.fbxCancel.Name = "fbxCancel";
|
||||
this.fbxCancel.Size = new System.Drawing.Size(75, 21);
|
||||
this.fbxCancel.TabIndex = 7;
|
||||
@ -282,7 +296,7 @@
|
||||
// showExpOpt
|
||||
//
|
||||
this.showExpOpt.AutoSize = true;
|
||||
this.showExpOpt.Location = new System.Drawing.Point(12, 367);
|
||||
this.showExpOpt.Location = new System.Drawing.Point(12, 372);
|
||||
this.showExpOpt.Name = "showExpOpt";
|
||||
this.showExpOpt.Size = new System.Drawing.Size(222, 16);
|
||||
this.showExpOpt.TabIndex = 8;
|
||||
@ -296,7 +310,7 @@
|
||||
this.groupBox1.Controls.Add(this.converttexture);
|
||||
this.groupBox1.Location = new System.Drawing.Point(267, 12);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(228, 349);
|
||||
this.groupBox1.Size = new System.Drawing.Size(228, 140);
|
||||
this.groupBox1.TabIndex = 9;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Convert";
|
||||
@ -306,7 +320,7 @@
|
||||
this.convertAudio.AutoSize = true;
|
||||
this.convertAudio.Checked = true;
|
||||
this.convertAudio.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.convertAudio.Location = new System.Drawing.Point(8, 81);
|
||||
this.convertAudio.Location = new System.Drawing.Point(6, 78);
|
||||
this.convertAudio.Name = "convertAudio";
|
||||
this.convertAudio.Size = new System.Drawing.Size(198, 28);
|
||||
this.convertAudio.TabIndex = 6;
|
||||
@ -360,20 +374,152 @@
|
||||
this.converttexture.AutoSize = true;
|
||||
this.converttexture.Checked = true;
|
||||
this.converttexture.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.converttexture.Location = new System.Drawing.Point(8, 20);
|
||||
this.converttexture.Location = new System.Drawing.Point(6, 20);
|
||||
this.converttexture.Name = "converttexture";
|
||||
this.converttexture.Size = new System.Drawing.Size(192, 16);
|
||||
this.converttexture.TabIndex = 1;
|
||||
this.converttexture.Text = "Convert Texture (If support)";
|
||||
this.converttexture.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.compatibility);
|
||||
this.groupBox2.Controls.Add(this.flatInbetween);
|
||||
this.groupBox2.Controls.Add(this.boneSize);
|
||||
this.groupBox2.Controls.Add(this.label2);
|
||||
this.groupBox2.Controls.Add(this.skins);
|
||||
this.groupBox2.Controls.Add(this.label1);
|
||||
this.groupBox2.Controls.Add(this.filterPrecision);
|
||||
this.groupBox2.Controls.Add(this.allBones);
|
||||
this.groupBox2.Controls.Add(this.allFrames);
|
||||
this.groupBox2.Controls.Add(this.EulerFilter);
|
||||
this.groupBox2.Location = new System.Drawing.Point(267, 158);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(228, 205);
|
||||
this.groupBox2.TabIndex = 11;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Animator";
|
||||
//
|
||||
// compatibility
|
||||
//
|
||||
this.compatibility.AutoSize = true;
|
||||
this.compatibility.Location = new System.Drawing.Point(6, 177);
|
||||
this.compatibility.Name = "compatibility";
|
||||
this.compatibility.Size = new System.Drawing.Size(102, 16);
|
||||
this.compatibility.TabIndex = 13;
|
||||
this.compatibility.Text = "compatibility";
|
||||
this.compatibility.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// flatInbetween
|
||||
//
|
||||
this.flatInbetween.AutoSize = true;
|
||||
this.flatInbetween.Location = new System.Drawing.Point(6, 155);
|
||||
this.flatInbetween.Name = "flatInbetween";
|
||||
this.flatInbetween.Size = new System.Drawing.Size(102, 16);
|
||||
this.flatInbetween.TabIndex = 12;
|
||||
this.flatInbetween.Text = "flatInbetween";
|
||||
this.flatInbetween.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// boneSize
|
||||
//
|
||||
this.boneSize.Location = new System.Drawing.Point(65, 128);
|
||||
this.boneSize.Name = "boneSize";
|
||||
this.boneSize.Size = new System.Drawing.Size(46, 21);
|
||||
this.boneSize.TabIndex = 11;
|
||||
this.boneSize.Value = new decimal(new int[] {
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(6, 130);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(53, 12);
|
||||
this.label2.TabIndex = 10;
|
||||
this.label2.Text = "boneSize";
|
||||
//
|
||||
// skins
|
||||
//
|
||||
this.skins.AutoSize = true;
|
||||
this.skins.Checked = true;
|
||||
this.skins.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.skins.Location = new System.Drawing.Point(6, 105);
|
||||
this.skins.Name = "skins";
|
||||
this.skins.Size = new System.Drawing.Size(54, 16);
|
||||
this.skins.TabIndex = 8;
|
||||
this.skins.Text = "skins";
|
||||
this.skins.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(26, 39);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(95, 12);
|
||||
this.label1.TabIndex = 7;
|
||||
this.label1.Text = "filterPrecision";
|
||||
//
|
||||
// filterPrecision
|
||||
//
|
||||
this.filterPrecision.DecimalPlaces = 2;
|
||||
this.filterPrecision.Increment = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
131072});
|
||||
this.filterPrecision.Location = new System.Drawing.Point(127, 37);
|
||||
this.filterPrecision.Name = "filterPrecision";
|
||||
this.filterPrecision.Size = new System.Drawing.Size(51, 21);
|
||||
this.filterPrecision.TabIndex = 6;
|
||||
this.filterPrecision.Value = new decimal(new int[] {
|
||||
25,
|
||||
0,
|
||||
0,
|
||||
131072});
|
||||
//
|
||||
// allBones
|
||||
//
|
||||
this.allBones.AutoSize = true;
|
||||
this.allBones.Checked = true;
|
||||
this.allBones.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.allBones.Location = new System.Drawing.Point(6, 83);
|
||||
this.allBones.Name = "allBones";
|
||||
this.allBones.Size = new System.Drawing.Size(72, 16);
|
||||
this.allBones.TabIndex = 5;
|
||||
this.allBones.Text = "allBones";
|
||||
this.allBones.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// allFrames
|
||||
//
|
||||
this.allFrames.AutoSize = true;
|
||||
this.allFrames.Location = new System.Drawing.Point(6, 61);
|
||||
this.allFrames.Name = "allFrames";
|
||||
this.allFrames.Size = new System.Drawing.Size(78, 16);
|
||||
this.allFrames.TabIndex = 4;
|
||||
this.allFrames.Text = "allFrames";
|
||||
this.allFrames.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// EulerFilter
|
||||
//
|
||||
this.EulerFilter.AutoSize = true;
|
||||
this.EulerFilter.Location = new System.Drawing.Point(6, 20);
|
||||
this.EulerFilter.Name = "EulerFilter";
|
||||
this.EulerFilter.Size = new System.Drawing.Size(90, 16);
|
||||
this.EulerFilter.TabIndex = 3;
|
||||
this.EulerFilter.Text = "EulerFilter";
|
||||
this.EulerFilter.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ExportOptions
|
||||
//
|
||||
this.AcceptButton = this.fbxOKbutton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.fbxCancel;
|
||||
this.ClientSize = new System.Drawing.Size(513, 392);
|
||||
this.ClientSize = new System.Drawing.Size(508, 398);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Controls.Add(this.showExpOpt);
|
||||
this.Controls.Add(this.fbxCancel);
|
||||
@ -399,6 +545,10 @@
|
||||
this.groupBox1.PerformLayout();
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.boneSize)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.filterPrecision)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
@ -432,5 +582,16 @@
|
||||
private System.Windows.Forms.RadioButton tobmp;
|
||||
private System.Windows.Forms.CheckBox convertAudio;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.CheckBox compatibility;
|
||||
private System.Windows.Forms.CheckBox flatInbetween;
|
||||
private System.Windows.Forms.NumericUpDown boneSize;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.CheckBox skins;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.NumericUpDown filterPrecision;
|
||||
private System.Windows.Forms.CheckBox allBones;
|
||||
private System.Windows.Forms.CheckBox allFrames;
|
||||
private System.Windows.Forms.CheckBox EulerFilter;
|
||||
}
|
||||
}
|
@ -36,6 +36,14 @@ namespace AssetStudio
|
||||
break;
|
||||
}
|
||||
}
|
||||
EulerFilter.Checked = (bool)Properties.Settings.Default["EulerFilter"];
|
||||
filterPrecision.Value = (decimal)Properties.Settings.Default["filterPrecision"];
|
||||
allFrames.Checked = (bool)Properties.Settings.Default["allFrames"];
|
||||
allBones.Checked = (bool)Properties.Settings.Default["allBones"];
|
||||
skins.Checked = (bool)Properties.Settings.Default["skins"];
|
||||
boneSize.Value = (decimal)Properties.Settings.Default["boneSize"];
|
||||
flatInbetween.Checked = (bool)Properties.Settings.Default["flatInbetween"];
|
||||
compatibility.Checked = (bool)Properties.Settings.Default["compatibility"];
|
||||
}
|
||||
|
||||
private void exportOpnions_CheckedChanged(object sender, EventArgs e)
|
||||
@ -63,6 +71,14 @@ namespace AssetStudio
|
||||
break;
|
||||
}
|
||||
}
|
||||
Properties.Settings.Default["EulerFilter"] = EulerFilter.Checked;
|
||||
Properties.Settings.Default["filterPrecision"] = filterPrecision.Value;
|
||||
Properties.Settings.Default["allFrames"] = allFrames.Checked;
|
||||
Properties.Settings.Default["allBones"] = allBones.Checked;
|
||||
Properties.Settings.Default["skins"] = skins.Checked;
|
||||
Properties.Settings.Default["boneSize"] = boneSize.Value;
|
||||
Properties.Settings.Default["flatInbetween"] = flatInbetween.Checked;
|
||||
Properties.Settings.Default["compatibility"] = compatibility.Checked;
|
||||
Properties.Settings.Default.Save();
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
|
BIN
AssetStudio/Library/SharpDX.dll
Normal file
BIN
AssetStudio/Library/SharpDX.dll
Normal file
Binary file not shown.
BIN
AssetStudio/Library/x64/libfbxsdk.dll
Normal file
BIN
AssetStudio/Library/x64/libfbxsdk.dll
Normal file
Binary file not shown.
BIN
AssetStudio/Library/x86/libfbxsdk.dll
Normal file
BIN
AssetStudio/Library/x86/libfbxsdk.dll
Normal file
Binary file not shown.
96
AssetStudio/Properties/Settings.Designer.cs
generated
96
AssetStudio/Properties/Settings.Designer.cs
generated
@ -238,5 +238,101 @@ namespace AssetStudio.Properties {
|
||||
this["displayOriginalName"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool EulerFilter {
|
||||
get {
|
||||
return ((bool)(this["EulerFilter"]));
|
||||
}
|
||||
set {
|
||||
this["EulerFilter"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("0.25")]
|
||||
public decimal filterPrecision {
|
||||
get {
|
||||
return ((decimal)(this["filterPrecision"]));
|
||||
}
|
||||
set {
|
||||
this["filterPrecision"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool allFrames {
|
||||
get {
|
||||
return ((bool)(this["allFrames"]));
|
||||
}
|
||||
set {
|
||||
this["allFrames"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool allBones {
|
||||
get {
|
||||
return ((bool)(this["allBones"]));
|
||||
}
|
||||
set {
|
||||
this["allBones"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool skins {
|
||||
get {
|
||||
return ((bool)(this["skins"]));
|
||||
}
|
||||
set {
|
||||
this["skins"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("10")]
|
||||
public decimal boneSize {
|
||||
get {
|
||||
return ((decimal)(this["boneSize"]));
|
||||
}
|
||||
set {
|
||||
this["boneSize"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool flatInbetween {
|
||||
get {
|
||||
return ((bool)(this["flatInbetween"]));
|
||||
}
|
||||
set {
|
||||
this["flatInbetween"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool compatibility {
|
||||
get {
|
||||
return ((bool)(this["compatibility"]));
|
||||
}
|
||||
set {
|
||||
this["compatibility"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,5 +56,29 @@
|
||||
<Setting Name="displayOriginalName" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="EulerFilter" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="filterPrecision" Type="System.Decimal" Scope="User">
|
||||
<Value Profile="(Default)">0.25</Value>
|
||||
</Setting>
|
||||
<Setting Name="allFrames" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="allBones" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="skins" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="boneSize" Type="System.Decimal" Scope="User">
|
||||
<Value Profile="(Default)">10</Value>
|
||||
</Setting>
|
||||
<Setting Name="flatInbetween" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="compatibility" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
@ -316,5 +316,39 @@ namespace AssetStudio
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ExportAnimator(AssetPreloadData animator, string exportPath)
|
||||
{
|
||||
var EulerFilter = (bool)Properties.Settings.Default["EulerFilter"];
|
||||
var filterPrecision = (float)(decimal)Properties.Settings.Default["filterPrecision"];
|
||||
var allFrames = (bool)Properties.Settings.Default["allFrames"];
|
||||
var allBones = (bool)Properties.Settings.Default["allBones"];
|
||||
var skins = (bool)Properties.Settings.Default["skins"];
|
||||
var boneSize = (int)(decimal)Properties.Settings.Default["boneSize"];
|
||||
var flatInbetween = (bool)Properties.Settings.Default["flatInbetween"];
|
||||
var compatibility = (bool)Properties.Settings.Default["compatibility"];
|
||||
var m_Animator = new Animator(animator);
|
||||
var convert = new ModelConverter(m_Animator);
|
||||
exportPath = exportPath + Studio.FixFileName(animator.Text) + ".fbx";
|
||||
Fbx.Exporter.Export(exportPath, convert, EulerFilter, filterPrecision, ".fbx", allFrames, allBones, skins, boneSize, flatInbetween, compatibility);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportAnimator(AssetPreloadData animator, List<AssetPreloadData> animations, string exportPath)
|
||||
{
|
||||
var EulerFilter = (bool)Properties.Settings.Default["EulerFilter"];
|
||||
var filterPrecision = (float)(decimal)Properties.Settings.Default["filterPrecision"];
|
||||
var allFrames = (bool)Properties.Settings.Default["allFrames"];
|
||||
var allBones = (bool)Properties.Settings.Default["allBones"];
|
||||
var skins = (bool)Properties.Settings.Default["skins"];
|
||||
var boneSize = (int)(decimal)Properties.Settings.Default["boneSize"];
|
||||
var flatInbetween = (bool)Properties.Settings.Default["flatInbetween"];
|
||||
var compatibility = (bool)Properties.Settings.Default["compatibility"];
|
||||
var m_Animator = new Animator(animator);
|
||||
var convert = new ModelConverter(m_Animator, animations);
|
||||
exportPath = exportPath + Studio.FixFileName(animator.Text) + ".fbx";
|
||||
Fbx.Exporter.Export(exportPath, convert, EulerFilter, filterPrecision, ".fbx", allFrames, allBones, skins, boneSize, flatInbetween, compatibility);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
876
AssetStudio/StudioClasses/ModelConverter.cs
Normal file
876
AssetStudio/StudioClasses/ModelConverter.cs
Normal file
@ -0,0 +1,876 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using SharpDX;
|
||||
using static AssetStudio.Studio;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
/* TODO Handle all things in one loop
|
||||
* Init with GameObject
|
||||
* Other optimization
|
||||
*/
|
||||
class ModelConverter : IImported
|
||||
{
|
||||
public List<ImportedFrame> FrameList { get; protected set; } = new List<ImportedFrame>();
|
||||
public List<ImportedMesh> MeshList { get; protected set; } = new List<ImportedMesh>();
|
||||
public List<ImportedMaterial> MaterialList { get; protected set; } = new List<ImportedMaterial>();
|
||||
public List<ImportedTexture> TextureList { get; protected set; } = new List<ImportedTexture>();
|
||||
public List<ImportedAnimation> AnimationList { get; protected set; } = new List<ImportedAnimation>();
|
||||
public List<ImportedMorph> MorphList { get; protected set; } = new List<ImportedMorph>();
|
||||
|
||||
private Avatar avatar;
|
||||
private Dictionary<uint, string> morphChannelInfo = new Dictionary<uint, string>();
|
||||
private HashSet<AssetPreloadData> animationClipHashSet = new HashSet<AssetPreloadData>();
|
||||
private Dictionary<uint, string> bonePathHash = new Dictionary<uint, string>();
|
||||
|
||||
public ModelConverter(Animator m_Animator)
|
||||
{
|
||||
InitWithAnimator(m_Animator);
|
||||
CollectAnimationClip(m_Animator);
|
||||
ConvertAnimations();
|
||||
}
|
||||
|
||||
public ModelConverter(Animator m_Animator, List<AssetPreloadData> animationList)
|
||||
{
|
||||
InitWithAnimator(m_Animator);
|
||||
foreach (var assetPreloadData in animationList)
|
||||
{
|
||||
animationClipHashSet.Add(assetPreloadData);
|
||||
}
|
||||
ConvertAnimations();
|
||||
}
|
||||
|
||||
private void InitWithAnimator(Animator m_Animator)
|
||||
{
|
||||
if (assetsfileList.TryGetPD(m_Animator.m_Avatar, out var m_Avatar))
|
||||
avatar = new Avatar(m_Avatar);
|
||||
|
||||
assetsfileList.TryGetGameObject(m_Animator.m_GameObject, out var m_GameObject);
|
||||
assetsfileList.TryGetTransform(m_GameObject.m_Transform, out var m_Transform);
|
||||
var rootTransform = m_Transform;
|
||||
while (assetsfileList.TryGetTransform(rootTransform.m_Father, out var m_Father))//Get Root Transform
|
||||
{
|
||||
rootTransform = m_Father;
|
||||
}
|
||||
|
||||
CreateBonePathHash(rootTransform);
|
||||
ConvertFrames(rootTransform, null);
|
||||
CollectMorphInfo(rootTransform);
|
||||
ConvertMeshRenderer(m_Transform);
|
||||
}
|
||||
|
||||
private void ConvertMeshRenderer(Transform m_Transform)
|
||||
{
|
||||
assetsfileList.TryGetGameObject(m_Transform.m_GameObject, out var m_GameObject);
|
||||
foreach (var m_Component in m_GameObject.m_Components)
|
||||
{
|
||||
if (assetsfileList.TryGetPD(m_Component, out var assetPreloadData))
|
||||
{
|
||||
switch (assetPreloadData.Type2)
|
||||
{
|
||||
case 23: //MeshRenderer
|
||||
{
|
||||
var m_Renderer = new MeshRenderer(assetPreloadData);
|
||||
ConvertMeshRenderer(m_Renderer);
|
||||
break;
|
||||
}
|
||||
case 137: //SkinnedMeshRenderer
|
||||
{
|
||||
var m_SkinnedMeshRenderer = new SkinnedMeshRenderer(assetPreloadData);
|
||||
ConvertMeshRenderer(m_SkinnedMeshRenderer);
|
||||
break;
|
||||
}
|
||||
case 111: //Animation
|
||||
{
|
||||
var m_Animation = new Animation(assetPreloadData);
|
||||
foreach (var animation in m_Animation.m_Animations)
|
||||
{
|
||||
if (assetsfileList.TryGetPD(animation, out var animationClip))
|
||||
{
|
||||
animationClipHashSet.Add(animationClip);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var pptr in m_Transform.m_Children)
|
||||
{
|
||||
if (assetsfileList.TryGetTransform(pptr, out var child))
|
||||
ConvertMeshRenderer(child);
|
||||
}
|
||||
}
|
||||
|
||||
private void CollectAnimationClip(Animator m_Animator)
|
||||
{
|
||||
if (assetsfileList.TryGetPD(m_Animator.m_Controller, out var assetPreloadData))
|
||||
{
|
||||
if (assetPreloadData.Type2 == 221)//AnimatorOverrideController
|
||||
{
|
||||
var m_AnimatorOverrideController = new AnimatorOverrideController(assetPreloadData);
|
||||
if (assetsfileList.TryGetPD(m_AnimatorOverrideController.m_Controller, out assetPreloadData))
|
||||
{
|
||||
var m_AnimatorController = new AnimatorController(assetPreloadData);
|
||||
foreach (var m_AnimationClip in m_AnimatorController.m_AnimationClips)
|
||||
{
|
||||
if (assetsfileList.TryGetPD(m_AnimationClip, out assetPreloadData))
|
||||
{
|
||||
animationClipHashSet.Add(assetPreloadData);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*foreach (var clip in m_AnimatorOverrideController.m_Clips)
|
||||
{
|
||||
if (assetsfileList.TryGetPD(clip[1], out assetPreloadData))
|
||||
{
|
||||
animationList.Add(new AnimationClip(assetPreloadData));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
else if (assetPreloadData.Type2 == 91)//AnimatorController
|
||||
{
|
||||
var m_AnimatorController = new AnimatorController(assetPreloadData);
|
||||
foreach (var m_AnimationClip in m_AnimatorController.m_AnimationClips)
|
||||
{
|
||||
if (assetsfileList.TryGetPD(m_AnimationClip, out assetPreloadData))
|
||||
{
|
||||
animationClipHashSet.Add(assetPreloadData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConvertFrames(Transform trans, ImportedFrame parent)
|
||||
{
|
||||
var frame = new ImportedFrame();
|
||||
assetsfileList.TryGetGameObject(trans.m_GameObject, out var m_GameObject);
|
||||
frame.Name = m_GameObject.m_Name;
|
||||
frame.InitChildren(trans.m_Children.Count);
|
||||
Quaternion mirroredRotation = new Quaternion(trans.m_LocalRotation[0], trans.m_LocalRotation[1], trans.m_LocalRotation[2], trans.m_LocalRotation[3]);
|
||||
mirroredRotation.Y *= -1;
|
||||
mirroredRotation.Z *= -1;
|
||||
var m_LocalScale = new Vector3(trans.m_LocalScale[0], trans.m_LocalScale[1], trans.m_LocalScale[2]);
|
||||
var m_LocalPosition = new Vector3(trans.m_LocalPosition[0], trans.m_LocalPosition[1], trans.m_LocalPosition[2]);
|
||||
frame.Matrix = Matrix.Scaling(m_LocalScale) * Matrix.RotationQuaternion(mirroredRotation) * Matrix.Translation(-m_LocalPosition.X, m_LocalPosition.Y, m_LocalPosition.Z);
|
||||
if (parent == null)
|
||||
{
|
||||
FrameList = new List<ImportedFrame>();
|
||||
FrameList.Add(frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.AddChild(frame);
|
||||
}
|
||||
foreach (var pptr in trans.m_Children)
|
||||
{
|
||||
if (assetsfileList.TryGetTransform(pptr, out var child))
|
||||
ConvertFrames(child, frame);
|
||||
}
|
||||
}
|
||||
|
||||
private void CollectMorphInfo(Transform m_Transform)
|
||||
{
|
||||
assetsfileList.TryGetGameObject(m_Transform.m_GameObject, out var m_GameObject);
|
||||
if (assetsfileList.TryGetPD(m_GameObject.m_SkinnedMeshRenderer, out var assetPreloadData))
|
||||
{
|
||||
var m_SkinnedMeshRenderer = new SkinnedMeshRenderer(assetPreloadData);
|
||||
if (assetsfileList.TryGetPD(m_SkinnedMeshRenderer.m_Mesh, out var MeshPD))
|
||||
{
|
||||
var mesh = new Mesh(MeshPD, true);
|
||||
foreach (var channel in mesh.m_Shapes.channels)
|
||||
{
|
||||
morphChannelInfo.Add(channel.nameHash, channel.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var pptr in m_Transform.m_Children)
|
||||
{
|
||||
if (assetsfileList.TryGetTransform(pptr, out var child))
|
||||
CollectMorphInfo(child);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ConvertMeshRenderer(MeshRenderer meshR)
|
||||
{
|
||||
var mesh = GetMesh(meshR);
|
||||
if (mesh == null)
|
||||
return;
|
||||
var iMesh = new ImportedMesh();
|
||||
assetsfileList.TryGetGameObject(meshR.m_GameObject, out var m_GameObject2);
|
||||
assetsfileList.TryGetTransform(m_GameObject2.m_Transform, out var meshTransform);
|
||||
iMesh.Name = GetTransformPath(meshTransform);
|
||||
iMesh.SubmeshList = new List<ImportedSubmesh>(mesh.m_SubMeshes.Count);
|
||||
int sum = 0;
|
||||
for (int i = 0; i < mesh.m_SubMeshes.Count; i++)
|
||||
{
|
||||
var submesh = mesh.m_SubMeshes[i];
|
||||
var iSubmesh = new ImportedSubmesh();
|
||||
iSubmesh.Index = i;
|
||||
iSubmesh.Visible = true;
|
||||
Material mat = null;
|
||||
if (i < meshR.m_Materials.Length)
|
||||
{
|
||||
if (assetsfileList.TryGetPD(meshR.m_Materials[i], out var MaterialPD))
|
||||
{
|
||||
mat = new Material(MaterialPD);
|
||||
}
|
||||
}
|
||||
ImportedMaterial iMat = ConvertMaterial(mat);
|
||||
iSubmesh.Material = iMat.Name;
|
||||
iSubmesh.VertexList = new List<ImportedVertex>((int)submesh.vertexCount);
|
||||
for (var j = mesh.m_SubMeshes[i].firstVertex; j < mesh.m_SubMeshes[i].firstVertex + mesh.m_SubMeshes[i].vertexCount; j++)
|
||||
{
|
||||
var iVertex = new ImportedVertexWithColour();
|
||||
//Vertices
|
||||
int c = 3;
|
||||
if (mesh.m_Vertices.Length == mesh.m_VertexCount * 4)
|
||||
{
|
||||
c = 4;
|
||||
}
|
||||
iVertex.Position = new Vector3(-mesh.m_Vertices[j * c], mesh.m_Vertices[j * c + 1], mesh.m_Vertices[j * c + 2]);
|
||||
//Normals
|
||||
if (mesh.m_Normals != null && mesh.m_Normals.Length > 0)
|
||||
{
|
||||
if (mesh.m_Normals.Length == mesh.m_VertexCount * 3)
|
||||
{
|
||||
c = 3;
|
||||
}
|
||||
else if (mesh.m_Normals.Length == mesh.m_VertexCount * 4)
|
||||
{
|
||||
c = 4;
|
||||
}
|
||||
iVertex.Normal = new Vector3(-mesh.m_Normals[j * c], mesh.m_Normals[j * c + 1], mesh.m_Normals[j * c + 2]);
|
||||
}
|
||||
//Colors
|
||||
if (mesh.m_Colors != null && mesh.m_Colors.Length > 0)
|
||||
{
|
||||
if (mesh.m_Colors.Length == mesh.m_VertexCount * 3)
|
||||
{
|
||||
iVertex.Colour = new Color4(mesh.m_Colors[j * 3], mesh.m_Colors[j * 3 + 1], mesh.m_Colors[j * 3 + 2], 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
iVertex.Colour = new Color4(mesh.m_Colors[j * 4], mesh.m_Colors[j * 4 + 1], mesh.m_Colors[j * 4 + 2], mesh.m_Colors[j * 4 + 3]);
|
||||
}
|
||||
}
|
||||
//UV
|
||||
if (mesh.m_UV1 != null && mesh.m_UV1.Length == mesh.m_VertexCount * 2)
|
||||
{
|
||||
iVertex.UV = new[] { mesh.m_UV1[j * 2], -mesh.m_UV1[j * 2 + 1] };
|
||||
}
|
||||
//Tangent
|
||||
if (mesh.m_Tangents != null)
|
||||
{
|
||||
iVertex.Tangent = new Vector4(-mesh.m_Tangents[j * 4], mesh.m_Tangents[j * 4 + 1], mesh.m_Tangents[j * 4 + 2], mesh.m_Tangents[j * 4 + 3]);
|
||||
}
|
||||
//BoneInfluence
|
||||
if (mesh.m_Skin.Length > 0)
|
||||
{
|
||||
var inf = mesh.m_Skin[j];
|
||||
iVertex.BoneIndices = new byte[inf.Count];
|
||||
iVertex.Weights = new float[inf.Count];
|
||||
for (var k = 0; k < inf.Count; k++)
|
||||
{
|
||||
iVertex.BoneIndices[k] = (byte)inf[k].boneIndex;
|
||||
iVertex.Weights[k] = inf[k].weight;
|
||||
}
|
||||
}
|
||||
iSubmesh.VertexList.Add(iVertex);
|
||||
}
|
||||
//Face
|
||||
int numFaces = (int)mesh.m_SubMeshes[i].indexCount / 3;
|
||||
iSubmesh.FaceList = new List<ImportedFace>(numFaces);
|
||||
var end = sum + numFaces;
|
||||
for (int f = sum; f < end; f++)
|
||||
{
|
||||
var face = new ImportedFace();
|
||||
face.VertexIndices = new int[3];
|
||||
face.VertexIndices[0] = (int)(mesh.m_Indices[f * 3 + 2] - submesh.firstVertex);
|
||||
face.VertexIndices[1] = (int)(mesh.m_Indices[f * 3 + 1] - submesh.firstVertex);
|
||||
face.VertexIndices[2] = (int)(mesh.m_Indices[f * 3] - submesh.firstVertex);
|
||||
iSubmesh.FaceList.Add(face);
|
||||
}
|
||||
sum = end;
|
||||
iMesh.SubmeshList.Add(iSubmesh);
|
||||
}
|
||||
|
||||
if (meshR is SkinnedMeshRenderer sMesh)
|
||||
{
|
||||
//Bone
|
||||
iMesh.BoneList = new List<ImportedBone>(sMesh.m_Bones.Length);
|
||||
/*if (meshR.m_Bones.Length >= 256)
|
||||
{
|
||||
throw new Exception("Too many bones (" + mesh.m_BindPose.Length + ")");
|
||||
}*/
|
||||
for (int i = 0; i < sMesh.m_Bones.Length; i++)
|
||||
{
|
||||
var bone = new ImportedBone();
|
||||
var boneHash = mesh.m_BoneNameHashes[i];
|
||||
bone.Name = GetNameFromBonePathHashes(boneHash);
|
||||
if (string.IsNullOrEmpty(bone.Name))
|
||||
{
|
||||
bone.Name = avatar?.FindBoneName(boneHash);
|
||||
}
|
||||
if (string.IsNullOrEmpty(bone.Name))
|
||||
{
|
||||
if (assetsfileList.TryGetTransform(sMesh.m_Bones[i], out var m_Transform))
|
||||
{
|
||||
assetsfileList.TryGetGameObject(m_Transform.m_GameObject, out var m_GameObject);
|
||||
bone.Name = m_GameObject.m_Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
var om = new Matrix();
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
om[x, y] = mesh.m_BindPose[i][x, y];
|
||||
}
|
||||
}
|
||||
var m = Matrix.Transpose(om);
|
||||
m.Decompose(out var s, out var q, out var t);
|
||||
t.X *= -1;
|
||||
q.Y *= -1;
|
||||
q.Z *= -1;
|
||||
bone.Matrix = Matrix.Scaling(s) * Matrix.RotationQuaternion(q) * Matrix.Translation(t);
|
||||
iMesh.BoneList.Add(bone);
|
||||
}
|
||||
|
||||
//Morphs
|
||||
if (mesh.m_Shapes.shapes.Count > 0)
|
||||
{
|
||||
ImportedMorph morph = null;
|
||||
string lastGroup = "";
|
||||
for (int i = 0; i < mesh.m_Shapes.channels.Count; i++)
|
||||
{
|
||||
string group = BlendShapeNameGroup(mesh, i);
|
||||
if (group != lastGroup)
|
||||
{
|
||||
morph = new ImportedMorph();
|
||||
MorphList.Add(morph);
|
||||
morph.Name = iMesh.Name;
|
||||
morph.ClipName = group;
|
||||
morph.Channels = new List<Tuple<float, int, int>>(mesh.m_Shapes.channels.Count);
|
||||
morph.KeyframeList = new List<ImportedMorphKeyframe>(mesh.m_Shapes.shapes.Count);
|
||||
lastGroup = group;
|
||||
}
|
||||
|
||||
morph.Channels.Add(new Tuple<float, int, int>(i < sMesh.m_BlendShapeWeights.Count ? sMesh.m_BlendShapeWeights[i] : 0f, morph.KeyframeList.Count, mesh.m_Shapes.channels[i].frameCount));
|
||||
for (int frameIdx = 0; frameIdx < mesh.m_Shapes.channels[i].frameCount; frameIdx++)
|
||||
{
|
||||
ImportedMorphKeyframe keyframe = new ImportedMorphKeyframe();
|
||||
keyframe.Name = BlendShapeNameExtension(mesh, i) + "_" + frameIdx;
|
||||
int shapeIdx = mesh.m_Shapes.channels[i].frameIndex + frameIdx;
|
||||
keyframe.VertexList = new List<ImportedVertex>((int)mesh.m_Shapes.shapes[shapeIdx].vertexCount);
|
||||
keyframe.MorphedVertexIndices = new List<ushort>((int)mesh.m_Shapes.shapes[shapeIdx].vertexCount);
|
||||
keyframe.Weight = shapeIdx < mesh.m_Shapes.fullWeights.Count ? mesh.m_Shapes.fullWeights[shapeIdx] : 100f;
|
||||
int lastVertIndex = (int)(mesh.m_Shapes.shapes[shapeIdx].firstVertex + mesh.m_Shapes.shapes[shapeIdx].vertexCount);
|
||||
for (int j = (int)mesh.m_Shapes.shapes[shapeIdx].firstVertex; j < lastVertIndex; j++)
|
||||
{
|
||||
var morphVert = mesh.m_Shapes.vertices[j];
|
||||
ImportedVertex vert = GetSourceVertex(iMesh.SubmeshList, (int)morphVert.index);
|
||||
ImportedVertex destVert = new ImportedVertex();
|
||||
Vector3 morphPos = morphVert.vertex;
|
||||
morphPos.X *= -1;
|
||||
destVert.Position = vert.Position + morphPos;
|
||||
Vector3 morphNormal = morphVert.normal;
|
||||
morphNormal.X *= -1;
|
||||
destVert.Normal = morphNormal;
|
||||
Vector4 morphTangent = new Vector4(morphVert.tangent, 0);
|
||||
morphTangent.X *= -1;
|
||||
destVert.Tangent = morphTangent;
|
||||
keyframe.VertexList.Add(destVert);
|
||||
keyframe.MorphedVertexIndices.Add((ushort)morphVert.index);
|
||||
}
|
||||
|
||||
morph.KeyframeList.Add(keyframe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MeshList.Add(iMesh);
|
||||
}
|
||||
|
||||
private Mesh GetMesh(MeshRenderer meshR)
|
||||
{
|
||||
if (meshR is SkinnedMeshRenderer sMesh)
|
||||
{
|
||||
if (assetsfileList.TryGetPD(sMesh.m_Mesh, out var MeshPD))
|
||||
{
|
||||
return new Mesh(MeshPD, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assetsfileList.TryGetGameObject(meshR.m_GameObject, out var m_GameObject);
|
||||
foreach (var m_Component in m_GameObject.m_Components)
|
||||
{
|
||||
if (assetsfileList.TryGetPD(m_Component, out var assetPreloadData))
|
||||
{
|
||||
if (assetPreloadData.Type2 == 33) //MeshFilter
|
||||
{
|
||||
var m_MeshFilter = new MeshFilter(assetPreloadData);
|
||||
if (assetsfileList.TryGetPD(m_MeshFilter.m_Mesh, out var MeshPD))
|
||||
{
|
||||
return new Mesh(MeshPD, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private string GetTransformPath(Transform meshTransform)
|
||||
{
|
||||
assetsfileList.TryGetGameObject(meshTransform.m_GameObject, out var m_GameObject);
|
||||
if (assetsfileList.TryGetTransform(meshTransform.m_Father, out var Father))
|
||||
{
|
||||
return GetTransformPath(Father) + "/" + m_GameObject.m_Name;
|
||||
}
|
||||
|
||||
return String.Empty + m_GameObject.m_Name;
|
||||
}
|
||||
|
||||
private ImportedMaterial ConvertMaterial(Material mat)
|
||||
{
|
||||
ImportedMaterial iMat;
|
||||
if (mat != null)
|
||||
{
|
||||
iMat = ImportedHelpers.FindMaterial(mat.m_Name, MaterialList);
|
||||
if (iMat != null)
|
||||
{
|
||||
return iMat;
|
||||
}
|
||||
iMat = new ImportedMaterial();
|
||||
iMat.Name = mat.m_Name;
|
||||
foreach (var col in mat.m_Colors)
|
||||
{
|
||||
var color = new Color4(col.second[0], col.second[1], col.second[2], col.second[3]);
|
||||
switch (col.first)
|
||||
{
|
||||
case "_Color":
|
||||
iMat.Diffuse = color;
|
||||
break;
|
||||
case "_SColor":
|
||||
iMat.Ambient = color;
|
||||
break;
|
||||
case "_EmissionColor":
|
||||
iMat.Emissive = color;
|
||||
break;
|
||||
case "_SpecColor":
|
||||
iMat.Specular = color;
|
||||
break;
|
||||
case "_RimColor":
|
||||
case "_OutlineColor":
|
||||
case "_ShadowColor":
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var flt in mat.m_Floats)
|
||||
{
|
||||
switch (flt.first)
|
||||
{
|
||||
case "_Shininess":
|
||||
iMat.Power = flt.second;
|
||||
break;
|
||||
case "_RimPower":
|
||||
case "_Outline":
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//textures
|
||||
iMat.Textures = new string[5];
|
||||
iMat.TexOffsets = new Vector2[5];
|
||||
iMat.TexScales = new Vector2[5];
|
||||
foreach (var texEnv in mat.m_TexEnvs)
|
||||
{
|
||||
Texture2D tex2D = null;
|
||||
if (assetsfileList.TryGetPD(texEnv.m_Texture, out var TexturePD) && TexturePD.Type2 == 28)//TODO other Texture
|
||||
{
|
||||
tex2D = new Texture2D(TexturePD, true);
|
||||
}
|
||||
|
||||
if (tex2D == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int dest = texEnv.name == "_MainTex" ? 0 : texEnv.name == "_BumpMap" ? 4 : texEnv.name.Contains("Spec") ? 2 : texEnv.name.Contains("Norm") ? 3 : -1;
|
||||
if (dest < 0 || iMat.Textures[dest] != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
iMat.Textures[dest] = TexturePD.Text + ".png";
|
||||
iMat.TexOffsets[dest] = new Vector2(texEnv.m_Offset[0], texEnv.m_Offset[1]);
|
||||
iMat.TexScales[dest] = new Vector2(texEnv.m_Scale[0], texEnv.m_Scale[1]);
|
||||
ConvertTexture2D(tex2D, iMat.Textures[dest]);
|
||||
}
|
||||
|
||||
MaterialList.Add(iMat);
|
||||
}
|
||||
else
|
||||
{
|
||||
iMat = new ImportedMaterial();
|
||||
}
|
||||
return iMat;
|
||||
}
|
||||
|
||||
private void ConvertTexture2D(Texture2D tex2D, string name)
|
||||
{
|
||||
var iTex = ImportedHelpers.FindTexture(name, TextureList);
|
||||
if (iTex != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (var memStream = new MemoryStream())
|
||||
{
|
||||
var bitmap = tex2D.ConvertToBitmap(true);
|
||||
if (bitmap != null)
|
||||
{
|
||||
bitmap.Save(memStream, ImageFormat.Png);
|
||||
memStream.Position = 0;
|
||||
iTex = new ImportedTexture(memStream, name);
|
||||
TextureList.Add(iTex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConvertAnimations()
|
||||
{
|
||||
foreach (var assetPreloadData in animationClipHashSet)
|
||||
{
|
||||
var clip = new AnimationClip(assetPreloadData);
|
||||
if (clip.m_Legacy)
|
||||
{
|
||||
var iAnim = new ImportedKeyframedAnimation();
|
||||
iAnim.Name = clip.m_Name;
|
||||
AnimationList.Add(iAnim);
|
||||
iAnim.TrackList = new List<ImportedAnimationKeyframedTrack>();
|
||||
foreach (var m_RotationCurve in clip.m_RotationCurves)
|
||||
{
|
||||
var path = m_RotationCurve.path;
|
||||
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||
var track = iAnim.FindTrack(boneName);
|
||||
if (track == null)
|
||||
{
|
||||
track = new ImportedAnimationKeyframedTrack();
|
||||
track.Name = boneName;
|
||||
iAnim.TrackList.Add(track);
|
||||
}
|
||||
foreach (var m_Curve in m_RotationCurve.curve.m_Curve)
|
||||
{
|
||||
if (!track.Keyframes.TryGetValue(m_Curve.time, out var keyFrames))
|
||||
{
|
||||
keyFrames = new ImportedAnimationKeyframe();
|
||||
track.Keyframes.Add(m_Curve.time, keyFrames);
|
||||
}
|
||||
keyFrames.Rotation = new ImportedKeyframe<Quaternion>(
|
||||
m_Curve.time,
|
||||
new Quaternion(m_Curve.value.X, -m_Curve.value.Y, -m_Curve.value.Z, m_Curve.value.W),
|
||||
new Quaternion(m_Curve.inSlope.X, -m_Curve.inSlope.Y, -m_Curve.inSlope.Z, m_Curve.inSlope.W),
|
||||
new Quaternion(m_Curve.outSlope.X, -m_Curve.outSlope.Y, -m_Curve.outSlope.Z, m_Curve.outSlope.W));
|
||||
}
|
||||
}
|
||||
foreach (var m_PositionCurve in clip.m_PositionCurves)
|
||||
{
|
||||
var path = m_PositionCurve.path;
|
||||
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||
var track = iAnim.FindTrack(boneName);
|
||||
if (track == null)
|
||||
{
|
||||
track = new ImportedAnimationKeyframedTrack();
|
||||
track.Name = boneName;
|
||||
iAnim.TrackList.Add(track);
|
||||
}
|
||||
foreach (var m_Curve in m_PositionCurve.curve.m_Curve)
|
||||
{
|
||||
if (!track.Keyframes.TryGetValue(m_Curve.time, out var keyFrames))
|
||||
{
|
||||
keyFrames = new ImportedAnimationKeyframe();
|
||||
track.Keyframes.Add(m_Curve.time, keyFrames);
|
||||
}
|
||||
keyFrames.Translation = new ImportedKeyframe<Vector3>(
|
||||
m_Curve.time,
|
||||
new Vector3(-m_Curve.value.X, m_Curve.value.Y, m_Curve.value.Z),
|
||||
new Vector3(-m_Curve.inSlope.X, m_Curve.inSlope.Y, m_Curve.inSlope.Z),
|
||||
new Vector3(-m_Curve.outSlope.X, m_Curve.outSlope.Y, m_Curve.outSlope.Z));
|
||||
}
|
||||
}
|
||||
foreach (var m_ScaleCurve in clip.m_ScaleCurves)
|
||||
{
|
||||
var path = m_ScaleCurve.path;
|
||||
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||
var track = iAnim.FindTrack(boneName);
|
||||
if (track == null)
|
||||
{
|
||||
track = new ImportedAnimationKeyframedTrack();
|
||||
track.Name = boneName;
|
||||
iAnim.TrackList.Add(track);
|
||||
}
|
||||
foreach (var m_Curve in m_ScaleCurve.curve.m_Curve)
|
||||
{
|
||||
if (!track.Keyframes.TryGetValue(m_Curve.time, out var keyFrames))
|
||||
{
|
||||
keyFrames = new ImportedAnimationKeyframe();
|
||||
track.Keyframes.Add(m_Curve.time, keyFrames);
|
||||
}
|
||||
keyFrames.Scaling = new ImportedKeyframe<Vector3>(
|
||||
m_Curve.time,
|
||||
new Vector3(m_Curve.value.X, m_Curve.value.Y, m_Curve.value.Z),
|
||||
new Vector3(m_Curve.inSlope.X, m_Curve.inSlope.Y, m_Curve.inSlope.Z),
|
||||
new Vector3(m_Curve.outSlope.X, m_Curve.outSlope.Y, m_Curve.outSlope.Z));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var iAnim = new ImportedSampledAnimation();
|
||||
iAnim.Name = clip.m_Name;
|
||||
iAnim.SampleRate = clip.m_SampleRate;
|
||||
AnimationList.Add(iAnim);
|
||||
int numTracks = (clip.m_MuscleClip.m_Clip.m_ConstantClip.data.Length + (int)clip.m_MuscleClip.m_Clip.m_DenseClip.m_CurveCount + (int)clip.m_MuscleClip.m_Clip.m_StreamedClip.curveCount + 9) / 10;
|
||||
iAnim.TrackList = new List<ImportedAnimationSampledTrack>(numTracks);
|
||||
var streamedFrames = clip.m_MuscleClip.m_Clip.m_StreamedClip.ReadData();
|
||||
float[] streamedValues = new float[clip.m_MuscleClip.m_Clip.m_StreamedClip.curveCount];
|
||||
int numFrames = Math.Max(clip.m_MuscleClip.m_Clip.m_DenseClip.m_FrameCount, streamedFrames.Count - 2);
|
||||
for (int frameIdx = 0; frameIdx < numFrames; frameIdx++)
|
||||
{
|
||||
if (1 + frameIdx < streamedFrames.Count)
|
||||
{
|
||||
for (int i = 0; i < streamedFrames[1 + frameIdx].keyList.Count; i++)
|
||||
{
|
||||
streamedValues[i] = streamedFrames[1 + frameIdx].keyList[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
int numStreamedCurves = 1 + frameIdx < streamedFrames.Count ? streamedFrames[1 + frameIdx].keyList.Count : 0;
|
||||
int numCurves = numStreamedCurves + (int)clip.m_MuscleClip.m_Clip.m_DenseClip.m_CurveCount + clip.m_MuscleClip.m_Clip.m_ConstantClip.data.Length;
|
||||
int streamOffset = numStreamedCurves - (int)clip.m_MuscleClip.m_Clip.m_StreamedClip.curveCount;
|
||||
for (int curveIdx = 0; curveIdx < numCurves;)
|
||||
{
|
||||
GenericBinding binding;
|
||||
float[] data;
|
||||
int dataOffset;
|
||||
if (1 + frameIdx < streamedFrames.Count && curveIdx < streamedFrames[1 + frameIdx].keyList.Count)
|
||||
{
|
||||
binding = clip.m_ClipBindingConstant.FindBinding(streamedFrames[1 + frameIdx].keyList[curveIdx].index);
|
||||
data = streamedValues;
|
||||
dataOffset = 0;
|
||||
}
|
||||
else if (curveIdx < numStreamedCurves + clip.m_MuscleClip.m_Clip.m_DenseClip.m_CurveCount)
|
||||
{
|
||||
binding = clip.m_ClipBindingConstant.FindBinding(curveIdx - streamOffset);
|
||||
data = clip.m_MuscleClip.m_Clip.m_DenseClip.m_SampleArray;
|
||||
dataOffset = numStreamedCurves - frameIdx * (int)clip.m_MuscleClip.m_Clip.m_DenseClip.m_CurveCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
binding = clip.m_ClipBindingConstant.FindBinding(curveIdx - streamOffset);
|
||||
data = clip.m_MuscleClip.m_Clip.m_ConstantClip.data;
|
||||
dataOffset = numStreamedCurves + (int)clip.m_MuscleClip.m_Clip.m_DenseClip.m_CurveCount;
|
||||
}
|
||||
|
||||
if (binding.path == 0)
|
||||
{
|
||||
curveIdx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
string boneName = GetNameFromHashes(binding.path, binding.attribute);
|
||||
ImportedAnimationSampledTrack track = iAnim.FindTrack(boneName);
|
||||
if (track == null)
|
||||
{
|
||||
track = new ImportedAnimationSampledTrack();
|
||||
track.Name = boneName;
|
||||
iAnim.TrackList.Add(track);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
switch (binding.attribute)
|
||||
{
|
||||
case 1:
|
||||
if (track.Translations == null)
|
||||
{
|
||||
track.Translations = new Vector3?[numFrames];
|
||||
}
|
||||
|
||||
track.Translations[frameIdx] = new Vector3
|
||||
(
|
||||
-data[curveIdx++ - dataOffset],
|
||||
data[curveIdx++ - dataOffset],
|
||||
data[curveIdx++ - dataOffset]
|
||||
);
|
||||
break;
|
||||
case 2:
|
||||
if (track.Rotations == null)
|
||||
{
|
||||
track.Rotations = new Quaternion?[numFrames];
|
||||
}
|
||||
|
||||
track.Rotations[frameIdx] = new Quaternion
|
||||
(
|
||||
data[curveIdx++ - dataOffset],
|
||||
-data[curveIdx++ - dataOffset],
|
||||
-data[curveIdx++ - dataOffset],
|
||||
data[curveIdx++ - dataOffset]
|
||||
);
|
||||
break;
|
||||
case 3:
|
||||
if (track.Scalings == null)
|
||||
{
|
||||
track.Scalings = new Vector3?[numFrames];
|
||||
}
|
||||
|
||||
track.Scalings[frameIdx] = new Vector3
|
||||
(
|
||||
data[curveIdx++ - dataOffset],
|
||||
data[curveIdx++ - dataOffset],
|
||||
data[curveIdx++ - dataOffset]
|
||||
);
|
||||
break;
|
||||
case 4:
|
||||
if (track.Rotations == null)
|
||||
{
|
||||
track.Rotations = new Quaternion?[numFrames];
|
||||
}
|
||||
|
||||
track.Rotations[frameIdx] = Fbx.EulerToQuaternion
|
||||
(
|
||||
new Vector3
|
||||
(
|
||||
data[curveIdx++ - dataOffset],
|
||||
-data[curveIdx++ - dataOffset],
|
||||
-data[curveIdx++ - dataOffset]
|
||||
)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
if (track.Curve == null)
|
||||
{
|
||||
track.Curve = new float?[numFrames];
|
||||
}
|
||||
|
||||
track.Curve[frameIdx] = data[curveIdx++ - dataOffset];
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//errors.Append(" ").Append(boneName).Append(" a=").Append(binding.attribute).Append(" ci=").Append(curveIdx).Append("/#=").Append(numCurves).Append(" of=").Append(dataOffset).Append(" f=").Append(frameIdx).Append("/#=").Append(numFrames).Append("\n");
|
||||
//TODO Display error
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetNameFromHashes(uint path, uint attribute)
|
||||
{
|
||||
var boneName = GetNameFromBonePathHashes(path);
|
||||
if (string.IsNullOrEmpty(boneName))
|
||||
{
|
||||
boneName = avatar?.FindBoneName(path);
|
||||
}
|
||||
if (string.IsNullOrEmpty(boneName))
|
||||
{
|
||||
boneName = "unknown " + path;
|
||||
}
|
||||
if (attribute > 4)
|
||||
{
|
||||
if (morphChannelInfo.TryGetValue(attribute, out var morphChannel))
|
||||
{
|
||||
return boneName + "." + morphChannel;
|
||||
}
|
||||
return boneName + ".unknown_morphChannel " + attribute;
|
||||
}
|
||||
return boneName;
|
||||
}
|
||||
|
||||
private string GetNameFromBonePathHashes(uint path)
|
||||
{
|
||||
if (bonePathHash.TryGetValue(path, out var boneName))
|
||||
boneName = boneName.Substring(boneName.LastIndexOf('/') + 1);
|
||||
return boneName;
|
||||
}
|
||||
|
||||
private static string BlendShapeNameGroup(Mesh mesh, int index)
|
||||
{
|
||||
string name = mesh.m_Shapes.channels[index].name;
|
||||
int dotPos = name.IndexOf('.');
|
||||
if (dotPos >= 0)
|
||||
{
|
||||
return name.Substring(0, dotPos);
|
||||
}
|
||||
return "Ungrouped";
|
||||
}
|
||||
|
||||
private static string BlendShapeNameExtension(Mesh mesh, int index)
|
||||
{
|
||||
string name = mesh.m_Shapes.channels[index].name;
|
||||
int dotPos = name.IndexOf('.');
|
||||
if (dotPos >= 0)
|
||||
{
|
||||
return name.Substring(dotPos + 1);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private static ImportedVertex GetSourceVertex(List<ImportedSubmesh> submeshList, int morphVertIndex)
|
||||
{
|
||||
for (int i = 0; i < submeshList.Count; i++)
|
||||
{
|
||||
List<ImportedVertex> vertList = submeshList[i].VertexList;
|
||||
if (morphVertIndex < vertList.Count)
|
||||
{
|
||||
return vertList[morphVertIndex];
|
||||
}
|
||||
morphVertIndex -= vertList.Count;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void CreateBonePathHash(Transform m_Transform)
|
||||
{
|
||||
var name = GetTransformPath(m_Transform);
|
||||
var crc = new SevenZip.CRC();
|
||||
var bytes = Encoding.UTF8.GetBytes(name);
|
||||
crc.Update(bytes, 0, (uint)bytes.Length);
|
||||
bonePathHash[crc.GetDigest()] = name;
|
||||
int index;
|
||||
while ((index = name.IndexOf("/", StringComparison.Ordinal)) >= 0)
|
||||
{
|
||||
name = name.Substring(index + 1);
|
||||
crc = new SevenZip.CRC();
|
||||
bytes = Encoding.UTF8.GetBytes(name);
|
||||
crc.Update(bytes, 0, (uint)bytes.Length);
|
||||
bonePathHash[crc.GetDigest()] = name;
|
||||
}
|
||||
foreach (var pptr in m_Transform.m_Children)
|
||||
{
|
||||
if (assetsfileList.TryGetTransform(pptr, out var child))
|
||||
CreateBonePathHash(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -181,6 +181,19 @@ namespace AssetStudio
|
||||
exportable = true;
|
||||
break;
|
||||
}
|
||||
case ClassIDReference.Animator:
|
||||
{
|
||||
exportable = true;
|
||||
break;
|
||||
}
|
||||
case ClassIDReference.AnimationClip:
|
||||
{
|
||||
exportable = true;
|
||||
var reader = asset.sourceFile.assetsFileReader;
|
||||
reader.Position = asset.Offset;
|
||||
asset.Text = reader.ReadAlignedString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exportable && displayAll)
|
||||
{
|
||||
@ -271,6 +284,11 @@ namespace AssetStudio
|
||||
m_GameObject.m_SkinnedMeshRenderer = m_Component;
|
||||
break;
|
||||
}
|
||||
case ClassIDReference.Animator:
|
||||
{
|
||||
asset.Text = m_GameObject.asset.Text;//TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,30 @@
|
||||
<setting name="displayOriginalName" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="EulerFilter" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="filterPrecision" serializeAs="String">
|
||||
<value>0.25</value>
|
||||
</setting>
|
||||
<setting name="allFrames" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="allBones" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="skins" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="boneSize" serializeAs="String">
|
||||
<value>10</value>
|
||||
</setting>
|
||||
<setting name="flatInbetween" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="compatibility" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
</AssetStudio.Properties.Settings>
|
||||
</userSettings>
|
||||
</configuration>
|
20
AssetStudioFBX/AssemblyInfo.cpp
Normal file
20
AssetStudioFBX/AssemblyInfo.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
using namespace System;
|
||||
using namespace System::Reflection;
|
||||
using namespace System::Runtime::CompilerServices;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using namespace System::Security::Permissions;
|
||||
|
||||
[assembly:AssemblyTitleAttribute(L"AssetStudioFBX")];
|
||||
[assembly:AssemblyDescriptionAttribute(L"")];
|
||||
[assembly:AssemblyConfigurationAttribute(L"")];
|
||||
[assembly:AssemblyCompanyAttribute(L"")];
|
||||
[assembly:AssemblyProductAttribute(L"AssetStudioFBX")];
|
||||
[assembly:AssemblyCopyrightAttribute(L"°æÈ¨ËùÓÐ(c) 2018")];
|
||||
[assembly:AssemblyTrademarkAttribute(L"")];
|
||||
[assembly:AssemblyCultureAttribute(L"")];
|
||||
|
||||
[assembly:AssemblyVersionAttribute("1.0.*")];
|
||||
|
||||
[assembly:ComVisible(false)];
|
||||
|
||||
[assembly:CLSCompliantAttribute(true)];
|
104
AssetStudioFBX/AssetStudioFBX-x86.vcxproj
Normal file
104
AssetStudioFBX/AssetStudioFBX-x86.vcxproj
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{276DE52E-3FFE-4C3D-9076-62BCB7A5B991}</ProjectGuid>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<Keyword>ManagedCProj</Keyword>
|
||||
<RootNamespace>AssetStudioFBX</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>WIN32;FBXSDK_SHARED;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>D:\FBX SDK\2015.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>D:\FBX SDK\2015.1\lib\vs2013\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;FBXSDK_SHARED;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>D:\FBX SDK\2015.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>D:\FBX SDK\2015.1\lib\vs2013\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AssemblyInfo.cpp" />
|
||||
<ClCompile Include="AssetStudioFBX.cpp" />
|
||||
<ClCompile Include="AssetStudioFBXExporter.cpp" />
|
||||
<ClCompile Include="ImportedFBXExporter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AssetStudioFBX.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="SharpDX">
|
||||
<HintPath>..\AssetStudio\Library\SharpDX.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SharpDX.Mathematics">
|
||||
<HintPath>..\AssetStudio\Library\SharpDX.Mathematics.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj">
|
||||
<Project>{9131c403-7fe8-444d-9af5-5fe5df76ff24}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
51
AssetStudioFBX/AssetStudioFBX.cpp
Normal file
51
AssetStudioFBX/AssetStudioFBX.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include <fbxsdk.h>
|
||||
#include <fbxsdk/fileio/fbxiosettings.h>
|
||||
#include "AssetStudioFBX.h"
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
char* Fbx::StringToCharArray(String^ s)
|
||||
{
|
||||
return (char*)(void*)Marshal::StringToHGlobalAnsi(s);
|
||||
}
|
||||
|
||||
void Fbx::Init(FbxManager** pSdkManager, FbxScene** pScene)
|
||||
{
|
||||
*pSdkManager = FbxManager::Create();
|
||||
if (!pSdkManager)
|
||||
{
|
||||
throw gcnew Exception(gcnew String("Unable to create the FBX SDK manager"));
|
||||
}
|
||||
|
||||
FbxIOSettings* ios = FbxIOSettings::Create(*pSdkManager, IOSROOT);
|
||||
(*pSdkManager)->SetIOSettings(ios);
|
||||
|
||||
FbxString lPath = FbxGetApplicationDirectory();
|
||||
#if defined(FBXSDK_ENV_WIN)
|
||||
FbxString lExtension = "dll";
|
||||
#elif defined(FBXSDK_ENV_MAC)
|
||||
FbxString lExtension = "dylib";
|
||||
#elif defined(FBXSDK_ENV_LINUX)
|
||||
FbxString lExtension = "so";
|
||||
#endif
|
||||
(*pSdkManager)->LoadPluginsDirectory(lPath.Buffer(), lExtension.Buffer());
|
||||
|
||||
*pScene = FbxScene::Create(*pSdkManager, "");
|
||||
}
|
||||
|
||||
Vector3 Fbx::QuaternionToEuler(Quaternion q)
|
||||
{
|
||||
FbxAMatrix lMatrixRot;
|
||||
lMatrixRot.SetQ(FbxQuaternion(q.X, q.Y, q.Z, q.W));
|
||||
FbxVector4 lEuler = lMatrixRot.GetR();
|
||||
return Vector3((float)lEuler[0], (float)lEuler[1], (float)lEuler[2]);
|
||||
}
|
||||
|
||||
Quaternion Fbx::EulerToQuaternion(Vector3 v)
|
||||
{
|
||||
FbxAMatrix lMatrixRot;
|
||||
lMatrixRot.SetR(FbxVector4(v.X, v.Y, v.Z));
|
||||
FbxQuaternion lQuaternion = lMatrixRot.GetQ();
|
||||
return Quaternion((float)lQuaternion[0], (float)lQuaternion[1], (float)lQuaternion[2], (float)lQuaternion[3]);
|
||||
}
|
||||
}
|
111
AssetStudioFBX/AssetStudioFBX.h
Normal file
111
AssetStudioFBX/AssetStudioFBX.h
Normal file
@ -0,0 +1,111 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef IOS_REF
|
||||
#undef IOS_REF
|
||||
#define IOS_REF (*(pSdkManager->GetIOSettings()))
|
||||
#endif
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Collections::Generic;
|
||||
using namespace System::IO;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using namespace SharpDX;
|
||||
|
||||
#define WITH_MARSHALLED_STRING(name,str,block)\
|
||||
{ \
|
||||
char* name; \
|
||||
try \
|
||||
{ \
|
||||
name = StringToCharArray(str); \
|
||||
block \
|
||||
} \
|
||||
finally \
|
||||
{ \
|
||||
Marshal::FreeHGlobal((IntPtr)name); \
|
||||
} \
|
||||
}
|
||||
|
||||
namespace AssetStudio {
|
||||
|
||||
public ref class Fbx
|
||||
{
|
||||
public:
|
||||
static Vector3 QuaternionToEuler(Quaternion q);
|
||||
static Quaternion EulerToQuaternion(Vector3 v);
|
||||
|
||||
ref class Exporter
|
||||
{
|
||||
public:
|
||||
static void Export(String^ path, IImported^ imported, bool EulerFilter, float filterPrecision, String^ exportFormat, bool allFrames, bool allBones, bool skins, float boneSize, bool flatInbetween, bool compatibility);
|
||||
static void ExportMorph(String^ path, IImported^ imported, String^ exportFormat, bool morphMask, bool flatInbetween, bool skins, float boneSize, bool compatibility);
|
||||
|
||||
private:
|
||||
HashSet<String^>^ frameNames;
|
||||
HashSet<String^>^ meshNames;
|
||||
bool EulerFilter;
|
||||
float filterPrecision;
|
||||
bool exportSkins;
|
||||
bool embedMedia;
|
||||
float boneSize;
|
||||
|
||||
IImported^ imported;
|
||||
|
||||
char* cDest;
|
||||
char* cFormat;
|
||||
FbxManager* pSdkManager;
|
||||
FbxScene* pScene;
|
||||
FbxExporter* pExporter;
|
||||
FbxArray<FbxSurfacePhong*>* pMaterials;
|
||||
FbxArray<FbxFileTexture*>* pTextures;
|
||||
FbxArray<FbxNode*>* pMeshNodes;
|
||||
|
||||
~Exporter();
|
||||
!Exporter();
|
||||
void Fbx::Exporter::LinkTexture(ImportedMaterial^ mat, int attIndex, FbxFileTexture* pTexture, FbxProperty& prop);
|
||||
void SetJointsNode(FbxNode* pNode, HashSet<String^>^ boneNames, bool allBones);
|
||||
|
||||
Exporter(String^ path, IImported^ imported, String^ exportFormat, bool allFrames, bool allBones, bool skins, float boneSize, bool compatibility, bool normals);
|
||||
HashSet<String^>^ SearchHierarchy();
|
||||
void SearchHierarchy(ImportedFrame^ frame, HashSet<String^>^ exportFrames);
|
||||
void SetJointsFromImportedMeshes(bool allBones);
|
||||
void ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame);
|
||||
void ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList, bool normals);
|
||||
FbxFileTexture* ExportTexture(ImportedTexture^ matTex, FbxMesh* pMesh);
|
||||
void ExportAnimations(bool EulerFilter, float filterValue, bool flatInbetween);
|
||||
void ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* EulerFilter, float filterPrecision,
|
||||
FbxPropertyT<FbxDouble3>& scale, FbxPropertyT<FbxDouble4>& rotate, FbxPropertyT<FbxDouble3>& translate, List<String^>^ pNotFound);
|
||||
void ExportSampledAnimation(ImportedSampledAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* EulerFilter, float filterPrecision, bool flatInbetween,
|
||||
FbxPropertyT<FbxDouble3>& scale, FbxPropertyT<FbxDouble4>& rotate, FbxPropertyT<FbxDouble3>& translate, List<String^>^ pNotFound);
|
||||
void ExportMorphs(IImported^ imported, bool morphMask, bool flatInbetween);
|
||||
};
|
||||
|
||||
private:
|
||||
ref class InterpolationHelper
|
||||
{
|
||||
private:
|
||||
FbxScene * pScene;
|
||||
FbxAnimLayer* pAnimLayer;
|
||||
FbxAnimEvaluator* pAnimEvaluator;
|
||||
|
||||
FbxAnimCurveDef::EInterpolationType interpolationMethod;
|
||||
FbxAnimCurveFilterUnroll* lFilter;
|
||||
float filterPrecision;
|
||||
|
||||
FbxPropertyT<FbxDouble3>* scale, *translate;
|
||||
FbxPropertyT<FbxDouble4>* rotate;
|
||||
FbxAnimCurve* pScaleCurveX, *pScaleCurveY, *pScaleCurveZ,
|
||||
*pRotateCurveX, *pRotateCurveY, *pRotateCurveZ, *pRotateCurveW,
|
||||
*pTranslateCurveX, *pTranslateCurveY, *pTranslateCurveZ;
|
||||
|
||||
array<FbxAnimCurve*>^ allCurves;
|
||||
|
||||
public:
|
||||
static const char* pScaleName = "Scale";
|
||||
static const char* pRotateName = "Rotate";
|
||||
static const char* pTranslateName = "Translate";
|
||||
};
|
||||
|
||||
static char* StringToCharArray(String^ s);
|
||||
static void Init(FbxManager** pSdkManager, FbxScene** pScene);
|
||||
};
|
||||
}
|
BIN
AssetStudioFBX/AssetStudioFBX.rc
Normal file
BIN
AssetStudioFBX/AssetStudioFBX.rc
Normal file
Binary file not shown.
104
AssetStudioFBX/AssetStudioFBX.vcxproj
Normal file
104
AssetStudioFBX/AssetStudioFBX.vcxproj
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}</ProjectGuid>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<Keyword>ManagedCProj</Keyword>
|
||||
<RootNamespace>AssetStudioFBX</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>FBXSDK_SHARED;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>D:\FBX SDK\2015.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>D:\FBX SDK\2015.1\lib\vs2013\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>FBXSDK_SHARED;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>D:\FBX SDK\2015.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>D:\FBX SDK\2015.1\lib\vs2013\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AssemblyInfo.cpp" />
|
||||
<ClCompile Include="AssetStudioFBX.cpp" />
|
||||
<ClCompile Include="AssetStudioFBXExporter.cpp" />
|
||||
<ClCompile Include="ImportedFBXExporter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AssetStudioFBX.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="SharpDX">
|
||||
<HintPath>..\AssetStudio\Library\SharpDX.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SharpDX.Mathematics">
|
||||
<HintPath>..\AssetStudio\Library\SharpDX.Mathematics.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj">
|
||||
<Project>{9131c403-7fe8-444d-9af5-5fe5df76ff24}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
32
AssetStudioFBX/AssetStudioFBX.vcxproj.filters
Normal file
32
AssetStudioFBX/AssetStudioFBX.vcxproj.filters
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AssemblyInfo.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ImportedFBXExporter.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AssetStudioFBX.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AssetStudioFBXExporter.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AssetStudioFBX.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
82
AssetStudioFBX/AssetStudioFBXExporter.cpp
Normal file
82
AssetStudioFBX/AssetStudioFBXExporter.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
#include <fbxsdk.h>
|
||||
#include <fbxsdk/fileio/fbxiosettings.h>
|
||||
#include "AssetStudioFBX.h"
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
Fbx::Exporter::~Exporter()
|
||||
{
|
||||
this->!Exporter();
|
||||
}
|
||||
|
||||
Fbx::Exporter::!Exporter()
|
||||
{
|
||||
if (pMeshNodes != NULL)
|
||||
{
|
||||
delete pMeshNodes;
|
||||
}
|
||||
if (pMaterials != NULL)
|
||||
{
|
||||
delete pMaterials;
|
||||
}
|
||||
if (pTextures != NULL)
|
||||
{
|
||||
if (embedMedia)
|
||||
{
|
||||
for (int i = 0; i < pTextures->GetCount(); i++)
|
||||
{
|
||||
FbxFileTexture* tex = pTextures->GetAt(i);
|
||||
File::Delete(gcnew String(tex->GetFileName()));
|
||||
}
|
||||
}
|
||||
delete pTextures;
|
||||
}
|
||||
if (pExporter != NULL)
|
||||
{
|
||||
pExporter->Destroy();
|
||||
}
|
||||
if (pScene != NULL)
|
||||
{
|
||||
pScene->Destroy();
|
||||
}
|
||||
if (pSdkManager != NULL)
|
||||
{
|
||||
pSdkManager->Destroy();
|
||||
}
|
||||
if (cFormat != NULL)
|
||||
{
|
||||
Marshal::FreeHGlobal((IntPtr)cFormat);
|
||||
}
|
||||
if (cDest != NULL)
|
||||
{
|
||||
Marshal::FreeHGlobal((IntPtr)cDest);
|
||||
}
|
||||
}
|
||||
|
||||
void Fbx::Exporter::SetJointsNode(FbxNode* pNode, HashSet<String^>^ boneNames, bool allBones)
|
||||
{
|
||||
String^ nodeName = gcnew String(pNode->GetName());
|
||||
if (allBones || boneNames->Contains(nodeName))
|
||||
{
|
||||
FbxSkeleton* pJoint = FbxSkeleton::Create(pSdkManager, "");
|
||||
pJoint->Size.Set((double)boneSize);
|
||||
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
|
||||
pNode->SetNodeAttribute(pJoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
FbxNull* pNull = FbxNull::Create(pSdkManager, "");
|
||||
if (pNode->GetChildCount() > 0)
|
||||
{
|
||||
pNull->Look.Set(FbxNull::eNone);
|
||||
}
|
||||
|
||||
pNode->SetNodeAttribute(pNull);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pNode->GetChildCount(); i++)
|
||||
{
|
||||
SetJointsNode(pNode->GetChild(i), boneNames, allBones);
|
||||
}
|
||||
}
|
||||
}
|
1287
AssetStudioFBX/ImportedFBXExporter.cpp
Normal file
1287
AssetStudioFBX/ImportedFBXExporter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
50
AssetStudioUtility/AssetStudioUtility.csproj
Normal file
50
AssetStudioUtility/AssetStudioUtility.csproj
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>AssetStudioUtility</RootNamespace>
|
||||
<AssemblyName>AssetStudioUtility</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="SharpDX.Mathematics">
|
||||
<HintPath>..\AssetStudio\Library\SharpDX.Mathematics.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Imported.cs" />
|
||||
<Compile Include="ObjChildren.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
263
AssetStudioUtility/Imported.cs
Normal file
263
AssetStudioUtility/Imported.cs
Normal file
@ -0,0 +1,263 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SharpDX;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public interface IImported
|
||||
{
|
||||
List<ImportedFrame> FrameList { get; }
|
||||
List<ImportedMesh> MeshList { get; }
|
||||
List<ImportedMaterial> MaterialList { get; }
|
||||
List<ImportedTexture> TextureList { get; }
|
||||
List<ImportedAnimation> AnimationList { get; }
|
||||
List<ImportedMorph> MorphList { get; }
|
||||
}
|
||||
|
||||
public class ImportedFrame : ObjChildren<ImportedFrame>, IObjChild
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Matrix Matrix { get; set; }
|
||||
|
||||
public dynamic Parent { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedMesh
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<ImportedSubmesh> SubmeshList { get; set; }
|
||||
public List<ImportedBone> BoneList { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedSubmesh
|
||||
{
|
||||
public List<ImportedVertex> VertexList { get; set; }
|
||||
public List<ImportedFace> FaceList { get; set; }
|
||||
public string Material { get; set; }
|
||||
public int Index { get; set; }
|
||||
public bool WorldCoords { get; set; }
|
||||
public bool Visible { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedVertex
|
||||
{
|
||||
public Vector3 Position { get; set; }
|
||||
public float[] Weights { get; set; }
|
||||
public byte[] BoneIndices { get; set; }
|
||||
public Vector3 Normal { get; set; }
|
||||
public float[] UV { get; set; }
|
||||
public Vector4 Tangent { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedVertexWithColour : ImportedVertex
|
||||
{
|
||||
public Color4 Colour { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedFace
|
||||
{
|
||||
public int[] VertexIndices { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedBone
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Matrix Matrix { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedMaterial
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Color4 Diffuse { get; set; }
|
||||
public Color4 Ambient { get; set; }
|
||||
public Color4 Specular { get; set; }
|
||||
public Color4 Emissive { get; set; }
|
||||
public float Power { get; set; }
|
||||
public string[] Textures { get; set; }
|
||||
public Vector2[] TexOffsets { get; set; }
|
||||
public Vector2[] TexScales { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedTexture
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public ImportedTexture(MemoryStream stream, string name)
|
||||
{
|
||||
Name = name;
|
||||
Data = stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public interface ImportedAnimation
|
||||
{
|
||||
}
|
||||
|
||||
public abstract class ImportedAnimationTrackContainer<TrackType> : ImportedAnimation where TrackType : ImportedAnimationTrack
|
||||
{
|
||||
public List<TrackType> TrackList { get; set; }
|
||||
|
||||
public TrackType FindTrack(string name)
|
||||
{
|
||||
return TrackList.Find(track => track.Name == name);
|
||||
}
|
||||
}
|
||||
|
||||
public class ImportedKeyframedAnimation : ImportedAnimationTrackContainer<ImportedAnimationKeyframedTrack>
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedSampledAnimation : ImportedAnimationTrackContainer<ImportedAnimationSampledTrack>
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public float SampleRate { get; set; }
|
||||
}
|
||||
|
||||
public abstract class ImportedAnimationTrack
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedAnimationKeyframedTrack : ImportedAnimationTrack
|
||||
{
|
||||
public Dictionary<float, ImportedAnimationKeyframe> Keyframes { get; set; } = new Dictionary<float, ImportedAnimationKeyframe>();
|
||||
}
|
||||
|
||||
public class ImportedKeyframe<T>
|
||||
{
|
||||
public float time { get; set; }
|
||||
public T value { get; set; }
|
||||
public T inSlope { get; set; }
|
||||
public T outSlope { get; set; }
|
||||
|
||||
public ImportedKeyframe(float time, T value, T inSlope, T outSlope)
|
||||
{
|
||||
this.time = time;
|
||||
this.value = value;
|
||||
this.inSlope = inSlope;
|
||||
this.outSlope = outSlope;
|
||||
}
|
||||
}
|
||||
|
||||
public class ImportedAnimationKeyframe
|
||||
{
|
||||
public ImportedKeyframe<Vector3> Scaling { get; set; }
|
||||
public ImportedKeyframe<Quaternion> Rotation { get; set; }
|
||||
public ImportedKeyframe<Vector3> Translation { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedAnimationSampledTrack : ImportedAnimationTrack
|
||||
{
|
||||
public Vector3?[] Scalings;
|
||||
public Quaternion?[] Rotations;
|
||||
public Vector3?[] Translations;
|
||||
public float?[] Curve;
|
||||
}
|
||||
|
||||
public class ImportedMorph
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string ClipName { get; set; }
|
||||
public List<Tuple<float, int, int>> Channels { get; set; }
|
||||
public List<ImportedMorphKeyframe> KeyframeList { get; set; }
|
||||
public List<ushort> MorphedVertexIndices { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedMorphKeyframe
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<ImportedVertex> VertexList { get; set; }
|
||||
public List<ushort> MorphedVertexIndices { get; set; }
|
||||
public float Weight { get; set; }
|
||||
}
|
||||
|
||||
public static class ImportedHelpers
|
||||
{
|
||||
public static ImportedFrame FindFrame(String name, ImportedFrame root)
|
||||
{
|
||||
ImportedFrame frame = root;
|
||||
if ((frame != null) && (frame.Name == name))
|
||||
{
|
||||
return frame;
|
||||
}
|
||||
|
||||
for (int i = 0; i < root.Count; i++)
|
||||
{
|
||||
if ((frame = FindFrame(name, root[i])) != null)
|
||||
{
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ImportedMesh FindMesh(String frameName, List<ImportedMesh> importedMeshList)
|
||||
{
|
||||
foreach (ImportedMesh mesh in importedMeshList)
|
||||
{
|
||||
if (mesh.Name == frameName)
|
||||
{
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ImportedMesh FindMesh(ImportedFrame frame, List<ImportedMesh> importedMeshList)
|
||||
{
|
||||
string framePath = frame.Name;
|
||||
ImportedFrame root = frame;
|
||||
while (root.Parent != null)
|
||||
{
|
||||
root = root.Parent;
|
||||
framePath = root.Name + "/" + framePath;
|
||||
}
|
||||
|
||||
foreach (ImportedMesh mesh in importedMeshList)
|
||||
{
|
||||
if (mesh.Name == framePath)
|
||||
{
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ImportedMaterial FindMaterial(String name, List<ImportedMaterial> importedMats)
|
||||
{
|
||||
foreach (ImportedMaterial mat in importedMats)
|
||||
{
|
||||
if (mat.Name == name)
|
||||
{
|
||||
return mat;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ImportedTexture FindTexture(string name, List<ImportedTexture> importedTextureList)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (ImportedTexture tex in importedTextureList)
|
||||
{
|
||||
if (tex.Name == name)
|
||||
{
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
71
AssetStudioUtility/ObjChildren.cs
Normal file
71
AssetStudioUtility/ObjChildren.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public interface IObjChild
|
||||
{
|
||||
dynamic Parent { get; set; }
|
||||
}
|
||||
|
||||
public abstract class ObjChildren<T> : IEnumerable<T> where T : IObjChild
|
||||
{
|
||||
protected List<T> children;
|
||||
|
||||
public T this[int i]
|
||||
{
|
||||
get { return (T)children[i]; }
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return children.Count; }
|
||||
}
|
||||
|
||||
public void InitChildren(int count)
|
||||
{
|
||||
children = new List<T>(count);
|
||||
}
|
||||
|
||||
public void AddChild(T obj)
|
||||
{
|
||||
children.Add(obj);
|
||||
obj.Parent = this;
|
||||
}
|
||||
|
||||
public void InsertChild(int i, T obj)
|
||||
{
|
||||
children.Insert(i, obj);
|
||||
obj.Parent = this;
|
||||
}
|
||||
|
||||
public void RemoveChild(T obj)
|
||||
{
|
||||
obj.Parent = null;
|
||||
children.Remove(obj);
|
||||
}
|
||||
|
||||
public void RemoveChild(int i)
|
||||
{
|
||||
children[i].Parent = null;
|
||||
children.RemoveAt(i);
|
||||
}
|
||||
|
||||
public int IndexOf(T obj)
|
||||
{
|
||||
return children.IndexOf(obj);
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return children.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
36
AssetStudioUtility/Properties/AssemblyInfo.cs
Normal file
36
AssetStudioUtility/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("AssetStudioUtility")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("AssetStudioUtility")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 会使此程序集中的类型
|
||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("9131c403-7fe8-444d-9af5-5fe5df76ff24")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
|
||||
//通过使用 "*",如下所示:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
Loading…
x
Reference in New Issue
Block a user