diff --git a/build/Stride.sln b/build/Stride.sln
index 4fe1055056..0a22d21885 100644
--- a/build/Stride.sln
+++ b/build/Stride.sln
@@ -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}
diff --git a/sources/editor/Stride.Assets.Presentation/Templates/ModelAssetTemplateWindow.xaml b/sources/editor/Stride.Assets.Presentation/Templates/ModelAssetTemplateWindow.xaml
index 61e63d85d1..082f24bb67 100644
--- a/sources/editor/Stride.Assets.Presentation/Templates/ModelAssetTemplateWindow.xaml
+++ b/sources/editor/Stride.Assets.Presentation/Templates/ModelAssetTemplateWindow.xaml
@@ -27,6 +27,7 @@
+
diff --git a/sources/editor/Stride.Assets.Presentation/Templates/ModelAssetTemplateWindow.xaml.cs b/sources/editor/Stride.Assets.Presentation/Templates/ModelAssetTemplateWindow.xaml.cs
index 35e8e902f6..d690569eef 100644
--- a/sources/editor/Stride.Assets.Presentation/Templates/ModelAssetTemplateWindow.xaml.cs
+++ b/sources/editor/Stride.Assets.Presentation/Templates/ModelAssetTemplateWindow.xaml.cs
@@ -44,6 +44,7 @@ public DummyReferenceContainer()
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 @@ public ImportModelFromFileViewModel(IViewModelServiceProvider serviceProvider)
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); } }
diff --git a/sources/editor/Stride.Assets.Presentation/Templates/ModelFromFileTemplateGenerator.cs b/sources/editor/Stride.Assets.Presentation/Templates/ModelFromFileTemplateGenerator.cs
index 4f3652fbd7..2a354fe8dc 100644
--- a/sources/editor/Stride.Assets.Presentation/Templates/ModelFromFileTemplateGenerator.cs
+++ b/sources/editor/Stride.Assets.Presentation/Templates/ModelFromFileTemplateGenerator.cs
@@ -26,6 +26,7 @@ public static class ModelFromFileTemplateSettings
public static SettingsKey ImportMaterials = new SettingsKey("Templates/ModelFromFile/ImportMaterials", PackageUserSettings.SettingsContainer, true);
public static SettingsKey DeduplicateMaterials = new SettingsKey("Templates/ModelFromFile/DeduplicateMaterials", PackageUserSettings.SettingsContainer, true);
public static SettingsKey ImportTextures = new SettingsKey("Templates/ModelFromFile/ImportTextures", PackageUserSettings.SettingsContainer, true);
+ public static SettingsKey ImportAnimations = new SettingsKey("Templates/ModelFromFile/ImportAnimations", PackageUserSettings.SettingsContainer, true);
public static SettingsKey ImportSkeleton = new SettingsKey("Templates/ModelFromFile/ImportSkeleton", PackageUserSettings.SettingsContainer, true);
public static SettingsKey DefaultSkeleton = new SettingsKey("Templates/ModelFromFile/DefaultSkeleton", PackageUserSettings.SettingsContainer, AssetId.Empty);
}
@@ -39,6 +40,7 @@ public class ModelFromFileTemplateGenerator : AssetFromFileTemplateGenerator
protected static readonly PropertyKey ImportMaterialsKey = new PropertyKey("ImportMaterials", typeof(ModelFromFileTemplateGenerator));
protected static readonly PropertyKey DeduplicateMaterialsKey = new PropertyKey("DeduplicateMaterials", typeof(ModelFromFileTemplateGenerator));
protected static readonly PropertyKey ImportTexturesKey = new PropertyKey("ImportTextures", typeof(ModelFromFileTemplateGenerator));
+ protected static readonly PropertyKey ImportAnimationsKey = new PropertyKey("ImportAnimations", typeof(ModelFromFileTemplateGenerator));
protected static readonly PropertyKey ImportSkeletonKey = new PropertyKey("ImportSkeleton", typeof(ModelFromFileTemplateGenerator));
protected static readonly PropertyKey SkeletonToUseKey = new PropertyKey("SkeletonToUse", typeof(ModelFromFileTemplateGenerator));
@@ -57,8 +59,7 @@ protected override async Task PrepareAssetCreation(AssetTemplateGeneratorP
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 @@ protected override async Task PrepareAssetCreation(AssetTemplateGeneratorP
{
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 @@ protected override async Task PrepareAssetCreation(AssetTemplateGeneratorP
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 @@ protected override async Task PrepareAssetCreation(AssetTemplateGeneratorP
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 @@ protected override IEnumerable CreateAssets(AssetTemplateGeneratorPar
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 @@ protected override IEnumerable CreateAssets(AssetTemplateGeneratorPar
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();
diff --git a/sources/engine/Stride.Assets.Models/FbxAssetImporter.cs b/sources/engine/Stride.Assets.Models/FbxAssetImporter.cs
deleted file mode 100644
index 5b49716dcc..0000000000
--- a/sources/engine/Stride.Assets.Models/FbxAssetImporter.cs
+++ /dev/null
@@ -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;
-
- ///
- 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;
- }
-
- ///
- 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);
- }
- }
-}
diff --git a/sources/engine/Stride.Assets.Models/ImportFbxCommand.cs b/sources/engine/Stride.Assets.Models/ImportFbxCommand.cs
deleted file mode 100644
index dd252e23a2..0000000000
--- a/sources/engine/Stride.Assets.Models/ImportFbxCommand.cs
+++ /dev/null
@@ -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
- {
- ///
- 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 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();
- }
- }
-}
diff --git a/sources/engine/Stride.Assets.Models/ImportModelCommand.Animation.cs b/sources/engine/Stride.Assets.Models/ImportModelCommand.Animation.cs
index b8488f7fa3..bf7b2b9e50 100644
--- a/sources/engine/Stride.Assets.Models/ImportModelCommand.Animation.cs
+++ b/sources/engine/Stride.Assets.Models/ImportModelCommand.Animation.cs
@@ -52,14 +52,17 @@ private unsafe object ExportAnimation(ICommandContext commandContext, ContentMan
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(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 @@ private unsafe object ExportAnimation(ICommandContext commandContext, ContentMan
// Load asset reference skeleton
if (SkeletonUrl != null)
- {
- var skeleton = contentManager.Load(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 @@ private unsafe object ExportAnimation(ICommandContext commandContext, ContentMan
{
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 @@ private unsafe object ExportAnimation(ICommandContext commandContext, ContentMan
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 @@ private unsafe object ExportAnimation(ICommandContext commandContext, ContentMan
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 @@ private unsafe object ExportAnimation(ICommandContext commandContext, ContentMan
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 @@ private unsafe object ExportAnimation(ICommandContext commandContext, ContentMan
}
return animationClip;
}
+
+ public bool GetAnimationKeyVirtualKey(string vKey, Dictionary 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;
+ }
}
}
diff --git a/sources/engine/Stride.Assets.Models/ImportModelCommand.SkeletonMapping.cs b/sources/engine/Stride.Assets.Models/ImportModelCommand.SkeletonMapping.cs
index 82f3442768..9b49047f12 100644
--- a/sources/engine/Stride.Assets.Models/ImportModelCommand.SkeletonMapping.cs
+++ b/sources/engine/Stride.Assets.Models/ImportModelCommand.SkeletonMapping.cs
@@ -16,10 +16,15 @@ class SkeletonMapping
// 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 @@ public SkeletonMapping(Skeleton targetSkeleton, Skeleton sourceSkeleton)
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)
diff --git a/sources/engine/Stride.Assets.Models/ImportModelCommand.cs b/sources/engine/Stride.Assets.Models/ImportModelCommand.cs
index 2e7149fa62..9c613aa9b9 100644
--- a/sources/engine/Stride.Assets.Models/ImportModelCommand.cs
+++ b/sources/engine/Stride.Assets.Models/ImportModelCommand.cs
@@ -28,10 +28,8 @@ public abstract partial class ImportModelCommand : SingleFileImportCommand
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;
}
diff --git a/sources/engine/Stride.Assets.Models/ImportAssimpCommand.cs b/sources/engine/Stride.Assets.Models/ImportThreeDCommand.cs
similarity index 92%
rename from sources/engine/Stride.Assets.Models/ImportAssimpCommand.cs
rename to sources/engine/Stride.Assets.Models/ImportThreeDCommand.cs
index 4e9ffd2ef3..0144aeac15 100644
--- a/sources/engine/Stride.Assets.Models/ImportAssimpCommand.cs
+++ b/sources/engine/Stride.Assets.Models/ImportThreeDCommand.cs
@@ -15,9 +15,9 @@
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(';');
///
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 @@ public static bool IsSupportingExtensions(string ext)
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,
};
diff --git a/sources/engine/Stride.Assets.Models/ModelAssetImporter.cs b/sources/engine/Stride.Assets.Models/ModelAssetImporter.cs
index 09e8e9f0d2..93f0c891a9 100644
--- a/sources/engine/Stride.Assets.Models/ModelAssetImporter.cs
+++ b/sources/engine/Stride.Assets.Models/ModelAssetImporter.cs
@@ -15,6 +15,8 @@
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 @@ public override IEnumerable AdditionalAssetTypes
/// The import parameters.
/// Returns the first (start) keyframe's time for the animation
/// Returns the last (end) keyframe's time for the animation
- 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);
///
/// Imports the model.
@@ -85,7 +87,7 @@ public override IEnumerable Import(UFile localPath, AssetImporterPara
// 1. Textures
if (isImportingTexture)
{
- ImportTextures(entityInfo.TextureDependencies, rawAssetReferences);
+ ImportTextures(entityInfo.TextureDependencies, rawAssetReferences, importParameters.Logger);
}
// 2. Skeleton
@@ -98,10 +100,18 @@ public override IEnumerable Import(UFile localPath, AssetImporterPara
// 3. Animation
if (importParameters.IsTypeSelectedForOutput())
{
- 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[_iAnimIndex], _iAnimIndex, skeletonAsset, startTime, endTime);
+
+ _iAnimIndex++;
+ });
- ImportAnimation(rawAssetReferences, localPath, entityInfo.AnimationNodes, isImportingModel, skeletonAsset, startTime, endTime);
+
}
// 4. Materials
@@ -157,6 +167,32 @@ private static void ImportAnimation(List assetReferences, UFile local
}
}
+ private static void ImportAnimation(List 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(skeletonAsset.Id, skeletonAsset.Location);
+
+ assetReferences.Add(new AssetItem(animUrl, asset));
+ }
+
private static void ImportModel(List assetReferences, UFile assetSource, UFile localPath, EntityInfo entityInfo, bool shouldPostFixName, AssetItem skeletonAsset)
{
var asset = new ModelAsset { Source = assetSource };
@@ -284,13 +320,19 @@ private static void AdjustForTransparency(MaterialAsset material)
//}
}
- private static void ImportTextures(IEnumerable textureDependencies, List assetReferences)
+ private static void ImportTextures(IEnumerable textureDependencies, List assetReferences, Logger logger)
{
if (textureDependencies == null)
return;
foreach (var textureFullPath in textureDependencies.Distinct(x => x))
{
+ if (!File.Exists(textureFullPath))
+ {
+ string texName = Path.GetFileNameWithoutExtension(textureFullPath)??"";
+ logger.Error($"Texture with name {texName} not found");
+ continue;
+ }
var texturePath = new UFile(textureFullPath);
var source = texturePath;
diff --git a/sources/engine/Stride.Assets.Models/Stride.Assets.Models.csproj b/sources/engine/Stride.Assets.Models/Stride.Assets.Models.csproj
index 6911571eaa..ca9fe291b3 100644
--- a/sources/engine/Stride.Assets.Models/Stride.Assets.Models.csproj
+++ b/sources/engine/Stride.Assets.Models/Stride.Assets.Models.csproj
@@ -13,9 +13,8 @@
-
-
+
@@ -32,16 +31,12 @@
-
-
-
-
\ No newline at end of file
diff --git a/sources/engine/Stride.Assets.Models/AssimpAssetImporter.cs b/sources/engine/Stride.Assets.Models/ThreeDAssetImporter.cs
similarity index 89%
rename from sources/engine/Stride.Assets.Models/AssimpAssetImporter.cs
rename to sources/engine/Stride.Assets.Models/ThreeDAssetImporter.cs
index 1394a0fb95..f7d9b2f1d8 100644
--- a/sources/engine/Stride.Assets.Models/AssimpAssetImporter.cs
+++ b/sources/engine/Stride.Assets.Models/ThreeDAssetImporter.cs
@@ -12,10 +12,10 @@
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 @@ public class AssimpAssetImporter : ModelAssetImporter
///
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 @@ public override EntityInfo GetEntityInfo(UFile localPath, Logger logger, AssetIm
}
///
- 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
diff --git a/sources/tools/Stride.Importer.Assimp/Material/Flags.cs b/sources/tools/Stride.Importer.3D/Material/Flags.cs
similarity index 60%
rename from sources/tools/Stride.Importer.Assimp/Material/Flags.cs
rename to sources/tools/Stride.Importer.3D/Material/Flags.cs
index 862d9404f7..1ac1aa87da 100644
--- a/sources/tools/Stride.Importer.Assimp/Material/Flags.cs
+++ b/sources/tools/Stride.Importer.3D/Material/Flags.cs
@@ -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
{
///
/// Enumeration of the new Assimp's flags.
diff --git a/sources/tools/Stride.Importer.Assimp/Material/MappingMode.cs b/sources/tools/Stride.Importer.3D/Material/MappingMode.cs
similarity index 68%
rename from sources/tools/Stride.Importer.Assimp/Material/MappingMode.cs
rename to sources/tools/Stride.Importer.3D/Material/MappingMode.cs
index 68aed2e39f..0c5af13f84 100644
--- a/sources/tools/Stride.Importer.Assimp/Material/MappingMode.cs
+++ b/sources/tools/Stride.Importer.3D/Material/MappingMode.cs
@@ -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
{
///
/// Enumeration of the different mapping modes in the new Assimp's material stack.
diff --git a/sources/tools/Stride.Importer.Assimp/Material/MaterialStack.cs b/sources/tools/Stride.Importer.3D/Material/MaterialStack.cs
similarity index 90%
rename from sources/tools/Stride.Importer.Assimp/Material/MaterialStack.cs
rename to sources/tools/Stride.Importer.3D/Material/MaterialStack.cs
index 0e58259377..77535f2336 100644
--- a/sources/tools/Stride.Importer.Assimp/Material/MaterialStack.cs
+++ b/sources/tools/Stride.Importer.3D/Material/MaterialStack.cs
@@ -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
{
///
/// Class representing the new Assimp's material stack in c#.
diff --git a/sources/tools/Stride.Importer.Assimp/Material/Materials.cs b/sources/tools/Stride.Importer.3D/Material/Materials.cs
similarity index 91%
rename from sources/tools/Stride.Importer.Assimp/Material/Materials.cs
rename to sources/tools/Stride.Importer.3D/Material/Materials.cs
index b89de8d0af..83d4f82f35 100644
--- a/sources/tools/Stride.Importer.Assimp/Material/Materials.cs
+++ b/sources/tools/Stride.Importer.3D/Material/Materials.cs
@@ -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 @@ public static unsafe class Materials
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 @@ public static unsafe MaterialStack ConvertAssimpStackCppToCs(Silk.NET.Assimp.Ass
{
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)
diff --git a/sources/tools/Stride.Importer.Assimp/Material/Operation.cs b/sources/tools/Stride.Importer.3D/Material/Operation.cs
similarity index 82%
rename from sources/tools/Stride.Importer.Assimp/Material/Operation.cs
rename to sources/tools/Stride.Importer.3D/Material/Operation.cs
index 3dfc41ed65..f1c2253245 100644
--- a/sources/tools/Stride.Importer.Assimp/Material/Operation.cs
+++ b/sources/tools/Stride.Importer.3D/Material/Operation.cs
@@ -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
{
///
/// Enumeration of the different operations in the new Assimp's material stack.
diff --git a/sources/tools/Stride.Importer.Assimp/Material/StackColor.cs b/sources/tools/Stride.Importer.3D/Material/StackColor.cs
similarity index 84%
rename from sources/tools/Stride.Importer.Assimp/Material/StackColor.cs
rename to sources/tools/Stride.Importer.3D/Material/StackColor.cs
index c1e21e0604..415c83d790 100644
--- a/sources/tools/Stride.Importer.Assimp/Material/StackColor.cs
+++ b/sources/tools/Stride.Importer.3D/Material/StackColor.cs
@@ -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
{
///
/// Class representing a color in the new Assimp's material stack.
diff --git a/sources/tools/Stride.Importer.Assimp/Material/StackElement.cs b/sources/tools/Stride.Importer.3D/Material/StackElement.cs
similarity index 89%
rename from sources/tools/Stride.Importer.Assimp/Material/StackElement.cs
rename to sources/tools/Stride.Importer.3D/Material/StackElement.cs
index f61cbb568b..3e00420082 100644
--- a/sources/tools/Stride.Importer.Assimp/Material/StackElement.cs
+++ b/sources/tools/Stride.Importer.3D/Material/StackElement.cs
@@ -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
{
///
/// Class representing an element in the new Assimp's material stack.
diff --git a/sources/tools/Stride.Importer.Assimp/Material/StackElementType.cs b/sources/tools/Stride.Importer.3D/Material/StackElementType.cs
similarity index 61%
rename from sources/tools/Stride.Importer.Assimp/Material/StackElementType.cs
rename to sources/tools/Stride.Importer.3D/Material/StackElementType.cs
index 77e608cab5..2dcabd1939 100644
--- a/sources/tools/Stride.Importer.Assimp/Material/StackElementType.cs
+++ b/sources/tools/Stride.Importer.3D/Material/StackElementType.cs
@@ -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
{
///
/// Enumeration of the different types of node in the new Assimp's material stack.
diff --git a/sources/tools/Stride.Importer.Assimp/Material/StackOperation.cs b/sources/tools/Stride.Importer.3D/Material/StackOperation.cs
similarity index 84%
rename from sources/tools/Stride.Importer.Assimp/Material/StackOperation.cs
rename to sources/tools/Stride.Importer.3D/Material/StackOperation.cs
index b2b7ae60de..d26c98fb5d 100644
--- a/sources/tools/Stride.Importer.Assimp/Material/StackOperation.cs
+++ b/sources/tools/Stride.Importer.3D/Material/StackOperation.cs
@@ -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
{
///
/// Class representing an operation in the new Assimp's material stack.
diff --git a/sources/tools/Stride.Importer.Assimp/Material/StackTexture.cs b/sources/tools/Stride.Importer.3D/Material/StackTexture.cs
similarity index 91%
rename from sources/tools/Stride.Importer.Assimp/Material/StackTexture.cs
rename to sources/tools/Stride.Importer.3D/Material/StackTexture.cs
index 0a451cde56..4ec127f9ae 100644
--- a/sources/tools/Stride.Importer.Assimp/Material/StackTexture.cs
+++ b/sources/tools/Stride.Importer.3D/Material/StackTexture.cs
@@ -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
{
///
/// Class representing a texture in the new Assimp's material stack.
diff --git a/sources/tools/Stride.Importer.Assimp/MeshConverter.cs b/sources/tools/Stride.Importer.3D/MeshConverter.cs
similarity index 92%
rename from sources/tools/Stride.Importer.Assimp/MeshConverter.cs
rename to sources/tools/Stride.Importer.3D/MeshConverter.cs
index 2ae9dcc383..9bbcd003db 100644
--- a/sources/tools/Stride.Importer.Assimp/MeshConverter.cs
+++ b/sources/tools/Stride.Importer.3D/MeshConverter.cs
@@ -5,6 +5,7 @@
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.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.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 @@ static MeshConverter()
public bool AllowUnsignedBlendIndices { get; set; }
- // Conversion data
private string vfsInputFilename;
private string vfsOutputFilename;
@@ -79,7 +101,7 @@ public unsafe EntityInfo ExtractEntity(string inputFilename, string outputFilena
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 @@ public unsafe EntityInfo ExtractEntity(string inputFilename, string outputFilena
return entityInfo;
}
- catch(Exception ex)
+ catch (Exception ex)
{
Logger.Error($"Exception has occured during Entity extraction : {ex.Message}");
throw;
@@ -123,31 +145,15 @@ public unsafe EntityInfo ExtractEntity(string inputFilename, string outputFilena
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 @@ public unsafe Rendering.Skeleton ConvertSkeleton(string inputFilename, string ou
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 @@ public unsafe Rendering.Skeleton ConvertSkeleton(string inputFilename, string ou
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 @@ private unsafe Model ConvertAssimpScene(Scene* scene)
// register the nodes and fill hierarchy
var meshIndexToNodeIndex = new Dictionary>();
- 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 @@ private unsafe Model ConvertAssimpScene(Scene* scene)
Draw = meshInfo.Draw,
Name = meshInfo.Name,
MaterialIndex = meshInfo.MaterialIndex,
- NodeIndex = nodeIndex
+ NodeIndex = nodeIndex,
};
if (meshInfo.Bones != null)
@@ -221,6 +239,7 @@ private unsafe Model ConvertAssimpScene(Scene* scene)
if (meshInfo.HasSkinningNormal && meshInfo.TotalClusterCount > 0)
nodeMeshData.Parameters.Set(MaterialKeys.HasSkinningNormal, true);
+
modelData.Meshes.Add(nodeMeshData);
}
}
@@ -242,7 +261,7 @@ private unsafe Rendering.Skeleton ProcessSkeleton(Scene* scene)
// register the nodes and fill hierarchy
var meshIndexToNodeIndex = new Dictionary>();
- RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex);
+ RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex, GetBoneList(scene));
return new Rendering.Skeleton
{
@@ -260,7 +279,7 @@ private unsafe AnimationInfo ProcessAnimations(Scene* scene, int animationIndex)
// register the nodes and fill hierarchy
var meshIndexToNodeIndex = new Dictionary>();
- RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex);
+ RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex, GetBoneList(scene));
if (scene->MNumAnimations > 0)
{
@@ -287,7 +306,7 @@ private unsafe AnimationInfo ProcessAnimations(Scene* scene, int animationIndex)
// 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 @@ private unsafe AnimationInfo ProcessAnimations(Scene* scene, int animationIndex)
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 @@ private unsafe AnimationInfo ProcessAnimations(Scene* scene, int animationIndex)
private unsafe void ProcessNodeAnimation(Dictionary 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 @@ private unsafe void GenerateUniqueNames(Dictionary finalNames, L
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 @@ private unsafe void GenerateUniqueNames(Dictionary finalNames, L
}
}
+ private unsafe HashSet GetBoneList(Scene* scene)
+ {
+ HashSet bones = new HashSet();
+ 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 meshNames)
{
var baseNames = new List();
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 @@ private unsafe void GenerateAnimationNames(Scene* scene, DictionaryMNumAnimations; i++)
{
var lAnimation = scene->MAnimations[i];
- var animationName = lAnimation->MName.AsString;
+ var animationName = lAnimation->MName.AsString.CleanNodeName();
baseNames.Add(animationName);
}
@@ -501,7 +523,7 @@ private unsafe void GenerateNodeNames(Scene* scene, Dictionary n
private unsafe void GetNodeNames(Node* node, List nodeNames, List 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 @@ private unsafe void GetNodeNames(Node* node, List nodeNames, List nodeNames, Dictionary> meshIndexToNodeIndex)
+ private unsafe void RegisterNodes(Node* fromNode, int parentIndex, Dictionary nodeNames, Dictionary> meshIndexToNodeIndex, HashSet filterInNodes)
{
var nodeIndex = nodes.Count;
@@ -536,8 +558,10 @@ private unsafe void RegisterNodes(Node* fromNode, int parentIndex, DictionaryMMeshes;
// 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 @@ private unsafe void RegisterNodes(Node* fromNode, int parentIndex, DictionaryMTransformation.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 @@ private unsafe MeshInfo ProcessMesh(Scene* scene, Silk.NET.Assimp.Mesh* mesh, Di
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 @@ private unsafe MeshInfo ProcessMesh(Scene* scene, Silk.NET.Assimp.Mesh* mesh, Di
// 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 @@ private unsafe MeshInfo ProcessMesh(Scene* scene, Silk.NET.Assimp.Mesh* mesh, Di
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 @@ private unsafe MeshInfo ProcessMesh(Scene* scene, Silk.NET.Assimp.Mesh* mesh, Di
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 @@ private unsafe MeshInfo ProcessMesh(Scene* scene, Silk.NET.Assimp.Mesh* mesh, Di
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 @@ private unsafe MeshInfo ProcessMesh(Scene* scene, Silk.NET.Assimp.Mesh* mesh, Di
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 @@ private unsafe MeshInfo ProcessMesh(Scene* scene, Silk.NET.Assimp.Mesh* mesh, Di
HasSkinningNormal = hasSkinningNormal,
TotalClusterCount = totalClusterCount
};
+
+
}
private void NormalizeVertexWeights(List> controlPts, int nbBoneByVertex)
@@ -986,7 +1030,7 @@ private unsafe void SetMaterialColorFlag(Silk.NET.Assimp.Material* pMaterial, st
}
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 @@ private unsafe void BuildLayeredSurface(Silk.NET.Assimp.Material* pMat, bool has
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();
@@ -1393,4 +1437,7 @@ public unsafe class MaterialInstances
public List Instances = new();
public string MaterialsName;
}
+
}
+
+
diff --git a/sources/tools/Stride.Importer.Assimp/Stride.Importer.Assimp.csproj b/sources/tools/Stride.Importer.3D/Stride.Importer.3D.csproj
similarity index 96%
rename from sources/tools/Stride.Importer.Assimp/Stride.Importer.Assimp.csproj
rename to sources/tools/Stride.Importer.3D/Stride.Importer.3D.csproj
index 67ba1fef0f..909689355c 100644
--- a/sources/tools/Stride.Importer.Assimp/Stride.Importer.Assimp.csproj
+++ b/sources/tools/Stride.Importer.3D/Stride.Importer.3D.csproj
@@ -14,6 +14,7 @@
+
diff --git a/sources/tools/Stride.Importer.Assimp/Utils.cs b/sources/tools/Stride.Importer.3D/Utils.cs
similarity index 62%
rename from sources/tools/Stride.Importer.Assimp/Utils.cs
rename to sources/tools/Stride.Importer.3D/Utils.cs
index 50fa77dba7..7629787ae5 100644
--- a/sources/tools/Stride.Importer.Assimp/Utils.cs
+++ b/sources/tools/Stride.Importer.3D/Utils.cs
@@ -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 @@ public static Matrix ToStrideMatrix(this Matrix4x4 matrix)
}
public static Core.Mathematics.Vector3 ToStrideVector3(this System.Numerics.Vector3 v)
- => new Core.Mathematics.Vector3(v.X, v.Y, v.Z);
+ => Unsafe.As(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 @@ public static CompressedTimeSpan AiTimeToStrideTimeSpan(double time, double aiTi
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;
+ }
}
}
diff --git a/sources/tools/Stride.Importer.FBX/AnimationConverter.h b/sources/tools/Stride.Importer.FBX/AnimationConverter.h
deleted file mode 100644
index aa682e3e2f..0000000000
--- a/sources/tools/Stride.Importer.FBX/AnimationConverter.h
+++ /dev/null
@@ -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();
-
- if (animStackCount > 0)
- {
- bool check = true;
- for (int i = 0; i < animStackCount && check; ++i)
- {
- FbxAnimStack* animStack = scene->GetMember(i);
- int animLayerCount = animStack->GetMemberCount();
- FbxAnimLayer* animLayer = animStack->GetMember(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();
- 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(animationStack);
- int animLayerCount = animStack->GetMemberCount();
-
- // 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(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^ ExtractAnimationNodesNoInit()
- {
- int animStackCount = scene->GetMemberCount();
- List^ animationNodes = nullptr;
-
- if (animStackCount > 0)
- {
- animationNodes = gcnew List();
- for (int i = 0; i < animStackCount; ++i)
- {
- FbxAnimStack* animStack = scene->GetMember(i);
- int animLayerCount = animStack->GetMemberCount();
- FbxAnimLayer* animLayer = animStack->GetMember(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
- AnimationCurve^ ProcessAnimationCurveVector(AnimationClip^ animationClip, String^ name, int numCurves, FbxAnimCurve** curves, T defaultValue, bool isUserDefinedProperty)
- {
- auto keyFrames = ProcessAnimationCurveFloatsHelper(curves, defaultValue, numCurves);
- if (keyFrames == nullptr)
- return nullptr;
-
- // Add curve
- auto animationCurve = gcnew AnimationCurve();
-
- // 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 AnimationCurve^ CreateCurve(AnimationClip^ animationClip, String^ name, List>^ keyFrames)
- {
- // Add curve
- auto animationCurve = gcnew AnimationCurve();
-
- 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^ ProcessAnimationCurveRotation(AnimationClip^ animationClip, String^ name, FbxAnimCurve** curves, Vector3 defaultValue)
- {
- auto keyFrames = ProcessAnimationCurveFloatsHelper(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();
-
- // Create keys
- for (int i = 0; i < keyFrames->Count; ++i)
- {
- auto keyFrame = keyFrames[i];
-
- KeyFrameData 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
- List>^ 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>();
-
- const float framerate = static_cast(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();
- 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^ 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^ 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^ 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^ 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^ 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(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(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(camera->FieldOfViewY.Get());
- auto FovAnimChannel = ProcessAnimationCurveVector(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(camera->FocalLength.Get());
- auto flAnimChannel = ProcessAnimationCurveVector(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(camera->NearPlane.Get());
- ProcessAnimationCurveVector(animationClip, cameraComponentKey+"NearClipPlane", 1, curves, defaultValue, false);
- }
-
- if (camera->FarPlane.GetCurve(animLayer))
- {
- curves[0] = camera->FarPlane.GetCurve(animLayer);
- float defaultValue = static_cast(camera->FarPlane.Get());
- ProcessAnimationCurveVector(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; cGetCurve(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(animationClip, lFbxFCurveNodeName, channelCount, curves, 0, true);
- }
- if (lDataType.GetType() == eFbxDouble2)
- {
- ProcessAnimationCurveVector(animationClip, lFbxFCurveNodeName, channelCount, curves, Vector2::Zero, true);
- }
- else if (lDataType.GetType() == eFbxDouble3)
- {
- ProcessAnimationCurveVector(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(0);
-
- if (HasAnimation(layer0, pNode))
- {
- auto evaluator = scene->GetAnimationEvaluator();
-
- auto animationName = animStack->GetName();
-
- // Create curves
- auto scalingFrames = gcnew List>();
- auto rotationFrames = gcnew List>();
- auto translationFrames = gcnew List>();
-
- 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(animStart.GetSecondDouble());
- FbxLongLong end = static_cast(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(time, scaling));
- translationFrames->Add(KeyFrameData(time, translation));
- rotationFrames->Add(KeyFrameData(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^ 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);
- }
- }
- };
-
- }
- }
-}
diff --git a/sources/tools/Stride.Importer.FBX/AssemblyInfo.h b/sources/tools/Stride.Importer.FBX/AssemblyInfo.h
deleted file mode 100644
index 504b106ebb..0000000000
--- a/sources/tools/Stride.Importer.FBX/AssemblyInfo.h
+++ /dev/null
@@ -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)];
diff --git a/sources/tools/Stride.Importer.FBX/ImporterUtils.h b/sources/tools/Stride.Importer.FBX/ImporterUtils.h
deleted file mode 100644
index c8caae6e6a..0000000000
--- a/sources/tools/Stride.Importer.FBX/ImporterUtils.h
+++ /dev/null
@@ -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__
diff --git a/sources/tools/Stride.Importer.FBX/MeshConverter.cpp b/sources/tools/Stride.Importer.FBX/MeshConverter.cpp
deleted file mode 100644
index 798ffee775..0000000000
--- a/sources/tools/Stride.Importer.FBX/MeshConverter.cpp
+++ /dev/null
@@ -1,2133 +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 "ImporterUtils.h"
-
-#include "SceneMapping.h"
-#include "AnimationConverter.h"
-
-using namespace System;
-using namespace System::IO;
-using namespace System::Collections::Generic;
-using namespace System::Runtime::InteropServices;
-using namespace Stride::Core::BuildEngine;
-using namespace Stride::Core::Diagnostics;
-using namespace Stride::Core::IO;
-using namespace Stride::Core::Mathematics;
-using namespace Stride::Core::Serialization;
-using namespace Stride::Core::Serialization::Contents;
-using namespace Stride::Rendering::Materials;
-using namespace Stride::Rendering::Materials::ComputeColors;
-using namespace Stride::Assets::Materials;
-using namespace Stride::Animations;
-using namespace Stride::Engine;
-using namespace Stride::Extensions;
-using namespace Stride::Graphics;
-using namespace Stride::Graphics::Data;
-using namespace Stride::Shaders;
-
-using namespace Stride::Importer::Common;
-
-namespace Stride { namespace Importer { namespace FBX {
-
-static const char* MappingModeName[] = { "None", "ByControlPoint", "ByPolygonVertex", "ByPolygon", "ByEdge", "AllSame" };
-static const char* MappingModeSuggestion[] = { "", "", "", "", " Try using ByPolygon mapping instead.", "" };
-
-public ref class MaterialInstantiation
-{
-public:
- MaterialInstantiation()
- {
- }
-
- FbxSurfaceMaterial* SourceMaterial;
- MaterialAsset^ Material;
- String^ MaterialName;
-};
-
-
-public ref class MeshConverter
-{
-public:
- property bool AllowUnsignedBlendIndices;
-
- Logger^ logger;
-
-internal:
- FbxManager* lSdkManager;
- FbxImporter* lImporter;
- FbxScene* scene;
-
- String^ inputFilename;
- String^ vfsOutputFilename;
- String^ inputPath;
-
- Model^ modelData;
-
- SceneMapping^ sceneMapping;
-
- static array^ currentBuffer;
-
- static bool WeightGreater(const std::pair& elem1, const std::pair& elem2)
- {
- return elem1.second > elem2.second;
- }
-
- bool IsGroupMappingModeByEdge(FbxLayerElement* layerElement)
- {
- return layerElement->GetMappingMode() == FbxLayerElement::eByEdge;
- }
-
- template
- int GetGroupIndexForLayerElementTemplate(FbxLayerElementTemplate* layerElement, int controlPointIndex, int vertexIndex, int edgeIndex, int polygonIndex, String^ meshName, bool& firstTimeError)
- {
- int groupIndex = 0;
- if (layerElement->GetMappingMode() == FbxLayerElement::eByControlPoint)
- {
- groupIndex = (layerElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
- ? layerElement->GetIndexArray().GetAt(controlPointIndex)
- : controlPointIndex;
- }
- else if (layerElement->GetMappingMode() == FbxLayerElement::eByPolygonVertex)
- {
- groupIndex = (layerElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
- ? layerElement->GetIndexArray().GetAt(vertexIndex)
- : vertexIndex;
- }
- else if (layerElement->GetMappingMode() == FbxLayerElement::eByPolygon)
- {
- groupIndex = (layerElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
- ? layerElement->GetIndexArray().GetAt(polygonIndex)
- : polygonIndex;
- }
- else if (layerElement->GetMappingMode() == FbxLayerElement::eByEdge)
- {
- groupIndex = (layerElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
- ? layerElement->GetIndexArray().GetAt(edgeIndex)
- : edgeIndex;
- }
- else if (layerElement->GetMappingMode() == FbxLayerElement::eAllSame)
- {
- groupIndex = (layerElement->GetReferenceMode() == FbxLayerElement::eIndexToDirect)
- ? layerElement->GetIndexArray().GetAt(0)
- : 0;
- }
- else if (firstTimeError)
- {
- firstTimeError = false;
- int mappingMode = layerElement->GetMappingMode();
- if (mappingMode > (int)FbxLayerElement::eAllSame)
- mappingMode = (int)FbxLayerElement::eAllSame;
- const char* layerName = layerElement->GetName();
- logger->Warning(String::Format("'{0}' mapping mode for layer '{1}' in mesh '{2}' is not supported by the FBX importer.{3}",
- gcnew String(MappingModeName[mappingMode]),
- strlen(layerName) > 0 ? gcnew String(layerName) : gcnew String("Unknown"),
- meshName,
- gcnew String(MappingModeSuggestion[mappingMode])), (CallerInfo^)nullptr);
- }
-
- return groupIndex;
- }
-
-
-public:
- MeshConverter(Logger^ Logger)
- {
- if(Logger == nullptr)
- Logger = Core::Diagnostics::GlobalLogger::GetLogger("Importer FBX");
-
- logger = Logger;
- lSdkManager = NULL;
- lImporter = NULL;
- }
-
- void Destroy()
- {
- //Marshal::FreeHGlobal((IntPtr)lFilename);
- currentBuffer = nullptr;
-
- // The file has been imported; we can get rid of the importer.
- lImporter->Destroy();
-
- // Destroy the sdk manager and all other objects it was handling.
- lSdkManager->Destroy();
-
- // -----------------------------------------------------
- // TODO: Workaround with FBX SDK not being multithreaded.
- // We protect the whole usage of this class with a monitor
- //
- // Lock the whole class between Initialize/Destroy
- // -----------------------------------------------------
- System::Threading::Monitor::Exit( globalLock );
- // -----------------------------------------------------
- }
-
- void ProcessMesh(FbxMesh* pMesh, std::map meshNames, std::map materials)
- {
- // Checks normals availability.
- bool has_normals = pMesh->GetElementNormalCount() > 0 && pMesh->GetElementNormal(0)->GetMappingMode() != FbxLayerElement::eNone;
- bool needEdgeIndexing = false;
-
- // Regenerate normals if necessary
- if (!has_normals)
- {
- pMesh->GenerateNormals(true, false, false);
- }
-
- FbxVector4* controlPoints = pMesh->GetControlPoints();
- FbxGeometryElementNormal* normalElement = pMesh->GetElementNormal();
- FbxGeometryElementTangent* tangentElement = pMesh->GetElementTangent();
- FbxGeometryElementBinormal* binormalElement = pMesh->GetElementBinormal();
- FbxGeometryElementSmoothing* smoothingElement = pMesh->GetElementSmoothing();
-
- // UV set name mapping
- std::map uvElementMapping;
- std::vector uvElements;
-
- for (int i = 0; i < pMesh->GetElementUVCount(); ++i)
- {
- auto uvElement = pMesh->GetElementUV(i);
- uvElements.push_back(uvElement);
- needEdgeIndexing |= IsGroupMappingModeByEdge(uvElement);
- }
-
- auto meshName = gcnew String(meshNames[pMesh].c_str());
-
- bool hasSkinningPosition = false;
- bool hasSkinningNormal = false;
- int totalClusterCount = 0;
- std::vector > > controlPointWeights;
-
- List^ bones = nullptr;
-
- // Dump skinning information
- int skinDeformerCount = pMesh->GetDeformerCount(FbxDeformer::eSkin);
- if (skinDeformerCount > 0)
- {
- bones = gcnew List();
- for (int deformerIndex = 0; deformerIndex < skinDeformerCount; deformerIndex++)
- {
- FbxSkin* skin = FbxCast(pMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
- controlPointWeights.resize(pMesh->GetControlPointsCount());
-
- totalClusterCount = skin->GetClusterCount();
- for (int clusterIndex = 0 ; clusterIndex < totalClusterCount; ++clusterIndex)
- {
- FbxCluster* cluster = skin->GetCluster(clusterIndex);
- int indexCount = cluster->GetControlPointIndicesCount();
- if (indexCount == 0)
- {
- continue;
- }
-
- FbxNode* link = cluster->GetLink();
- const char* boneName = link->GetName();
- int *indices = cluster->GetControlPointIndices();
- double *weights = cluster->GetControlPointWeights();
-
- FbxAMatrix transformMatrix;
- FbxAMatrix transformLinkMatrix;
-
- cluster->GetTransformMatrix(transformMatrix);
- cluster->GetTransformLinkMatrix(transformLinkMatrix);
- auto globalBindposeInverseMatrix = transformLinkMatrix.Inverse() * transformMatrix;
-
- MeshBoneDefinition bone;
- int boneIndex = bones->Count;
- bone.NodeIndex = sceneMapping->FindNodeIndex(link);
- bone.LinkToMeshMatrix = sceneMapping->ConvertMatrixFromFbx(globalBindposeInverseMatrix);
-
- // Check if the bone was not already there, else update it
- // TODO: this is not the correct way to handle multiple deformers (additive...etc.)
- bool isBoneAlreadyFound = false;
- for (int i = 0; i < bones->Count; i++)
- {
- if (bones[i].NodeIndex == bone.NodeIndex)
- {
- bones[i] = bone;
- boneIndex = i;
- isBoneAlreadyFound = true;
- break;
- }
- }
-
- // Gather skin indices and weights
- for (int j = 0 ; j < indexCount; j++)
- {
- int controlPointIndex = indices[j];
- controlPointWeights[controlPointIndex].push_back(std::pair((short)boneIndex, (float)weights[j]));
- }
-
- // Find an existing bone and update it
- // TODO: this is probably not correct to do this (we should handle cluster additive...etc. more correctly here)
- if (!isBoneAlreadyFound)
- {
- bones->Add(bone);
- }
- }
-
- // look for position/normals skinning
- if (pMesh->GetControlPointsCount() > 0)
- {
- hasSkinningPosition = true;
- hasSkinningNormal = (pMesh->GetElementNormal() != NULL);
- }
-
- for (int i = 0 ; i < pMesh->GetControlPointsCount(); i++)
- {
- std::sort(controlPointWeights[i].begin(), controlPointWeights[i].end(), WeightGreater);
- controlPointWeights[i].resize(4, std::pair(0, 0.0f));
- float totalWeight = 0.0f;
- for (int j = 0; j < 4; ++j)
- totalWeight += controlPointWeights[i][j].second;
- if (totalWeight == 0.0f)
- {
- for (int j = 0; j < 4; ++j)
- controlPointWeights[i][j].second = (j == 0) ? 1.0f : 0.0f;
- }
- else
- {
- totalWeight = 1.0f / totalWeight;
- for (int j = 0; j < 4; ++j)
- controlPointWeights[i][j].second *= totalWeight;
- }
- }
- }
- }
-
- // *********************************************************************************
- // Build the vertex declaration
- // *********************************************************************************
- auto vertexElements = gcnew List();
-
- // POSITION
- int vertexStride = 0;
- int positionOffset = vertexStride;
- vertexElements->Add(VertexElement::Position(0, vertexStride));
- vertexStride += 12;
-
- // NORMAL
- int normalOffset = vertexStride;
- if (normalElement != NULL)
- {
- vertexElements->Add(VertexElement::Normal(0, vertexStride));
- vertexStride += 12;
-
- needEdgeIndexing |= IsGroupMappingModeByEdge(normalElement);
- }
-
- int tangentOffset = vertexStride;
- if (tangentElement != NULL)
- {
- vertexElements->Add(VertexElement::Tangent(0, vertexStride));
- vertexStride += 16;
-
- needEdgeIndexing |= IsGroupMappingModeByEdge(tangentElement);
- }
-
- // TEXCOORD
- std::vector uvOffsets;
- for (int i = 0; i < (int)uvElements.size(); ++i)
- {
- uvOffsets.push_back(vertexStride);
- vertexElements->Add(VertexElement::TextureCoordinate(i, vertexStride));
- vertexStride += 8;
- uvElementMapping[pMesh->GetElementUV(i)->GetName()] = i;
- }
-
- // BLENDINDICES
- int blendIndicesOffset = vertexStride;
- bool controlPointIndices16 = (AllowUnsignedBlendIndices && totalClusterCount > 256) || (!AllowUnsignedBlendIndices && totalClusterCount > 128);
- if (!controlPointWeights.empty())
- {
- if (controlPointIndices16)
- {
- if (AllowUnsignedBlendIndices)
- {
- vertexElements->Add(VertexElement("BLENDINDICES", 0, PixelFormat::R16G16B16A16_UInt, vertexStride));
- vertexStride += sizeof(unsigned short) * 4;
- }
- else
- {
- vertexElements->Add(VertexElement("BLENDINDICES", 0, PixelFormat::R16G16B16A16_SInt, vertexStride));
- vertexStride += sizeof(short) * 4;
- }
- }
- else
- {
- if (AllowUnsignedBlendIndices)
- {
- vertexElements->Add(VertexElement("BLENDINDICES", 0, PixelFormat::R8G8B8A8_UInt, vertexStride));
- vertexStride += sizeof(unsigned char) * 4;
- }
- else
- {
- vertexElements->Add(VertexElement("BLENDINDICES", 0, PixelFormat::R8G8B8A8_SInt, vertexStride));
- vertexStride += sizeof(char) * 4;
- }
- }
- }
-
- // BLENDWEIGHT
- int blendWeightOffset = vertexStride;
- if (!controlPointWeights.empty())
- {
- vertexElements->Add(VertexElement("BLENDWEIGHT", 0, PixelFormat::R32G32B32A32_Float, vertexStride));
- vertexStride += sizeof(float) * 4;
- }
-
- // COLOR
- auto elementVertexColorCount = pMesh->GetElementVertexColorCount();
- std::vector vertexColorElements;
- int colorOffset = vertexStride;
- for (int i = 0; i < elementVertexColorCount; i++)
- {
- auto vertexColorElement = pMesh->GetElementVertexColor(i);
- vertexColorElements.push_back(vertexColorElement);
- vertexElements->Add(VertexElement::Color(i, vertexStride));
- vertexStride += sizeof(Color);
- needEdgeIndexing |= IsGroupMappingModeByEdge(vertexColorElement);
- }
-
- // USERDATA
- // TODO: USERData how to handle then?
- //auto userDataCount = pMesh->GetElementUserDataCount();
- //for (int i = 0; i < userDataCount; i++)
- //{
- // auto userData = pMesh->GetElementUserData(i);
- // auto dataType = userData->GetDataName(0);
- // Console::WriteLine("DataName {0}", gcnew String(dataType));
- //}
-
- // Add the smoothing group information at the end of the vertex declaration
- // *************************************************************************
- // WARNING - DONT PUT ANY VertexElement after SMOOTHINGGROUP
- // *************************************************************************
- // Iit is important that to be the LAST ELEMENT of the declaration because it is dropped later in the process by partial memcopys
- // SMOOTHINGGROUP
- int smoothingOffset = vertexStride;
- if (smoothingElement != NULL)
- {
- vertexElements->Add(VertexElement("SMOOTHINGGROUP", 0, PixelFormat::R32_UInt, vertexStride));
- vertexStride += sizeof(int);
-
- needEdgeIndexing |= IsGroupMappingModeByEdge(smoothingElement);
- }
-
- int polygonCount = pMesh->GetPolygonCount();
-
- FbxGeometryElement::EMappingMode materialMappingMode = FbxGeometryElement::eNone;
- FbxLayerElementArrayTemplate* materialIndices = NULL;
-
- if (pMesh->GetElementMaterial())
- {
- materialMappingMode = pMesh->GetElementMaterial()->GetMappingMode();
- materialIndices = &pMesh->GetElementMaterial()->GetIndexArray();
- }
-
- auto buildMeshes = gcnew List();
-
- // Count polygon per materials
- for (int i = 0; i < polygonCount; i++)
- {
- int materialIndex = 0;
- if (materialMappingMode == FbxGeometryElement::eByPolygon)
- {
- materialIndex = materialIndices->GetAt(i);
- }
-
- // Equivalent to std::vector::resize()
- while (materialIndex >= buildMeshes->Count)
- {
- buildMeshes->Add(nullptr);
- }
-
- if (buildMeshes[materialIndex] == nullptr)
- buildMeshes[materialIndex] = gcnew BuildMesh();
-
- int polygonSize = pMesh->GetPolygonSize(i) - 2;
- if (polygonSize > 0)
- buildMeshes[materialIndex]->polygonCount += polygonSize;
- }
-
- // Create arrays
- for each(BuildMesh^ buildMesh in buildMeshes)
- {
- if (buildMesh == nullptr)
- continue;
-
- buildMesh->buffer = gcnew array(vertexStride * buildMesh->polygonCount * 3);
- }
-
- bool layerIndexFirstTimeError = true;
-
- if (needEdgeIndexing)
- pMesh->BeginGetMeshEdgeIndexForPolygon();
-
- // Build polygons
- int polygonVertexStartIndex = 0;
- for (int i = 0; i < polygonCount; i++)
- {
- int materialIndex = 0;
- if (materialMappingMode == FbxGeometryElement::eByPolygon)
- {
- materialIndex = materialIndices->GetAt(i);
- }
-
- auto buildMesh = buildMeshes[materialIndex];
- auto buffer = buildMesh->buffer;
-
- int polygonSize = pMesh->GetPolygonSize(i);
-
- for (int polygonFanIndex = 2; polygonFanIndex < polygonSize; ++polygonFanIndex)
- {
- pin_ptr vbPointer = &buffer[buildMesh->bufferOffset];
- buildMesh->bufferOffset += vertexStride * 3;
-
- int vertexInPolygon[3] = { 0, polygonFanIndex, polygonFanIndex - 1};
- int edgesInPolygon[3];
-
- if (needEdgeIndexing)
- {
- // Default case for polygon of size 3
- // Since our polygon order is 0,2,1, edge order is 2 (edge from 0 to 2),1 (edge from 2 to 1),0 (edge from 1 to 0)
- // Note: all that code computing edge should change if vertexInPolygon changes
- edgesInPolygon[0] = polygonFanIndex;
- edgesInPolygon[1] = polygonFanIndex - 1;
- edgesInPolygon[2] = 0;
-
- if (polygonSize > 3)
- {
- // Since we create non-existing edges inside the fan, we might have to use another edge in those cases
- // If edge doesn't exist, we have to use edge from (polygonFanIndex-1) to polygonFanIndex (only one that always exists)
-
- // Let's say polygon is 0,4,3,2,1
-
- // First polygons (except last): 0,2,1 (edge doesn't exist, use the one from 2 to 1 so edge 1)
- // Last polygon : 0,4,3 (edge exists:4, from 0 to 4)
- if (polygonFanIndex != polygonSize - 1)
- edgesInPolygon[0] = polygonFanIndex - 1;
-
- // First polygon: 0,2,1 (edge exists:0, from 1 to 0)
- // Last polygons: 0,4,3 (edge doesn't exist, use the one from 4 to 3 so edge 3)
- if (polygonFanIndex != 2)
- edgesInPolygon[2] = polygonFanIndex - 1;
- }
- }
-
- //if (polygonSwap)
- //{
- // int temp = vertexInPolygon[1];
- // vertexInPolygon[1] = vertexInPolygon[2];
- // vertexInPolygon[2] = temp;
- //}
- int controlPointIndices[3] = { pMesh->GetPolygonVertex(i, vertexInPolygon[0]), pMesh->GetPolygonVertex(i, vertexInPolygon[1]), pMesh->GetPolygonVertex(i, vertexInPolygon[2]) };
-
- for (int polygonFanVertex = 0; polygonFanVertex < 3; ++polygonFanVertex)
- {
- int j = vertexInPolygon[polygonFanVertex];
- int vertexIndex = polygonVertexStartIndex + j;
- int jNext = vertexInPolygon[(polygonFanVertex + 1) % 3];
- int vertexIndexNext = polygonVertexStartIndex + jNext;
- int controlPointIndex = controlPointIndices[polygonFanVertex];
- int edgeIndex = needEdgeIndexing ? pMesh->GetMeshEdgeIndexForPolygon(i, edgesInPolygon[polygonFanVertex]) : 0;
-
- // POSITION
- auto controlPoint = sceneMapping->ConvertPointFromFbx(controlPoints[controlPointIndex]);
- *(Vector3*)(vbPointer + positionOffset) = controlPoint;
-
- // NORMAL
- Vector3 normal = Vector3(1, 0, 0);
- if (normalElement != NULL)
- {
- int normalIndex = GetGroupIndexForLayerElementTemplate(normalElement, controlPointIndex, vertexIndex, edgeIndex, i, meshName, layerIndexFirstTimeError);
- auto src_normal = normalElement->GetDirectArray().GetAt(normalIndex);
- auto normalPointer = ((Vector3*)(vbPointer + normalOffset));
- normal = sceneMapping->ConvertNormalFromFbx(src_normal);
- if (isnan(normal.X) || isnan(normal.Y) || isnan(normal.Z) || normal.Length() < FLT_EPSILON)
- normal = Vector3(1, 0, 0);
- normal = Vector3::Normalize(normal);
- *normalPointer = normal;
- }
-
- // UV
- for (int uvGroupIndex = 0; uvGroupIndex < (int)uvElements.size(); ++uvGroupIndex)
- {
- auto uvElement = uvElements[uvGroupIndex];
- int uvIndex = GetGroupIndexForLayerElementTemplate(uvElement, controlPointIndex, vertexIndex, edgeIndex, i, meshName, layerIndexFirstTimeError);
- auto uv = uvElement->GetDirectArray().GetAt(uvIndex);
-
- ((float*)(vbPointer + uvOffsets[uvGroupIndex]))[0] = (float)uv[0];
- ((float*)(vbPointer + uvOffsets[uvGroupIndex]))[1] = 1.0f - (float)uv[1];
- }
-
- // TANGENT
- if (tangentElement != NULL)
- {
- int tangentIndex = GetGroupIndexForLayerElementTemplate(tangentElement, controlPointIndex, vertexIndex, edgeIndex, i, meshName, layerIndexFirstTimeError);
- auto src_tangent = tangentElement->GetDirectArray().GetAt(tangentIndex);
- auto tangentPointer = ((Vector4*)(vbPointer + tangentOffset));
- Vector3 tangent = sceneMapping->ConvertNormalFromFbx(src_tangent);
- if (isnan(tangent.X) || isnan(tangent.Y) || isnan(tangent.Z) || tangent.Length() < FLT_EPSILON)
- {
- *tangentPointer = Vector4(1, 0, 0, 1);
- }
- else
- {
- tangent = Vector3::Normalize(tangent);
-
- int binormalIndex = GetGroupIndexForLayerElementTemplate(binormalElement, controlPointIndex, vertexIndex, edgeIndex, i, meshName, layerIndexFirstTimeError);
- auto src_binormal = binormalElement->GetDirectArray().GetAt(binormalIndex);
- Vector3 binormal = sceneMapping->ConvertNormalFromFbx(src_binormal);
- if (isnan(binormal.X) || isnan(binormal.Y) || isnan(binormal.Z) || binormal.Length() < FLT_EPSILON)
- {
- *tangentPointer = Vector4(tangent.X, tangent.Y, tangent.Z, 1.0f);
- }
- else
- {
- // See GenerateTangentBinormal()
- *tangentPointer = Vector4(tangent.X, tangent.Y, tangent.Z, Vector3::Dot(Vector3::Cross(normal, tangent), binormal) < 0.0f ? -1.0f : 1.0f);
- }
- }
- }
-
- // BLENDINDICES and BLENDWEIGHT
- if (!controlPointWeights.empty())
- {
- const auto& blendWeights = controlPointWeights[controlPointIndex];
- for (int i = 0; i < 4; ++i)
- {
- if (controlPointIndices16)
- {
- if (AllowUnsignedBlendIndices)
- ((unsigned short*)(vbPointer + blendIndicesOffset))[i] = (unsigned short)blendWeights[i].first;
- else
- ((short*)(vbPointer + blendIndicesOffset))[i] = (short)blendWeights[i].first;
- }
- else
- {
- if (AllowUnsignedBlendIndices)
- ((unsigned char*)(vbPointer + blendIndicesOffset))[i] = (unsigned char)blendWeights[i].first;
- else
- ((char*)(vbPointer + blendIndicesOffset))[i] = (char)blendWeights[i].first;
- }
- ((float*)(vbPointer + blendWeightOffset))[i] = blendWeights[i].second;
- }
- }
-
- // COLOR
- for (int elementColorIndex = 0; elementColorIndex < elementVertexColorCount; elementColorIndex++)
- {
- auto vertexColorElement = vertexColorElements[elementColorIndex];
- auto groupIndex = GetGroupIndexForLayerElementTemplate(vertexColorElement, controlPointIndex, vertexIndex, edgeIndex, i, meshName, layerIndexFirstTimeError);
- auto color = vertexColorElement->GetDirectArray().GetAt(groupIndex);
- ((Color*)(vbPointer + colorOffset))[elementColorIndex] = Color((float)color.mRed, (float)color.mGreen, (float)color.mBlue, (float)color.mAlpha);
- }
-
- // USERDATA
- // TODO HANDLE USERDATA HERE
-
- // SMOOTHINGGROUP
- if (smoothingElement != NULL)
- {
- auto groupIndex = GetGroupIndexForLayerElementTemplate(smoothingElement, controlPointIndex, vertexIndex, edgeIndex, i, meshName, layerIndexFirstTimeError);
- auto group = smoothingElement->GetDirectArray().GetAt(groupIndex);
- ((int*)(vbPointer + smoothingOffset))[0] = (int)group;
- }
-
- vbPointer += vertexStride;
- }
- }
-
- polygonVertexStartIndex += polygonSize;
- }
-
- if (needEdgeIndexing)
- pMesh->EndGetMeshEdgeIndexForPolygon();
-
- // Create submeshes
- for (int i = 0; i < buildMeshes->Count; ++i)
- {
- auto buildMesh = buildMeshes[i];
- if (buildMesh == nullptr)
- continue;
-
- auto buffer = buildMesh->buffer;
- auto vertexBufferBinding = VertexBufferBinding(GraphicsSerializerExtensions::ToSerializableVersion(gcnew BufferData(BufferFlags::VertexBuffer, buffer)), gcnew VertexDeclaration(vertexElements->ToArray()), buildMesh->polygonCount * 3, 0, 0);
-
- auto drawData = gcnew MeshDraw();
- auto vbb = gcnew List();
- vbb->Add(vertexBufferBinding);
- drawData->VertexBuffers = vbb->ToArray();
- drawData->PrimitiveType = PrimitiveType::TriangleList;
- drawData->DrawCount = buildMesh->polygonCount * 3;
-
- // build the final VertexDeclaration removing the declaration element needed only for the buffer's correct construction
- auto finalVertexElements = gcnew List();
- for each (VertexElement element in vertexElements)
- {
- if (element.SemanticName != "SMOOTHINGGROUP")
- finalVertexElements->Add(element);
- }
- auto finalDeclaration = gcnew VertexDeclaration(finalVertexElements->ToArray());
-
- // Generate index buffer
- // For now, if user requests 16 bits indices but it doesn't fit, it
- // won't generate an index buffer, but ideally it should just split it in multiple render calls
- IndexExtensions::GenerateIndexBuffer(drawData, finalDeclaration);
- /*if (drawData->DrawCount < 65536)
- {
- IndexExtensions::GenerateIndexBuffer(drawData);
- }
- else
- {
- logger->Warning("The index buffer could not be generated with --force-compact-indices because it would use more than 16 bits per index.", nullptr, CallerInfo::Get(__FILEW__, __FUNCTIONW__, __LINE__));
- }*/
-
- auto lMaterial = pMesh->GetNode()->GetMaterial(i);
-
- // Generate TNB
- if (tangentElement == NULL && normalElement != NULL && uvElements.size() > 0)
- TNBExtensions::GenerateTangentBinormal(drawData);
-
- auto meshData = gcnew Mesh();
- meshData->NodeIndex = sceneMapping->FindNodeIndex(pMesh->GetNode());
- meshData->Draw = drawData;
- if (!controlPointWeights.empty())
- {
- meshData->Skinning = gcnew MeshSkinningDefinition();
- meshData->Skinning->Bones = bones->ToArray();
- }
-
- auto materialIndex = materials.find(lMaterial);
- meshData->MaterialIndex = (materialIndex != materials.end()) ? materialIndex->second : 0;
-
- auto meshName = meshNames[pMesh];
- if (buildMeshes->Count > 1)
- meshName = meshName + "_" + std::to_string(i + 1);
- meshData->Name = gcnew String(meshName.c_str());
-
- if (hasSkinningPosition || hasSkinningNormal || totalClusterCount > 0)
- {
- if (hasSkinningPosition)
- meshData->Parameters->Set(MaterialKeys::HasSkinningPosition, true);
- if (hasSkinningNormal)
- meshData->Parameters->Set(MaterialKeys::HasSkinningNormal, true);
- }
- modelData->Meshes->Add(meshData);
- }
- }
-
- // return a boolean indicating whether the built material is transparent or not
- MaterialAsset^ ProcessMeshMaterialAsset(FbxSurfaceMaterial* lMaterial, std::map& uvElementMapping)
- {
- auto uvEltMappingOverride = uvElementMapping;
- auto textureMap = gcnew Dictionary();
- std::map textureNameCount;
-
- auto finalMaterial = gcnew Stride::Assets::Materials::MaterialAsset();
-
- auto phongSurface = FbxCast(lMaterial);
- auto lambertSurface = FbxCast(lMaterial);
-
- { // The diffuse color
- auto diffuseTree = (IComputeColor^)GenerateSurfaceTextureTree(lMaterial, uvEltMappingOverride, textureMap, textureNameCount, FbxSurfaceMaterial::sDiffuse, FbxSurfaceMaterial::sDiffuseFactor, finalMaterial);
- if(lambertSurface || diffuseTree != nullptr)
- {
- if(diffuseTree == nullptr)
- {
- auto diffuseColor = lambertSurface->Diffuse.Get();
- auto diffuseFactor = lambertSurface->DiffuseFactor.Get();
- auto diffuseColorValue = diffuseFactor * diffuseColor;
-
- // Create diffuse value even if the color is black
- diffuseTree = gcnew ComputeColor(FbxDouble3ToColor4(diffuseColorValue));
- }
-
- if (diffuseTree != nullptr)
- {
- finalMaterial->Attributes->Diffuse = gcnew MaterialDiffuseMapFeature(diffuseTree);
- finalMaterial->Attributes->DiffuseModel = gcnew MaterialDiffuseLambertModelFeature();
- }
- }
- }
- { // The emissive color
- auto emissiveTree = (IComputeColor^)GenerateSurfaceTextureTree(lMaterial, uvEltMappingOverride, textureMap, textureNameCount, FbxSurfaceMaterial::sEmissive, FbxSurfaceMaterial::sEmissiveFactor, finalMaterial);
- if(lambertSurface || emissiveTree != nullptr)
- {
- if(emissiveTree == nullptr)
- {
- auto emissiveColor = lambertSurface->Emissive.Get();
- auto emissiveFactor = lambertSurface->EmissiveFactor.Get();
- auto emissiveColorValue = emissiveFactor * emissiveColor;
-
- // Do not create the node if the value has not been explicitly specified by the user.
- if(emissiveColorValue != FbxDouble3(0))
- {
- emissiveTree = gcnew ComputeColor(FbxDouble3ToColor4(emissiveColorValue));
- }
- }
-
- if (emissiveTree != nullptr)
- {
- finalMaterial->Attributes->Emissive = gcnew MaterialEmissiveMapFeature(emissiveTree);
- }
- }
- }
- // TODO: Check if we want to support Ambient Color
- //{ // The ambient color
- // auto ambientTree = GenerateSurfaceTextureTree(lMaterial, uvEltMappingOverride, textureMap, textureNameCount, FbxSurfaceMaterial::sAmbient, FbxSurfaceMaterial::sAmbientFactor, finalMaterial);
- // if(lambertSurface || ambientTree != nullptr)
- // {
- // if(ambientTree == nullptr)
- // {
- // auto ambientColor = lambertSurface->Emissive.Get();
- // auto ambientFactor = lambertSurface->EmissiveFactor.Get();
- // auto ambientColorValue = ambientFactor * ambientColor;
-
- // // Do not create the node if the value has not been explicitly specified by the user.
- // if(ambientColorValue != FbxDouble3(0))
- // {
- // ambientTree = gcnew ComputeColor(FbxDouble3ToColor4(ambientColorValue));
- // }
- // }
-
- // if(ambientTree != nullptr)
- // finalMaterial->AddColorNode(MaterialParameters::AmbientMap, "ambient", ambientTree);
- // }
- //}
- { // The normal map
- auto normalMapTree = (IComputeColor^)GenerateSurfaceTextureTree(lMaterial, uvEltMappingOverride, textureMap, textureNameCount, FbxSurfaceMaterial::sNormalMap, NULL, finalMaterial);
- if(lambertSurface || normalMapTree != nullptr)
- {
- if(normalMapTree == nullptr)
- {
- auto normalMapValue = lambertSurface->NormalMap.Get();
-
- // Do not create the node if the value has not been explicitly specified by the user.
- if(normalMapValue != FbxDouble3(0))
- {
- normalMapTree = gcnew ComputeFloat4(FbxDouble3ToVector4(normalMapValue));
- }
- }
-
- if (normalMapTree != nullptr)
- {
- finalMaterial->Attributes->Surface = gcnew MaterialNormalMapFeature(normalMapTree);
- }
- }
- }
- // TODO: Support for BumpMap
- //{ // The bump map
- // auto bumpMapTree = GenerateSurfaceTextureTree(lMaterial, uvEltMappingOverride, textureMap, textureNameCount, FbxSurfaceMaterial::sBump, FbxSurfaceMaterial::sBumpFactor, finalMaterial);
- // if(lambertSurface || bumpMapTree != nullptr)
- // {
- // if(bumpMapTree == nullptr)
- // {
- // auto bumpValue = lambertSurface->Bump.Get();
- // auto bumpFactor = lambertSurface->BumpFactor.Get();
- // auto bumpMapValue = bumpFactor * bumpValue;
-
- // // Do not create the node if the value has not been explicitly specified by the user.
- // if(bumpMapValue != FbxDouble3(0))
- // {
- // bumpMapTree = gcnew MaterialFloat4ComputeColor(FbxDouble3ToVector4(bumpMapValue));
- // }
- // }
- //
- // if (bumpMapTree != nullptr)
- // {
- // finalMaterial->AddColorNode(MaterialParameters::BumpMap, "bumpMap", bumpMapTree);
- // }
- // }
- //}
- // TODO: Support for Transparency
- //{ // The transparency
- // auto transparencyTree = GenerateSurfaceTextureTree(lMaterial, uvEltMappingOverride, textureMap, textureNameCount, FbxSurfaceMaterial::sTransparentColor, FbxSurfaceMaterial::sTransparencyFactor, finalMaterial);
- // if(lambertSurface || transparencyTree != nullptr)
- // {
- // if(transparencyTree == nullptr)
- // {
- // auto transparencyColor = lambertSurface->TransparentColor.Get();
- // auto transparencyFactor = lambertSurface->TransparencyFactor.Get();
- // auto transparencyValue = transparencyFactor * transparencyColor;
- // auto opacityValue = std::min(1.0f, std::max(0.0f, 1-(float)transparencyValue[0]));
-
- // // Do not create the node if the value has not been explicitly specified by the user.
- // if(opacityValue < 1)
- // {
- // transparencyTree = gcnew MaterialFloatComputeColor(opacityValue);
- // }
- // }
-
- // if(transparencyTree != nullptr)
- // finalMaterial->AddColorNode(MaterialParameters::TransparencyMap, "transparencyMap", transparencyTree);
- // }
- //}
- //// TODO: Support for displacement map
- //{ // The displacement map
- // auto displacementColorTree = GenerateSurfaceTextureTree(lMaterial, uvEltMappingOverride, textureMap, textureNameCount, FbxSurfaceMaterial::sDisplacementColor, FbxSurfaceMaterial::sDisplacementFactor, finalMaterial);
- // if(lambertSurface || displacementColorTree != nullptr)
- // {
- // if(displacementColorTree == nullptr)
- // {
- // auto displacementColor = lambertSurface->DisplacementColor.Get();
- // auto displacementFactor = lambertSurface->DisplacementFactor.Get();
- // auto displacementValue = displacementFactor * displacementColor;
-
- // // Do not create the node if the value has not been explicitly specified by the user.
- // if(displacementValue != FbxDouble3(0))
- // {
- // displacementColorTree = gcnew MaterialFloat4ComputeColor(FbxDouble3ToVector4(displacementValue));
- // }
- // }
- //
- // if(displacementColorTree != nullptr)
- // finalMaterial->AddColorNode(MaterialParameters::DisplacementMap, "displacementMap", displacementColorTree);
- // }
- //}
- { // The specular color
- auto specularTree = (IComputeColor^)GenerateSurfaceTextureTree(lMaterial, uvEltMappingOverride, textureMap, textureNameCount, FbxSurfaceMaterial::sSpecular, NULL, finalMaterial);
- if(phongSurface || specularTree != nullptr)
- {
- if(specularTree == nullptr)
- {
- auto specularColor = phongSurface->Specular.Get();
-
- // Do not create the node if the value has not been explicitly specified by the user.
- if(specularColor != FbxDouble3(0))
- {
- specularTree = gcnew ComputeColor(FbxDouble3ToColor4(specularColor));
- }
- }
-
- if (specularTree != nullptr)
- {
- auto specularFeature = gcnew MaterialSpecularMapFeature();
- specularFeature->SpecularMap = specularTree;
- finalMaterial->Attributes->Specular = specularFeature;
-
- auto specularModel = gcnew MaterialSpecularMicrofacetModelFeature();
- specularModel->Fresnel = gcnew MaterialSpecularMicrofacetFresnelSchlick();
- specularModel->Visibility = gcnew MaterialSpecularMicrofacetVisibilityImplicit();
- specularModel->NormalDistribution = gcnew MaterialSpecularMicrofacetNormalDistributionBlinnPhong();
-
- finalMaterial->Attributes->SpecularModel = specularModel;
- }
- }
- }
- // TODO REPLUG SPECULAR INTENSITY
- //{ // The specular intensity map
- // auto specularIntensityTree = (IComputeColor^)GenerateSurfaceTextureTree(lMaterial, uvEltMappingOverride, textureMap, textureNameCount, FbxSurfaceMaterial::sSpecularFactor, NULL, finalMaterial);
- // if(phongSurface || specularIntensityTree != nullptr)
- // {
- // if(specularIntensityTree == nullptr)
- // {
- // auto specularIntensity = phongSurface->SpecularFactor.Get();
- //
- // // Do not create the node if the value has not been explicitly specified by the user.
- // if(specularIntensity > 0)
- // {
- // specularIntensityTree = gcnew MaterialFloatComputeNode((float)specularIntensity);
- // }
- // }
- //
- // if (specularIntensityTree != nullptr)
- // {
- // MaterialSpecularMapFeature^ specularFeature;
- // if (finalMaterial->Attributes->Specular == nullptr || finalMaterial->Attributes->Specular->GetType() != MaterialSpecularMapFeature::typeid)
- // {
- // specularFeature = gcnew MaterialSpecularMapFeature();
- // }
- // else
- // {
- // specularFeature = (MaterialSpecularMapFeature^)finalMaterial->Attributes->Specular;
- // }
- // // TODO: Check Specular Intensity and Power
- // specularFeature->Intensity = specularIntensityTree;
- // finalMaterial->Attributes->Specular = specularFeature;
- // }
- // }
- // }
- /* { // The specular power map
- auto specularPowerTree = GenerateSurfaceTextureTree(lMaterial, uvEltMappingOverride, textureMap, textureNameCount, FbxSurfaceMaterial::sShininess, NULL, finalMaterial);
- if(phongSurface || specularPowerTree != nullptr)
- {
- if(specularPowerTree == nullptr)
- {
- auto specularPower = phongSurface->Shininess.Get();
-
- // Do not create the node if the value has not been explicitly specified by the user.
- if(specularPower > 0)
- {
- specularPowerTree = gcnew MaterialFloatComputeColor((float)specularPower);
- }
- }
-
- if (specularPowerTree != nullptr)
- {
- MaterialSpecularMapFeature^ specularFeature;
- if (finalMaterial->Attributes->Specular == nullptr || finalMaterial->Attributes->Specular->GetType() != MaterialSpecularMapFeature::typeid)
- {
- specularFeature = gcnew MaterialSpecularMapFeature();
- }
- else
- {
- specularFeature = (MaterialSpecularMapFeature^)finalMaterial->Attributes->Specular;
- }
- // TODO: Check Specular Intensity and Power
- specularFeature->Intensity = specularPowerTree;
- finalMaterial->Attributes->Specular = specularFeature;
- }
- }
- }*/
- //// TODO: Support for reflection map
- //{ // The reflection map
- // auto reflectionMapTree = GenerateSurfaceTextureTree(lMaterial, uvEltMappingOverride, textureMap, textureNameCount, FbxSurfaceMaterial::sReflection, FbxSurfaceMaterial::sReflectionFactor, finalMaterial);
- // if(phongSurface || reflectionMapTree != nullptr)
- // {
- // if(reflectionMapTree == nullptr)
- // {
- // auto reflectionColor = lambertSurface->DisplacementColor.Get();
- // auto reflectionFactor = lambertSurface->DisplacementFactor.Get();
- // auto reflectionValue = reflectionFactor * reflectionColor;
-
- // // Do not create the node if the value has not been explicitly specified by the user.
- // if(reflectionValue != FbxDouble3(0))
- // {
- // reflectionMapTree = gcnew ComputeColor(FbxDouble3ToColor4(reflectionValue));
- // }
- // }
- //
- // if(reflectionMapTree != nullptr)
- // finalMaterial->AddColorNode(MaterialParameters::ReflectionMap, "reflectionMap", reflectionMapTree);
- // }
- //}
- return finalMaterial;
- }
-
- bool IsTransparent(FbxSurfaceMaterial* lMaterial)
- {
- for (int i = 0; i < 2; ++i)
- {
- auto propertyName = i == 0 ? FbxSurfaceMaterial::sTransparentColor : FbxSurfaceMaterial::sTransparencyFactor;
- if (propertyName == NULL)
- continue;
-
- FbxProperty lProperty = lMaterial->FindProperty(propertyName);
- if (lProperty.IsValid())
- {
- const int lTextureCount = lProperty.GetSrcObjectCount();
- for (int j = 0; j < lTextureCount; ++j)
- {
- FbxLayeredTexture *lLayeredTexture = FbxCast(lProperty.GetSrcObject(j));
- FbxFileTexture *lFileTexture = FbxCast(lProperty.GetSrcObject(j));
- if (lLayeredTexture)
- {
- int lNbTextures = lLayeredTexture->GetSrcObjectCount();
- if (lNbTextures > 0)
- return true;
- }
- else if (lFileTexture)
- return true;
- }
- if (lTextureCount == 0)
- {
- auto val = FbxDouble3ToVector3(lProperty.Get());
- if (val == Vector3::Zero || val != Vector3::One)
- return true;
- }
- }
- }
- return false;
- }
-
- IComputeNode^ GenerateSurfaceTextureTree(FbxSurfaceMaterial* lMaterial, std::map& uvElementMapping, Dictionary^ textureMap,
- std::map& textureNameCount, char const* surfaceMaterial, char const* surfaceMaterialFactor,
- Stride::Assets::Materials::MaterialAsset^ finalMaterial)
- {
- auto compositionTrees = gcnew cli::array(2);
-
- for (int i = 0; i < 2; ++i)
- {
- // Scan first for component name, then its factor (i.e. sDiffuse, then sDiffuseFactor)
- auto propertyName = i == 0 ? surfaceMaterial : surfaceMaterialFactor;
- if (propertyName == NULL)
- continue;
-
- int compositionCount = 0;
-
- FbxProperty lProperty = lMaterial->FindProperty(propertyName);
- if (lProperty.IsValid())
- {
- IComputeColor^ previousNode = nullptr;
- const int lTextureCount = lProperty.GetSrcObjectCount();
- for (int j = 0; j < lTextureCount; ++j)
- {
- FbxLayeredTexture *lLayeredTexture = FbxCast(lProperty.GetSrcObject(j));
- FbxFileTexture *lFileTexture = FbxCast(lProperty.GetSrcObject(j));
- if (lLayeredTexture)
- {
- int lNbTextures = lLayeredTexture->GetSrcObjectCount();
- for (int k = 0; k < lNbTextures; ++k)
- {
- FbxFileTexture* lSubTexture = FbxCast(lLayeredTexture->GetSrcObject(k));
-
- auto uvName = std::string(lSubTexture->UVSet.Get());
- if (uvElementMapping.find(uvName) == uvElementMapping.end())
- uvElementMapping[uvName] = uvElementMapping.size();
-
- auto currentMaterialReference = GenerateMaterialTextureNodeFBX(lSubTexture, uvElementMapping, textureMap, textureNameCount, finalMaterial);
-
- if (lNbTextures == 1 || compositionCount == 0)
- {
- if (previousNode == nullptr)
- previousNode = currentMaterialReference;
- else
- previousNode = gcnew ComputeBinaryColor(previousNode, currentMaterialReference, BinaryOperator::Add); // not sure
- }
- else
- {
- auto newNode = gcnew ComputeBinaryColor(previousNode, currentMaterialReference, BinaryOperator::Add);
- previousNode = newNode;
-
- FbxLayeredTexture::EBlendMode blendMode;
- lLayeredTexture->GetTextureBlendMode(k, blendMode);
- newNode->Operator = BlendModeToBlendOperand(blendMode);
- }
-
- compositionCount++;
- }
- }
- else if (lFileTexture)
- {
- compositionCount++;
-
- auto newMaterialReference = GenerateMaterialTextureNodeFBX(lFileTexture, uvElementMapping, textureMap, textureNameCount, finalMaterial);
-
- if (previousNode == nullptr)
- previousNode = newMaterialReference;
- else
- previousNode = gcnew ComputeBinaryColor(previousNode, newMaterialReference, BinaryOperator::Add); // not sure
- }
- }
-
- compositionTrees[i] = previousNode;
- }
- }
-
- // If we only have one of either Color or Factor, use directly, otherwise multiply them together
- IComputeColor^ compositionTree;
- if (compositionTrees[0] == nullptr) // TODO do we want only the factor??? -> delete
- {
- compositionTree = compositionTrees[1];
- }
- else if (compositionTrees[1] == nullptr)
- {
- compositionTree = compositionTrees[0];
- }
- else
- {
- compositionTree = gcnew ComputeBinaryColor(compositionTrees[0], compositionTrees[1], BinaryOperator::Multiply);
- }
-
- return compositionTree;
- }
-
- BinaryOperator BlendModeToBlendOperand(FbxLayeredTexture::EBlendMode blendMode)
- {
- switch (blendMode)
- {
- case FbxLayeredTexture::eOver:
- return BinaryOperator::Over;
- case FbxLayeredTexture::eAdditive:
- return BinaryOperator::Add;
- case FbxLayeredTexture::eModulate:
- return BinaryOperator::Multiply;
- //case FbxLayeredTexture::eTranslucent:
- // return BinaryOperator::Multiply;
- //case FbxLayeredTexture::eModulate2:
- // return BinaryOperator::Multiply;
- //case FbxLayeredTexture::eNormal:
- // return BinaryOperator::Multiply;
- //case FbxLayeredTexture::eDissolve:
- // return BinaryOperator::Multiply;
- case FbxLayeredTexture::eDarken:
- return BinaryOperator::Darken;
- case FbxLayeredTexture::eColorBurn:
- return BinaryOperator::ColorBurn;
- case FbxLayeredTexture::eLinearBurn:
- return BinaryOperator::LinearBurn;
- //case FbxLayeredTexture::eDarkerColor:
- // return BinaryOperator::Multiply;
- case FbxLayeredTexture::eLighten:
- return BinaryOperator::Lighten;
- case FbxLayeredTexture::eScreen:
- return BinaryOperator::Screen;
- case FbxLayeredTexture::eColorDodge:
- return BinaryOperator::ColorDodge;
- case FbxLayeredTexture::eLinearDodge:
- return BinaryOperator::LinearDodge;
- //case FbxLayeredTexture::eLighterColor:
- // return BinaryOperator::Multiply;
- case FbxLayeredTexture::eSoftLight:
- return BinaryOperator::SoftLight;
- case FbxLayeredTexture::eHardLight:
- return BinaryOperator::HardLight;
- //case FbxLayeredTexture::eVividLight:
- // return BinaryOperator::Multiply;
- //case FbxLayeredTexture::eLinearLight:
- // return BinaryOperator::Multiply;
- case FbxLayeredTexture::ePinLight:
- return BinaryOperator::PinLight;
- case FbxLayeredTexture::eHardMix:
- return BinaryOperator::HardMix;
- case FbxLayeredTexture::eDifference:
- return BinaryOperator::Difference;
- case FbxLayeredTexture::eExclusion:
- return BinaryOperator::Exclusion;
- case FbxLayeredTexture::eSubtract:
- return BinaryOperator::Subtract;
- case FbxLayeredTexture::eDivide:
- return BinaryOperator::Divide;
- case FbxLayeredTexture::eHue:
- return BinaryOperator::Hue;
- case FbxLayeredTexture::eSaturation:
- return BinaryOperator::Saturation;
- //case FbxLayeredTexture::eColor:
- // return BinaryOperator::Multiply;
- //case FbxLayeredTexture::eLuminosity:
- // return BinaryOperator::Multiply;
- case FbxLayeredTexture::eOverlay:
- return BinaryOperator::Overlay;
- default:
- logger->Error(String::Format("Material blending mode '{0}' is not supported yet. Multiplying blending mode will be used instead.", gcnew Int32(blendMode)), (CallerInfo^)nullptr);
- return BinaryOperator::Multiply;
- }
- }
-
- ShaderClassSource^ GenerateTextureLayerFBX(FbxFileTexture* lFileTexture, std::map& uvElementMapping, Mesh^ meshData, int& textureCount, ParameterKey^ surfaceMaterialKey)
- {
- auto texScale = lFileTexture->GetUVScaling();
- auto texturePath = FindFilePath(lFileTexture);
-
- return TextureLayerGenerator::GenerateTextureLayer(vfsOutputFilename, texturePath, uvElementMapping[std::string(lFileTexture->UVSet.Get())], Vector2((float)texScale[0], (float)texScale[1]) ,
- textureCount, surfaceMaterialKey,
- meshData,
- nullptr);
- }
-
- String^ FindFilePath(FbxFileTexture* lFileTexture)
- {
- auto relFileName = gcnew String(lFileTexture->GetRelativeFileName());
- auto absFileName = gcnew String(lFileTexture->GetFileName());
-
- // First try to get the texture filename by relative path, if not valid then use absolute path
- // (According to FBX doc, resolved first by absolute name, and relative name if absolute name is not valid)
- auto fileNameToUse = Path::Combine(inputPath, relFileName);
- if(fileNameToUse->StartsWith("\\\\", StringComparison::Ordinal))
- {
- logger->Warning(String::Format("Importer detected a network address in referenced assets. This may temporary block the build if the file does not exist. [Address='{0}']", fileNameToUse), (CallerInfo^)nullptr);
- }
- if (!File::Exists(fileNameToUse) && !String::IsNullOrEmpty(absFileName))
- {
- fileNameToUse = absFileName;
- }
-
- // Make sure path is absolute
- if (!(gcnew UFile(fileNameToUse))->IsAbsolute)
- {
- fileNameToUse = Path::Combine(inputPath, fileNameToUse);
- }
-
- return fileNameToUse;
- }
-
- ComputeTextureColor^ GenerateMaterialTextureNodeFBX(FbxFileTexture* lFileTexture, std::map& uvElementMapping, Dictionary^ textureMap, std::map& textureNameCount, Stride::Assets::Materials::MaterialAsset^ finalMaterial)
- {
- auto texScale = lFileTexture->GetUVScaling();
- auto texturePath = FindFilePath(lFileTexture);
- auto wrapModeU = lFileTexture->GetWrapModeU();
- auto wrapModeV = lFileTexture->GetWrapModeV();
- auto wrapTextureU = (wrapModeU == FbxTexture::EWrapMode::eRepeat) ? TextureAddressMode::Wrap : TextureAddressMode::Clamp;
- auto wrapTextureV = (wrapModeV == FbxTexture::EWrapMode::eRepeat) ? TextureAddressMode::Wrap : TextureAddressMode::Clamp;
-
- ComputeTextureColor^ textureValue;
-
- if (textureMap->TryGetValue(IntPtr(lFileTexture), textureValue))
- {
- return textureValue;
- }
- else
- {
- textureValue = TextureLayerGenerator::GenerateMaterialTextureNode(vfsOutputFilename, texturePath, uvElementMapping[std::string(lFileTexture->UVSet.Get())], Vector2((float)texScale[0], (float)texScale[1]), wrapTextureU, wrapTextureV, nullptr);
-
- auto attachedReference = AttachedReferenceManager::GetAttachedReference(textureValue->Texture);
-
- auto textureNamePtr = Marshal::StringToHGlobalAnsi(attachedReference->Url);
- std::string textureName = std::string((char*)textureNamePtr.ToPointer());
- Marshal:: FreeHGlobal(textureNamePtr);
-
- auto textureCount = GetTextureNameCount(textureNameCount, textureName);
- if (textureCount > 1)
- textureName = textureName + "_" + std::to_string(textureCount - 1);
-
- auto referenceName = gcnew String(textureName.c_str());
- //auto materialReference = gcnew MaterialReferenceNode(referenceName);
- //finalMaterial->AddNode(referenceName, textureValue);
- textureMap[IntPtr(lFileTexture)] = textureValue;
- return textureValue;
- }
-
- return nullptr;
- }
-
- int GetTextureNameCount(std::map& textureNameCount, std::string textureName)
- {
- auto textureFound = textureNameCount.find(textureName);
- if (textureFound == textureNameCount.end())
- textureNameCount[textureName] = 1;
- else
- textureNameCount[textureName] = textureNameCount[textureName] + 1;
- return textureNameCount[textureName];
- }
-
- void ProcessAttribute(FbxNode* pNode, FbxNodeAttribute* pAttribute, std::map meshNames, std::map materials)
- {
- if(!pAttribute) return;
-
- if (pAttribute->GetAttributeType() == FbxNodeAttribute::eMesh)
- {
- ProcessMesh((FbxMesh*)pAttribute, meshNames, materials);
- }
- }
-
- void ProcessNodeTransformation(FbxNode* pNode)
- {
- auto nodeIndex = sceneMapping->FindNodeIndex(pNode);
- auto nodes = sceneMapping->Nodes;
- auto node = &nodes[nodeIndex];
-
- // Use GlobalTransform instead of LocalTransform
-
- auto fbxMatrix = pNode->EvaluateLocalTransform(FBXSDK_TIME_ZERO);
- auto matrix = sceneMapping->ConvertMatrixFromFbx(fbxMatrix);
-
- // Extract the translation and scaling
- Vector3 translation;
- Quaternion rotation;
- Vector3 scaling;
- matrix.Decompose(scaling, rotation, translation);
-
- // Apply rotation on top level nodes only
- if (node->ParentIndex == 0)
- {
- Vector3::TransformCoordinate(translation, sceneMapping->AxisSystemRotationMatrix, translation);
- rotation = Quaternion::Multiply(rotation, Quaternion::RotationMatrix(sceneMapping->AxisSystemRotationMatrix));
- }
-
- // Setup the transform for this node
- node->Transform.Position = translation;
- node->Transform.Rotation = rotation;
- node->Transform.Scale = scaling;
-
- // Recursively process the children nodes.
- for (int j = 0; j < pNode->GetChildCount(); j++)
- {
- ProcessNodeTransformation(pNode->GetChild(j));
- }
- }
-
- void ProcessNodeAttributes(FbxNode* pNode, std::map meshNames, std::map materials)
- {
- // Process the node's attributes.
- for(int i = 0; i < pNode->GetNodeAttributeCount(); i++)
- ProcessAttribute(pNode, pNode->GetNodeAttributeByIndex(i), meshNames, materials);
-
- // Recursively process the children nodes.
- for(int j = 0; j < pNode->GetChildCount(); j++)
- {
- ProcessNodeAttributes(pNode->GetChild(j), meshNames, materials);
- }
- }
-
- ref class BuildMesh
- {
- public:
- array^ buffer;
- int bufferOffset;
- int polygonCount;
- };
-
- ref struct ImportConfiguration
- {
- public:
- property bool ImportTemplates;
- property bool ImportPivots;
- property bool ImportGlobalSettings;
- property bool ImportCharacters;
- property bool ImportConstraints;
- property bool ImportGobos;
- property bool ImportShapes;
- property bool ImportLinks;
- property bool ImportMaterials;
- property bool ImportTextures;
- property bool ImportModels;
- property bool ImportAnimations;
- property bool ExtractEmbeddedData;
-
- public:
- static ImportConfiguration^ ImportAll()
- {
- auto config = gcnew ImportConfiguration();
-
- config->ImportTemplates = true;
- config->ImportPivots = true;
- config->ImportGlobalSettings = true;
- config->ImportCharacters = true;
- config->ImportConstraints = true;
- config->ImportGobos = true;
- config->ImportShapes = true;
- config->ImportLinks = true;
- config->ImportMaterials = true;
- config->ImportTextures = true;
- config->ImportModels = true;
- config->ImportAnimations = true;
- config->ExtractEmbeddedData = true;
-
- return config;
- }
-
- static ImportConfiguration^ ImportModelOnly()
- {
- auto config = gcnew ImportConfiguration();
-
- config->ImportTemplates = false;
- config->ImportPivots = false;
- config->ImportGlobalSettings = true;
- config->ImportCharacters = false;
- config->ImportConstraints = false;
- config->ImportGobos = false;
- config->ImportShapes = false;
- config->ImportLinks = false;
- config->ImportMaterials = true;
- config->ImportTextures = false;
- config->ImportModels = true;
- config->ImportAnimations = false;
- config->ExtractEmbeddedData = false;
-
- return config;
- }
-
- static ImportConfiguration^ ImportMaterialsOnly()
- {
- auto config = gcnew ImportConfiguration();
-
- config->ImportTemplates = false;
- config->ImportPivots = false;
- config->ImportGlobalSettings = true;
- config->ImportCharacters = false;
- config->ImportConstraints = false;
- config->ImportGobos = false;
- config->ImportShapes = false;
- config->ImportLinks = false;
- config->ImportMaterials = true;
- config->ImportTextures = false;
- config->ImportModels = false;
- config->ImportAnimations = false;
- config->ExtractEmbeddedData = false;
-
- return config;
- }
-
- static ImportConfiguration^ ImportAnimationsOnly()
- {
- auto config = gcnew ImportConfiguration();
-
- config->ImportTemplates = false;
- config->ImportPivots = false;
- config->ImportGlobalSettings = true;
- config->ImportCharacters = false;
- config->ImportConstraints = false;
- config->ImportGobos = false;
- config->ImportShapes = false;
- config->ImportLinks = false;
- config->ImportMaterials = false;
- config->ImportTextures = false;
- config->ImportModels = false;
- config->ImportAnimations = true;
- config->ExtractEmbeddedData = false;
-
- return config;
- }
-
- static ImportConfiguration^ ImportSkeletonOnly()
- {
- auto config = gcnew ImportConfiguration();
-
- config->ImportTemplates = false;
- config->ImportPivots = false;
- config->ImportGlobalSettings = true;
- config->ImportCharacters = false;
- config->ImportConstraints = false;
- config->ImportGobos = false;
- config->ImportShapes = false;
- config->ImportLinks = false;
- config->ImportMaterials = false;
- config->ImportTextures = false;
- config->ImportModels = false;
- config->ImportAnimations = false;
- config->ExtractEmbeddedData = false;
-
- return config;
- }
-
- static ImportConfiguration^ ImportTexturesOnly()
- {
- auto config = gcnew ImportConfiguration();
-
- config->ImportTemplates = false;
- config->ImportPivots = false;
- config->ImportGlobalSettings = false;
- config->ImportCharacters = false;
- config->ImportConstraints = false;
- config->ImportGobos = false;
- config->ImportShapes = false;
- config->ImportLinks = false;
- config->ImportMaterials = false;
- config->ImportTextures = true;
- config->ImportModels = false;
- config->ImportAnimations = false;
- config->ExtractEmbeddedData = true;
-
- return config;
- }
-
- static ImportConfiguration^ ImportEntityConfig()
- {
- auto config = gcnew ImportConfiguration();
-
- config->ImportTemplates = false;
- config->ImportPivots = false;
- config->ImportGlobalSettings = true;
- config->ImportCharacters = false;
- config->ImportConstraints = false;
- config->ImportGobos = false;
- config->ImportShapes = false;
- config->ImportLinks = false;
- config->ImportMaterials = true;
- config->ImportTextures = true;
- config->ImportModels = true;
- config->ImportAnimations = true;
- config->ExtractEmbeddedData = true;
-
- return config;
- }
-
- static ImportConfiguration^ ImportGlobalSettingsOnly()
- {
- auto config = gcnew ImportConfiguration();
-
- config->ImportGlobalSettings = true;
-
- return config;
- }
- };
-
-private:
- static System::Object^ globalLock = gcnew System::Object();
-
- void Initialize(String^ inputFilename, String^ vfsOutputFilename, ImportConfiguration^ importConfig)
- {
- // -----------------------------------------------------
- // TODO: Workaround with FBX SDK not being multithreaded.
- // We protect the whole usage of this class with a monitor
- //
- // Lock the whole class between Initialize/Destroy
- // -----------------------------------------------------
- System::Threading::Monitor::Enter( globalLock );
- // -----------------------------------------------------
-
- this->inputFilename = inputFilename;
- this->vfsOutputFilename = vfsOutputFilename;
- this->inputPath = Path::GetDirectoryName(inputFilename);
-
- // Initialize the sdk manager. This object handles all our memory management.
- lSdkManager = FbxManager::Create();
-
- // Create the io settings object.
- FbxIOSettings *ios = FbxIOSettings::Create(lSdkManager, IOSROOT);
- ios->SetBoolProp(IMP_FBX_TEMPLATE, importConfig->ImportTemplates);
- ios->SetBoolProp(IMP_FBX_PIVOT, importConfig->ImportPivots);
- ios->SetBoolProp(IMP_FBX_GLOBAL_SETTINGS, importConfig->ImportGlobalSettings);
- ios->SetBoolProp(IMP_FBX_CHARACTER, importConfig->ImportCharacters);
- ios->SetBoolProp(IMP_FBX_CONSTRAINT, importConfig->ImportConstraints);
- ios->SetBoolProp(IMP_FBX_GOBO, importConfig->ImportGobos);
- ios->SetBoolProp(IMP_FBX_SHAPE, importConfig->ImportShapes);
- ios->SetBoolProp(IMP_FBX_LINK, importConfig->ImportLinks);
- ios->SetBoolProp(IMP_FBX_MATERIAL, importConfig->ImportMaterials);
- ios->SetBoolProp(IMP_FBX_TEXTURE, importConfig->ImportTextures);
- ios->SetBoolProp(IMP_FBX_MODEL, importConfig->ImportModels);
- ios->SetBoolProp(IMP_FBX_ANIMATION, importConfig->ImportAnimations);
- ios->SetBoolProp(IMP_FBX_EXTRACT_EMBEDDED_DATA, importConfig->ExtractEmbeddedData);
- lSdkManager->SetIOSettings(ios);
-
- // Create an importer using our sdk manager.
- lImporter = FbxImporter::Create(lSdkManager,"");
-
- auto inputFilenameUtf8 = System::Text::Encoding::UTF8->GetBytes(inputFilename);
- pin_ptr inputFilenameUtf8Ptr = &inputFilenameUtf8[0];
-
- if(!lImporter->Initialize((const char*)inputFilenameUtf8Ptr, -1, lSdkManager->GetIOSettings()))
- {
- throw gcnew InvalidOperationException(String::Format("Call to FbxImporter::Initialize() failed.\n"
- "Error returned: {0}\n\n", gcnew String(lImporter->GetStatus().GetErrorString())));
- }
-
- // Create a new scene so it can be populated by the imported file.
- scene = FbxScene::Create(lSdkManager, "myScene");
-
- // Import the contents of the file into the scene.
- lImporter->Import(scene);
-
- const float framerate = static_cast(FbxTime::GetFrameRate(scene->GetGlobalSettings().GetTimeMode()));
- scene->GetRootNode()->ResetPivotSetAndConvertAnimation(framerate, false, false);
-
- // Initialize the node mapping
- sceneMapping = gcnew SceneMapping(scene);
- }
-
- bool HasAnimationData(String^ inputFile)
- {
- try
- {
- Initialize(inputFile, nullptr, ImportConfiguration::ImportAnimationsOnly());
- auto animConverter = gcnew AnimationConverter(logger, sceneMapping);
- return animConverter->HasAnimationData();
- }
- finally
- {
- Destroy();
- }
- }
-
- void GenerateMaterialNames(std::map& materialNames)
- {
- auto materials = gcnew List();
- std::map materialNameTotalCount;
- std::map materialNameCurrentCount;
- std::map tempNames;
- auto materialCount = scene->GetMaterialCount();
-
- for (int i = 0; i < materialCount; i++)
- {
- auto lMaterial = scene->GetMaterial(i);
- auto materialName = std::string(lMaterial->GetName());
- auto materialPart = std::string();
-
- size_t materialNameSplitPosition = materialName.find('#');
- if (materialNameSplitPosition != std::string::npos)
- {
- materialPart = materialName.substr(materialNameSplitPosition + 1);
- materialName = materialName.substr(0, materialNameSplitPosition);
- }
-
- materialNameSplitPosition = materialName.find("__");
- if (materialNameSplitPosition != std::string::npos)
- {
- materialPart = materialName.substr(materialNameSplitPosition + 2);
- materialName = materialName.substr(0, materialNameSplitPosition);
- }
-
- // remove all bad characters
- ReplaceCharacter(materialName, ':', '_');
- ReplaceCharacter(materialName, '/', '_');
- RemoveCharacter(materialName, ' ');
- tempNames[lMaterial] = materialName;
-
- if (materialNameTotalCount.count(materialName) == 0)
- materialNameTotalCount[materialName] = 1;
- else
- materialNameTotalCount[materialName] = materialNameTotalCount[materialName] + 1;
- }
-
- for (int i = 0; i < materialCount; i++)
- {
- auto lMaterial = scene->GetMaterial(i);
- auto materialName = tempNames[lMaterial];
- int currentCount = 0;
-
- if (materialNameCurrentCount.count(materialName) == 0)
- materialNameCurrentCount[materialName] = 1;
- else
- materialNameCurrentCount[materialName] = materialNameCurrentCount[materialName] + 1;
-
- if(materialNameTotalCount[materialName] > 1)
- materialName = materialName + "_" + std::to_string(materialNameCurrentCount[materialName]);
-
- materialNames[lMaterial] = materialName;
- }
- }
-
- void GetMeshes(FbxNode* pNode, std::vector& meshes)
- {
- // Process the node's attributes.
- for(int i = 0; i < pNode->GetNodeAttributeCount(); i++)
- {
- auto pAttribute = pNode->GetNodeAttributeByIndex(i);
-
- if(!pAttribute) return;
-
- if (pAttribute->GetAttributeType() == FbxNodeAttribute::eMesh)
- {
- auto pMesh = (FbxMesh*)pAttribute;
- meshes.push_back(pMesh);
- }
- }
-
- // Recursively process the children nodes.
- for(int j = 0; j < pNode->GetChildCount(); j++)
- {
- GetMeshes(pNode->GetChild(j), meshes);
- }
- }
-
- void GenerateMeshesName(std::map& meshNames)
- {
- std::vector meshes;
- GetMeshes(scene->GetRootNode(), meshes);
-
- std::map meshNameTotalCount;
- std::map meshNameCurrentCount;
- std::map tempNames;
-
- for (auto iter = meshes.begin(); iter != meshes.end(); ++iter)
- {
- auto pMesh = *iter;
- auto meshName = std::string(pMesh->GetNode()->GetName());
-
- // remove all bad characters
- RemoveCharacter(meshName, ' ');
- tempNames[pMesh] = meshName;
-
- if (meshNameTotalCount.count(meshName) == 0)
- meshNameTotalCount[meshName] = 1;
- else
- meshNameTotalCount[meshName] = meshNameTotalCount[meshName] + 1;
- }
-
- for (auto iter = meshes.begin(); iter != meshes.end(); ++iter)
- {
- auto pMesh = *iter;
- auto meshName = tempNames[pMesh];
- int currentCount = 0;
-
- if (meshNameCurrentCount.count(meshName) == 0)
- meshNameCurrentCount[meshName] = 1;
- else
- meshNameCurrentCount[meshName] = meshNameCurrentCount[meshName] + 1;
-
- if(meshNameTotalCount[meshName] > 1)
- meshName = meshName + "_" + std::to_string(meshNameCurrentCount[meshName]);
-
- meshNames[pMesh] = meshName;
- }
- }
-
- MaterialInstantiation^ GetOrCreateMaterial(FbxSurfaceMaterial* lMaterial, List^ uvNames, List^ instances, std::map& uvElements, std::map& materialNames)
- {
- for (int i = 0; i < instances->Count; ++i)
- {
- if (lMaterial == instances[i]->SourceMaterial)
- return instances[i];
- }
-
- auto newMaterialInstantiation = gcnew MaterialInstantiation();
- newMaterialInstantiation->SourceMaterial = lMaterial;
- newMaterialInstantiation->MaterialName = gcnew String(materialNames[lMaterial].c_str());
-
- // TODO: We currently use UV mapping of first requesting mesh.
- // However, we probably need to reverse everything: mesh describes what they have, materials what they need, and an appropriate input layout is created at runtime?
- // Such a mechanism would also be able to handle missing streams gracefully.
- newMaterialInstantiation->Material = ProcessMeshMaterialAsset(lMaterial, uvElements);
- instances->Add(newMaterialInstantiation);
- return newMaterialInstantiation;
- }
-
- void SearchMeshInAttribute(FbxNode* pNode, FbxNodeAttribute* pAttribute, std::map materialNames, std::map meshNames, List^ models, List^ materialInstantiations)
- {
- if(!pAttribute) return;
-
- if (pAttribute->GetAttributeType() == FbxNodeAttribute::eMesh)
- {
- auto pMesh = (FbxMesh*)pAttribute;
- int polygonCount = pMesh->GetPolygonCount();
- FbxGeometryElement::EMappingMode materialMappingMode = FbxGeometryElement::eNone;
- FbxLayerElementArrayTemplate* materialIndices = NULL;
-
- if (pMesh->GetElementMaterial())
- {
- materialMappingMode = pMesh->GetElementMaterial()->GetMappingMode();
- materialIndices = &pMesh->GetElementMaterial()->GetIndexArray();
- }
-
- auto buildMeshes = gcnew List();
-
- // Count polygon per materials
- for (int i = 0; i < polygonCount; i++)
- {
- int materialIndex = 0;
- if (materialMappingMode == FbxGeometryElement::eByPolygon)
- {
- materialIndex = materialIndices->GetAt(i);
- }
- else if (materialMappingMode == FbxGeometryElement::eAllSame)
- {
- materialIndex = materialIndices->GetAt(0);
- }
-
- // Equivalent to std::vector::resize()
- while (materialIndex >= buildMeshes->Count)
- {
- buildMeshes->Add(nullptr);
- }
-
- if (buildMeshes[materialIndex] == nullptr)
- buildMeshes[materialIndex] = gcnew BuildMesh();
-
- int polygonSize = pMesh->GetPolygonSize(i) - 2;
- if (polygonSize > 0)
- buildMeshes[materialIndex]->polygonCount += polygonSize;
- }
-
- for (int i = 0; i < buildMeshes->Count; ++i)
- {
- auto meshParams = gcnew MeshParameters();
- auto meshName = meshNames[pMesh];
- if (buildMeshes->Count > 1)
- meshName = meshName + "_" + std::to_string(i + 1);
- meshParams->MeshName = gcnew String(meshName.c_str());
- meshParams->NodeName = sceneMapping->FindNode(pNode).Name;
-
- // Collect bones
- int skinDeformerCount = pMesh->GetDeformerCount(FbxDeformer::eSkin);
- if (skinDeformerCount > 0)
- {
- meshParams->BoneNodes = gcnew HashSet();
- for (int deformerIndex = 0; deformerIndex < skinDeformerCount; deformerIndex++)
- {
- FbxSkin* skin = FbxCast(pMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
-
- auto totalClusterCount = skin->GetClusterCount();
- for (int clusterIndex = 0; clusterIndex < totalClusterCount; ++clusterIndex)
- {
- FbxCluster* cluster = skin->GetCluster(clusterIndex);
- int indexCount = cluster->GetControlPointIndicesCount();
- if (indexCount == 0)
- {
- continue;
- }
-
- FbxNode* link = cluster->GetLink();
-
- MeshBoneDefinition bone;
- meshParams->BoneNodes->Add(sceneMapping->FindNode(link).Name);
- }
- }
- }
-
- FbxGeometryElementMaterial* lMaterialElement = pMesh->GetElementMaterial();
- FbxSurfaceMaterial* lMaterial = pNode->GetMaterial(i);
- if ((materialMappingMode == FbxGeometryElement::eByPolygon || materialMappingMode == FbxGeometryElement::eAllSame)
- && lMaterialElement != NULL && lMaterial != NULL)
- {
- std::map uvElements;
- auto uvNames = gcnew List();
- for (int j = 0; j < pMesh->GetElementUVCount(); ++j)
- {
- uvElements[pMesh->GetElementUV(j)->GetName()] = j;
- uvNames->Add(gcnew String(pMesh->GetElementUV(j)->GetName()));
- }
-
- auto material = GetOrCreateMaterial(lMaterial, uvNames, materialInstantiations, uvElements, materialNames);
- meshParams->MaterialName = material->MaterialName;
- }
- else
- {
- logger->Warning(String::Format("Mesh {0} does not have a material. It might not be displayed.", meshParams->MeshName), (CallerInfo^)nullptr);
- }
-
- models->Add(meshParams);
- }
- }
- }
-
- void SearchMesh(FbxNode* pNode, std::map materialNames, std::map meshNames, List^ models, List^ materialInstantiations)
- {
- // Process the node's attributes.
- for(int i = 0; i < pNode->GetNodeAttributeCount(); i++)
- SearchMeshInAttribute(pNode, pNode->GetNodeAttributeByIndex(i), materialNames, meshNames, models, materialInstantiations);
-
- // Recursively process the children nodes.
- for(int j = 0; j < pNode->GetChildCount(); j++)
- {
- SearchMesh(pNode->GetChild(j), materialNames, meshNames, models, materialInstantiations);
- }
- }
-
- Dictionary^ ExtractMaterialsNoInit()
- {
- std::map materialNames;
- GenerateMaterialNames(materialNames);
-
- auto materials = gcnew Dictionary();
- for (int i = 0; i < scene->GetMaterialCount(); i++)
- {
- std::map dict;
- auto lMaterial = scene->GetMaterial(i);
- auto materialName = materialNames[lMaterial];
- materials->Add(gcnew String(materialName.c_str()), ProcessMeshMaterialAsset(lMaterial, dict));
- }
- return materials;
- }
-
- MeshMaterials^ ExtractModelNoInit()
- {
- std::map materialNames;
- GenerateMaterialNames(materialNames);
-
- std::map meshNames;
- GenerateMeshesName(meshNames);
-
- std::map materialPerMesh;
- auto models = gcnew List();
- auto materialInstantiations = gcnew List();
- SearchMesh(scene->GetRootNode(), materialNames, meshNames, models, materialInstantiations);
-
- auto ret = gcnew MeshMaterials();
- ret->Models = models;
- ret->Materials = gcnew Dictionary();
- for (int i = 0; i < materialInstantiations->Count; ++i)
- {
- if (!ret->Materials->ContainsKey(materialInstantiations[i]->MaterialName))
- {
- ret->Materials->Add(materialInstantiations[i]->MaterialName, materialInstantiations[i]->Material);
- }
- }
-
- return ret;
- }
-
- List^ ExtractTextureDependenciesNoInit()
- {
- auto textureNames = gcnew List();
-
- auto textureCount = scene->GetTextureCount();
- for(int i=0; i(scene->GetTexture(i));
-
- if(texture == nullptr)
- continue;
-
- auto texturePath = FindFilePath(texture);
- if (!String::IsNullOrEmpty(texturePath))
- {
- if (texturePath->Contains(".fbm\\"))
- logger->Info(String::Format("Importer detected an embedded texture. It has been extracted at address '{0}'.", texturePath), (CallerInfo^)nullptr);
- if (!File::Exists(texturePath))
- logger->Warning(String::Format("Importer detected a texture not available on disk at address '{0}'", texturePath), (CallerInfo^)nullptr);
-
- textureNames->Add(texturePath);
- }
- }
-
- return textureNames;
- }
-
- List^ ExtractTextureDependencies(String^ inputFile)
- {
- try
- {
- Initialize(inputFile, nullptr, ImportConfiguration::ImportTexturesOnly());
- return ExtractTextureDependenciesNoInit();
- }
- finally
- {
- Destroy();
- }
- return nullptr;
- }
-
- Dictionary^ ExtractMaterials(String^ inputFilename)
- {
- try
- {
- Initialize(inputFilename, nullptr, ImportConfiguration::ImportMaterialsOnly());
- return ExtractMaterialsNoInit();
- }
- finally
- {
- Destroy();
- }
- return nullptr;
- }
-
- void GetNodes(FbxNode* node, int depth, List^ allNodes)
- {
- auto newNodeInfo = gcnew NodeInfo();
- newNodeInfo->Name = sceneMapping->FindNode(node).Name;
- newNodeInfo->Depth = depth;
- newNodeInfo->Preserve = true;
-
- allNodes->Add(newNodeInfo);
- for (int i = 0; i < node->GetChildCount(); ++i)
- GetNodes(node->GetChild(i), depth + 1, allNodes);
- }
-
- List^ ExtractNodeHierarchy()
- {
- auto allNodes = gcnew List();
- GetNodes(scene->GetRootNode(), 0, allNodes);
- return allNodes;
- }
-
-public:
- EntityInfo^ ExtractEntity(String^ inputFileName, bool extractTextureDependencies)
- {
- try
- {
- Initialize(inputFileName, nullptr, ImportConfiguration::ImportEntityConfig());
-
- auto animationConverter = gcnew AnimationConverter(logger, sceneMapping);
-
- auto entityInfo = gcnew EntityInfo();
- if (extractTextureDependencies)
- entityInfo->TextureDependencies = ExtractTextureDependenciesNoInit();
- entityInfo->AnimationNodes = animationConverter->ExtractAnimationNodesNoInit();
- auto models = ExtractModelNoInit();
- entityInfo->Models = models->Models;
- entityInfo->Materials = models->Materials;
- entityInfo->Nodes = ExtractNodeHierarchy();
-
- return entityInfo;
- }
- finally
- {
- Destroy();
- }
- return nullptr;
- }
-
- double GetAnimationDuration(String^ inputFileName, int animationStack)
- {
- try
- {
- Initialize(inputFileName, nullptr, ImportConfiguration::ImportEntityConfig());
-
- auto animationConverter = gcnew AnimationConverter(logger, sceneMapping);
- auto animationData = animationConverter->ProcessAnimation(inputFilename, "", true, animationStack);
-
- return animationData->Duration.TotalSeconds;
- }
- finally
- {
- Destroy();
- }
-
- return 0;
- }
-
- Model^ Convert(String^ inputFilename, String^ vfsOutputFilename, Dictionary^ materialIndices)
- {
- try
- {
- Initialize(inputFilename, vfsOutputFilename, ImportConfiguration::ImportAll());
-
- // Create default ModelViewData
- modelData = gcnew Model();
-
- //auto sceneName = scene->GetName();
- //if (sceneName != NULL && strlen(sceneName) > 0)
- //{
- // entity->Name = gcnew String(sceneName);
- //}
- //else
- //{
- // // Build scene name from file name
- // entity->Name = Path::GetFileName(this->inputFilename);
- //}
-
- std::map meshNames;
- GenerateMeshesName(meshNames);
-
- std::map materialNames;
- GenerateMaterialNames(materialNames);
-
- std::map materials;
- for (auto it = materialNames.begin(); it != materialNames.end(); ++it)
- {
- auto materialName = gcnew String(it->second.c_str());
- int materialIndex;
- if (materialIndices->TryGetValue(materialName, materialIndex))
- {
- materials[it->first] = materialIndex;
- }
- else
- {
- logger->Warning(String::Format("Model references material '{0}', but it was not defined in the ModelAsset.", materialName), (CallerInfo^)nullptr);
- }
- }
-
- // Process and add root entity
- ProcessNodeTransformation(scene->GetRootNode());
- ProcessNodeAttributes(scene->GetRootNode(), meshNames, materials);
-
- return modelData;
- }
- finally
- {
- Destroy();
- }
-
- return nullptr;
- }
-
- AnimationInfo^ ConvertAnimation(String^ inputFilename, String^ vfsOutputFilename, bool importCustomAttributeAnimations, int animationStack)
- {
- try
- {
- Initialize(inputFilename, vfsOutputFilename, ImportConfiguration::ImportAnimationsOnly());
-
- auto animationConverter = gcnew AnimationConverter(logger, sceneMapping);
- return animationConverter->ProcessAnimation(inputFilename, vfsOutputFilename, importCustomAttributeAnimations, animationStack);
- }
- finally
- {
- Destroy();
- }
-
- return nullptr;
- }
-
- Skeleton^ ConvertSkeleton(String^ inputFilename, String^ vfsOutputFilename)
- {
- try
- {
- Initialize(inputFilename, vfsOutputFilename, ImportConfiguration::ImportSkeletonOnly());
- ProcessNodeTransformation(scene->GetRootNode());
-
- auto skeleton = gcnew Skeleton();
- skeleton->Nodes = sceneMapping->Nodes;
- return skeleton;
- }
- finally
- {
- Destroy();
- }
-
- return nullptr;
- }
-};
-
-} } }
diff --git a/sources/tools/Stride.Importer.FBX/SceneMapping.h b/sources/tools/Stride.Importer.FBX/SceneMapping.h
deleted file mode 100644
index 308e349e2f..0000000000
--- a/sources/tools/Stride.Importer.FBX/SceneMapping.h
+++ /dev/null
@@ -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 {
- ///
- /// Contains mapping between FBX nodes and Stride ModelNodeDefinition
- ///
- ref class SceneMapping
- {
- private:
- FbxScene* scene;
- Dictionary^ nodeMapping;
- array^ nodes;
-
- Matrix convertMatrix;
- Matrix inverseConvertMatrix;
- Matrix normalConvertMatrix;
- public:
- ///
- /// Initializes a new instance of the class.
- ///
- /// The scene argument.
- SceneMapping(FbxScene* scene) : scene(scene)
- {
- if (scene == nullptr)
- {
- throw gcnew ArgumentNullException("scene");
- }
- nodeMapping = gcnew Dictionary();
-
- // Generate names for all nodes
- std::map nodeNames;
- GenerateNodesName(scene, nodeNames);
-
- // Generate all ModelNodeDefinition
- auto nodeList = gcnew List();
- RegisterNode(scene->GetRootNode(), -1, nodeNames, nodeMapping, nodeList);
- nodes = nodeList->ToArray();
-
- // Setup the convertion
- FbxGlobalSettings& settings = scene->GetGlobalSettings();
- InitializeMatrix(settings.GetAxisSystem(), settings.GetSystemUnit());
- }
-
- ///
- /// Gets all the nodes.
- ///
- property array^ Nodes
- {
- array^ get()
- {
- return nodes;
- }
- }
-
- ///
- /// Gets the associated FbxScene.
- ///
- property FbxScene* Scene
- {
- FbxScene* get()
- {
- return scene;
- }
- }
-
- property Matrix MatrixModifier
- {
- Matrix get()
- {
- return convertMatrix;
- }
- }
-
- property float ScaleToMeters;
-
- property Matrix AxisSystemRotationMatrix;
-
- ///
- /// Finds the index of the FBX node in the from a FBX node.
- ///
- /// The node.
- /// Stride.Rendering.ModelNodeDefinition.
- int FindNodeIndex(FbxNode* node)
- {
- int nodeIndex;
- if (!nodeMapping->TryGetValue((IntPtr)node, nodeIndex))
- {
- throw gcnew ArgumentException("Invalid node not found", "node");
- }
-
- return nodeIndex;
- }
-
-
- ///
- /// Finds a from a FBX node.
- ///
- /// The node.
- /// Stride.Rendering.ModelNodeDefinition.
- 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& 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& nodeNames)
- {
- std::vector nodes;
- GetNodes(scene->GetRootNode(), nodes);
-
- std::map nodeNameTotalCount;
- std::map nodeNameCurrentCount;
- std::map 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& nodeNames, Dictionary^ nodeMapping, List^ 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;
- }
- };
- }
- }
-}
diff --git a/sources/tools/Stride.Importer.FBX/StreamReader.cpp b/sources/tools/Stride.Importer.FBX/StreamReader.cpp
deleted file mode 100644
index a3f72b4cd1..0000000000
--- a/sources/tools/Stride.Importer.FBX/StreamReader.cpp
+++ /dev/null
@@ -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
-
-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(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;
-}
diff --git a/sources/tools/Stride.Importer.FBX/StreamReader.h b/sources/tools/Stride.Importer.FBX/StreamReader.h
deleted file mode 100644
index 3ed041a95b..0000000000
--- a/sources/tools/Stride.Importer.FBX/StreamReader.h
+++ /dev/null
@@ -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);
-
diff --git a/sources/tools/Stride.Importer.FBX/Stride.Importer.FBX.vcxproj b/sources/tools/Stride.Importer.FBX/Stride.Importer.FBX.vcxproj
deleted file mode 100644
index f1b6046d26..0000000000
--- a/sources/tools/Stride.Importer.FBX/Stride.Importer.FBX.vcxproj
+++ /dev/null
@@ -1,262 +0,0 @@
-
-
-
-
- Cpp
- $(StrideEditorTargetFramework)
- WindowsTools
-
-
- 14.0
- 2019.0
- https://www.autodesk.com/developer-network/platform-technologies/fbx-sdk-2019-0
- $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk FBX SDK $(FbxSdkVersion)', 'Install_Dir', null, RegistryView.Registry32))
- v143
- vs2015\
-
-
-
- Debug
- Win32
-
-
- Release
- Win32
-
-
- Debug
- x64
-
-
- Release
- x64
-
-
-
- {0467D515-FD66-4B8A-A128-CB642C2ED03F}
- ManagedCProj
- Stride.Importer.FBX
- 10.0
-
-
-
- DynamicLibrary
- true
- NetCore
-
-
- DynamicLibrary
- false
- NetCore
-
-
- Unicode
-
-
- Unicode
-
-
-
-
-
-
-
-
-
- true
- bin\$(TargetFramework)\$(Platform)\$(Configuration)\
- obj\$(TargetFramework)\$(Platform)\$(Configuration)\
-
-
- false
- bin\$(TargetFramework)\$(Platform)\$(Configuration)\
- obj\$(TargetFramework)\$(Platform)\$(Configuration)\
-
-
- $(FbxSdkDir)\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);$(IncludePath)
-
-
- $(FbxSdkDir)\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);$(IncludePath)
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)
-
-
- Use
- /wd 4945 %(AdditionalOptions)
-
-
- true
- libfbxsdk.lib;user32.lib;advapi32.lib
- $(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\debug
- /ignore:4049 %(AdditionalOptions)
-
-
- xcopy /D /Y "$(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\debug\libfbxsdk.dll" "$(TargetDir)x86"
- $(TargetDir)x86\libfbxsdk.dll;%(Outputs)
- $(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\release\libfbxsdk.dll
- true
-
-
-
-
- Level3
- WIN32;NDEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)
- $(FbxSdkDir)\include
- Use
- /wd 4945 %(AdditionalOptions)
-
-
- true
- libfbxsdk.lib;user32.lib;advapi32.lib
- $(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\release
- /ignore:4049 %(AdditionalOptions)
-
-
-
-
- Level3
- Disabled
- _DEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)
-
-
- Use
- /wd 4945 %(AdditionalOptions)
-
-
- true
- libfbxsdk.lib
- $(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\debug
- /ignore:4049 %(AdditionalOptions)
-
-
- xcopy /D /Y "$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\debug\libfbxsdk.dll" "$(TargetDir)x64"
- $(TargetDir)x64\libfbxsdk.dll;%(Outputs)
- $(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release\libfbxsdk.dll
- true
-
-
-
-
- Level3
- NDEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)
- $(FbxSdkDir)\include
- Use
- /wd 4945 %(AdditionalOptions)
-
-
- true
- libfbxsdk.lib
- $(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release
- /ignore:4049 %(AdditionalOptions)
-
-
- xcopy /D /Y "$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release\libfbxsdk.dll" "$(TargetDir)x64"
- $(TargetDir)x64\libfbxsdk.dll;%(Outputs)
- $(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release\libfbxsdk.dll
- true
-
-
-
-
-
-
-
-
-
-
-
-
- Create
-
-
-
-
-
-
-
-
-
-
- runtimes\win-x64\native\%(Filename)%(Extension)
- runtimes\win-x64\native\%(Filename)%(Extension)
- PreserveNewest
-
-
-
-
- {1e54a9a2-4439-4444-ae57-6d2ed3c0dc47}
- False
-
-
- {66581dad-70ad-4475-ae47-c6c0df1ec5e2}
- False
-
-
- {39ae9c77-e94b-404f-8768-b6261b3c1e0e}
- False
-
-
- {c121a566-555e-42b9-9b0a-1696529a9088}
- False
-
-
- {ad4fdc24-b64d-4ed7-91aa-62c9eda12fa4}
- False
-
-
- {0e916ab7-5a6c-4820-8ab1-aa492fe66d68}
- False
-
-
- {fb06c76a-6bb7-40be-9afa-fec13b045fb5}
- False
-
-
- {1de01410-22c9-489b-9796-1addab1f64e5}
- False
-
-
- {5210fb81-b807-49bb-af0d-31fb6a83a572}
- False
-
-
- {f2d52edb-bc17-4243-b06d-33cd20f87a7f}
- False
-
-
- {1677b922-ccf0-44de-b57e-1cdd3d2b8e8a}
- False
-
-
- {273bdd15-7392-4078-91f0-af23594a3d7b}
- False
-
-
- {72390339-b2a1-4f61-a800-31ed0975b515}
- False
-
-
- {7732cb84-a39a-4adf-b740-fd32a352fa8a}
- False
-
-
- {806aa078-6070-4bb6-b05b-6ee6b21b1cde}
-
-
-
-
- ..\..\..\deps\BulletPhysics\BulletSharp.NetStandard.dll
-
-
-
-
-
-
-
-
-
-
diff --git a/sources/tools/Stride.Importer.FBX/Stride.Importer.FBX.vcxproj.filters b/sources/tools/Stride.Importer.FBX/Stride.Importer.FBX.vcxproj.filters
deleted file mode 100644
index c2646e480e..0000000000
--- a/sources/tools/Stride.Importer.FBX/Stride.Importer.FBX.vcxproj.filters
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/sources/tools/Stride.Importer.FBX/UtilityFunctions.cpp b/sources/tools/Stride.Importer.FBX/UtilityFunctions.cpp
deleted file mode 100644
index b5376753e6..0000000000
--- a/sources/tools/Stride.Importer.FBX/UtilityFunctions.cpp
+++ /dev/null
@@ -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
-
-// 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^ bytes = gcnew array((int) byteCount);
- pin_ptr p = &bytes[0];
- memcpy(p, str.c_str(), byteCount);
- return System::Text::Encoding::UTF8->GetString(bytes);
-}
diff --git a/sources/tools/Stride.Importer.FBX/UtilityFunctions.h b/sources/tools/Stride.Importer.FBX/UtilityFunctions.h
deleted file mode 100644
index 55e0e70d7a..0000000000
--- a/sources/tools/Stride.Importer.FBX/UtilityFunctions.h
+++ /dev/null
@@ -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);
diff --git a/sources/tools/Stride.Importer.FBX/stdafx.cpp b/sources/tools/Stride.Importer.FBX/stdafx.cpp
deleted file mode 100644
index f356258ae4..0000000000
--- a/sources/tools/Stride.Importer.FBX/stdafx.cpp
+++ /dev/null
@@ -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"
-
diff --git a/sources/tools/Stride.Importer.FBX/stdafx.h b/sources/tools/Stride.Importer.FBX/stdafx.h
deleted file mode 100644
index e10a49ed1f..0000000000
--- a/sources/tools/Stride.Importer.FBX/stdafx.h
+++ /dev/null
@@ -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
-#include
-#include