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 -#include -#include -#include -#include -#include - -#include "UtilityFunctions.h"