fix: [Asset] Unified 3D asset importer (on behalf of Noa7/Noah7071) (#2163)
Co-authored-by: noa7 <noahwdv@gmail.com> Co-authored-by: noa7707 <157441788+noa7707@users.noreply.github.com> Co-authored-by: Noah7071 <157886157+Noah7071@users.noreply.github.com>
This commit is contained in:
Родитель
4a263c4faa
Коммит
0e053a3b88
|
@ -90,8 +90,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Input.Tests.Windows"
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Core.Tests", "..\sources\core\Stride.Core.Tests\Stride.Core.Tests.csproj", "{5AA408BA-E766-453E-B661-E3D7EC46E2A6}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Stride.Importer.FBX", "..\sources\tools\Stride.Importer.FBX\Stride.Importer.FBX.vcxproj", "{0467D515-FD66-4B8A-A128-CB642C2ED03F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Core.Shaders", "..\sources\shaders\Stride.Core.Shaders\Stride.Core.Shaders.csproj", "{F2D52EDB-BC17-4243-B06D-33CD20F87A7F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Core.Presentation.Wpf", "..\sources\presentation\Stride.Core.Presentation.Wpf\Stride.Core.Presentation.Wpf.csproj", "{47AFCC2E-E9F0-47D6-9D75-9E646546A92B}"
|
||||
|
@ -312,8 +310,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xunit.runner.stride", "..\s
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Engine.NoAssets.Tests.Windows", "..\sources\engine\Stride.Engine.NoAssets.Tests\Stride.Engine.NoAssets.Tests.Windows.csproj", "{1C94168A-3C0D-4C6B-883B-91627D2EF3A1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.Assimp", "..\sources\tools\Stride.Importer.Assimp\Stride.Importer.Assimp.csproj", "{967BA05D-4AC4-4848-AEFD-894EF2309E4D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.Common", "..\sources\tools\Stride.Importer.Common\Stride.Importer.Common.csproj", "{806AA078-6070-4BB6-B05B-6EE6B21B1CDE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Core.CompilerServices", "..\sources\core\Stride.Core.CompilerServices\Stride.Core.CompilerServices.csproj", "{D62BBD65-AB1C-41C7-8EC3-88949993C71E}"
|
||||
|
@ -334,6 +330,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGetResolver", "NuGetResol
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Core.Presentation", "..\sources\presentation\Stride.Core.Presentation\Stride.Core.Presentation.csproj", "{0C63EF8B-26F9-4511-9FC5-7431DE9657D6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.3D", "..\sources\tools\Stride.Importer.3D\Stride.Importer.3D.csproj", "{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -405,16 +403,6 @@ Global
|
|||
{5AA408BA-E766-453E-B661-E3D7EC46E2A6}.Release|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{5AA408BA-E766-453E-B661-E3D7EC46E2A6}.Release|Win32.ActiveCfg = Debug|Any CPU
|
||||
{5AA408BA-E766-453E-B661-E3D7EC46E2A6}.Release|Win32.Build.0 = Debug|Any CPU
|
||||
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Debug|Mixed Platforms.ActiveCfg = Debug|x64
|
||||
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Debug|Mixed Platforms.Build.0 = Debug|x64
|
||||
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Release|Mixed Platforms.ActiveCfg = Release|x64
|
||||
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Release|Mixed Platforms.Build.0 = Release|x64
|
||||
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Release|Win32.Build.0 = Release|Win32
|
||||
{F2D52EDB-BC17-4243-B06D-33CD20F87A7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F2D52EDB-BC17-4243-B06D-33CD20F87A7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F2D52EDB-BC17-4243-B06D-33CD20F87A7F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
|
@ -1385,18 +1373,6 @@ Global
|
|||
{1C94168A-3C0D-4C6B-883B-91627D2EF3A1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{1C94168A-3C0D-4C6B-883B-91627D2EF3A1}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{1C94168A-3C0D-4C6B-883B-91627D2EF3A1}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{806AA078-6070-4BB6-B05B-6EE6B21B1CDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{806AA078-6070-4BB6-B05B-6EE6B21B1CDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{806AA078-6070-4BB6-B05B-6EE6B21B1CDE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
|
@ -1493,6 +1469,18 @@ Global
|
|||
{0C63EF8B-26F9-4511-9FC5-7431DE9657D6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{0C63EF8B-26F9-4511-9FC5-7431DE9657D6}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{0C63EF8B-26F9-4511-9FC5-7431DE9657D6}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Win32.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -1502,13 +1490,13 @@ Global
|
|||
{6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C} = {1AE1AC60-5D2F-4CA7-AE20-888F44551185}
|
||||
{4A15BAAD-AA37-4754-A2BF-8D4049211E36} = {1AE1AC60-5D2F-4CA7-AE20-888F44551185}
|
||||
{1AC70118-C90F-4EC6-9D8B-C628BDF900F7} = {4C142567-C42B-40F5-B092-798882190209}
|
||||
{B175D318-B4D0-49EA-9AEF-A54ACA2F03DC} = {25F10A0B-7259-404C-86BE-FD2363C92F72}
|
||||
{2FCA2D8B-B10F-4DCA-9847-4221F74BA586} = {5D2D3BE8-9910-45CA-8E45-95660DA4C563}
|
||||
{C121A566-555E-42B9-9B0A-1696529A9088} = {4C142567-C42B-40F5-B092-798882190209}
|
||||
{FB06C76A-6BB7-40BE-9AFA-FEC13B045FB5} = {4C142567-C42B-40F5-B092-798882190209}
|
||||
{A8F8D125-7A22-489F-99BC-9A02F545A17F} = {A7ED9F01-7D78-4381-90A6-D50E51C17250}
|
||||
{01700344-CF44-482C-BEBC-60213B0F844C} = {A7ED9F01-7D78-4381-90A6-D50E51C17250}
|
||||
{5AA408BA-E766-453E-B661-E3D7EC46E2A6} = {22ADD4CD-092E-4ADC-A21E-64CF42230152}
|
||||
{0467D515-FD66-4B8A-A128-CB642C2ED03F} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C}
|
||||
{F2D52EDB-BC17-4243-B06D-33CD20F87A7F} = {10D145AF-C8AE-428F-A80F-CA1B591D0DB2}
|
||||
{47AFCC2E-E9F0-47D6-9D75-9E646546A92B} = {75A820AB-0F21-40F2-9448-5D7F495B97A0}
|
||||
{C223FCD7-CDCC-4943-9E11-9C2CC8FA9FC4} = {52AE329E-B588-40D0-A578-8D0DB1BD83E5}
|
||||
|
@ -1608,7 +1596,6 @@ Global
|
|||
{66BE41FC-FC52-48D0-9C04-BCE8CC393020} = {4C142567-C42B-40F5-B092-798882190209}
|
||||
{D5B023BE-010F-44A8-ABF1-DB6F3BCEA392} = {1AE1AC60-5D2F-4CA7-AE20-888F44551185}
|
||||
{1C94168A-3C0D-4C6B-883B-91627D2EF3A1} = {A7ED9F01-7D78-4381-90A6-D50E51C17250}
|
||||
{967BA05D-4AC4-4848-AEFD-894EF2309E4D} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C}
|
||||
{806AA078-6070-4BB6-B05B-6EE6B21B1CDE} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C}
|
||||
{D62BBD65-AB1C-41C7-8EC3-88949993C71E} = {2E93E2B5-4500-4E47-9B65-E705218AB578}
|
||||
{BACD76E5-35D0-4389-9BB9-8743AC4D89DE} = {22ADD4CD-092E-4ADC-A21E-64CF42230152}
|
||||
|
@ -1619,6 +1606,7 @@ Global
|
|||
{02FD0BDE-4293-414F-97E6-69FF71105420} = {158087CF-AF74-44E9-AA20-A6AEB1E398A9}
|
||||
{158087CF-AF74-44E9-AA20-A6AEB1E398A9} = {1AE1AC60-5D2F-4CA7-AE20-888F44551185}
|
||||
{0C63EF8B-26F9-4511-9FC5-7431DE9657D6} = {75A820AB-0F21-40F2-9448-5D7F495B97A0}
|
||||
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {FF877973-604D-4EA7-B5F5-A129961F9EF2}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<CheckBox Content="{sd:Localize Deduplicate materials, Context=Button}" IsChecked="{Binding DeduplicateMaterials}" Margin="5" Visibility="{Binding ShowDeduplicateMaterialsCheckBox, Converter={sd:VisibleOrCollapsed}}"/>
|
||||
<TextBlock Text="{sd:Localize Warning\: Deduplicate materials is currently not supported for FBX files}" Margin="5" Visibility="{Binding ShowFbxDedupeNotSupportedWarning, Converter={sd:VisibleOrCollapsed}}"/>
|
||||
<CheckBox Content="{sd:Localize Import textures, Context=Button}" IsChecked="{Binding ImportTextures}" Margin="5"/>
|
||||
<CheckBox Content="{sd:Localize Import Animations, Context=Button}" IsChecked="{Binding ImportAnimations}" Margin="5"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Background="{StaticResource EmphasisColorBrush}" Margin="20,0">
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace Stride.Assets.Presentation.Templates
|
|||
private bool showFbxDedupeNotSupportedWarning = false;
|
||||
private bool deduplicateMaterials = true;
|
||||
private bool importTextures = true;
|
||||
private bool importAnimations = true;
|
||||
private bool importSkeleton = true;
|
||||
private bool dontImportSkeleton;
|
||||
private bool reuseSkeleton;
|
||||
|
@ -62,6 +63,8 @@ namespace Stride.Assets.Presentation.Templates
|
|||
|
||||
public bool ImportTextures { get { return importTextures; } set { SetValue(ref importTextures, value); } }
|
||||
|
||||
public bool ImportAnimations { get { return importAnimations; } set { SetValue(ref importAnimations, value); } }
|
||||
|
||||
public bool ImportSkeleton { get { return importSkeleton; } set { SetValue(ref importSkeleton, value); } }
|
||||
|
||||
public bool DontImportSkeleton { get { return dontImportSkeleton; } set { SetValue(ref dontImportSkeleton, value); } }
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace Stride.Assets.Presentation.Templates
|
|||
public static SettingsKey<bool> ImportMaterials = new SettingsKey<bool>("Templates/ModelFromFile/ImportMaterials", PackageUserSettings.SettingsContainer, true);
|
||||
public static SettingsKey<bool> DeduplicateMaterials = new SettingsKey<bool>("Templates/ModelFromFile/DeduplicateMaterials", PackageUserSettings.SettingsContainer, true);
|
||||
public static SettingsKey<bool> ImportTextures = new SettingsKey<bool>("Templates/ModelFromFile/ImportTextures", PackageUserSettings.SettingsContainer, true);
|
||||
public static SettingsKey<bool> ImportAnimations = new SettingsKey<bool>("Templates/ModelFromFile/ImportAnimations", PackageUserSettings.SettingsContainer, true);
|
||||
public static SettingsKey<bool> ImportSkeleton = new SettingsKey<bool>("Templates/ModelFromFile/ImportSkeleton", PackageUserSettings.SettingsContainer, true);
|
||||
public static SettingsKey<AssetId> DefaultSkeleton = new SettingsKey<AssetId>("Templates/ModelFromFile/DefaultSkeleton", PackageUserSettings.SettingsContainer, AssetId.Empty);
|
||||
}
|
||||
|
@ -39,6 +40,7 @@ namespace Stride.Assets.Presentation.Templates
|
|||
protected static readonly PropertyKey<bool> ImportMaterialsKey = new PropertyKey<bool>("ImportMaterials", typeof(ModelFromFileTemplateGenerator));
|
||||
protected static readonly PropertyKey<bool> DeduplicateMaterialsKey = new PropertyKey<bool>("DeduplicateMaterials", typeof(ModelFromFileTemplateGenerator));
|
||||
protected static readonly PropertyKey<bool> ImportTexturesKey = new PropertyKey<bool>("ImportTextures", typeof(ModelFromFileTemplateGenerator));
|
||||
protected static readonly PropertyKey<bool> ImportAnimationsKey = new PropertyKey<bool>("ImportAnimations", typeof(ModelFromFileTemplateGenerator));
|
||||
protected static readonly PropertyKey<bool> ImportSkeletonKey = new PropertyKey<bool>("ImportSkeleton", typeof(ModelFromFileTemplateGenerator));
|
||||
protected static readonly PropertyKey<Skeleton> SkeletonToUseKey = new PropertyKey<Skeleton>("SkeletonToUse", typeof(ModelFromFileTemplateGenerator));
|
||||
|
||||
|
@ -57,8 +59,7 @@ namespace Stride.Assets.Presentation.Templates
|
|||
if (files == null)
|
||||
return true;
|
||||
|
||||
var showDeduplicateMaterialsCheckBox = files.Any(x => ImportAssimpCommand.IsSupportingExtensions(x.GetFileExtension()));
|
||||
var showFbxDedupeNotSupportedWarning = showDeduplicateMaterialsCheckBox && files.Any(x => ImportFbxCommand.IsSupportingExtensions(x.GetFileExtension()));
|
||||
var showDeduplicateMaterialsCheckBox = files.Any(x => ImportThreeDCommand.IsSupportingExtensions(x.GetFileExtension()));
|
||||
// Load settings from the last time this template was used for this project
|
||||
var profile = parameters.Package.UserSettings.Profile;
|
||||
var window = new ModelAssetTemplateWindow
|
||||
|
@ -67,9 +68,10 @@ namespace Stride.Assets.Presentation.Templates
|
|||
{
|
||||
ImportMaterials = ModelFromFileTemplateSettings.ImportMaterials.GetValue(profile, true),
|
||||
ShowDeduplicateMaterialsCheckBox = showDeduplicateMaterialsCheckBox,
|
||||
ShowFbxDedupeNotSupportedWarning = showFbxDedupeNotSupportedWarning,
|
||||
ShowFbxDedupeNotSupportedWarning = false,
|
||||
DeduplicateMaterials = ModelFromFileTemplateSettings.DeduplicateMaterials.GetValue(profile, true),
|
||||
ImportTextures = ModelFromFileTemplateSettings.ImportTextures.GetValue(profile, true),
|
||||
ImportAnimations = ModelFromFileTemplateSettings.ImportAnimations.GetValue(profile, true),
|
||||
ImportSkeleton = ModelFromFileTemplateSettings.ImportSkeleton.GetValue(profile, true)
|
||||
}
|
||||
};
|
||||
|
@ -92,6 +94,7 @@ namespace Stride.Assets.Presentation.Templates
|
|||
parameters.Tags.Set(ImportMaterialsKey, window.Parameters.ImportMaterials);
|
||||
parameters.Tags.Set(DeduplicateMaterialsKey, window.Parameters.DeduplicateMaterials);
|
||||
parameters.Tags.Set(ImportTexturesKey, window.Parameters.ImportTextures);
|
||||
parameters.Tags.Set(ImportAnimationsKey, window.Parameters.ImportAnimations);
|
||||
parameters.Tags.Set(ImportSkeletonKey, window.Parameters.ImportSkeleton);
|
||||
parameters.Tags.Set(SkeletonToUseKey, skeletonToReuse);
|
||||
|
||||
|
@ -99,6 +102,7 @@ namespace Stride.Assets.Presentation.Templates
|
|||
ModelFromFileTemplateSettings.ImportMaterials.SetValue(window.Parameters.ImportMaterials, profile);
|
||||
ModelFromFileTemplateSettings.DeduplicateMaterials.SetValue(window.Parameters.DeduplicateMaterials, profile);
|
||||
ModelFromFileTemplateSettings.ImportTextures.SetValue(window.Parameters.ImportTextures, profile);
|
||||
ModelFromFileTemplateSettings.ImportAnimations.SetValue(window.Parameters.ImportAnimations, profile);
|
||||
ModelFromFileTemplateSettings.ImportSkeleton.SetValue(window.Parameters.ImportSkeleton, profile);
|
||||
skeletonId = AttachedReferenceManager.GetAttachedReference(skeletonToReuse)?.Id ?? AssetId.Empty;
|
||||
ModelFromFileTemplateSettings.DefaultSkeleton.SetValue(skeletonId, profile);
|
||||
|
@ -116,6 +120,7 @@ namespace Stride.Assets.Presentation.Templates
|
|||
var importMaterials = parameters.Tags.Get(ImportMaterialsKey);
|
||||
var deduplicateMaterials = parameters.Tags.Get(DeduplicateMaterialsKey);
|
||||
var importTextures = parameters.Tags.Get(ImportTexturesKey);
|
||||
var importAnimations = parameters.Tags.Get(ImportAnimationsKey);
|
||||
var importSkeleton = parameters.Tags.Get(ImportSkeletonKey);
|
||||
var skeletonToReuse = parameters.Tags.Get(SkeletonToUseKey);
|
||||
|
||||
|
@ -124,6 +129,7 @@ namespace Stride.Assets.Presentation.Templates
|
|||
importParameters.SelectedOutputTypes.Add(typeof(ModelAsset), true);
|
||||
importParameters.SelectedOutputTypes.Add(typeof(MaterialAsset), importMaterials);
|
||||
importParameters.SelectedOutputTypes.Add(typeof(TextureAsset), importTextures);
|
||||
importParameters.SelectedOutputTypes.Add(typeof(AnimationAsset), importAnimations);
|
||||
importParameters.SelectedOutputTypes.Add(typeof(SkeletonAsset), importSkeleton);
|
||||
|
||||
var importedAssets = new List<AssetItem>();
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
using System;
|
||||
using Stride.Core.Assets;
|
||||
using Stride.Core;
|
||||
using Stride.Core.Diagnostics;
|
||||
using Stride.Core.IO;
|
||||
using Stride.Assets.Textures;
|
||||
using Stride.Importer.Common;
|
||||
|
||||
namespace Stride.Assets.Models
|
||||
{
|
||||
public class FbxAssetImporter : ModelAssetImporter
|
||||
{
|
||||
static FbxAssetImporter()
|
||||
{
|
||||
NativeLibraryHelper.PreloadLibrary("libfbxsdk", typeof(FbxAssetImporter));
|
||||
}
|
||||
|
||||
// Supported file extensions for this importer
|
||||
private const string FileExtensions = ".fbx";
|
||||
|
||||
private static readonly Guid Uid = new Guid("a15ae42d-42c5-4a3b-9f7e-f8cd91eda595");
|
||||
|
||||
public override Guid Id => Uid;
|
||||
|
||||
public override string Description => "FBX importer used for creating entities, 3D Models or animations assets";
|
||||
|
||||
public override string SupportedFileExtensions => FileExtensions;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override EntityInfo GetEntityInfo(UFile localPath, Logger logger, AssetImporterParameters importParameters)
|
||||
{
|
||||
var meshConverter = new Importer.FBX.MeshConverter(logger);
|
||||
var entityInfo = meshConverter.ExtractEntity(localPath.FullPath, importParameters.IsTypeSelectedForOutput(typeof(TextureAsset)));
|
||||
return entityInfo;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GetAnimationDuration(UFile localPath, Logger logger, AssetImporterParameters importParameters, out TimeSpan startTime, out TimeSpan endTime)
|
||||
{
|
||||
var meshConverter = new Importer.FBX.MeshConverter(logger);
|
||||
// Use the first animation stack by default
|
||||
var durationInSeconds = meshConverter.GetAnimationDuration(localPath.FullPath, 0);
|
||||
|
||||
startTime = TimeSpan.Zero;
|
||||
endTime = TimeSpan.FromSeconds(durationInSeconds);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Stride.Core.BuildEngine;
|
||||
using Stride.Core.Serialization.Contents;
|
||||
using Stride.Animations;
|
||||
using Stride.Rendering;
|
||||
|
||||
namespace Stride.Assets.Models
|
||||
{
|
||||
[Description("Import FBX")]
|
||||
public class ImportFbxCommand : ImportModelCommand
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override string Title { get { string title = "Import FBX "; try { title += Path.GetFileName(SourcePath) ?? "[File]"; } catch { title += "[INVALID PATH]"; } return title; } }
|
||||
|
||||
public static bool IsSupportingExtensions(string ext)
|
||||
{
|
||||
return !String.IsNullOrEmpty(ext) && ext.ToLowerInvariant().Equals(".fbx");
|
||||
}
|
||||
|
||||
protected override Model LoadModel(ICommandContext commandContext, ContentManager contentManager)
|
||||
{
|
||||
var meshConverter = CreateMeshConverter(commandContext);
|
||||
var materialMapping = Materials.Select((s, i) => new { Value = s, Index = i }).ToDictionary(x => x.Value.Name, x => x.Index);
|
||||
var sceneData = meshConverter.Convert(SourcePath, Location, materialMapping);
|
||||
return sceneData;
|
||||
}
|
||||
|
||||
protected override Dictionary<string, AnimationClip> LoadAnimation(ICommandContext commandContext, ContentManager contentManager, out TimeSpan duration)
|
||||
{
|
||||
var meshConverter = CreateMeshConverter(commandContext);
|
||||
var sceneData = meshConverter.ConvertAnimation(SourcePath, Location, ImportCustomAttributes, AnimationStack);
|
||||
duration = sceneData.Duration;
|
||||
return sceneData.AnimationClips;
|
||||
}
|
||||
|
||||
protected override Skeleton LoadSkeleton(ICommandContext commandContext, ContentManager contentManager)
|
||||
{
|
||||
var meshConverter = CreateMeshConverter(commandContext);
|
||||
var sceneData = meshConverter.ConvertSkeleton(SourcePath, Location);
|
||||
return sceneData;
|
||||
}
|
||||
|
||||
private Importer.FBX.MeshConverter CreateMeshConverter(ICommandContext commandContext)
|
||||
{
|
||||
return new Importer.FBX.MeshConverter(commandContext.Logger)
|
||||
{
|
||||
AllowUnsignedBlendIndices = AllowUnsignedBlendIndices,
|
||||
};
|
||||
}
|
||||
|
||||
public override bool ShouldSpawnNewProcess()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "Import FBX " + base.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,14 +52,17 @@ namespace Stride.Assets.Models
|
|||
if (duration > durationTimeSpan)
|
||||
duration = durationTimeSpan;
|
||||
|
||||
// Incase of no mapping or only root mapping use source skeleton
|
||||
var animationClip = new AnimationClip { Duration = duration };
|
||||
var skeleton = string.IsNullOrWhiteSpace(SkeletonUrl)?null:contentManager.Load<Skeleton>(SkeletonUrl);
|
||||
var skeletonMapping = new SkeletonMapping(skeleton, modelSkeleton);
|
||||
|
||||
if (animationClips.Count > 0)
|
||||
{
|
||||
AnimationClip rootMotionAnimationClip = null;
|
||||
|
||||
// If root motion is explicitely enabled, or if there is no skeleton, try to find root node and apply animation directly on TransformComponent
|
||||
if ((AnimationRootMotion || SkeletonUrl == null) && modelSkeleton.Nodes.Length >= 1)
|
||||
if ((AnimationRootMotion || skeleton == null || skeletonMapping.MapCount < 2) && modelSkeleton.Nodes.Length >= 1)
|
||||
{
|
||||
// No skeleton, map root node only
|
||||
// TODO: For now, it seems to be located on node 1 in FBX files. Need to check if always the case, and what happens with Assimp
|
||||
|
@ -91,17 +94,17 @@ namespace Stride.Assets.Models
|
|||
|
||||
// Load asset reference skeleton
|
||||
if (SkeletonUrl != null)
|
||||
{
|
||||
var skeleton = contentManager.Load<Skeleton>(SkeletonUrl);
|
||||
var skeletonMapping = new SkeletonMapping(skeleton, modelSkeleton);
|
||||
|
||||
{
|
||||
// Process missing nodes
|
||||
foreach (var nodeAnimationClipEntry in animationClips)
|
||||
{
|
||||
var nodeName = nodeAnimationClipEntry.Key;
|
||||
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
|
||||
{
|
||||
nodeName = nodeName.Replace(c, '_');
|
||||
}
|
||||
var nodeAnimationClip = nodeAnimationClipEntry.Value;
|
||||
var nodeIndex = modelSkeleton.Nodes.IndexOf(x => x.Name == nodeName);
|
||||
|
||||
var nodeIndex = modelSkeleton.Nodes.IndexOf(x => x.Name == nodeName.ToString());
|
||||
// Node doesn't exist in skeleton? skip it
|
||||
if (nodeIndex == -1 || skeletonMapping.SourceToSource[nodeIndex] != nodeIndex)
|
||||
continue;
|
||||
|
@ -122,8 +125,8 @@ namespace Stride.Assets.Models
|
|||
{
|
||||
AnimationClip animationClipToMerge;
|
||||
AnimationClipEvaluator animationClipEvaluator = null;
|
||||
AnimationBlender animationBlender = null;
|
||||
if (animationClips.TryGetValue(modelSkeleton.Nodes[currentNodeIndex].Name, out animationClipToMerge))
|
||||
AnimationBlender animationBlender = null;
|
||||
if(GetAnimationKeyVirtualKey(modelSkeleton.Nodes[currentNodeIndex].Name, animationClips, out animationClipToMerge))
|
||||
{
|
||||
animationBlender = new AnimationBlender();
|
||||
animationClipEvaluator = animationBlender.CreateEvaluator(animationClipToMerge);
|
||||
|
@ -142,13 +145,13 @@ namespace Stride.Assets.Models
|
|||
foreach (var node in nodesToMerge)
|
||||
{
|
||||
if (node.Item3 != null)
|
||||
foreach (var curve in node.Item3.Clip.Curves)
|
||||
{
|
||||
foreach (CompressedTimeSpan time in curve.Keys)
|
||||
foreach (var curve in node.Item3.Clip.Curves)
|
||||
{
|
||||
animationKeysSet.Add(time);
|
||||
foreach (CompressedTimeSpan time in curve.Keys)
|
||||
{
|
||||
animationKeysSet.Add(time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort key times
|
||||
|
@ -172,7 +175,7 @@ namespace Stride.Assets.Models
|
|||
foreach (var node in nodesToMerge)
|
||||
{
|
||||
// Needs to be an array in order for it to be modified by the UpdateEngine, otherwise it would get passed by value
|
||||
var modelNodeDefinitions = new ModelNodeDefinition[1] {node.Item1};
|
||||
var modelNodeDefinitions = new ModelNodeDefinition[1] { node.Item1 };
|
||||
|
||||
if (node.Item2 != null && node.Item3 != null)
|
||||
{
|
||||
|
@ -273,7 +276,6 @@ namespace Stride.Assets.Models
|
|||
if (animationClip.Channels.Count == 0)
|
||||
{
|
||||
var logString = $"File {SourcePath} doesn't have any animation information.";
|
||||
|
||||
if (failOnEmptyAnimation)
|
||||
{
|
||||
commandContext.Logger.Error(logString);
|
||||
|
@ -295,5 +297,24 @@ namespace Stride.Assets.Models
|
|||
}
|
||||
return animationClip;
|
||||
}
|
||||
|
||||
public bool GetAnimationKeyVirtualKey(string vKey, Dictionary<string, AnimationClip> animationClips, out AnimationClip clip)
|
||||
{
|
||||
bool isFound = false;
|
||||
AnimationClip outClip = null;
|
||||
animationClips.ForEach(c =>
|
||||
{
|
||||
string _lineItem = c.Key;
|
||||
System.IO.Path.GetInvalidFileNameChars().ForEach(x => { _lineItem = _lineItem.Replace(x, '_'); });
|
||||
if (_lineItem == vKey)
|
||||
{
|
||||
outClip = c.Value;
|
||||
isFound = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
clip = outClip;
|
||||
return isFound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,15 @@ namespace Stride.Assets.Models
|
|||
// Round-trip through TargetToSource[SourceToTarget[i]] so that we know easily what nodes are remapped in source skeleton side
|
||||
public readonly int[] SourceToSource;
|
||||
|
||||
public readonly string[] NodeNames;
|
||||
|
||||
public int MapCount=0;
|
||||
|
||||
public SkeletonMapping(Skeleton targetSkeleton, Skeleton sourceSkeleton)
|
||||
{
|
||||
SourceToTarget = new int[sourceSkeleton.Nodes.Length]; // model => skeleton mapping
|
||||
SourceToSource = new int[sourceSkeleton.Nodes.Length]; // model => model mapping
|
||||
NodeNames = new string[sourceSkeleton.Nodes.Length];
|
||||
|
||||
if (targetSkeleton == null)
|
||||
{
|
||||
|
@ -44,20 +49,23 @@ namespace Stride.Assets.Models
|
|||
var parentModelIndex = node.ParentIndex;
|
||||
|
||||
// Find matching node in skeleton (or map to best parent)
|
||||
var skeletonIndex = targetSkeleton.Nodes.IndexOf(x => x.Name == node.Name);
|
||||
|
||||
var skeletonIndex = targetSkeleton.Nodes.IndexOf(x => x.Name == node.Name);
|
||||
if (skeletonIndex == -1)
|
||||
{
|
||||
// Nothing match, remap to parent node
|
||||
SourceToTarget[modelIndex] = parentModelIndex != -1 ? SourceToTarget[parentModelIndex] : 0;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
++MapCount;
|
||||
}
|
||||
|
||||
// TODO: Check hierarchy for inconsistencies
|
||||
|
||||
// Name match
|
||||
SourceToTarget[modelIndex] = skeletonIndex;
|
||||
targetToSource[skeletonIndex] = modelIndex;
|
||||
NodeNames[modelIndex] = node.Name;
|
||||
}
|
||||
|
||||
for (int modelIndex = 0; modelIndex < sourceSkeleton.Nodes.Length; ++modelIndex)
|
||||
|
|
|
@ -28,10 +28,8 @@ namespace Stride.Assets.Models
|
|||
|
||||
public static ImportModelCommand Create(string extension)
|
||||
{
|
||||
if (ImportFbxCommand.IsSupportingExtensions(extension))
|
||||
return new ImportFbxCommand();
|
||||
if (ImportAssimpCommand.IsSupportingExtensions(extension))
|
||||
return new ImportAssimpCommand();
|
||||
if (ImportThreeDCommand.IsSupportingExtensions(extension))
|
||||
return new ImportThreeDCommand();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@ using Stride.Rendering.Data;
|
|||
namespace Stride.Assets.Models
|
||||
{
|
||||
[Description("Import Assimp")]
|
||||
public class ImportAssimpCommand : ImportModelCommand
|
||||
public class ImportThreeDCommand : ImportModelCommand
|
||||
{
|
||||
private static string[] supportedExtensions = AssimpAssetImporter.FileExtensions.Split(';');
|
||||
private static string[] supportedExtensions = ThreeDAssetImporter.FileExtensions.Split(';');
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Title { get { string title = "Import Assimp "; try { title += Path.GetFileName(SourcePath) ?? "[File]"; } catch { title += "[INVALID PATH]"; } return title; } }
|
||||
|
@ -32,9 +32,9 @@ namespace Stride.Assets.Models
|
|||
return supportedExtensions.Any(supExt => supExt.Equals(extToLower));
|
||||
}
|
||||
|
||||
private Stride.Importer.Assimp.MeshConverter CreateMeshConverter(ICommandContext commandContext)
|
||||
private Stride.Importer.ThreeD.MeshConverter CreateMeshConverter(ICommandContext commandContext)
|
||||
{
|
||||
return new Stride.Importer.Assimp.MeshConverter(commandContext.Logger)
|
||||
return new Stride.Importer.ThreeD.MeshConverter(commandContext.Logger)
|
||||
{
|
||||
AllowUnsignedBlendIndices = this.AllowUnsignedBlendIndices,
|
||||
};
|
|
@ -15,6 +15,8 @@ using Stride.Assets.Materials;
|
|||
using Stride.Assets.Textures;
|
||||
using Stride.Rendering;
|
||||
using Stride.Importer.Common;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Stride.Assets.Models
|
||||
{
|
||||
|
@ -58,7 +60,7 @@ namespace Stride.Assets.Models
|
|||
/// <param name="importParameters">The import parameters.</param>
|
||||
/// <param name="startTime">Returns the first (start) keyframe's time for the animation</param>
|
||||
/// <param name="endTime">Returns the last (end) keyframe's time for the animation</param>
|
||||
public abstract void GetAnimationDuration(UFile localPath, Logger logger, AssetImporterParameters importParameters, out TimeSpan startTime, out TimeSpan endTime);
|
||||
public abstract void GetAnimationDuration(UFile localPath, Logger logger, AssetImporterParameters importParameters, int animIndex, out TimeSpan startTime, out TimeSpan endTime);
|
||||
|
||||
/// <summary>
|
||||
/// Imports the model.
|
||||
|
@ -85,7 +87,7 @@ namespace Stride.Assets.Models
|
|||
// 1. Textures
|
||||
if (isImportingTexture)
|
||||
{
|
||||
ImportTextures(entityInfo.TextureDependencies, rawAssetReferences);
|
||||
ImportTextures(entityInfo.TextureDependencies, rawAssetReferences, importParameters.Logger);
|
||||
}
|
||||
|
||||
// 2. Skeleton
|
||||
|
@ -98,10 +100,18 @@ namespace Stride.Assets.Models
|
|||
// 3. Animation
|
||||
if (importParameters.IsTypeSelectedForOutput<AnimationAsset>())
|
||||
{
|
||||
TimeSpan startTime, endTime;
|
||||
GetAnimationDuration(localPath, importParameters.Logger, importParameters, out startTime, out endTime);
|
||||
int _iAnimIndex = 0;
|
||||
entityInfo?.AnimationNodes?.ForEach(c =>
|
||||
{
|
||||
TimeSpan startTime, endTime;
|
||||
GetAnimationDuration(localPath, importParameters.Logger, importParameters, _iAnimIndex, out startTime, out endTime);
|
||||
|
||||
ImportAnimation(rawAssetReferences, localPath, entityInfo.AnimationNodes, isImportingModel, skeletonAsset, startTime, endTime);
|
||||
ImportAnimation(rawAssetReferences, localPath, entityInfo.AnimationNodes[_iAnimIndex], _iAnimIndex, skeletonAsset, startTime, endTime);
|
||||
|
||||
_iAnimIndex++;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 4. Materials
|
||||
|
@ -157,6 +167,32 @@ namespace Stride.Assets.Models
|
|||
}
|
||||
}
|
||||
|
||||
private static void ImportAnimation(List<AssetItem> assetReferences, UFile localPath, string animationNodeName, int animationNodeIndex, AssetItem skeletonAsset, TimeSpan animationStartTime, TimeSpan animationEndTime)
|
||||
{
|
||||
var assetSource = localPath;
|
||||
var asset = new AnimationAsset { Source = assetSource, AnimationTimeMaximum = animationEndTime, AnimationTimeMinimum = animationStartTime };
|
||||
|
||||
var animNodePostFix = new StringBuilder();
|
||||
foreach (var charNodeName in animationNodeName)
|
||||
{
|
||||
if (Path.GetInvalidFileNameChars().Contains(charNodeName))
|
||||
{
|
||||
animNodePostFix.Append("_");
|
||||
}
|
||||
else
|
||||
{
|
||||
animNodePostFix.Append(charNodeName);
|
||||
}
|
||||
}
|
||||
|
||||
var animUrl = localPath.GetFileNameWithoutExtension() + "_" + animNodePostFix.ToString();
|
||||
asset.AnimationStack = animationNodeIndex;
|
||||
if (skeletonAsset != null)
|
||||
asset.Skeleton = AttachedReferenceManager.CreateProxyObject<Skeleton>(skeletonAsset.Id, skeletonAsset.Location);
|
||||
|
||||
assetReferences.Add(new AssetItem(animUrl, asset));
|
||||
}
|
||||
|
||||
private static void ImportModel(List<AssetItem> assetReferences, UFile assetSource, UFile localPath, EntityInfo entityInfo, bool shouldPostFixName, AssetItem skeletonAsset)
|
||||
{
|
||||
var asset = new ModelAsset { Source = assetSource };
|
||||
|
@ -284,13 +320,19 @@ namespace Stride.Assets.Models
|
|||
//}
|
||||
}
|
||||
|
||||
private static void ImportTextures(IEnumerable<string> textureDependencies, List<AssetItem> assetReferences)
|
||||
private static void ImportTextures(IEnumerable<string> textureDependencies, List<AssetItem> assetReferences, Logger logger)
|
||||
{
|
||||
if (textureDependencies == null)
|
||||
return;
|
||||
|
||||
foreach (var textureFullPath in textureDependencies.Distinct(x => x))
|
||||
{
|
||||
if (!File.Exists(textureFullPath))
|
||||
{
|
||||
string texName = Path.GetFileNameWithoutExtension(textureFullPath)??"<unknown>";
|
||||
logger.Error($"Texture with name {texName} not found");
|
||||
continue;
|
||||
}
|
||||
var texturePath = new UFile(textureFullPath);
|
||||
|
||||
var source = texturePath;
|
||||
|
|
|
@ -13,9 +13,8 @@
|
|||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\tools\Stride.Importer.Assimp\Stride.Importer.Assimp.csproj" />
|
||||
<ProjectReference Include="..\..\tools\Stride.Importer.Common\Stride.Importer.Common.csproj" />
|
||||
<ProjectReference Include="..\..\tools\Stride.Importer.FBX\Stride.Importer.FBX.vcxproj" PrivateAssets="All" />
|
||||
<ProjectReference Include="..\..\tools\Stride.Importer.3D\Stride.Importer.3D.csproj" />
|
||||
<ProjectReference Include="..\Stride.Assets\Stride.Assets.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -32,16 +31,12 @@
|
|||
<ItemGroup>
|
||||
<!-- Needed by .NET Core runtime to be able to load C++/CLI assemblies -->
|
||||
<BuildOutputInPackage Include="$(OutputPath)ijwhost.dll" Condition="Exists('$(OutputPath)ijwhost.dll')" />
|
||||
<BuildOutputInPackage Include="$(OutputPath)Stride.Importer.Assimp.dll" />
|
||||
<BuildOutputInPackage Include="$(OutputPath)Stride.Importer.FBX.dll" />
|
||||
<BuildOutputInPackage Include="$(OutputPath)Stride.Importer.FBX.ssdeps" />
|
||||
<BuildOutputInPackage Include="$(OutputPath)Stride.Importer.Common.dll" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="_StrideIncludeNativeLibs">
|
||||
<ItemGroup>
|
||||
<TfmSpecificPackageFile Include="$(OutputPath)runtimes\win-x64\native\libfbxsdk.dll" PackagePath="runtimes\win-x64\native\libfbxsdk.dll" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
|
@ -12,10 +12,10 @@ using Stride.Importer.Common;
|
|||
|
||||
namespace Stride.Assets.Models
|
||||
{
|
||||
public class AssimpAssetImporter : ModelAssetImporter
|
||||
public class ThreeDAssetImporter : ModelAssetImporter
|
||||
{
|
||||
// Supported file extensions for this importer
|
||||
internal const string FileExtensions = ".dae;.3ds;.gltf;.glb;.obj;.blend;.x;.md2;.md3;.dxf;.ply;.stl;.stp";
|
||||
internal const string FileExtensions = ".dae;.3ds;.gltf;.glb;.obj;.blend;.x;.md2;.md3;.dxf;.ply;.stl;.stp;.fbx;";
|
||||
|
||||
private static readonly Guid Uid = new Guid("30243FC0-CEC7-4433-977E-95DCA29D846E");
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace Stride.Assets.Models
|
|||
/// <inheritdoc/>
|
||||
public override EntityInfo GetEntityInfo(UFile localPath, Logger logger, AssetImporterParameters importParameters)
|
||||
{
|
||||
var meshConverter = new Importer.Assimp.MeshConverter(logger);
|
||||
var meshConverter = new Importer.ThreeD.MeshConverter(logger);
|
||||
|
||||
if (!importParameters.InputParameters.TryGet(DeduplicateMaterialsKey, out var deduplicateMaterials))
|
||||
deduplicateMaterials = true; // Dedupe is the default value
|
||||
|
@ -38,10 +38,10 @@ namespace Stride.Assets.Models
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void GetAnimationDuration(UFile localPath, Logger logger, AssetImporterParameters importParameters, out TimeSpan startTime, out TimeSpan endTime)
|
||||
public override void GetAnimationDuration(UFile localPath, Logger logger, AssetImporterParameters importParameters, int animIndex, out TimeSpan startTime, out TimeSpan endTime)
|
||||
{
|
||||
var meshConverter = new Importer.Assimp.MeshConverter(logger);
|
||||
var sceneData = meshConverter.ConvertAnimation(localPath.FullPath, "", 0);
|
||||
var meshConverter = new Importer.ThreeD.MeshConverter(logger);
|
||||
var sceneData = meshConverter.ConvertAnimation(localPath.FullPath, "", animIndex);
|
||||
|
||||
startTime = CompressedTimeSpan.MaxValue; // This will go down, so we start from positive infinity
|
||||
endTime = CompressedTimeSpan.MinValue; // This will go up, so we start from negative infinity
|
|
@ -1,9 +1,9 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Stride.Importer.Assimp.Material
|
||||
namespace Stride.Importer.ThreeD.Material
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumeration of the new Assimp's flags.
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
|
||||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
|
||||
namespace Stride.Importer.Assimp.Material
|
||||
namespace Stride.Importer.ThreeD.Material
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumeration of the different mapping modes in the new Assimp's material stack.
|
|
@ -1,9 +1,9 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Stride.Importer.Assimp.Material
|
||||
namespace Stride.Importer.ThreeD.Material
|
||||
{
|
||||
/// <summary>
|
||||
/// Class representing the new Assimp's material stack in c#.
|
|
@ -1,10 +1,11 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
|
||||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Silk.NET.Assimp;
|
||||
using Stride.Core.Diagnostics;
|
||||
using Stride.Core.Mathematics;
|
||||
|
||||
namespace Stride.Importer.Assimp.Material
|
||||
namespace Stride.Importer.ThreeD.Material
|
||||
{
|
||||
public static unsafe class Materials
|
||||
{
|
||||
|
@ -76,7 +77,7 @@ namespace Stride.Importer.Assimp.Material
|
|||
MappingMode.Decal // aiTextureMapMode_Decal
|
||||
};
|
||||
|
||||
public static unsafe MaterialStack ConvertAssimpStackCppToCs(Silk.NET.Assimp.Assimp assimp, Silk.NET.Assimp.Material* material, Silk.NET.Assimp.TextureType type)
|
||||
public static unsafe MaterialStack ConvertAssimpStackCppToCs(Silk.NET.Assimp.Assimp assimp, Silk.NET.Assimp.Material* material, Silk.NET.Assimp.TextureType type, Logger logger)
|
||||
{
|
||||
var ret = new MaterialStack();
|
||||
var count = (int)assimp.GetMaterialTextureCount(material, type);
|
||||
|
@ -110,20 +111,31 @@ namespace Stride.Importer.Assimp.Material
|
|||
{
|
||||
case StackElementType.Operation:
|
||||
if (assimp.GetMaterialIntegerArray(material, Silk.NET.Assimp.Assimp.MaterialTexopBase, (uint)type, (uint)iEl, ref elOp, ref pMax) != Return.Success)
|
||||
{
|
||||
logger?.Error("Material not found");
|
||||
continue; // error !
|
||||
|
||||
}
|
||||
el = new StackOperation(ConvertAssimpStackOperationCppToCs[elOp], elAlpha, elBlend, elFlags);
|
||||
break;
|
||||
case StackElementType.Color:
|
||||
if (assimp.GetMaterialColor(material, MatKeyTexColorBase, (uint)type, (uint)iEl, ref elColor) != Return.Success)
|
||||
{
|
||||
logger?.Error("Material with index not found");
|
||||
continue; // error !
|
||||
}
|
||||
el = new StackColor(new Color3(elColor.X, elColor.Y, elColor.Z), elAlpha, elBlend, elFlags);
|
||||
break;
|
||||
case StackElementType.Texture:
|
||||
if (assimp.GetMaterialString(material, Silk.NET.Assimp.Assimp.MaterialTextureBase, (uint)type, (uint)iEl, ref elTexPath) != Return.Success)
|
||||
{
|
||||
logger?.Error("Material texture item not found");
|
||||
continue; // error !
|
||||
}
|
||||
if (assimp.GetMaterialIntegerArray(material, Silk.NET.Assimp.Assimp.MaterialUvwsrcBase, (uint)type, (uint)iEl, ref elTexChannel, ref pMax) != Return.Success)
|
||||
elTexChannel = 0; // default channel
|
||||
{
|
||||
logger?.Error("Material integer item not found");
|
||||
continue; // error !
|
||||
}
|
||||
if (assimp.GetMaterialIntegerArray(material, Silk.NET.Assimp.Assimp.MaterialMappingmodeUBase, (uint)type, (uint)iEl, ref elMappingModeU, ref pMax) != Return.Success)
|
||||
elMappingModeU = (int)TextureMapMode.Wrap; // default mapping mode
|
||||
if (assimp.GetMaterialIntegerArray(material, Silk.NET.Assimp.Assimp.MaterialMappingmodeVBase, (uint)type, (uint)iEl, ref elMappingModeV, ref pMax) != Return.Success)
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
|
||||
namespace Stride.Importer.Assimp.Material
|
||||
namespace Stride.Importer.ThreeD.Material
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumeration of the different operations in the new Assimp's material stack.
|
|
@ -1,9 +1,9 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using Stride.Core.Mathematics;
|
||||
|
||||
namespace Stride.Importer.Assimp.Material
|
||||
namespace Stride.Importer.ThreeD.Material
|
||||
{
|
||||
/// <summary>
|
||||
/// Class representing a color in the new Assimp's material stack.
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
|
||||
namespace Stride.Importer.Assimp.Material
|
||||
namespace Stride.Importer.ThreeD.Material
|
||||
{
|
||||
/// <summary>
|
||||
/// Class representing an element in the new Assimp's material stack.
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
|
||||
namespace Stride.Importer.Assimp.Material
|
||||
namespace Stride.Importer.ThreeD.Material
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumeration of the different types of node in the new Assimp's material stack.
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
|
||||
namespace Stride.Importer.Assimp.Material
|
||||
namespace Stride.Importer.ThreeD.Material
|
||||
{
|
||||
/// <summary>
|
||||
/// Class representing an operation in the new Assimp's material stack.
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
|
||||
namespace Stride.Importer.Assimp.Material
|
||||
namespace Stride.Importer.ThreeD.Material
|
||||
{
|
||||
/// <summary>
|
||||
/// Class representing a texture in the new Assimp's material stack.
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Silk.NET.Assimp;
|
||||
using Stride.Animations;
|
||||
using Stride.Assets.Materials;
|
||||
|
@ -13,6 +14,7 @@ using Stride.Core.Diagnostics;
|
|||
using Stride.Core.IO;
|
||||
using Stride.Core.Mathematics;
|
||||
using Stride.Core.Serialization;
|
||||
using Stride.Engine;
|
||||
using Stride.Graphics;
|
||||
using Stride.Graphics.Data;
|
||||
using Stride.Importer.Common;
|
||||
|
@ -21,11 +23,32 @@ using Stride.Rendering.Materials;
|
|||
using Stride.Rendering.Materials.ComputeColors;
|
||||
using Mesh = Stride.Rendering.Mesh;
|
||||
using PrimitiveType = Stride.Graphics.PrimitiveType;
|
||||
using Scene = Silk.NET.Assimp.Scene;
|
||||
|
||||
namespace Stride.Importer.Assimp
|
||||
namespace Stride.Importer.ThreeD
|
||||
{
|
||||
public class MeshConverter
|
||||
{
|
||||
|
||||
static class PostProcessActions
|
||||
{
|
||||
public const uint CalculateTangentSpace = 1;
|
||||
public const uint Triangulate = 8;
|
||||
public const uint GenerateNormals = 32;
|
||||
public const uint JoinIdenticalVertices = 2;
|
||||
public const uint LimitBoneWeights = 512;
|
||||
public const uint SortByPrimitiveType = 32768;
|
||||
public const uint FlipWindingOrder = 16777216;
|
||||
public const uint FlipUVs = 8388608;
|
||||
public const uint GenSmoothNormals = 64;
|
||||
public const uint ImproveCacheLocality = 2048;
|
||||
public const uint RemoveRedundantMaterials = 4096;
|
||||
public const uint SplitLargeMeshes = 128;
|
||||
public const uint GenUVCoords = 262144;
|
||||
public const uint GlobalScaling = 134217728;
|
||||
public const uint OptimizeGraph = 4194304;
|
||||
}
|
||||
|
||||
static MeshConverter()
|
||||
{
|
||||
if (Platform.Type == PlatformType.Windows)
|
||||
|
@ -42,7 +65,6 @@ namespace Stride.Importer.Assimp
|
|||
|
||||
public bool AllowUnsignedBlendIndices { get; set; }
|
||||
|
||||
// Conversion data
|
||||
|
||||
private string vfsInputFilename;
|
||||
private string vfsOutputFilename;
|
||||
|
@ -79,7 +101,7 @@ namespace Stride.Importer.Assimp
|
|||
postProcessFlags |= PostProcessSteps.RemoveRedundantMaterials;
|
||||
}
|
||||
|
||||
var scene = Initialize(inputFilename, outputFilename, importFlags, (uint)postProcessFlags);
|
||||
var scene = Initialize(inputFilename, outputFilename, importFlags, 0);
|
||||
|
||||
// If scene is null, something went wrong inside Assimp
|
||||
if (scene == null)
|
||||
|
@ -113,7 +135,7 @@ namespace Stride.Importer.Assimp
|
|||
|
||||
return entityInfo;
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"Exception has occured during Entity extraction : {ex.Message}");
|
||||
throw;
|
||||
|
@ -123,31 +145,15 @@ namespace Stride.Importer.Assimp
|
|||
public unsafe Model Convert(string inputFilename, string outputFilename, bool deduplicateMaterials)
|
||||
{
|
||||
uint importFlags = 0;
|
||||
var postProcessFlags =
|
||||
PostProcessSteps.CalculateTangentSpace
|
||||
| PostProcessSteps.Triangulate
|
||||
| PostProcessSteps.GenerateNormals
|
||||
| PostProcessSteps.JoinIdenticalVertices
|
||||
| PostProcessSteps.LimitBoneWeights
|
||||
| PostProcessSteps.SortByPrimitiveType
|
||||
| PostProcessSteps.FlipWindingOrder
|
||||
| PostProcessSteps.FlipUVs;
|
||||
|
||||
if (deduplicateMaterials)
|
||||
{
|
||||
postProcessFlags |= PostProcessSteps.RemoveRedundantMaterials;
|
||||
}
|
||||
|
||||
var scene = Initialize(inputFilename, outputFilename, importFlags, (uint)postProcessFlags);
|
||||
var scene = Initialize(inputFilename, outputFilename, importFlags, 0);
|
||||
return ConvertAssimpScene(scene);
|
||||
}
|
||||
|
||||
public unsafe AnimationInfo ConvertAnimation(string inputFilename, string outputFilename, int animationIndex)
|
||||
{
|
||||
uint importFlags = 0;
|
||||
var postProcessFlags = PostProcessSteps.None;
|
||||
|
||||
var scene = Initialize(inputFilename, outputFilename, importFlags, (uint)postProcessFlags);
|
||||
var scene = Initialize(inputFilename, outputFilename, importFlags, 0);
|
||||
|
||||
return ProcessAnimations(scene, animationIndex);
|
||||
}
|
||||
|
@ -157,7 +163,7 @@ namespace Stride.Importer.Assimp
|
|||
uint importFlags = 0;
|
||||
var postProcessFlags = PostProcessSteps.None;
|
||||
|
||||
var scene = Initialize(inputFilename, outputFilename, importFlags, (uint)postProcessFlags);
|
||||
var scene = Initialize(inputFilename, outputFilename, importFlags, 0);
|
||||
|
||||
return ProcessSkeleton(scene);
|
||||
}
|
||||
|
@ -170,9 +176,21 @@ namespace Stride.Importer.Assimp
|
|||
vfsOutputFilename = outputFilename;
|
||||
vfsInputPath = VirtualFileSystem.GetParentFolder(inputFilename);
|
||||
|
||||
var scene = assimp.ImportFile(inputFilename, importFlags);
|
||||
scene = assimp.ApplyPostProcessing(scene, postProcessFlags);
|
||||
var propStore = assimp.CreatePropertyStore();
|
||||
assimp.SetImportPropertyInteger(propStore, "IMPORT_FBX_PRESERVE_PIVOTS", 0);
|
||||
assimp.SetImportPropertyFloat(propStore, "APP_SCALE_FACTOR", .01f);
|
||||
var scene = assimp.ImportFileExWithProperties(inputFilename, importFlags, null, propStore);
|
||||
|
||||
var postProcessFlags1 = PostProcessActions.CalculateTangentSpace
|
||||
| PostProcessActions.Triangulate
|
||||
| PostProcessActions.GenerateNormals
|
||||
| PostProcessActions.SortByPrimitiveType
|
||||
| PostProcessActions.FlipWindingOrder
|
||||
| PostProcessActions.FlipUVs
|
||||
| PostProcessActions.GlobalScaling;
|
||||
|
||||
scene = assimp.ApplyPostProcessing(scene, postProcessFlags1);
|
||||
assimp.ReleasePropertyStore(propStore);
|
||||
return scene;
|
||||
}
|
||||
|
||||
|
@ -188,7 +206,7 @@ namespace Stride.Importer.Assimp
|
|||
|
||||
// register the nodes and fill hierarchy
|
||||
var meshIndexToNodeIndex = new Dictionary<int, List<int>>();
|
||||
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex);
|
||||
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex, GetBoneList(scene));
|
||||
|
||||
// meshes
|
||||
for (var i = 0; i < scene->MNumMeshes; ++i)
|
||||
|
@ -204,7 +222,7 @@ namespace Stride.Importer.Assimp
|
|||
Draw = meshInfo.Draw,
|
||||
Name = meshInfo.Name,
|
||||
MaterialIndex = meshInfo.MaterialIndex,
|
||||
NodeIndex = nodeIndex
|
||||
NodeIndex = nodeIndex,
|
||||
};
|
||||
|
||||
if (meshInfo.Bones != null)
|
||||
|
@ -221,6 +239,7 @@ namespace Stride.Importer.Assimp
|
|||
if (meshInfo.HasSkinningNormal && meshInfo.TotalClusterCount > 0)
|
||||
nodeMeshData.Parameters.Set(MaterialKeys.HasSkinningNormal, true);
|
||||
|
||||
|
||||
modelData.Meshes.Add(nodeMeshData);
|
||||
}
|
||||
}
|
||||
|
@ -242,7 +261,7 @@ namespace Stride.Importer.Assimp
|
|||
|
||||
// register the nodes and fill hierarchy
|
||||
var meshIndexToNodeIndex = new Dictionary<int, List<int>>();
|
||||
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex);
|
||||
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex, GetBoneList(scene));
|
||||
|
||||
return new Rendering.Skeleton
|
||||
{
|
||||
|
@ -260,7 +279,7 @@ namespace Stride.Importer.Assimp
|
|||
|
||||
// register the nodes and fill hierarchy
|
||||
var meshIndexToNodeIndex = new Dictionary<int, List<int>>();
|
||||
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex);
|
||||
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex, GetBoneList(scene));
|
||||
|
||||
if (scene->MNumAnimations > 0)
|
||||
{
|
||||
|
@ -287,7 +306,7 @@ namespace Stride.Importer.Assimp
|
|||
// Nevertheless the second one do not seems to be usable in assimp 3.0 so it will be ignored here.
|
||||
|
||||
// name of the animation (dropped)
|
||||
var animName = aiAnim->MName.AsString; // used only be the logger
|
||||
var animName = aiAnim->MName.AsString.CleanNodeName(); // used only be the logger
|
||||
|
||||
// animation using meshes (not supported)
|
||||
for (uint meshAnimId = 0; meshAnimId < aiAnim->MNumMeshChannels; ++meshAnimId)
|
||||
|
@ -300,7 +319,7 @@ namespace Stride.Importer.Assimp
|
|||
for (uint nodeAnimId = 0; nodeAnimId < aiAnim->MNumChannels; ++nodeAnimId)
|
||||
{
|
||||
var nodeAnim = aiAnim->MChannels[nodeAnimId];
|
||||
var nodeName = nodeAnim->MNodeName.AsString;
|
||||
var nodeName = nodeAnim->MNodeName.AsString.CleanNodeName();
|
||||
|
||||
if (!visitedNodeNames.Contains(nodeName))
|
||||
{
|
||||
|
@ -321,7 +340,7 @@ namespace Stride.Importer.Assimp
|
|||
private unsafe void ProcessNodeAnimation(Dictionary<string, AnimationClip> animationClips, NodeAnim* nodeAnim, double ticksPerSec)
|
||||
{
|
||||
// Find the nodes on which the animation is performed
|
||||
var nodeName = nodeAnim->MNodeName.AsString;
|
||||
var nodeName = nodeAnim->MNodeName.AsString.CleanNodeName();
|
||||
|
||||
var animationClip = new AnimationClip();
|
||||
|
||||
|
@ -419,23 +438,7 @@ namespace Stride.Importer.Assimp
|
|||
for (var i = 0; i < baseNames.Count; ++i)
|
||||
{
|
||||
// Clean the name by removing unwanted characters
|
||||
var itemName = baseNames[i];
|
||||
|
||||
var itemNameSplitPosition = itemName.IndexOf('#');
|
||||
if (itemNameSplitPosition != -1)
|
||||
{
|
||||
itemName = itemName.Substring(0, itemNameSplitPosition);
|
||||
}
|
||||
|
||||
itemNameSplitPosition = itemName.IndexOf("__", StringComparison.Ordinal);
|
||||
if (itemNameSplitPosition != -1)
|
||||
{
|
||||
itemName = itemName.Substring(0, itemNameSplitPosition);
|
||||
}
|
||||
|
||||
// remove all bad characters
|
||||
itemName = itemName.Replace(':', '_');
|
||||
itemName = itemName.Replace(" ", string.Empty);
|
||||
var itemName = baseNames[i].CleanNodeName();
|
||||
|
||||
tempNames.Add(itemName);
|
||||
|
||||
|
@ -465,15 +468,34 @@ namespace Stride.Importer.Assimp
|
|||
}
|
||||
}
|
||||
|
||||
private unsafe HashSet<string> GetBoneList(Scene* scene)
|
||||
{
|
||||
HashSet<string> bones = new HashSet<string>();
|
||||
for (uint i = 0; i < scene->MNumMeshes; i++)
|
||||
{
|
||||
var lMesh = scene->MMeshes[i];
|
||||
var boneCount = lMesh->MNumBones;
|
||||
for (int j = 0; j < boneCount; j++)
|
||||
{
|
||||
string boneName = lMesh->MBones[j]->MName.AsString;
|
||||
if(!bones.Contains(boneName))
|
||||
{
|
||||
bones.Add(boneName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bones;
|
||||
}
|
||||
|
||||
private unsafe void GenerateMeshNames(Scene* scene, Dictionary<IntPtr, string> meshNames)
|
||||
{
|
||||
var baseNames = new List<string>();
|
||||
for (uint i = 0; i < scene->MNumMeshes; i++)
|
||||
{
|
||||
var lMesh = scene->MMeshes[i];
|
||||
baseNames.Add(lMesh->MName.AsString);
|
||||
baseNames.Add(lMesh->MName.AsString.CleanNodeName());
|
||||
|
||||
}
|
||||
|
||||
GenerateUniqueNames(meshNames, baseNames, i => (IntPtr)scene->MMeshes[i]);
|
||||
}
|
||||
|
||||
|
@ -483,7 +505,7 @@ namespace Stride.Importer.Assimp
|
|||
for (uint i = 0; i < scene->MNumAnimations; i++)
|
||||
{
|
||||
var lAnimation = scene->MAnimations[i];
|
||||
var animationName = lAnimation->MName.AsString;
|
||||
var animationName = lAnimation->MName.AsString.CleanNodeName();
|
||||
baseNames.Add(animationName);
|
||||
}
|
||||
|
||||
|
@ -501,7 +523,7 @@ namespace Stride.Importer.Assimp
|
|||
|
||||
private unsafe void GetNodeNames(Node* node, List<string> nodeNames, List<IntPtr> orderedNodes)
|
||||
{
|
||||
nodeNames.Add(node->MName.AsString);
|
||||
nodeNames.Add(node->MName.AsString.CleanNodeName());
|
||||
orderedNodes.Add((IntPtr)node);
|
||||
|
||||
for (uint i = 0; i < node->MNumChildren; ++i)
|
||||
|
@ -510,7 +532,7 @@ namespace Stride.Importer.Assimp
|
|||
}
|
||||
}
|
||||
|
||||
private unsafe void RegisterNodes(Node* fromNode, int parentIndex, Dictionary<IntPtr, string> nodeNames, Dictionary<int, List<int>> meshIndexToNodeIndex)
|
||||
private unsafe void RegisterNodes(Node* fromNode, int parentIndex, Dictionary<IntPtr, string> nodeNames, Dictionary<int, List<int>> meshIndexToNodeIndex, HashSet<string> filterInNodes)
|
||||
{
|
||||
var nodeIndex = nodes.Count;
|
||||
|
||||
|
@ -536,8 +558,10 @@ namespace Stride.Importer.Assimp
|
|||
Flags = ModelNodeFlags.Default
|
||||
};
|
||||
|
||||
var meshes = fromNode->MMeshes;
|
||||
// Extract scene scaling and rotation from the root node.
|
||||
// Bake scaling into all node's positions and rotation into the 1st-level nodes.
|
||||
|
||||
if (parentIndex == -1)
|
||||
{
|
||||
rootTransform = fromNode->MTransformation.ToStrideMatrix();
|
||||
|
@ -552,16 +576,27 @@ namespace Stride.Importer.Assimp
|
|||
}
|
||||
else
|
||||
{
|
||||
var transform = rootTransformInverse * fromNode->MTransformation.ToStrideMatrix() * rootTransform;
|
||||
var transform = fromNode->MTransformation.ToStrideMatrix();
|
||||
transform.Decompose(out modelNodeDefinition.Transform.Scale, out modelNodeDefinition.Transform.Rotation, out modelNodeDefinition.Transform.Position);
|
||||
}
|
||||
|
||||
if (filterInNodes!=null
|
||||
&& filterInNodes.Count>0)
|
||||
{
|
||||
if(!filterInNodes.Contains(fromNode->MName.AsString))
|
||||
{
|
||||
modelNodeDefinition.Transform.Rotation = Quaternion.Identity;
|
||||
modelNodeDefinition.Transform.Scale = Vector3.One;
|
||||
modelNodeDefinition.Transform.Position = Vector3.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
nodes.Add(modelNodeDefinition);
|
||||
|
||||
// register the children
|
||||
for (uint child = 0; child < fromNode->MNumChildren; ++child)
|
||||
{
|
||||
RegisterNodes(fromNode->MChildren[child], nodeIndex, nodeNames, meshIndexToNodeIndex);
|
||||
RegisterNodes(fromNode->MChildren[child], nodeIndex, nodeNames, meshIndexToNodeIndex, filterInNodes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,7 +606,7 @@ namespace Stride.Importer.Assimp
|
|||
var hasSkinningPosition = false;
|
||||
var hasSkinningNormal = false;
|
||||
var totalClusterCount = 0;
|
||||
|
||||
var drawData = new MeshDraw();
|
||||
// Build the bone's indices/weights and attach bones to NodeData
|
||||
//(bones info are present in the mesh so that is why we have to perform that here)
|
||||
|
||||
|
@ -603,7 +638,11 @@ namespace Stride.Importer.Assimp
|
|||
|
||||
// find the node where the bone is mapped - based on the name(?)
|
||||
var nodeIndex = -1;
|
||||
var boneName = bone->MName.AsString;
|
||||
var boneName = bone->MName.AsString.CleanNodeName();
|
||||
foreach (char c in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
boneName = boneName.Replace(c, '_');
|
||||
}
|
||||
for (var nodeDefId = 0; nodeDefId < nodes.Count; ++nodeDefId)
|
||||
{
|
||||
var nodeDef = nodes[nodeDefId];
|
||||
|
@ -623,7 +662,8 @@ namespace Stride.Importer.Assimp
|
|||
bones.Add(new MeshBoneDefinition
|
||||
{
|
||||
NodeIndex = nodeIndex,
|
||||
LinkToMeshMatrix = rootTransformInverse * bone->MOffsetMatrix.ToStrideMatrix() * rootTransform
|
||||
LinkToMeshMatrix = bone->MOffsetMatrix.ToStrideMatrix()
|
||||
// LinkToMeshMatrix = rootTransformInverse * bone->MOffsetMatrix.ToStrideMatrix() * rootTransform
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -825,6 +865,8 @@ namespace Stride.Importer.Assimp
|
|||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
*((uint*)ibPointer) = mesh->MFaces[(int)i].MIndices[j];
|
||||
|
||||
var _index = (ushort)(mesh->MFaces[(int)i].MIndices[j]);
|
||||
ibPointer += sizeof(uint);
|
||||
}
|
||||
}
|
||||
|
@ -833,6 +875,7 @@ namespace Stride.Importer.Assimp
|
|||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
*((ushort*)ibPointer) = (ushort)(mesh->MFaces[(int)i].MIndices[j]);
|
||||
var _index = (ushort)(mesh->MFaces[(int)i].MIndices[j]);
|
||||
ibPointer += sizeof(ushort);
|
||||
}
|
||||
}
|
||||
|
@ -844,13 +887,12 @@ namespace Stride.Importer.Assimp
|
|||
var vertexBufferBinding = new VertexBufferBinding(GraphicsSerializerExtensions.ToSerializableVersion(new BufferData(BufferFlags.VertexBuffer, vertexBuffer)), vertexDeclaration, (int)mesh->MNumVertices, vertexDeclaration.VertexStride, 0);
|
||||
var indexBufferBinding = new IndexBufferBinding(GraphicsSerializerExtensions.ToSerializableVersion(new BufferData(BufferFlags.IndexBuffer, indexBuffer)), is32BitIndex, (int)nbIndices, 0);
|
||||
|
||||
var drawData = new MeshDraw
|
||||
{
|
||||
VertexBuffers = new VertexBufferBinding[] { vertexBufferBinding },
|
||||
IndexBuffer = indexBufferBinding,
|
||||
PrimitiveType = PrimitiveType.TriangleList,
|
||||
DrawCount = (int)nbIndices
|
||||
};
|
||||
|
||||
drawData.VertexBuffers = new VertexBufferBinding[] { vertexBufferBinding };
|
||||
drawData.IndexBuffer = indexBufferBinding;
|
||||
drawData.PrimitiveType = PrimitiveType.TriangleList;
|
||||
drawData.DrawCount = (int)nbIndices;
|
||||
|
||||
|
||||
return new MeshInfo
|
||||
{
|
||||
|
@ -862,6 +904,8 @@ namespace Stride.Importer.Assimp
|
|||
HasSkinningNormal = hasSkinningNormal,
|
||||
TotalClusterCount = totalClusterCount
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void NormalizeVertexWeights(List<List<(short, float)>> controlPts, int nbBoneByVertex)
|
||||
|
@ -986,7 +1030,7 @@ namespace Stride.Importer.Assimp
|
|||
}
|
||||
private unsafe void SetMaterialFloatArrayFlag(Silk.NET.Assimp.Material* pMaterial, string materialBase, ref bool hasMatProperty, float matColor, bool condition)
|
||||
{
|
||||
if(assimp.GetMaterialFloatArray(pMaterial, materialBase, 0, 0, &matColor, (uint*)0x0) == Return.Success && condition)
|
||||
if (assimp.GetMaterialFloatArray(pMaterial, materialBase, 0, 0, &matColor, (uint*)0x0) == Return.Success && condition)
|
||||
{
|
||||
hasMatProperty = true;
|
||||
}
|
||||
|
@ -1095,7 +1139,7 @@ namespace Stride.Importer.Assimp
|
|||
|
||||
private unsafe IComputeColor GenerateOneTextureTypeLayers(Silk.NET.Assimp.Material* pMat, TextureType textureType, int textureCount, MaterialAsset finalMaterial)
|
||||
{
|
||||
var stack = Material.Materials.ConvertAssimpStackCppToCs(assimp, pMat, textureType);
|
||||
var stack = Material.Materials.ConvertAssimpStackCppToCs(assimp, pMat, textureType, Logger);
|
||||
|
||||
var compositionFathers = new Stack<IComputeColor>();
|
||||
|
||||
|
@ -1393,4 +1437,7 @@ namespace Stride.Importer.Assimp
|
|||
public List<MaterialInstantiation> Instances = new();
|
||||
public string MaterialsName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Analysis\" />
|
||||
<Folder Include="Material\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Silk.NET.Assimp" />
|
|
@ -4,9 +4,11 @@
|
|||
using Silk.NET.Assimp;
|
||||
using Stride.Animations;
|
||||
using Stride.Core.Mathematics;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Stride.Importer.Assimp
|
||||
namespace Stride.Importer.ThreeD
|
||||
{
|
||||
public static class Utils
|
||||
{
|
||||
|
@ -24,13 +26,13 @@ namespace Stride.Importer.Assimp
|
|||
}
|
||||
|
||||
public static Core.Mathematics.Vector3 ToStrideVector3(this System.Numerics.Vector3 v)
|
||||
=> new Core.Mathematics.Vector3(v.X, v.Y, v.Z);
|
||||
=> Unsafe.As<System.Numerics.Vector3, Core.Mathematics.Vector3>(ref v);
|
||||
|
||||
public static Color ToStrideColor(this System.Numerics.Vector4 v)
|
||||
=> new Color(v.X, v.Y, v.Z, v.W);
|
||||
|
||||
public static Core.Mathematics.Quaternion ToStrideQuaternion(this AssimpQuaternion q)
|
||||
=> new Core.Mathematics.Quaternion(q.X, q.Y, q.Z, q.W);
|
||||
=> new Core.Mathematics.Quaternion(q.X, q.Y, q.Z, q.W);
|
||||
|
||||
public static unsafe uint GetNumUVChannels(Silk.NET.Assimp.Mesh* mesh)
|
||||
{
|
||||
|
@ -59,5 +61,36 @@ namespace Stride.Importer.Assimp
|
|||
var sdTime = CompressedTimeSpan.TicksPerSecond / aiTickPerSecond * time;
|
||||
return new CompressedTimeSpan((int)sdTime);
|
||||
}
|
||||
|
||||
public static string CleanNodeName(this string itemName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(itemName)) { return itemName; }
|
||||
var itemNameSplitPosition = itemName.IndexOf('#');
|
||||
if (itemNameSplitPosition != -1)
|
||||
{
|
||||
itemName = itemName.Substring(0, itemNameSplitPosition);
|
||||
}
|
||||
|
||||
itemNameSplitPosition = itemName.IndexOf("__", StringComparison.Ordinal);
|
||||
if (itemNameSplitPosition != -1)
|
||||
{
|
||||
itemName = itemName.Substring(0, itemNameSplitPosition);
|
||||
}
|
||||
|
||||
itemNameSplitPosition = itemName.LastIndexOf(":", StringComparison.Ordinal);
|
||||
if (itemNameSplitPosition != -1)
|
||||
{
|
||||
if (itemName.Length > itemNameSplitPosition + 1)
|
||||
{
|
||||
itemName = itemName.Substring(itemNameSplitPosition + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// remove all bad characters
|
||||
itemName = itemName.Replace(':', '_');
|
||||
itemName = itemName.Replace(" ", string.Empty);
|
||||
|
||||
return itemName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,868 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "SceneMapping.h"
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Text;
|
||||
using namespace System::IO;
|
||||
using namespace System::Collections::Generic;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using namespace Stride::Core::Mathematics;
|
||||
using namespace Stride::Importer::Common;
|
||||
|
||||
namespace Stride {
|
||||
namespace Importer {
|
||||
namespace FBX {
|
||||
|
||||
ref class AnimationConverter
|
||||
{
|
||||
private:
|
||||
Logger^ logger;
|
||||
FbxScene* scene;
|
||||
bool exportedFromMaya;
|
||||
SceneMapping^ sceneMapping;
|
||||
|
||||
CompressedTimeSpan animStartTime;
|
||||
|
||||
public:
|
||||
AnimationConverter(Logger^ logger, SceneMapping^ sceneMapping)
|
||||
{
|
||||
if (logger == nullptr) throw gcnew ArgumentNullException("logger");
|
||||
if (sceneMapping == nullptr) throw gcnew ArgumentNullException("sceneMapping");
|
||||
|
||||
this->logger = logger;
|
||||
this->sceneMapping = sceneMapping;
|
||||
this->scene = sceneMapping->Scene;
|
||||
|
||||
auto documentInfo = scene->GetDocumentInfo();
|
||||
if (documentInfo->Original_ApplicationName.Get() == "Maya")
|
||||
exportedFromMaya = true;
|
||||
}
|
||||
|
||||
bool HasAnimationData()
|
||||
{
|
||||
int animStackCount = scene->GetMemberCount<FbxAnimStack>();
|
||||
|
||||
if (animStackCount > 0)
|
||||
{
|
||||
bool check = true;
|
||||
for (int i = 0; i < animStackCount && check; ++i)
|
||||
{
|
||||
FbxAnimStack* animStack = scene->GetMember<FbxAnimStack>(i);
|
||||
int animLayerCount = animStack->GetMemberCount<FbxAnimLayer>();
|
||||
FbxAnimLayer* animLayer = animStack->GetMember<FbxAnimLayer>(0);
|
||||
|
||||
check = check && CheckAnimationData(animLayer, scene->GetRootNode());
|
||||
}
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AnimationInfo^ ProcessAnimation(String^ inputFilename, String^ vfsOutputFilename, bool importCustomAttributeAnimations, int animationStack)
|
||||
{
|
||||
auto animationData = gcnew AnimationInfo();
|
||||
|
||||
int animStackCount = scene->GetMemberCount<FbxAnimStack>();
|
||||
if (animStackCount == 0)
|
||||
return animationData;
|
||||
|
||||
if (animationStack < 0)
|
||||
{
|
||||
animationStack = 0;
|
||||
logger->Warning(String::Format("Animation stack specified in '{0}' less than zero, exporting first stack to '{1}",
|
||||
gcnew String(inputFilename), gcnew String(vfsOutputFilename)), (CallerInfo^)nullptr);
|
||||
}
|
||||
|
||||
if (animationStack >= animStackCount)
|
||||
{
|
||||
animationStack = animStackCount - 1;
|
||||
logger->Warning(String::Format("Animation stack count in '{0}' greater than specified stack index, exporting last available stack to '{1}",
|
||||
gcnew String(inputFilename), gcnew String(vfsOutputFilename)), (CallerInfo^)nullptr);
|
||||
}
|
||||
|
||||
FbxAnimStack* animStack = scene->GetMember<FbxAnimStack>(animationStack);
|
||||
int animLayerCount = animStack->GetMemberCount<FbxAnimLayer>();
|
||||
|
||||
// We support only anim layer count == 1
|
||||
if (animLayerCount > 1)
|
||||
{
|
||||
logger->Warning(String::Format("Multiple FBX animation layers detected in '{0}', exporting only the first one to '{1}'",
|
||||
gcnew String(inputFilename), gcnew String(vfsOutputFilename)), (CallerInfo^)nullptr);
|
||||
}
|
||||
|
||||
FbxAnimLayer* animLayer = animStack->GetMember<FbxAnimLayer>(0);
|
||||
|
||||
FbxTime animStart, animEnd;
|
||||
|
||||
// Store start/end info
|
||||
const FbxTakeInfo* take_info = scene->GetTakeInfo(animStack->GetName());
|
||||
if (take_info)
|
||||
{
|
||||
animStart = take_info->mLocalTimeSpan.GetStart();
|
||||
animEnd = take_info->mLocalTimeSpan.GetStop();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take the time line value.
|
||||
FbxTimeSpan lTimeLineTimeSpan;
|
||||
scene->GetGlobalSettings().GetTimelineDefaultTimeSpan(lTimeLineTimeSpan);
|
||||
animStart = lTimeLineTimeSpan.GetStart();
|
||||
animEnd = lTimeLineTimeSpan.GetStop();
|
||||
}
|
||||
|
||||
animStartTime = FBXTimeToTimeSpan(animStart);
|
||||
|
||||
// Optimized code
|
||||
// From http://www.the-area.com/forum/autodesk-fbx/fbx-sdk/resetpivotsetandconvertanimation-issue/page-1/
|
||||
scene->GetRootNode()->ResetPivotSet(FbxNode::eDestinationPivot);
|
||||
SetPivotStateRecursive(scene->GetRootNode());
|
||||
scene->GetRootNode()->ConvertPivotAnimationRecursive(animStack, FbxNode::eDestinationPivot, 30.0f);
|
||||
ProcessAnimationByNode(animationData->AnimationClips, animLayer, scene->GetRootNode(), importCustomAttributeAnimations);
|
||||
scene->GetRootNode()->ResetPivotSet(FbxNode::eSourcePivot);
|
||||
|
||||
// Set duration
|
||||
// Note: we can't use animEnd - animStart since some FBX has wrong data there
|
||||
for each (auto animationClip in animationData->AnimationClips)
|
||||
{
|
||||
if (animationData->Duration < animationClip.Value->Duration)
|
||||
animationData->Duration = animationClip.Value->Duration;
|
||||
}
|
||||
|
||||
// Reference code (Uncomment Optimized code to use this part)
|
||||
//scene->SetCurrentAnimationStack(animStack);
|
||||
//ProcessAnimation(animationClip, animStack, scene->GetRootNode());
|
||||
|
||||
return animationData;
|
||||
}
|
||||
|
||||
List<String^>^ ExtractAnimationNodesNoInit()
|
||||
{
|
||||
int animStackCount = scene->GetMemberCount<FbxAnimStack>();
|
||||
List<String^>^ animationNodes = nullptr;
|
||||
|
||||
if (animStackCount > 0)
|
||||
{
|
||||
animationNodes = gcnew List<String^>();
|
||||
for (int i = 0; i < animStackCount; ++i)
|
||||
{
|
||||
FbxAnimStack* animStack = scene->GetMember<FbxAnimStack>(i);
|
||||
int animLayerCount = animStack->GetMemberCount<FbxAnimLayer>();
|
||||
FbxAnimLayer* animLayer = animStack->GetMember<FbxAnimLayer>(0);
|
||||
GetAnimationNodes(animLayer, scene->GetRootNode(), animationNodes);
|
||||
}
|
||||
}
|
||||
|
||||
return animationNodes;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ref class CurveEvaluator
|
||||
{
|
||||
FbxAnimCurve* curve;
|
||||
int index;
|
||||
|
||||
public:
|
||||
CurveEvaluator(FbxAnimCurve* curve)
|
||||
: curve(curve), index(0)
|
||||
{
|
||||
}
|
||||
|
||||
float Evaluate(CompressedTimeSpan time)
|
||||
{
|
||||
auto fbxTime = FbxTime((long long)time.Ticks * FBXSDK_TIME_ONE_SECOND.Get() / (long long)CompressedTimeSpan::TicksPerSecond);
|
||||
int currentIndex = index;
|
||||
auto result = curve->Evaluate(fbxTime, ¤tIndex);
|
||||
index = currentIndex;
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
AnimationCurve<T>^ ProcessAnimationCurveVector(AnimationClip^ animationClip, String^ name, int numCurves, FbxAnimCurve** curves, T defaultValue, bool isUserDefinedProperty)
|
||||
{
|
||||
auto keyFrames = ProcessAnimationCurveFloatsHelper<T>(curves, defaultValue, numCurves);
|
||||
if (keyFrames == nullptr)
|
||||
return nullptr;
|
||||
|
||||
// Add curve
|
||||
auto animationCurve = gcnew AnimationCurve<T>();
|
||||
|
||||
// Switch to cubic implicit interpolation mode for Vector3
|
||||
animationCurve->InterpolationType = AnimationCurveInterpolationType::Cubic;
|
||||
|
||||
// Create keys
|
||||
for (int i = 0; i < keyFrames->Count; ++i)
|
||||
{
|
||||
animationCurve->KeyFrames->Add(keyFrames[i]);
|
||||
}
|
||||
|
||||
animationClip->AddCurve(name, animationCurve, isUserDefinedProperty);
|
||||
|
||||
if (keyFrames->Count > 0)
|
||||
{
|
||||
auto curveDuration = keyFrames[keyFrames->Count - 1].Time;
|
||||
if (animationClip->Duration < curveDuration)
|
||||
animationClip->Duration = curveDuration;
|
||||
}
|
||||
|
||||
return animationCurve;
|
||||
}
|
||||
|
||||
template <class T> AnimationCurve<T>^ CreateCurve(AnimationClip^ animationClip, String^ name, List<KeyFrameData<T>>^ keyFrames)
|
||||
{
|
||||
// Add curve
|
||||
auto animationCurve = gcnew AnimationCurve<T>();
|
||||
|
||||
if (T::typeid == Vector3::typeid)
|
||||
{
|
||||
// Switch to cubic implicit interpolation mode for Vector3
|
||||
animationCurve->InterpolationType = AnimationCurveInterpolationType::Cubic;
|
||||
}
|
||||
|
||||
// Create keys
|
||||
for (int i = 0; i < keyFrames->Count; ++i)
|
||||
{
|
||||
animationCurve->KeyFrames->Add(keyFrames[i]);
|
||||
}
|
||||
|
||||
animationClip->AddCurve(name, animationCurve, false);
|
||||
|
||||
if (keyFrames->Count > 0)
|
||||
{
|
||||
auto curveDuration = keyFrames[keyFrames->Count - 1].Time;
|
||||
if (animationClip->Duration < curveDuration)
|
||||
animationClip->Duration = curveDuration;
|
||||
}
|
||||
|
||||
return animationCurve;
|
||||
}
|
||||
|
||||
AnimationCurve<Quaternion>^ ProcessAnimationCurveRotation(AnimationClip^ animationClip, String^ name, FbxAnimCurve** curves, Vector3 defaultValue)
|
||||
{
|
||||
auto keyFrames = ProcessAnimationCurveFloatsHelper<Vector3>(curves, defaultValue, 3);
|
||||
if (keyFrames == nullptr)
|
||||
return nullptr;
|
||||
|
||||
// Convert euler angles to radians
|
||||
for (int i = 0; i < keyFrames->Count; ++i)
|
||||
{
|
||||
auto keyFrame = keyFrames[i];
|
||||
keyFrame.Value *= (float)Math::PI / 180.0f;
|
||||
keyFrames[i] = keyFrame;
|
||||
}
|
||||
|
||||
// Add curve
|
||||
auto animationCurve = gcnew AnimationCurve<Quaternion>();
|
||||
|
||||
// Create keys
|
||||
for (int i = 0; i < keyFrames->Count; ++i)
|
||||
{
|
||||
auto keyFrame = keyFrames[i];
|
||||
|
||||
KeyFrameData<Quaternion> newKeyFrame;
|
||||
newKeyFrame.Time = keyFrame.Time;
|
||||
newKeyFrame.Value = AxisRotationToQuaternion(keyFrame.Value);
|
||||
animationCurve->KeyFrames->Add(newKeyFrame);
|
||||
}
|
||||
|
||||
animationClip->AddCurve(name, animationCurve, false);
|
||||
|
||||
if (keyFrames->Count > 0)
|
||||
{
|
||||
auto curveDuration = keyFrames[keyFrames->Count - 1].Time;
|
||||
if (animationClip->Duration < curveDuration)
|
||||
animationClip->Duration = curveDuration;
|
||||
}
|
||||
|
||||
return animationCurve;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
List<KeyFrameData<T>>^ ProcessAnimationCurveFloatsHelper(FbxAnimCurve** curves, T defaultValue, int numCurves)
|
||||
{
|
||||
FbxTime startTime = FBXSDK_TIME_INFINITE;
|
||||
FbxTime endTime = FBXSDK_TIME_MINUS_INFINITE;
|
||||
for (int i = 0; i < numCurves; ++i)
|
||||
{
|
||||
auto curve = curves[i];
|
||||
if (curve == NULL)
|
||||
continue;
|
||||
|
||||
FbxTimeSpan timeSpan;
|
||||
curve->GetTimeInterval(timeSpan);
|
||||
|
||||
if (curve != NULL && curve->KeyGetCount() > 0)
|
||||
{
|
||||
auto firstKeyTime = curve->KeyGetTime(0);
|
||||
auto lastKeyTime = curve->KeyGetTime(curve->KeyGetCount() - 1);
|
||||
if (startTime > firstKeyTime)
|
||||
startTime = firstKeyTime;
|
||||
if (endTime < lastKeyTime)
|
||||
endTime = lastKeyTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (startTime == FBXSDK_TIME_INFINITE
|
||||
|| endTime == FBXSDK_TIME_MINUS_INFINITE)
|
||||
{
|
||||
// No animation
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto keyFrames = gcnew List<KeyFrameData<T>>();
|
||||
|
||||
const float framerate = static_cast<float>(FbxTime::GetFrameRate(scene->GetGlobalSettings().GetTimeMode()));
|
||||
auto oneFrame = FbxTime::GetOneFrameValue(scene->GetGlobalSettings().GetTimeMode());
|
||||
|
||||
//FIX: If scene->GetGlobalSettings().GetTimeMode() returns FbxTime::eFrames30Drop then oneFrame is going to be 0.
|
||||
// This is (propably) undesired since time will increment by 0 in the next second loop, resulting in a infinite loop
|
||||
// that finally leads to a out-of-memory exception.
|
||||
|
||||
if (oneFrame <= 0)
|
||||
oneFrame = FbxTime::GetOneFrameValue(FbxTime::eNTSCDropFrame); // FbxTime::eNTSCDropFrame is equivalent to FbxTime::eFrames30Drop.
|
||||
//Source: (FBX Docs : http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/index.html?url=cpp_ref/class_fbx_time.html,topicNumber=cpp_ref_class_fbx_time_html29087af6-8c2c-4e9d-aede-7dc5a1c2436c)
|
||||
//Refer to: enum EMode
|
||||
|
||||
// Step1: Pregenerate curve with discontinuities
|
||||
int currentKeyIndices[4];
|
||||
int currentEvaluationIndices[4];
|
||||
bool isConstant[4];
|
||||
|
||||
for (int i = 0; i < numCurves; ++i)
|
||||
{
|
||||
// Start with current key at -1, so we properly advance to key 0 in the first iteration
|
||||
currentKeyIndices[i] = -1;
|
||||
currentEvaluationIndices[i] = 0;
|
||||
isConstant[i] = false;
|
||||
}
|
||||
|
||||
//float values[4];
|
||||
auto key = KeyFrameData<T>();
|
||||
float* values = (float*)&key.Value;
|
||||
float* defaultValues = (float*)&defaultValue;
|
||||
|
||||
FbxTime time;
|
||||
bool lastFrame = false;
|
||||
for (time = startTime; time < endTime || !lastFrame; time += oneFrame)
|
||||
{
|
||||
// Last frame with time = endTime
|
||||
if (time >= endTime)
|
||||
{
|
||||
lastFrame = true;
|
||||
time = endTime;
|
||||
}
|
||||
|
||||
key.Time = FBXTimeToTimeSpan(time) - animStartTime;
|
||||
|
||||
bool hasAnyDiscontinuity = false;
|
||||
bool hasDiscontinuity[4];
|
||||
|
||||
for (int i = 0; i < numCurves; ++i)
|
||||
{
|
||||
auto curve = curves[i];
|
||||
if (curve != nullptr)
|
||||
{
|
||||
|
||||
int currentIndex = currentKeyIndices[i];
|
||||
|
||||
FbxAnimCurveKey curveKey;
|
||||
|
||||
// Advance to appropriate key that should be active during this frame
|
||||
// (The current key is the latest key at or before the current time)
|
||||
bool wasConstant = false;
|
||||
while (currentIndex + 1 < curve->KeyGetCount() && curve->KeyGetTime(currentIndex + 1) <= time)
|
||||
{
|
||||
++currentIndex;
|
||||
|
||||
// If we reached a new key and the previous one was constant, we have a discontinuity
|
||||
wasConstant = isConstant[i];
|
||||
|
||||
auto interpolation = curve->KeyGetInterpolation(currentIndex);
|
||||
isConstant[i] = interpolation == FbxAnimCurveDef::eInterpolationConstant;
|
||||
}
|
||||
|
||||
currentKeyIndices[i] = currentIndex;
|
||||
hasDiscontinuity[i] = wasConstant;
|
||||
hasAnyDiscontinuity |= wasConstant;
|
||||
|
||||
// Update non-constant values
|
||||
if (!wasConstant)
|
||||
{
|
||||
values[i] = curve->Evaluate(time, ¤tEvaluationIndices[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
values[i] = defaultValues[i];
|
||||
}
|
||||
}
|
||||
|
||||
// If discontinuity, we need to add previous values twice (with updated time), and new values twice (with updated time) to ignore any implicit tangents
|
||||
if (hasAnyDiscontinuity)
|
||||
{
|
||||
keyFrames->Add(key);
|
||||
keyFrames->Add(key);
|
||||
}
|
||||
|
||||
// Update constant values
|
||||
for (int i = 0; i < numCurves; ++i)
|
||||
{
|
||||
auto curve = curves[i];
|
||||
if (hasDiscontinuity[i])
|
||||
values[i] = curve == nullptr ? defaultValues[i] : curve->Evaluate(time, ¤tEvaluationIndices[i]);
|
||||
}
|
||||
|
||||
keyFrames->Add(key);
|
||||
|
||||
if (hasAnyDiscontinuity)
|
||||
keyFrames->Add(key);
|
||||
}
|
||||
|
||||
return keyFrames;
|
||||
}
|
||||
|
||||
void ConvertDegreeToRadians(AnimationCurve<float>^ channel)
|
||||
{
|
||||
for (int i = 0; i < channel->KeyFrames->Count; ++i)
|
||||
{
|
||||
auto keyFrame = channel->KeyFrames[i];
|
||||
keyFrame.Value *= (float)Math::PI / 180.0f;
|
||||
channel->KeyFrames[i] = keyFrame;
|
||||
}
|
||||
}
|
||||
|
||||
void ReverseChannelZ(AnimationCurve<Vector3>^ channel)
|
||||
{
|
||||
// Used for handedness conversion
|
||||
for (int i = 0; i < channel->KeyFrames->Count; ++i)
|
||||
{
|
||||
auto keyFrame = channel->KeyFrames[i];
|
||||
keyFrame.Value.Z = -keyFrame.Value.Z;
|
||||
channel->KeyFrames[i] = keyFrame;
|
||||
}
|
||||
}
|
||||
|
||||
void ComputeFovFromFL(AnimationCurve<float>^ channel, FbxCamera* pCamera)
|
||||
{
|
||||
// Used for handedness conversion
|
||||
for (int i = 0; i < channel->KeyFrames->Count; ++i)
|
||||
{
|
||||
auto keyFrame = channel->KeyFrames[i];
|
||||
keyFrame.Value = (float)(FocalLengthToVerticalFov(pCamera->FilmHeight.Get(), keyFrame.Value) * 180.0 / Math::PI);
|
||||
channel->KeyFrames[i] = keyFrame;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiplyChannel(AnimationCurve<float>^ channel, double factor)
|
||||
{
|
||||
// Used for handedness conversion
|
||||
for (int i = 0; i < channel->KeyFrames->Count; ++i)
|
||||
{
|
||||
auto keyFrame = channel->KeyFrames[i];
|
||||
keyFrame.Value = (float)(factor * keyFrame.Value);
|
||||
channel->KeyFrames[i] = keyFrame;
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessAnimationByNode(Dictionary<String^, AnimationClip^>^ animationClips, FbxAnimLayer* animLayer, FbxNode* pNode, bool importCustomAttributeAnimations)
|
||||
{
|
||||
auto animationClip = gcnew AnimationClip();
|
||||
|
||||
auto nodeData = sceneMapping->FindNode(pNode);
|
||||
FbxAnimCurve* curves[3];
|
||||
|
||||
auto nodeName = nodeData.Name;
|
||||
|
||||
auto defaultTranslation = FbxDouble3ToVector3(pNode->LclTranslation.Get());
|
||||
curves[0] = pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X);
|
||||
curves[1] = pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
|
||||
curves[2] = pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
|
||||
auto translationCurve = ProcessAnimationCurveVector<Vector3>(animationClip, "Transform.Position", 3, curves, defaultTranslation, false);
|
||||
|
||||
auto defaultRotation = FbxDouble3ToVector3(pNode->LclRotation.Get());
|
||||
curves[0] = pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X);
|
||||
curves[1] = pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
|
||||
curves[2] = pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
|
||||
auto rotationCurve = ProcessAnimationCurveRotation(animationClip, "Transform.Rotation", curves, defaultRotation);
|
||||
|
||||
auto defaultScale = FbxDouble3ToVector3(pNode->LclScaling.Get());
|
||||
curves[0] = pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X);
|
||||
curves[1] = pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
|
||||
curves[2] = pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
|
||||
auto scalingCurve = ProcessAnimationCurveVector<Vector3>(animationClip, "Transform.Scale", 3, curves, defaultScale, false);
|
||||
|
||||
if (translationCurve != nullptr)
|
||||
{
|
||||
auto keyFrames = translationCurve->KeyFrames;
|
||||
for (int i = 0; i < keyFrames->Count; i++)
|
||||
{
|
||||
auto keyFrame = keyFrames[i];
|
||||
keyFrame.Value = keyFrame.Value * sceneMapping->ScaleToMeters;
|
||||
Vector3::TransformCoordinate(keyFrame.Value, sceneMapping->AxisSystemRotationMatrix, keyFrame.Value);
|
||||
keyFrames[i] = keyFrame;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodeData.ParentIndex == 0)
|
||||
{
|
||||
if (rotationCurve != nullptr)
|
||||
{
|
||||
auto axisSystemRotationQuaternion = Quaternion::RotationMatrix(sceneMapping->AxisSystemRotationMatrix);
|
||||
auto keyFrames = rotationCurve->KeyFrames;
|
||||
for (int i = 0; i < keyFrames->Count; i++)
|
||||
{
|
||||
auto keyFrame = keyFrames[i];
|
||||
keyFrame.Value = Quaternion::Multiply(keyFrame.Value, axisSystemRotationQuaternion);
|
||||
keyFrames[i] = keyFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FbxCamera* camera = pNode->GetCamera();
|
||||
if (camera != NULL)
|
||||
{
|
||||
String^ cameraComponentKey = "[CameraComponent.Key].";
|
||||
if (camera->FieldOfViewY.GetCurve(animLayer))
|
||||
{
|
||||
curves[0] = camera->FieldOfViewY.GetCurve(animLayer);
|
||||
float defaultValue = static_cast<float>(camera->FieldOfViewY.Get());
|
||||
auto FovAnimChannel = ProcessAnimationCurveVector<float>(animationClip, cameraComponentKey+"VerticalFieldOfView", 1, curves, defaultValue, false);
|
||||
|
||||
// TODO: Check again Max
|
||||
//if (!exportedFromMaya)
|
||||
// MultiplyChannel(FovAnimChannel, 0.6); // Random factor to match what we see in 3dsmax, need to check why!
|
||||
}
|
||||
|
||||
|
||||
if (camera->FocalLength.GetCurve(animLayer))
|
||||
{
|
||||
curves[0] = camera->FocalLength.GetCurve(animLayer);
|
||||
float defaultValue = static_cast<float>(camera->FocalLength.Get());
|
||||
auto flAnimChannel = ProcessAnimationCurveVector<float>(animationClip, cameraComponentKey+"VerticalFieldOfView", 1, curves, defaultValue, false);
|
||||
ComputeFovFromFL(flAnimChannel, camera);
|
||||
}
|
||||
|
||||
if (camera->NearPlane.GetCurve(animLayer))
|
||||
{
|
||||
curves[0] = camera->NearPlane.GetCurve(animLayer);
|
||||
float defaultValue = static_cast<float>(camera->NearPlane.Get());
|
||||
ProcessAnimationCurveVector<float>(animationClip, cameraComponentKey+"NearClipPlane", 1, curves, defaultValue, false);
|
||||
}
|
||||
|
||||
if (camera->FarPlane.GetCurve(animLayer))
|
||||
{
|
||||
curves[0] = camera->FarPlane.GetCurve(animLayer);
|
||||
float defaultValue = static_cast<float>(camera->FarPlane.Get());
|
||||
ProcessAnimationCurveVector<float>(animationClip, cameraComponentKey+"FarClipPlane", 1, curves, defaultValue, false);
|
||||
}
|
||||
}
|
||||
if (importCustomAttributeAnimations)
|
||||
{
|
||||
FbxProperty lProperty = pNode->GetFirstProperty();
|
||||
while (lProperty.IsValid())
|
||||
{
|
||||
auto isUserDefined = lProperty.GetFlag(FbxPropertyFlags::eUserDefined); // import only user custom properties
|
||||
FbxAnimCurveNode* lCurveNode = lProperty.GetCurveNode(animLayer); // import only animated properties
|
||||
if (!isUserDefined || !lCurveNode)
|
||||
{
|
||||
lProperty = pNode->GetNextProperty(lProperty);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto lFbxFCurveNodeName = gcnew String(lProperty.GetName());
|
||||
|
||||
// extract the animation from the property
|
||||
auto channelCount = lCurveNode->GetChannelsCount();
|
||||
for (unsigned int c = 0; c<channelCount && c<3; ++c)
|
||||
curves[c] = lCurveNode->GetCurve(c);
|
||||
|
||||
FbxDataType lDataType = lProperty.GetPropertyDataType();
|
||||
if (lDataType.GetType() == eFbxBool ||
|
||||
lDataType.GetType() == eFbxDouble || lDataType.GetType() == eFbxFloat ||
|
||||
lDataType.GetType() == eFbxInt || lDataType.GetType() == eFbxUInt ||
|
||||
lDataType.GetType() == eFbxChar || lDataType.GetType() == eFbxUChar ||
|
||||
lDataType.GetType() == eFbxShort || lDataType.GetType() == eFbxUShort)
|
||||
{
|
||||
ProcessAnimationCurveVector<float>(animationClip, lFbxFCurveNodeName, channelCount, curves, 0, true);
|
||||
}
|
||||
if (lDataType.GetType() == eFbxDouble2)
|
||||
{
|
||||
ProcessAnimationCurveVector<Vector2>(animationClip, lFbxFCurveNodeName, channelCount, curves, Vector2::Zero, true);
|
||||
}
|
||||
else if (lDataType.GetType() == eFbxDouble3)
|
||||
{
|
||||
ProcessAnimationCurveVector<Vector3>(animationClip, lFbxFCurveNodeName, channelCount, curves, Vector3::Zero, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO add support for the type
|
||||
}
|
||||
lProperty = pNode->GetNextProperty(lProperty);
|
||||
} // while
|
||||
}
|
||||
|
||||
if (animationClip->Curves->Count > 0)
|
||||
{
|
||||
animationClips->Add(nodeName, animationClip);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pNode->GetChildCount(); ++i)
|
||||
{
|
||||
ProcessAnimationByNode(animationClips, animLayer, pNode->GetChild(i), importCustomAttributeAnimations);
|
||||
}
|
||||
}
|
||||
|
||||
// This code is not used but is a reference code for code animation but less optimized than ProcessAnimationByCurve.
|
||||
void ProcessAnimation(FbxTime animStart, FbxTime animEnd, AnimationClip^ animationClip, FbxAnimStack* animStack, FbxNode* pNode)
|
||||
{
|
||||
auto layer0 = animStack->GetMember<FbxAnimLayer>(0);
|
||||
|
||||
if (HasAnimation(layer0, pNode))
|
||||
{
|
||||
auto evaluator = scene->GetAnimationEvaluator();
|
||||
|
||||
auto animationName = animStack->GetName();
|
||||
|
||||
// Create curves
|
||||
auto scalingFrames = gcnew List<KeyFrameData<Vector3>>();
|
||||
auto rotationFrames = gcnew List<KeyFrameData<Quaternion>>();
|
||||
auto translationFrames = gcnew List<KeyFrameData<Vector3>>();
|
||||
|
||||
auto nodeData = sceneMapping->FindNode(pNode);
|
||||
|
||||
auto parentNode = pNode->GetParent();
|
||||
auto nodeName = nodeData.Name;
|
||||
String^ parentNodeName = nullptr;
|
||||
if (parentNode != nullptr)
|
||||
{
|
||||
parentNodeName = sceneMapping->FindNode(parentNode).Name;
|
||||
}
|
||||
|
||||
FbxLongLong start = static_cast<FbxLongLong>(animStart.GetSecondDouble());
|
||||
FbxLongLong end = static_cast<FbxLongLong>(animEnd.GetSecondDouble());
|
||||
|
||||
FbxTime sampling_period = FbxTimeSeconds(1.f / 60.0f);
|
||||
bool loop_again = true;
|
||||
for (FbxTime t = start; loop_again; t += sampling_period) {
|
||||
if (t >= end) {
|
||||
t = end;
|
||||
loop_again = false;
|
||||
}
|
||||
|
||||
// Use GlobalTransform instead of LocalTransform
|
||||
auto fbxMatrix = evaluator->GetNodeGlobalTransform(pNode, t);
|
||||
if (parentNode != nullptr)
|
||||
{
|
||||
auto parentMatrixInverse = evaluator->GetNodeGlobalTransform(parentNode, t).Inverse();
|
||||
fbxMatrix = parentMatrixInverse * fbxMatrix;
|
||||
}
|
||||
auto matrix = sceneMapping->ConvertMatrixFromFbx(fbxMatrix);
|
||||
|
||||
Vector3 scaling;
|
||||
Vector3 translation;
|
||||
Quaternion rotation;
|
||||
matrix.Decompose(scaling, rotation, translation);
|
||||
|
||||
auto time = FBXTimeToTimeSpan(t);
|
||||
|
||||
scalingFrames->Add(KeyFrameData<Vector3>(time, scaling));
|
||||
translationFrames->Add(KeyFrameData<Vector3>(time, translation));
|
||||
rotationFrames->Add(KeyFrameData<Quaternion>(time, rotation));
|
||||
}
|
||||
|
||||
CreateCurve(animationClip, String::Format("Transform.Position[{0}]", nodeName), translationFrames);
|
||||
CreateCurve(animationClip, String::Format("Transform.Rotation[{0}]", nodeName), rotationFrames);
|
||||
CreateCurve(animationClip, String::Format("Transform.Scale[{0}]", nodeName), scalingFrames);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pNode->GetChildCount(); ++i)
|
||||
{
|
||||
ProcessAnimation(animStart, animEnd, animationClip, animStack, pNode->GetChild(i));
|
||||
}
|
||||
}
|
||||
|
||||
void SetPivotStateRecursive(FbxNode* pNode)
|
||||
{
|
||||
// From FbxNode.h
|
||||
FbxVector4 lZero(0, 0, 0);
|
||||
FbxVector4 lOne(1, 1, 1);
|
||||
pNode->SetPivotState(FbxNode::eSourcePivot, FbxNode::ePivotActive);
|
||||
pNode->SetPivotState(FbxNode::eDestinationPivot, FbxNode::ePivotActive);
|
||||
|
||||
EFbxRotationOrder lRotationOrder;
|
||||
pNode->GetRotationOrder(FbxNode::eSourcePivot, lRotationOrder);
|
||||
pNode->SetRotationOrder(FbxNode::eDestinationPivot, lRotationOrder);
|
||||
|
||||
//For cameras and lights (without targets) let's compensate the postrotation.
|
||||
if (pNode->GetCamera() || pNode->GetLight())
|
||||
{
|
||||
if (!pNode->GetTarget())
|
||||
{
|
||||
FbxVector4 lRV(90, 0, 0);
|
||||
if (pNode->GetCamera())
|
||||
lRV.Set(0, 90, 0);
|
||||
|
||||
FbxVector4 prV = pNode->GetPostRotation(FbxNode::eSourcePivot);
|
||||
FbxAMatrix lSourceR;
|
||||
FbxAMatrix lR(lZero, lRV, lOne);
|
||||
FbxVector4 res = prV;
|
||||
|
||||
// Rotation order don't affect post rotation, so just use the default XYZ order
|
||||
FbxRotationOrder rOrder;
|
||||
rOrder.V2M(lSourceR, res);
|
||||
|
||||
lR = lSourceR * lR;
|
||||
rOrder.M2V(res, lR);
|
||||
prV = res;
|
||||
pNode->SetPostRotation(FbxNode::eSourcePivot, prV);
|
||||
pNode->SetRotationActive(true);
|
||||
}
|
||||
|
||||
// Point light do not need to be adjusted (since they radiate in all the directions).
|
||||
if (pNode->GetLight() && pNode->GetLight()->LightType.Get() == FbxLight::ePoint)
|
||||
{
|
||||
pNode->SetPostRotation(FbxNode::eSourcePivot, FbxVector4(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
// apply Pre rotations only on bones / end of chains
|
||||
if (pNode->GetNodeAttribute() && pNode->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eSkeleton
|
||||
|| (pNode->GetMarker() && pNode->GetMarker()->GetType() == FbxMarker::eEffectorFK)
|
||||
|| (pNode->GetMarker() && pNode->GetMarker()->GetType() == FbxMarker::eEffectorIK))
|
||||
{
|
||||
if (pNode->GetRotationActive())
|
||||
{
|
||||
pNode->SetPreRotation(FbxNode::eDestinationPivot, pNode->GetPreRotation(FbxNode::eSourcePivot));
|
||||
}
|
||||
|
||||
// No pivots on bones
|
||||
pNode->SetRotationPivot(FbxNode::eDestinationPivot, lZero);
|
||||
pNode->SetScalingPivot(FbxNode::eDestinationPivot, lZero);
|
||||
pNode->SetRotationOffset(FbxNode::eDestinationPivot, lZero);
|
||||
pNode->SetScalingOffset(FbxNode::eDestinationPivot, lZero);
|
||||
}
|
||||
else
|
||||
{
|
||||
// any other type: no pre-rotation support but...
|
||||
pNode->SetPreRotation(FbxNode::eDestinationPivot, lZero);
|
||||
|
||||
// support for rotation and scaling pivots.
|
||||
pNode->SetRotationPivot(FbxNode::eDestinationPivot, pNode->GetRotationPivot(FbxNode::eSourcePivot));
|
||||
pNode->SetScalingPivot(FbxNode::eDestinationPivot, pNode->GetScalingPivot(FbxNode::eSourcePivot));
|
||||
// Rotation and scaling offset are supported
|
||||
pNode->SetRotationOffset(FbxNode::eDestinationPivot, pNode->GetRotationOffset(FbxNode::eSourcePivot));
|
||||
pNode->SetScalingOffset(FbxNode::eDestinationPivot, pNode->GetScalingOffset(FbxNode::eSourcePivot));
|
||||
//
|
||||
// If we don't "support" scaling pivots, we can simply do:
|
||||
// pNode->SetRotationPivot(FbxNode::eDestinationPivot, lZero);
|
||||
// pNode->SetScalingPivot(FbxNode::eDestinationPivot, lZero);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pNode->GetChildCount(); ++i)
|
||||
{
|
||||
SetPivotStateRecursive(pNode->GetChild(i));
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckAnimationData(FbxAnimLayer* animLayer, FbxNode* pNode)
|
||||
{
|
||||
if ((pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
|
||||
&& pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
|
||||
&& pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL)
|
||||
||
|
||||
(pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
|
||||
&& pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
|
||||
&& pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL)
|
||||
||
|
||||
(pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
|
||||
&& pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
|
||||
&& pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL))
|
||||
return true;
|
||||
|
||||
FbxCamera* camera = pNode->GetCamera();
|
||||
if (camera != NULL)
|
||||
{
|
||||
if (camera->FieldOfViewY.GetCurve(animLayer))
|
||||
return true;
|
||||
|
||||
if (camera->FocalLength.GetCurve(animLayer))
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pNode->GetChildCount(); ++i)
|
||||
{
|
||||
if (CheckAnimationData(animLayer, pNode->GetChild(i)))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasAnimation(FbxAnimLayer* animLayer, FbxNode* pNode)
|
||||
{
|
||||
return (pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
|
||||
|| pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
|
||||
|| pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL
|
||||
|| pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
|
||||
|| pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
|
||||
|| pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL
|
||||
|| pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
|
||||
|| pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
|
||||
|| pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL);
|
||||
}
|
||||
|
||||
void GetAnimationNodes(FbxAnimLayer* animLayer, FbxNode* pNode, List<String^>^ animationNodes)
|
||||
{
|
||||
auto nodeData = sceneMapping->FindNode(pNode);
|
||||
auto nodeName = nodeData.Name;
|
||||
|
||||
bool checkTranslation = pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL;
|
||||
checkTranslation = checkTranslation || pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL;
|
||||
checkTranslation = checkTranslation || pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL;
|
||||
|
||||
bool checkRotation = pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL;
|
||||
checkRotation = checkRotation || pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL;
|
||||
checkRotation = checkRotation || pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL;
|
||||
|
||||
bool checkScale = pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL;
|
||||
checkScale = checkScale || pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL;
|
||||
checkScale = checkScale || pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL;
|
||||
|
||||
if (checkTranslation || checkRotation || checkScale)
|
||||
{
|
||||
animationNodes->Add(nodeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool checkCamera = true;
|
||||
FbxCamera* camera = pNode->GetCamera();
|
||||
if (camera != NULL)
|
||||
{
|
||||
if (camera->FieldOfViewY.GetCurve(animLayer))
|
||||
checkCamera = checkCamera && camera->FieldOfViewY.GetCurve(animLayer) != NULL;
|
||||
|
||||
if (camera->FocalLength.GetCurve(animLayer))
|
||||
checkCamera = checkCamera && camera->FocalLength.GetCurve(animLayer) != NULL;
|
||||
|
||||
if (checkCamera)
|
||||
animationNodes->Add(nodeName);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < pNode->GetChildCount(); ++i)
|
||||
{
|
||||
GetAnimationNodes(animLayer, pNode->GetChild(i), animationNodes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
#include "stdafx.h"
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Reflection;
|
||||
using namespace System::Runtime::CompilerServices;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using namespace System::Security::Permissions;
|
||||
|
||||
//
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
//
|
||||
[assembly:AssemblyTitleAttribute("Stride.Importer.FBX")];
|
||||
[assembly:AssemblyDescriptionAttribute("")];
|
||||
[assembly:AssemblyConfigurationAttribute("")];
|
||||
[assembly:AssemblyProductAttribute("Stride.Importer.FBX")];
|
||||
[assembly:AssemblyCopyrightAttribute("Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)")];
|
||||
[assembly:AssemblyTrademarkAttribute("")];
|
||||
[assembly:AssemblyCultureAttribute("")];
|
||||
|
||||
//
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the value or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly:AssemblyVersionAttribute("1.0.*")];
|
||||
|
||||
[assembly:ComVisible(false)];
|
||||
|
||||
[assembly:CLSCompliantAttribute(true)];
|
|
@ -1,26 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
#ifndef __IMPORTER_UTILS_H__
|
||||
#define __IMPORTER_UTILS_H__
|
||||
|
||||
void ReplaceCharacter(std::string& name, char c, char replacement)
|
||||
{
|
||||
size_t nextCharacterPos = name.find(c);
|
||||
while (nextCharacterPos != std::string::npos)
|
||||
{
|
||||
name.replace(nextCharacterPos, 1, 1, replacement);
|
||||
nextCharacterPos = name.find(c, nextCharacterPos);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveCharacter(std::string& name, char c)
|
||||
{
|
||||
size_t nextCharacterPos = name.find(c);
|
||||
while (nextCharacterPos != std::string::npos)
|
||||
{
|
||||
name.erase(nextCharacterPos, 1);
|
||||
nextCharacterPos = name.find(c, nextCharacterPos);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __IMPORTER_UTILS_H__
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,278 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
using namespace System;
|
||||
using namespace System::IO;
|
||||
using namespace System::Collections::Generic;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using namespace Stride::Core::Diagnostics;
|
||||
using namespace Stride::Animations;
|
||||
using namespace Stride::Rendering;
|
||||
using namespace Stride::Engine;
|
||||
using namespace Stride::Core::Mathematics;
|
||||
|
||||
namespace Stride {
|
||||
namespace Importer {
|
||||
namespace FBX {
|
||||
/// <summary>
|
||||
/// Contains mapping between FBX nodes and Stride ModelNodeDefinition
|
||||
/// </summary>
|
||||
ref class SceneMapping
|
||||
{
|
||||
private:
|
||||
FbxScene* scene;
|
||||
Dictionary<IntPtr, int>^ nodeMapping;
|
||||
array<ModelNodeDefinition>^ nodes;
|
||||
|
||||
Matrix convertMatrix;
|
||||
Matrix inverseConvertMatrix;
|
||||
Matrix normalConvertMatrix;
|
||||
public:
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NodeMapping"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sceneArg">The scene argument.</param>
|
||||
SceneMapping(FbxScene* scene) : scene(scene)
|
||||
{
|
||||
if (scene == nullptr)
|
||||
{
|
||||
throw gcnew ArgumentNullException("scene");
|
||||
}
|
||||
nodeMapping = gcnew Dictionary<IntPtr, int>();
|
||||
|
||||
// Generate names for all nodes
|
||||
std::map<FbxNode*, std::string> nodeNames;
|
||||
GenerateNodesName(scene, nodeNames);
|
||||
|
||||
// Generate all ModelNodeDefinition
|
||||
auto nodeList = gcnew List<ModelNodeDefinition>();
|
||||
RegisterNode(scene->GetRootNode(), -1, nodeNames, nodeMapping, nodeList);
|
||||
nodes = nodeList->ToArray();
|
||||
|
||||
// Setup the convertion
|
||||
FbxGlobalSettings& settings = scene->GetGlobalSettings();
|
||||
InitializeMatrix(settings.GetAxisSystem(), settings.GetSystemUnit());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the nodes.
|
||||
/// </summary>
|
||||
property array<ModelNodeDefinition>^ Nodes
|
||||
{
|
||||
array<ModelNodeDefinition>^ get()
|
||||
{
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the associated FbxScene.
|
||||
/// </summary>
|
||||
property FbxScene* Scene
|
||||
{
|
||||
FbxScene* get()
|
||||
{
|
||||
return scene;
|
||||
}
|
||||
}
|
||||
|
||||
property Matrix MatrixModifier
|
||||
{
|
||||
Matrix get()
|
||||
{
|
||||
return convertMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
property float ScaleToMeters;
|
||||
|
||||
property Matrix AxisSystemRotationMatrix;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the index of the FBX node in the <see cref="ModelNodeDefinition"/> from a FBX node.
|
||||
/// </summary>
|
||||
/// <param name="node">The node.</param>
|
||||
/// <returns>Stride.Rendering.ModelNodeDefinition.</returns>
|
||||
int FindNodeIndex(FbxNode* node)
|
||||
{
|
||||
int nodeIndex;
|
||||
if (!nodeMapping->TryGetValue((IntPtr)node, nodeIndex))
|
||||
{
|
||||
throw gcnew ArgumentException("Invalid node not found", "node");
|
||||
}
|
||||
|
||||
return nodeIndex;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds a <see cref="ModelNodeDefinition"/> from a FBX node.
|
||||
/// </summary>
|
||||
/// <param name="node">The node.</param>
|
||||
/// <returns>Stride.Rendering.ModelNodeDefinition.</returns>
|
||||
ModelNodeDefinition FindNode(FbxNode* node)
|
||||
{
|
||||
int nodeIndex;
|
||||
if (!nodeMapping->TryGetValue((IntPtr)node, nodeIndex))
|
||||
{
|
||||
throw gcnew ArgumentException("Invalid node not found", "node");
|
||||
}
|
||||
|
||||
return nodes[nodeIndex];
|
||||
}
|
||||
|
||||
Matrix ConvertMatrixFromFbx(FbxAMatrix& _m)
|
||||
{
|
||||
auto result = FBXMatrixToMatrix(_m);
|
||||
// Adjust translation
|
||||
result.M41 *= ScaleToMeters;
|
||||
result.M42 *= ScaleToMeters;
|
||||
result.M43 *= ScaleToMeters;
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector3 ConvertPointFromFbx(const FbxVector4& _p)
|
||||
{
|
||||
return (Vector3)FbxDouble4ToVector4(_p) * ScaleToMeters;
|
||||
}
|
||||
|
||||
Vector3 ConvertNormalFromFbx(const FbxVector4& _p)
|
||||
{
|
||||
return (Vector3)FbxDouble4ToVector4(_p);
|
||||
}
|
||||
private:
|
||||
static void GetNodes(FbxNode* pNode, std::vector<FbxNode*>& nodes)
|
||||
{
|
||||
nodes.push_back(pNode);
|
||||
|
||||
// Recursively process the children nodes.
|
||||
for (int j = 0; j < pNode->GetChildCount(); j++)
|
||||
GetNodes(pNode->GetChild(j), nodes);
|
||||
}
|
||||
|
||||
static void GenerateNodesName(FbxScene* scene, std::map<FbxNode*, std::string>& nodeNames)
|
||||
{
|
||||
std::vector<FbxNode*> nodes;
|
||||
GetNodes(scene->GetRootNode(), nodes);
|
||||
|
||||
std::map<std::string, int> nodeNameTotalCount;
|
||||
std::map<std::string, int> nodeNameCurrentCount;
|
||||
std::map<FbxNode*, std::string> tempNames;
|
||||
|
||||
for (auto iter = nodes.begin(); iter != nodes.end(); ++iter)
|
||||
{
|
||||
auto pNode = *iter;
|
||||
auto nodeName = std::string(pNode->GetName());
|
||||
auto subBegin = nodeName.find_last_of(':');
|
||||
if (subBegin != std::string::npos)
|
||||
nodeName = nodeName.substr(subBegin + 1);
|
||||
tempNames[pNode] = nodeName;
|
||||
|
||||
if (nodeNameTotalCount.count(nodeName) == 0)
|
||||
nodeNameTotalCount[nodeName] = 1;
|
||||
else
|
||||
nodeNameTotalCount[nodeName] = nodeNameTotalCount[nodeName] + 1;
|
||||
}
|
||||
|
||||
for (auto iter = nodes.begin(); iter != nodes.end(); ++iter)
|
||||
{
|
||||
auto pNode = *iter;
|
||||
auto nodeName = tempNames[pNode];
|
||||
int currentCount = 0;
|
||||
|
||||
if (nodeNameCurrentCount.count(nodeName) == 0)
|
||||
nodeNameCurrentCount[nodeName] = 1;
|
||||
else
|
||||
nodeNameCurrentCount[nodeName] = nodeNameCurrentCount[nodeName] + 1;
|
||||
|
||||
if (nodeNameTotalCount[nodeName] > 1)
|
||||
nodeName = nodeName + "_" + std::to_string(nodeNameCurrentCount[nodeName]);
|
||||
|
||||
nodeNames[pNode] = nodeName;
|
||||
}
|
||||
}
|
||||
|
||||
static void RegisterNode(FbxNode* pNode, int parentIndex, std::map<FbxNode*, std::string>& nodeNames, Dictionary<IntPtr, int>^ nodeMapping, List<ModelNodeDefinition>^ nodes)
|
||||
{
|
||||
int currentIndex = nodes->Count;
|
||||
|
||||
nodeMapping[(IntPtr)pNode] = currentIndex;
|
||||
|
||||
// Create node
|
||||
ModelNodeDefinition modelNodeDefinition;
|
||||
modelNodeDefinition.ParentIndex = parentIndex;
|
||||
modelNodeDefinition.Transform.Scale = Vector3::One;
|
||||
modelNodeDefinition.Name = ConvertToUTF8(nodeNames[pNode]);
|
||||
modelNodeDefinition.Flags = ModelNodeFlags::Default;
|
||||
nodes->Add(modelNodeDefinition);
|
||||
|
||||
// Recursively process the children nodes.
|
||||
for (int j = 0; j < pNode->GetChildCount(); j++)
|
||||
{
|
||||
RegisterNode(pNode->GetChild(j), currentIndex, nodeNames, nodeMapping, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeMatrix(const FbxAxisSystem& axisSystem, const FbxSystemUnit& unitSystem)
|
||||
{
|
||||
auto fromMatrix = BuildAxisSystemMatrix(axisSystem);
|
||||
fromMatrix.Invert();
|
||||
//auto fromMatrix = Matrix::Identity;
|
||||
|
||||
// Finds unit conversion ratio to ScaleImport (usually 0.01 so 1 meter). GetScaleFactor() is in cm.
|
||||
ScaleToMeters = (float)unitSystem.GetScaleFactor() * 0.01f;
|
||||
|
||||
// Builds conversion matrices.
|
||||
AxisSystemRotationMatrix = fromMatrix;
|
||||
}
|
||||
|
||||
static Matrix BuildAxisSystemMatrix(const FbxAxisSystem& axisSystem) {
|
||||
|
||||
int signUp;
|
||||
int signFront;
|
||||
Vector3 up = Vector3::UnitY;
|
||||
Vector3 at = Vector3::UnitZ;
|
||||
|
||||
const auto upAxis = axisSystem.GetUpVector(signUp);
|
||||
const auto frontAxisParityEven = axisSystem.GetFrontVector(signFront) == FbxAxisSystem::eParityEven;
|
||||
switch (upAxis)
|
||||
{
|
||||
case FbxAxisSystem::eXAxis:
|
||||
{
|
||||
up = Vector3::UnitX;
|
||||
at = frontAxisParityEven ? Vector3::UnitY : Vector3::UnitZ;
|
||||
break;
|
||||
}
|
||||
|
||||
case FbxAxisSystem::eYAxis:
|
||||
{
|
||||
up = Vector3::UnitY;
|
||||
at = frontAxisParityEven ? Vector3::UnitX : Vector3::UnitZ;
|
||||
break;
|
||||
}
|
||||
|
||||
case FbxAxisSystem::eZAxis:
|
||||
{
|
||||
up = Vector3::UnitZ;
|
||||
at = frontAxisParityEven ? Vector3::UnitX : Vector3::UnitY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
up *= (float)signUp;
|
||||
at *= (float)signFront;
|
||||
|
||||
auto right = axisSystem.GetCoorSystem() == FbxAxisSystem::eRightHanded ? Vector3::Cross(up, at) : Vector3::Cross(at, up);
|
||||
|
||||
auto matrix = Matrix::Identity;
|
||||
matrix.Right = right;
|
||||
matrix.Up = up;
|
||||
matrix.Backward = at;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
/****************************************************************************************
|
||||
|
||||
Copyright (C) 2011 Autodesk, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Use of this software is subject to the terms of the Autodesk license agreement
|
||||
provided at the time of installation or download, or which otherwise accompanies
|
||||
this software in either electronic or hard copy form.
|
||||
|
||||
****************************************************************************************/
|
||||
#include "stdafx.h"
|
||||
#include "StreamReader.h"
|
||||
|
||||
#include <fbxfilesdk/fbxfilesdk_nsuse.h>
|
||||
|
||||
StreamReader::StreamReader(KFbxSdkManager &pFbxSdkManager, int pID):
|
||||
KFbxReader(pFbxSdkManager, pID),
|
||||
mFilePointer(NULL),
|
||||
mManager(&pFbxSdkManager)
|
||||
{
|
||||
}
|
||||
|
||||
StreamReader::~StreamReader()
|
||||
{
|
||||
FileClose();
|
||||
}
|
||||
|
||||
void StreamReader::GetVersion(int& pMajor, int& pMinor, int& pRevision) const
|
||||
|
||||
{
|
||||
pMajor = 1;
|
||||
pMinor = 0;
|
||||
pRevision=0;
|
||||
}
|
||||
|
||||
bool StreamReader::FileOpen(char* pFileName)
|
||||
{
|
||||
if(mFilePointer != NULL)
|
||||
FileClose();
|
||||
mFilePointer = fopen(pFileName, "r");
|
||||
if(mFilePointer == NULL)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool StreamReader::FileClose()
|
||||
{
|
||||
if(mFilePointer!=NULL)
|
||||
fclose(mFilePointer);
|
||||
return true;
|
||||
|
||||
}
|
||||
bool StreamReader::IsFileOpen()
|
||||
{
|
||||
if(mFilePointer != NULL)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StreamReader::GetReadOptions(bool pParseFileAsNeeded)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//Read the custom file and reconstruct node hierarchy.
|
||||
bool StreamReader::Read(KFbxDocument* pDocument)
|
||||
{
|
||||
if (!pDocument)
|
||||
{
|
||||
GetError().SetLastErrorID(eINVALID_DOCUMENT_HANDLE);
|
||||
return false;
|
||||
}
|
||||
KFbxScene* lScene = KFbxCast<KFbxScene>(pDocument);
|
||||
bool lIsAScene = (lScene != NULL);
|
||||
bool lResult = false;
|
||||
|
||||
if(lIsAScene)
|
||||
{
|
||||
KFbxNode* lRootNode = lScene->GetRootNode();
|
||||
KFbxNodeAttribute * lRootNodeAttribute = KFbxNull::Create(lScene,"");
|
||||
lRootNode->SetNodeAttribute(lRootNodeAttribute);
|
||||
|
||||
int lSize;
|
||||
char* lBuffer = NULL;
|
||||
if(mFilePointer != NULL)
|
||||
{
|
||||
//To obtain file size
|
||||
fseek (mFilePointer , 0 , SEEK_END);
|
||||
lSize = ftell (mFilePointer);
|
||||
rewind (mFilePointer);
|
||||
|
||||
//Read file content to a string.
|
||||
lBuffer = (char*) malloc (sizeof(char)*lSize + 1);
|
||||
size_t lRead = fread(lBuffer, 1, lSize, mFilePointer);
|
||||
lBuffer[lRead]='\0';
|
||||
KString lString(lBuffer);
|
||||
|
||||
//Parse the string to get name and relation of Nodes.
|
||||
KString lSubString, lChildName, lParentName;
|
||||
KFbxNode* lChildNode;
|
||||
KFbxNode* lParentNode;
|
||||
KFbxNodeAttribute* lChildAttribute;
|
||||
int lEndTokenCount = lString.GetTokenCount("\n");
|
||||
|
||||
for (int i = 0; i < lEndTokenCount; i++)
|
||||
{
|
||||
lSubString = lString.GetToken(i, "\n");
|
||||
KString lNodeString;
|
||||
lChildName = lSubString.GetToken(0, "\"");
|
||||
lParentName = lSubString.GetToken(2, "\"");
|
||||
|
||||
//Build node hierarchy.
|
||||
if(lParentName == "RootNode")
|
||||
{
|
||||
lChildNode = KFbxNode::Create(lScene,lChildName.Buffer());
|
||||
lChildAttribute = KFbxNull::Create(mManager,"");
|
||||
lChildNode->SetNodeAttribute(lChildAttribute);
|
||||
|
||||
lRootNode->AddChild(lChildNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
lChildNode = KFbxNode::Create(lScene,lChildName.Buffer());
|
||||
lChildAttribute = KFbxNull::Create(lScene,"");
|
||||
lChildNode->SetNodeAttribute(lChildAttribute);
|
||||
|
||||
lParentNode = lRootNode->FindChild(lParentName.Buffer());
|
||||
lParentNode->AddChild(lChildNode);
|
||||
}
|
||||
}
|
||||
free(lBuffer);
|
||||
}
|
||||
lResult = true;
|
||||
}
|
||||
return lResult;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
class StreamReader : public KFbxReader
|
||||
{
|
||||
public:
|
||||
StreamReader(KFbxSdkManager &pFbxSdkManager, int pID);
|
||||
|
||||
//VERY important to put the file close in the destructor
|
||||
virtual ~StreamReader();
|
||||
|
||||
virtual void GetVersion(int& pMajor, int& pMinor, int& pRevision) const;
|
||||
virtual bool FileOpen(char* pFileName);
|
||||
virtual bool FileClose();
|
||||
virtual bool IsFileOpen();
|
||||
|
||||
virtual bool GetReadOptions(bool pParseFileAsNeeded = true);
|
||||
virtual bool Read(KFbxDocument* pDocument);
|
||||
|
||||
private:
|
||||
FILE *mFilePointer;
|
||||
KFbxSdkManager *mManager;
|
||||
};
|
||||
|
||||
KFbxReader* CreateMyOwnReader(KFbxSdkManager& pManager, KFbxImporter& pImporter, int pSubID, int pPluginID);
|
||||
void *GetMyOwnReaderInfo(KFbxReader::KInfoRequest pRequest, int pId);
|
||||
void FillOwnReaderIOSettings(KFbxIOSettings& pIOS);
|
||||
|
|
@ -1,262 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\targets\Stride.props" />
|
||||
<PropertyGroup>
|
||||
<StrideProjectType>Cpp</StrideProjectType>
|
||||
<TargetFramework>$(StrideEditorTargetFramework)</TargetFramework>
|
||||
<StrideBuildTags>WindowsTools</StrideBuildTags>
|
||||
<StrideAssemblyProcessorOptions>
|
||||
</StrideAssemblyProcessorOptions>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<FbxSdkVersion>2019.0</FbxSdkVersion>
|
||||
<FbxSdkUrl>https://www.autodesk.com/developer-network/platform-technologies/fbx-sdk-2019-0</FbxSdkUrl>
|
||||
<FbxSdkDir>$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk FBX SDK $(FbxSdkVersion)', 'Install_Dir', null, RegistryView.Registry32))</FbxSdkDir>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<FbxLibVersionDir>vs2015\</FbxLibVersionDir>
|
||||
</PropertyGroup>
|
||||
<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>
|
||||
<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">
|
||||
<ProjectGuid>{0467D515-FD66-4B8A-A128-CB642C2ED03F}</ProjectGuid>
|
||||
<Keyword>ManagedCProj</Keyword>
|
||||
<RootNamespace>Stride.Importer.FBX</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CLRSupport>NetCore</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CLRSupport>NetCore</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<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)'=='Debug'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>bin\$(TargetFramework)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(TargetFramework)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>bin\$(TargetFramework)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(TargetFramework)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>$(FbxSdkDir)\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IncludePath>$(FbxSdkDir)\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>
|
||||
</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalOptions>/wd 4945 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk.lib;user32.lib;advapi32.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\debug</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
<CustomBuildStep>
|
||||
<Command>xcopy /D /Y "$(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\debug\libfbxsdk.dll" "$(TargetDir)x86"</Command>
|
||||
<Outputs>$(TargetDir)x86\libfbxsdk.dll;%(Outputs)</Outputs>
|
||||
<Inputs>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\release\libfbxsdk.dll</Inputs>
|
||||
<TreatOutputAsContent>true</TreatOutputAsContent>
|
||||
</CustomBuildStep>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(FbxSdkDir)\include</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalOptions>/wd 4945 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk.lib;user32.lib;advapi32.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\release</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>
|
||||
</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalOptions>/wd 4945 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\debug</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
<CustomBuildStep>
|
||||
<Command>xcopy /D /Y "$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\debug\libfbxsdk.dll" "$(TargetDir)x64"</Command>
|
||||
<Outputs>$(TargetDir)x64\libfbxsdk.dll;%(Outputs)</Outputs>
|
||||
<Inputs>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release\libfbxsdk.dll</Inputs>
|
||||
<TreatOutputAsContent>true</TreatOutputAsContent>
|
||||
</CustomBuildStep>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>NDEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(FbxSdkDir)\include</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalOptions>/wd 4945 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
<CustomBuildStep>
|
||||
<Command>xcopy /D /Y "$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release\libfbxsdk.dll" "$(TargetDir)x64"</Command>
|
||||
<Outputs>$(TargetDir)x64\libfbxsdk.dll;%(Outputs)</Outputs>
|
||||
<Inputs>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release\libfbxsdk.dll</Inputs>
|
||||
<TreatOutputAsContent>true</TreatOutputAsContent>
|
||||
</CustomBuildStep>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AnimationConverter.h" />
|
||||
<ClCompile Include="AssemblyInfo.h" />
|
||||
<ClCompile Include="SceneMapping.h" />
|
||||
<ClCompile Include="MeshConverter.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="UtilityFunctions.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ImporterUtils.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="UtilityFunctions.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<StrideNativeLib Include="$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\debug\libfbxsdk.dll">
|
||||
<Link>runtimes\win-x64\native\%(Filename)%(Extension)</Link>
|
||||
<RelativePath>runtimes\win-x64\native\%(Filename)%(Extension)</RelativePath>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</StrideNativeLib>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\assets\Stride.Core.Assets\Stride.Core.Assets.csproj">
|
||||
<Project>{1e54a9a2-4439-4444-ae57-6d2ed3c0dc47}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\core\Stride.Core.Design\Stride.Core.Design.csproj">
|
||||
<Project>{66581dad-70ad-4475-ae47-c6c0df1ec5e2}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\engine\Stride.Assets\Stride.Assets.csproj">
|
||||
<Project>{39ae9c77-e94b-404f-8768-b6261b3c1e0e}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\engine\Stride.Engine\Stride.Engine.csproj">
|
||||
<Project>{c121a566-555e-42b9-9b0a-1696529a9088}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\engine\Stride.Rendering\Stride.Rendering.csproj">
|
||||
<Project>{ad4fdc24-b64d-4ed7-91aa-62c9eda12fa4}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\core\Stride.Core\Stride.Core.csproj">
|
||||
<Project>{0e916ab7-5a6c-4820-8ab1-aa492fe66d68}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\engine\Stride.Graphics\Stride.Graphics.csproj">
|
||||
<Project>{fb06c76a-6bb7-40be-9afa-fec13b045fb5}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\core\Stride.Core.IO\Stride.Core.IO.csproj">
|
||||
<Project>{1de01410-22c9-489b-9796-1addab1f64e5}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\core\Stride.Core.Serialization\Stride.Core.Serialization.csproj">
|
||||
<Project>{5210fb81-b807-49bb-af0d-31fb6a83a572}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\shaders\Stride.Core.Shaders\Stride.Core.Shaders.csproj">
|
||||
<Project>{f2d52edb-bc17-4243-b06d-33cd20f87a7f}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\core\Stride.Core.Mathematics\Stride.Core.Mathematics.csproj">
|
||||
<Project>{1677b922-ccf0-44de-b57e-1cdd3d2b8e8a}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\engine\Stride.Shaders\Stride.Shaders.csproj">
|
||||
<Project>{273bdd15-7392-4078-91f0-af23594a3d7b}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\engine\Stride\Stride.csproj">
|
||||
<Project>{72390339-b2a1-4f61-a800-31ed0975b515}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\buildengine\Stride.Core.BuildEngine.Common\Stride.Core.BuildEngine.Common.csproj">
|
||||
<Project>{7732cb84-a39a-4adf-b740-fd32a352fa8a}</Project>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Stride.Importer.Common\Stride.Importer.Common.csproj">
|
||||
<Project>{806aa078-6070-4bb6-b05b-6ee6b21b1cde}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BulletSharp">
|
||||
<HintPath>..\..\..\deps\BulletPhysics\BulletSharp.NetStandard.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(StrideSdkTargets)" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureFbxSdkInstalled" BeforeTargets="PrepareForBuild">
|
||||
<Message Condition="'$(FbxSdkDir)' != ''" Importance="Normal" Text="Found FBX SDK $(FbxSdkVersion) at $(FbxSdkDir)" />
|
||||
<Error Condition="'$(FbxSdkDir)' == ''" Text="FBX SDK $(FbxSdkVersion) was not found. Please download and install it from $(FbxSdkUrl) (version Windows VS2015) and reload this solution." />
|
||||
</Target>
|
||||
</Project>
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
<ClCompile Include="UtilityFunctions.cpp" />
|
||||
<ClCompile Include="AssemblyInfo.h" />
|
||||
<ClCompile Include="AnimationConverter.h" />
|
||||
<ClCompile Include="SceneMapping.h" />
|
||||
<ClCompile Include="MeshConverter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="UtilityFunctions.h" />
|
||||
<ClInclude Include="ImporterUtils.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="$(MSBuildThisFileDirectory)nuget-icon.png" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,95 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
#include "stdafx.h"
|
||||
#include <assert.h>
|
||||
|
||||
// Conversion functions
|
||||
Quaternion AxisRotationToQuaternion(Vector3 axisRotation)
|
||||
{
|
||||
return Quaternion::RotationX(axisRotation.X) * Quaternion::RotationY(axisRotation.Y) * Quaternion::RotationZ(axisRotation.Z);
|
||||
}
|
||||
Quaternion AxisRotationToQuaternion(FbxDouble3 axisRotation)
|
||||
{
|
||||
return AxisRotationToQuaternion(FbxDouble3ToVector3(axisRotation));
|
||||
}
|
||||
|
||||
Vector2 FbxDouble2ToVector2(FbxDouble2 vector)
|
||||
{
|
||||
return Vector2((float)vector[0], (float)vector[1]);
|
||||
}
|
||||
|
||||
Color4 FbxDouble3ToColor4(FbxDouble3 vector, float alphaValue)
|
||||
{
|
||||
return Color4((float)vector[0], (float)vector[1], (float)vector[2], alphaValue);
|
||||
}
|
||||
|
||||
Vector3 FbxDouble3ToVector3(FbxDouble3 vector)
|
||||
{
|
||||
return Vector3((float)vector[0], (float)vector[1], (float)vector[2]);
|
||||
}
|
||||
|
||||
Vector4 FbxDouble3ToVector4(FbxDouble3 vector, float wValue)
|
||||
{
|
||||
return Vector4((float)vector[0], (float)vector[1], (float)vector[2], wValue);
|
||||
}
|
||||
|
||||
Vector4 FbxDouble4ToVector4(FbxDouble4 vector)
|
||||
{
|
||||
return Vector4((float)vector[0], (float)vector[1], (float)vector[2], (float)vector[3]);
|
||||
}
|
||||
|
||||
CompressedTimeSpan FBXTimeToTimeSpan(const FbxTime& time)
|
||||
{
|
||||
double resultTime = (double)time.Get();
|
||||
resultTime *= (double)CompressedTimeSpan::TicksPerSecond / (double)FBXSDK_TIME_ONE_SECOND.Get();
|
||||
return CompressedTimeSpan((int)resultTime);
|
||||
}
|
||||
|
||||
Matrix FBXMatrixToMatrix(FbxAMatrix& matrix)
|
||||
{
|
||||
Matrix result;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int j = 0; j < 4; ++j)
|
||||
((float*)&result)[i * 4 + j] = (float)((double*)&matrix)[j * 4 + i];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
FbxAMatrix MatrixToFBXMatrix(Matrix& matrix)
|
||||
{
|
||||
FbxAMatrix result;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int j = 0; j < 4; ++j)
|
||||
((double*)&result)[i * 4 + j] = (double)((float*)&matrix)[j * 4 + i];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double FocalLengthToVerticalFov(double filmHeight, double focalLength)
|
||||
{
|
||||
return 2.0 * Math::Atan(filmHeight * 0.5 * 10.0 * 2.54 / focalLength);
|
||||
}
|
||||
|
||||
// Operators
|
||||
FbxDouble3 operator*(double factor, FbxDouble3 vector)
|
||||
{
|
||||
return FbxDouble3(factor * vector[0], factor * vector[1], factor * vector[2]);
|
||||
}
|
||||
|
||||
// string manipulation
|
||||
System::String^ ConvertToUTF8(std::string str)
|
||||
{
|
||||
auto byteCount = str.length();
|
||||
// Check `str' cannot be more than the size of a int.
|
||||
assert(byteCount <= INT32_MAX);
|
||||
if (byteCount <= 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
array<Byte>^ bytes = gcnew array<Byte>((int) byteCount);
|
||||
pin_ptr<Byte> p = &bytes[0];
|
||||
memcpy(p, str.c_str(), byteCount);
|
||||
return System::Text::Encoding::UTF8->GetString(bytes);
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
using namespace System;
|
||||
using namespace Stride::Core::Mathematics;
|
||||
using namespace Stride::Animations;
|
||||
|
||||
// conversion functions
|
||||
Color4 FbxDouble3ToColor4(FbxDouble3 vector, float alphaValue = 1.0f);
|
||||
|
||||
Vector3 FbxDouble3ToVector3(FbxDouble3 vector);
|
||||
Vector4 FbxDouble3ToVector4(FbxDouble3 vector, float wValue = 0.0f);
|
||||
|
||||
Vector4 FbxDouble4ToVector4(FbxDouble4 vector);
|
||||
|
||||
Matrix FBXMatrixToMatrix(FbxAMatrix& matrix);
|
||||
FbxAMatrix MatrixToFBXMatrix(Matrix& matrix);
|
||||
|
||||
Quaternion AxisRotationToQuaternion(Vector3 axisRotation);
|
||||
Quaternion AxisRotationToQuaternion(FbxDouble3 axisRotation);
|
||||
|
||||
CompressedTimeSpan FBXTimeToTimeSpan(const FbxTime& time);
|
||||
|
||||
double FocalLengthToVerticalFov(double filmHeight, double focalLength);
|
||||
|
||||
// operators
|
||||
FbxDouble3 operator*(double factor, FbxDouble3 vector);
|
||||
|
||||
// string manipulation
|
||||
System::String^ ConvertToUTF8(std::string str);
|
|
@ -1,4 +0,0 @@
|
|||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||
#include "stdafx.h"
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma warning( disable : 4945 )
|
||||
|
||||
#include <fbxsdk.h>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <wchar.h>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "UtilityFunctions.h"
|
Загрузка…
Ссылка в новой задаче