fix: [Asset] Unified 3D asset importer (on behalf of Noa7/Noah7071) (#2163)

Co-authored-by: noa7 <noahwdv@gmail.com>
Co-authored-by: noa7707 <157441788+noa7707@users.noreply.github.com>
Co-authored-by: Noah7071 <157886157+Noah7071@users.noreply.github.com>
This commit is contained in:
Eideren 2024-04-04 02:11:36 +02:00 коммит произвёл GitHub
Родитель 4a263c4faa
Коммит 0e053a3b88
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
39 изменённых файлов: 325 добавлений и 4223 удалений

Просмотреть файл

@ -90,8 +90,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Input.Tests.Windows"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Core.Tests", "..\sources\core\Stride.Core.Tests\Stride.Core.Tests.csproj", "{5AA408BA-E766-453E-B661-E3D7EC46E2A6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Stride.Importer.FBX", "..\sources\tools\Stride.Importer.FBX\Stride.Importer.FBX.vcxproj", "{0467D515-FD66-4B8A-A128-CB642C2ED03F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Core.Shaders", "..\sources\shaders\Stride.Core.Shaders\Stride.Core.Shaders.csproj", "{F2D52EDB-BC17-4243-B06D-33CD20F87A7F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Core.Presentation.Wpf", "..\sources\presentation\Stride.Core.Presentation.Wpf\Stride.Core.Presentation.Wpf.csproj", "{47AFCC2E-E9F0-47D6-9D75-9E646546A92B}"
@ -312,8 +310,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xunit.runner.stride", "..\s
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Engine.NoAssets.Tests.Windows", "..\sources\engine\Stride.Engine.NoAssets.Tests\Stride.Engine.NoAssets.Tests.Windows.csproj", "{1C94168A-3C0D-4C6B-883B-91627D2EF3A1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.Assimp", "..\sources\tools\Stride.Importer.Assimp\Stride.Importer.Assimp.csproj", "{967BA05D-4AC4-4848-AEFD-894EF2309E4D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.Common", "..\sources\tools\Stride.Importer.Common\Stride.Importer.Common.csproj", "{806AA078-6070-4BB6-B05B-6EE6B21B1CDE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Core.CompilerServices", "..\sources\core\Stride.Core.CompilerServices\Stride.Core.CompilerServices.csproj", "{D62BBD65-AB1C-41C7-8EC3-88949993C71E}"
@ -334,6 +330,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGetResolver", "NuGetResol
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Core.Presentation", "..\sources\presentation\Stride.Core.Presentation\Stride.Core.Presentation.csproj", "{0C63EF8B-26F9-4511-9FC5-7431DE9657D6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stride.Importer.3D", "..\sources\tools\Stride.Importer.3D\Stride.Importer.3D.csproj", "{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -405,16 +403,6 @@ Global
{5AA408BA-E766-453E-B661-E3D7EC46E2A6}.Release|Mixed Platforms.Build.0 = Debug|Any CPU
{5AA408BA-E766-453E-B661-E3D7EC46E2A6}.Release|Win32.ActiveCfg = Debug|Any CPU
{5AA408BA-E766-453E-B661-E3D7EC46E2A6}.Release|Win32.Build.0 = Debug|Any CPU
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Debug|Any CPU.ActiveCfg = Debug|Win32
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Debug|Mixed Platforms.ActiveCfg = Debug|x64
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Debug|Mixed Platforms.Build.0 = Debug|x64
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Debug|Win32.ActiveCfg = Debug|Win32
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Debug|Win32.Build.0 = Debug|Win32
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Release|Any CPU.ActiveCfg = Release|Win32
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Release|Mixed Platforms.ActiveCfg = Release|x64
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Release|Mixed Platforms.Build.0 = Release|x64
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Release|Win32.ActiveCfg = Release|Win32
{0467D515-FD66-4B8A-A128-CB642C2ED03F}.Release|Win32.Build.0 = Release|Win32
{F2D52EDB-BC17-4243-B06D-33CD20F87A7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F2D52EDB-BC17-4243-B06D-33CD20F87A7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2D52EDB-BC17-4243-B06D-33CD20F87A7F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -1385,18 +1373,6 @@ Global
{1C94168A-3C0D-4C6B-883B-91627D2EF3A1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{1C94168A-3C0D-4C6B-883B-91627D2EF3A1}.Release|Win32.ActiveCfg = Release|Any CPU
{1C94168A-3C0D-4C6B-883B-91627D2EF3A1}.Release|Win32.Build.0 = Release|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Win32.ActiveCfg = Debug|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Debug|Win32.Build.0 = Debug|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Any CPU.Build.0 = Release|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Win32.ActiveCfg = Release|Any CPU
{967BA05D-4AC4-4848-AEFD-894EF2309E4D}.Release|Win32.Build.0 = Release|Any CPU
{806AA078-6070-4BB6-B05B-6EE6B21B1CDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{806AA078-6070-4BB6-B05B-6EE6B21B1CDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{806AA078-6070-4BB6-B05B-6EE6B21B1CDE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -1493,6 +1469,18 @@ Global
{0C63EF8B-26F9-4511-9FC5-7431DE9657D6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{0C63EF8B-26F9-4511-9FC5-7431DE9657D6}.Release|Win32.ActiveCfg = Release|Any CPU
{0C63EF8B-26F9-4511-9FC5-7431DE9657D6}.Release|Win32.Build.0 = Release|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Win32.ActiveCfg = Debug|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Debug|Win32.Build.0 = Debug|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Any CPU.Build.0 = Release|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Win32.ActiveCfg = Release|Any CPU
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E}.Release|Win32.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1502,13 +1490,13 @@ Global
{6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C} = {1AE1AC60-5D2F-4CA7-AE20-888F44551185}
{4A15BAAD-AA37-4754-A2BF-8D4049211E36} = {1AE1AC60-5D2F-4CA7-AE20-888F44551185}
{1AC70118-C90F-4EC6-9D8B-C628BDF900F7} = {4C142567-C42B-40F5-B092-798882190209}
{B175D318-B4D0-49EA-9AEF-A54ACA2F03DC} = {25F10A0B-7259-404C-86BE-FD2363C92F72}
{2FCA2D8B-B10F-4DCA-9847-4221F74BA586} = {5D2D3BE8-9910-45CA-8E45-95660DA4C563}
{C121A566-555E-42B9-9B0A-1696529A9088} = {4C142567-C42B-40F5-B092-798882190209}
{FB06C76A-6BB7-40BE-9AFA-FEC13B045FB5} = {4C142567-C42B-40F5-B092-798882190209}
{A8F8D125-7A22-489F-99BC-9A02F545A17F} = {A7ED9F01-7D78-4381-90A6-D50E51C17250}
{01700344-CF44-482C-BEBC-60213B0F844C} = {A7ED9F01-7D78-4381-90A6-D50E51C17250}
{5AA408BA-E766-453E-B661-E3D7EC46E2A6} = {22ADD4CD-092E-4ADC-A21E-64CF42230152}
{0467D515-FD66-4B8A-A128-CB642C2ED03F} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C}
{F2D52EDB-BC17-4243-B06D-33CD20F87A7F} = {10D145AF-C8AE-428F-A80F-CA1B591D0DB2}
{47AFCC2E-E9F0-47D6-9D75-9E646546A92B} = {75A820AB-0F21-40F2-9448-5D7F495B97A0}
{C223FCD7-CDCC-4943-9E11-9C2CC8FA9FC4} = {52AE329E-B588-40D0-A578-8D0DB1BD83E5}
@ -1608,7 +1596,6 @@ Global
{66BE41FC-FC52-48D0-9C04-BCE8CC393020} = {4C142567-C42B-40F5-B092-798882190209}
{D5B023BE-010F-44A8-ABF1-DB6F3BCEA392} = {1AE1AC60-5D2F-4CA7-AE20-888F44551185}
{1C94168A-3C0D-4C6B-883B-91627D2EF3A1} = {A7ED9F01-7D78-4381-90A6-D50E51C17250}
{967BA05D-4AC4-4848-AEFD-894EF2309E4D} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C}
{806AA078-6070-4BB6-B05B-6EE6B21B1CDE} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C}
{D62BBD65-AB1C-41C7-8EC3-88949993C71E} = {2E93E2B5-4500-4E47-9B65-E705218AB578}
{BACD76E5-35D0-4389-9BB9-8743AC4D89DE} = {22ADD4CD-092E-4ADC-A21E-64CF42230152}
@ -1619,6 +1606,7 @@ Global
{02FD0BDE-4293-414F-97E6-69FF71105420} = {158087CF-AF74-44E9-AA20-A6AEB1E398A9}
{158087CF-AF74-44E9-AA20-A6AEB1E398A9} = {1AE1AC60-5D2F-4CA7-AE20-888F44551185}
{0C63EF8B-26F9-4511-9FC5-7431DE9657D6} = {75A820AB-0F21-40F2-9448-5D7F495B97A0}
{66EFFDE4-24F0-4E57-9618-0F5577E20A1E} = {6F473FA6-4F8B-4FBA-AE33-EE5AF997D50C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FF877973-604D-4EA7-B5F5-A129961F9EF2}

Просмотреть файл

@ -27,6 +27,7 @@
<CheckBox Content="{sd:Localize Deduplicate materials, Context=Button}" IsChecked="{Binding DeduplicateMaterials}" Margin="5" Visibility="{Binding ShowDeduplicateMaterialsCheckBox, Converter={sd:VisibleOrCollapsed}}"/>
<TextBlock Text="{sd:Localize Warning\: Deduplicate materials is currently not supported for FBX files}" Margin="5" Visibility="{Binding ShowFbxDedupeNotSupportedWarning, Converter={sd:VisibleOrCollapsed}}"/>
<CheckBox Content="{sd:Localize Import textures, Context=Button}" IsChecked="{Binding ImportTextures}" Margin="5"/>
<CheckBox Content="{sd:Localize Import Animations, Context=Button}" IsChecked="{Binding ImportAnimations}" Margin="5"/>
</StackPanel>
</Border>
<Border Background="{StaticResource EmphasisColorBrush}" Margin="20,0">

Просмотреть файл

@ -44,6 +44,7 @@ namespace Stride.Assets.Presentation.Templates
private bool showFbxDedupeNotSupportedWarning = false;
private bool deduplicateMaterials = true;
private bool importTextures = true;
private bool importAnimations = true;
private bool importSkeleton = true;
private bool dontImportSkeleton;
private bool reuseSkeleton;
@ -62,6 +63,8 @@ namespace Stride.Assets.Presentation.Templates
public bool ImportTextures { get { return importTextures; } set { SetValue(ref importTextures, value); } }
public bool ImportAnimations { get { return importAnimations; } set { SetValue(ref importAnimations, value); } }
public bool ImportSkeleton { get { return importSkeleton; } set { SetValue(ref importSkeleton, value); } }
public bool DontImportSkeleton { get { return dontImportSkeleton; } set { SetValue(ref dontImportSkeleton, value); } }

Просмотреть файл

@ -26,6 +26,7 @@ namespace Stride.Assets.Presentation.Templates
public static SettingsKey<bool> ImportMaterials = new SettingsKey<bool>("Templates/ModelFromFile/ImportMaterials", PackageUserSettings.SettingsContainer, true);
public static SettingsKey<bool> DeduplicateMaterials = new SettingsKey<bool>("Templates/ModelFromFile/DeduplicateMaterials", PackageUserSettings.SettingsContainer, true);
public static SettingsKey<bool> ImportTextures = new SettingsKey<bool>("Templates/ModelFromFile/ImportTextures", PackageUserSettings.SettingsContainer, true);
public static SettingsKey<bool> ImportAnimations = new SettingsKey<bool>("Templates/ModelFromFile/ImportAnimations", PackageUserSettings.SettingsContainer, true);
public static SettingsKey<bool> ImportSkeleton = new SettingsKey<bool>("Templates/ModelFromFile/ImportSkeleton", PackageUserSettings.SettingsContainer, true);
public static SettingsKey<AssetId> DefaultSkeleton = new SettingsKey<AssetId>("Templates/ModelFromFile/DefaultSkeleton", PackageUserSettings.SettingsContainer, AssetId.Empty);
}
@ -39,6 +40,7 @@ namespace Stride.Assets.Presentation.Templates
protected static readonly PropertyKey<bool> ImportMaterialsKey = new PropertyKey<bool>("ImportMaterials", typeof(ModelFromFileTemplateGenerator));
protected static readonly PropertyKey<bool> DeduplicateMaterialsKey = new PropertyKey<bool>("DeduplicateMaterials", typeof(ModelFromFileTemplateGenerator));
protected static readonly PropertyKey<bool> ImportTexturesKey = new PropertyKey<bool>("ImportTextures", typeof(ModelFromFileTemplateGenerator));
protected static readonly PropertyKey<bool> ImportAnimationsKey = new PropertyKey<bool>("ImportAnimations", typeof(ModelFromFileTemplateGenerator));
protected static readonly PropertyKey<bool> ImportSkeletonKey = new PropertyKey<bool>("ImportSkeleton", typeof(ModelFromFileTemplateGenerator));
protected static readonly PropertyKey<Skeleton> SkeletonToUseKey = new PropertyKey<Skeleton>("SkeletonToUse", typeof(ModelFromFileTemplateGenerator));
@ -57,8 +59,7 @@ namespace Stride.Assets.Presentation.Templates
if (files == null)
return true;
var showDeduplicateMaterialsCheckBox = files.Any(x => ImportAssimpCommand.IsSupportingExtensions(x.GetFileExtension()));
var showFbxDedupeNotSupportedWarning = showDeduplicateMaterialsCheckBox && files.Any(x => ImportFbxCommand.IsSupportingExtensions(x.GetFileExtension()));
var showDeduplicateMaterialsCheckBox = files.Any(x => ImportThreeDCommand.IsSupportingExtensions(x.GetFileExtension()));
// Load settings from the last time this template was used for this project
var profile = parameters.Package.UserSettings.Profile;
var window = new ModelAssetTemplateWindow
@ -67,9 +68,10 @@ namespace Stride.Assets.Presentation.Templates
{
ImportMaterials = ModelFromFileTemplateSettings.ImportMaterials.GetValue(profile, true),
ShowDeduplicateMaterialsCheckBox = showDeduplicateMaterialsCheckBox,
ShowFbxDedupeNotSupportedWarning = showFbxDedupeNotSupportedWarning,
ShowFbxDedupeNotSupportedWarning = false,
DeduplicateMaterials = ModelFromFileTemplateSettings.DeduplicateMaterials.GetValue(profile, true),
ImportTextures = ModelFromFileTemplateSettings.ImportTextures.GetValue(profile, true),
ImportAnimations = ModelFromFileTemplateSettings.ImportAnimations.GetValue(profile, true),
ImportSkeleton = ModelFromFileTemplateSettings.ImportSkeleton.GetValue(profile, true)
}
};
@ -92,6 +94,7 @@ namespace Stride.Assets.Presentation.Templates
parameters.Tags.Set(ImportMaterialsKey, window.Parameters.ImportMaterials);
parameters.Tags.Set(DeduplicateMaterialsKey, window.Parameters.DeduplicateMaterials);
parameters.Tags.Set(ImportTexturesKey, window.Parameters.ImportTextures);
parameters.Tags.Set(ImportAnimationsKey, window.Parameters.ImportAnimations);
parameters.Tags.Set(ImportSkeletonKey, window.Parameters.ImportSkeleton);
parameters.Tags.Set(SkeletonToUseKey, skeletonToReuse);
@ -99,6 +102,7 @@ namespace Stride.Assets.Presentation.Templates
ModelFromFileTemplateSettings.ImportMaterials.SetValue(window.Parameters.ImportMaterials, profile);
ModelFromFileTemplateSettings.DeduplicateMaterials.SetValue(window.Parameters.DeduplicateMaterials, profile);
ModelFromFileTemplateSettings.ImportTextures.SetValue(window.Parameters.ImportTextures, profile);
ModelFromFileTemplateSettings.ImportAnimations.SetValue(window.Parameters.ImportAnimations, profile);
ModelFromFileTemplateSettings.ImportSkeleton.SetValue(window.Parameters.ImportSkeleton, profile);
skeletonId = AttachedReferenceManager.GetAttachedReference(skeletonToReuse)?.Id ?? AssetId.Empty;
ModelFromFileTemplateSettings.DefaultSkeleton.SetValue(skeletonId, profile);
@ -116,6 +120,7 @@ namespace Stride.Assets.Presentation.Templates
var importMaterials = parameters.Tags.Get(ImportMaterialsKey);
var deduplicateMaterials = parameters.Tags.Get(DeduplicateMaterialsKey);
var importTextures = parameters.Tags.Get(ImportTexturesKey);
var importAnimations = parameters.Tags.Get(ImportAnimationsKey);
var importSkeleton = parameters.Tags.Get(ImportSkeletonKey);
var skeletonToReuse = parameters.Tags.Get(SkeletonToUseKey);
@ -124,6 +129,7 @@ namespace Stride.Assets.Presentation.Templates
importParameters.SelectedOutputTypes.Add(typeof(ModelAsset), true);
importParameters.SelectedOutputTypes.Add(typeof(MaterialAsset), importMaterials);
importParameters.SelectedOutputTypes.Add(typeof(TextureAsset), importTextures);
importParameters.SelectedOutputTypes.Add(typeof(AnimationAsset), importAnimations);
importParameters.SelectedOutputTypes.Add(typeof(SkeletonAsset), importSkeleton);
var importedAssets = new List<AssetItem>();

Просмотреть файл

@ -1,50 +0,0 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System;
using Stride.Core.Assets;
using Stride.Core;
using Stride.Core.Diagnostics;
using Stride.Core.IO;
using Stride.Assets.Textures;
using Stride.Importer.Common;
namespace Stride.Assets.Models
{
public class FbxAssetImporter : ModelAssetImporter
{
static FbxAssetImporter()
{
NativeLibraryHelper.PreloadLibrary("libfbxsdk", typeof(FbxAssetImporter));
}
// Supported file extensions for this importer
private const string FileExtensions = ".fbx";
private static readonly Guid Uid = new Guid("a15ae42d-42c5-4a3b-9f7e-f8cd91eda595");
public override Guid Id => Uid;
public override string Description => "FBX importer used for creating entities, 3D Models or animations assets";
public override string SupportedFileExtensions => FileExtensions;
/// <inheritdoc/>
public override EntityInfo GetEntityInfo(UFile localPath, Logger logger, AssetImporterParameters importParameters)
{
var meshConverter = new Importer.FBX.MeshConverter(logger);
var entityInfo = meshConverter.ExtractEntity(localPath.FullPath, importParameters.IsTypeSelectedForOutput(typeof(TextureAsset)));
return entityInfo;
}
/// <inheritdoc/>
public override void GetAnimationDuration(UFile localPath, Logger logger, AssetImporterParameters importParameters, out TimeSpan startTime, out TimeSpan endTime)
{
var meshConverter = new Importer.FBX.MeshConverter(logger);
// Use the first animation stack by default
var durationInSeconds = meshConverter.GetAnimationDuration(localPath.FullPath, 0);
startTime = TimeSpan.Zero;
endTime = TimeSpan.FromSeconds(durationInSeconds);
}
}
}

Просмотреть файл

@ -1,67 +0,0 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using Stride.Core.BuildEngine;
using Stride.Core.Serialization.Contents;
using Stride.Animations;
using Stride.Rendering;
namespace Stride.Assets.Models
{
[Description("Import FBX")]
public class ImportFbxCommand : ImportModelCommand
{
/// <inheritdoc/>
public override string Title { get { string title = "Import FBX "; try { title += Path.GetFileName(SourcePath) ?? "[File]"; } catch { title += "[INVALID PATH]"; } return title; } }
public static bool IsSupportingExtensions(string ext)
{
return !String.IsNullOrEmpty(ext) && ext.ToLowerInvariant().Equals(".fbx");
}
protected override Model LoadModel(ICommandContext commandContext, ContentManager contentManager)
{
var meshConverter = CreateMeshConverter(commandContext);
var materialMapping = Materials.Select((s, i) => new { Value = s, Index = i }).ToDictionary(x => x.Value.Name, x => x.Index);
var sceneData = meshConverter.Convert(SourcePath, Location, materialMapping);
return sceneData;
}
protected override Dictionary<string, AnimationClip> LoadAnimation(ICommandContext commandContext, ContentManager contentManager, out TimeSpan duration)
{
var meshConverter = CreateMeshConverter(commandContext);
var sceneData = meshConverter.ConvertAnimation(SourcePath, Location, ImportCustomAttributes, AnimationStack);
duration = sceneData.Duration;
return sceneData.AnimationClips;
}
protected override Skeleton LoadSkeleton(ICommandContext commandContext, ContentManager contentManager)
{
var meshConverter = CreateMeshConverter(commandContext);
var sceneData = meshConverter.ConvertSkeleton(SourcePath, Location);
return sceneData;
}
private Importer.FBX.MeshConverter CreateMeshConverter(ICommandContext commandContext)
{
return new Importer.FBX.MeshConverter(commandContext.Logger)
{
AllowUnsignedBlendIndices = AllowUnsignedBlendIndices,
};
}
public override bool ShouldSpawnNewProcess()
{
return true;
}
public override string ToString()
{
return "Import FBX " + base.ToString();
}
}
}

Просмотреть файл

@ -52,14 +52,17 @@ namespace Stride.Assets.Models
if (duration > durationTimeSpan)
duration = durationTimeSpan;
// Incase of no mapping or only root mapping use source skeleton
var animationClip = new AnimationClip { Duration = duration };
var skeleton = string.IsNullOrWhiteSpace(SkeletonUrl)?null:contentManager.Load<Skeleton>(SkeletonUrl);
var skeletonMapping = new SkeletonMapping(skeleton, modelSkeleton);
if (animationClips.Count > 0)
{
AnimationClip rootMotionAnimationClip = null;
// If root motion is explicitely enabled, or if there is no skeleton, try to find root node and apply animation directly on TransformComponent
if ((AnimationRootMotion || SkeletonUrl == null) && modelSkeleton.Nodes.Length >= 1)
if ((AnimationRootMotion || skeleton == null || skeletonMapping.MapCount < 2) && modelSkeleton.Nodes.Length >= 1)
{
// No skeleton, map root node only
// TODO: For now, it seems to be located on node 1 in FBX files. Need to check if always the case, and what happens with Assimp
@ -91,17 +94,17 @@ namespace Stride.Assets.Models
// Load asset reference skeleton
if (SkeletonUrl != null)
{
var skeleton = contentManager.Load<Skeleton>(SkeletonUrl);
var skeletonMapping = new SkeletonMapping(skeleton, modelSkeleton);
{
// Process missing nodes
foreach (var nodeAnimationClipEntry in animationClips)
{
var nodeName = nodeAnimationClipEntry.Key;
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
nodeName = nodeName.Replace(c, '_');
}
var nodeAnimationClip = nodeAnimationClipEntry.Value;
var nodeIndex = modelSkeleton.Nodes.IndexOf(x => x.Name == nodeName);
var nodeIndex = modelSkeleton.Nodes.IndexOf(x => x.Name == nodeName.ToString());
// Node doesn't exist in skeleton? skip it
if (nodeIndex == -1 || skeletonMapping.SourceToSource[nodeIndex] != nodeIndex)
continue;
@ -122,8 +125,8 @@ namespace Stride.Assets.Models
{
AnimationClip animationClipToMerge;
AnimationClipEvaluator animationClipEvaluator = null;
AnimationBlender animationBlender = null;
if (animationClips.TryGetValue(modelSkeleton.Nodes[currentNodeIndex].Name, out animationClipToMerge))
AnimationBlender animationBlender = null;
if(GetAnimationKeyVirtualKey(modelSkeleton.Nodes[currentNodeIndex].Name, animationClips, out animationClipToMerge))
{
animationBlender = new AnimationBlender();
animationClipEvaluator = animationBlender.CreateEvaluator(animationClipToMerge);
@ -142,13 +145,13 @@ namespace Stride.Assets.Models
foreach (var node in nodesToMerge)
{
if (node.Item3 != null)
foreach (var curve in node.Item3.Clip.Curves)
{
foreach (CompressedTimeSpan time in curve.Keys)
foreach (var curve in node.Item3.Clip.Curves)
{
animationKeysSet.Add(time);
foreach (CompressedTimeSpan time in curve.Keys)
{
animationKeysSet.Add(time);
}
}
}
}
// Sort key times
@ -172,7 +175,7 @@ namespace Stride.Assets.Models
foreach (var node in nodesToMerge)
{
// Needs to be an array in order for it to be modified by the UpdateEngine, otherwise it would get passed by value
var modelNodeDefinitions = new ModelNodeDefinition[1] {node.Item1};
var modelNodeDefinitions = new ModelNodeDefinition[1] { node.Item1 };
if (node.Item2 != null && node.Item3 != null)
{
@ -273,7 +276,6 @@ namespace Stride.Assets.Models
if (animationClip.Channels.Count == 0)
{
var logString = $"File {SourcePath} doesn't have any animation information.";
if (failOnEmptyAnimation)
{
commandContext.Logger.Error(logString);
@ -295,5 +297,24 @@ namespace Stride.Assets.Models
}
return animationClip;
}
public bool GetAnimationKeyVirtualKey(string vKey, Dictionary<string, AnimationClip> animationClips, out AnimationClip clip)
{
bool isFound = false;
AnimationClip outClip = null;
animationClips.ForEach(c =>
{
string _lineItem = c.Key;
System.IO.Path.GetInvalidFileNameChars().ForEach(x => { _lineItem = _lineItem.Replace(x, '_'); });
if (_lineItem == vKey)
{
outClip = c.Value;
isFound = true;
return;
}
});
clip = outClip;
return isFound;
}
}
}

Просмотреть файл

@ -16,10 +16,15 @@ namespace Stride.Assets.Models
// Round-trip through TargetToSource[SourceToTarget[i]] so that we know easily what nodes are remapped in source skeleton side
public readonly int[] SourceToSource;
public readonly string[] NodeNames;
public int MapCount=0;
public SkeletonMapping(Skeleton targetSkeleton, Skeleton sourceSkeleton)
{
SourceToTarget = new int[sourceSkeleton.Nodes.Length]; // model => skeleton mapping
SourceToSource = new int[sourceSkeleton.Nodes.Length]; // model => model mapping
NodeNames = new string[sourceSkeleton.Nodes.Length];
if (targetSkeleton == null)
{
@ -44,20 +49,23 @@ namespace Stride.Assets.Models
var parentModelIndex = node.ParentIndex;
// Find matching node in skeleton (or map to best parent)
var skeletonIndex = targetSkeleton.Nodes.IndexOf(x => x.Name == node.Name);
var skeletonIndex = targetSkeleton.Nodes.IndexOf(x => x.Name == node.Name);
if (skeletonIndex == -1)
{
// Nothing match, remap to parent node
SourceToTarget[modelIndex] = parentModelIndex != -1 ? SourceToTarget[parentModelIndex] : 0;
continue;
}
else
{
++MapCount;
}
// TODO: Check hierarchy for inconsistencies
// Name match
SourceToTarget[modelIndex] = skeletonIndex;
targetToSource[skeletonIndex] = modelIndex;
NodeNames[modelIndex] = node.Name;
}
for (int modelIndex = 0; modelIndex < sourceSkeleton.Nodes.Length; ++modelIndex)

Просмотреть файл

@ -28,10 +28,8 @@ namespace Stride.Assets.Models
public static ImportModelCommand Create(string extension)
{
if (ImportFbxCommand.IsSupportingExtensions(extension))
return new ImportFbxCommand();
if (ImportAssimpCommand.IsSupportingExtensions(extension))
return new ImportAssimpCommand();
if (ImportThreeDCommand.IsSupportingExtensions(extension))
return new ImportThreeDCommand();
return null;
}

Просмотреть файл

@ -15,9 +15,9 @@ using Stride.Rendering.Data;
namespace Stride.Assets.Models
{
[Description("Import Assimp")]
public class ImportAssimpCommand : ImportModelCommand
public class ImportThreeDCommand : ImportModelCommand
{
private static string[] supportedExtensions = AssimpAssetImporter.FileExtensions.Split(';');
private static string[] supportedExtensions = ThreeDAssetImporter.FileExtensions.Split(';');
/// <inheritdoc/>
public override string Title { get { string title = "Import Assimp "; try { title += Path.GetFileName(SourcePath) ?? "[File]"; } catch { title += "[INVALID PATH]"; } return title; } }
@ -32,9 +32,9 @@ namespace Stride.Assets.Models
return supportedExtensions.Any(supExt => supExt.Equals(extToLower));
}
private Stride.Importer.Assimp.MeshConverter CreateMeshConverter(ICommandContext commandContext)
private Stride.Importer.ThreeD.MeshConverter CreateMeshConverter(ICommandContext commandContext)
{
return new Stride.Importer.Assimp.MeshConverter(commandContext.Logger)
return new Stride.Importer.ThreeD.MeshConverter(commandContext.Logger)
{
AllowUnsignedBlendIndices = this.AllowUnsignedBlendIndices,
};

Просмотреть файл

@ -15,6 +15,8 @@ using Stride.Assets.Materials;
using Stride.Assets.Textures;
using Stride.Rendering;
using Stride.Importer.Common;
using System.IO;
using System.Text;
namespace Stride.Assets.Models
{
@ -58,7 +60,7 @@ namespace Stride.Assets.Models
/// <param name="importParameters">The import parameters.</param>
/// <param name="startTime">Returns the first (start) keyframe's time for the animation</param>
/// <param name="endTime">Returns the last (end) keyframe's time for the animation</param>
public abstract void GetAnimationDuration(UFile localPath, Logger logger, AssetImporterParameters importParameters, out TimeSpan startTime, out TimeSpan endTime);
public abstract void GetAnimationDuration(UFile localPath, Logger logger, AssetImporterParameters importParameters, int animIndex, out TimeSpan startTime, out TimeSpan endTime);
/// <summary>
/// Imports the model.
@ -85,7 +87,7 @@ namespace Stride.Assets.Models
// 1. Textures
if (isImportingTexture)
{
ImportTextures(entityInfo.TextureDependencies, rawAssetReferences);
ImportTextures(entityInfo.TextureDependencies, rawAssetReferences, importParameters.Logger);
}
// 2. Skeleton
@ -98,10 +100,18 @@ namespace Stride.Assets.Models
// 3. Animation
if (importParameters.IsTypeSelectedForOutput<AnimationAsset>())
{
TimeSpan startTime, endTime;
GetAnimationDuration(localPath, importParameters.Logger, importParameters, out startTime, out endTime);
int _iAnimIndex = 0;
entityInfo?.AnimationNodes?.ForEach(c =>
{
TimeSpan startTime, endTime;
GetAnimationDuration(localPath, importParameters.Logger, importParameters, _iAnimIndex, out startTime, out endTime);
ImportAnimation(rawAssetReferences, localPath, entityInfo.AnimationNodes, isImportingModel, skeletonAsset, startTime, endTime);
ImportAnimation(rawAssetReferences, localPath, entityInfo.AnimationNodes[_iAnimIndex], _iAnimIndex, skeletonAsset, startTime, endTime);
_iAnimIndex++;
});
}
// 4. Materials
@ -157,6 +167,32 @@ namespace Stride.Assets.Models
}
}
private static void ImportAnimation(List<AssetItem> assetReferences, UFile localPath, string animationNodeName, int animationNodeIndex, AssetItem skeletonAsset, TimeSpan animationStartTime, TimeSpan animationEndTime)
{
var assetSource = localPath;
var asset = new AnimationAsset { Source = assetSource, AnimationTimeMaximum = animationEndTime, AnimationTimeMinimum = animationStartTime };
var animNodePostFix = new StringBuilder();
foreach (var charNodeName in animationNodeName)
{
if (Path.GetInvalidFileNameChars().Contains(charNodeName))
{
animNodePostFix.Append("_");
}
else
{
animNodePostFix.Append(charNodeName);
}
}
var animUrl = localPath.GetFileNameWithoutExtension() + "_" + animNodePostFix.ToString();
asset.AnimationStack = animationNodeIndex;
if (skeletonAsset != null)
asset.Skeleton = AttachedReferenceManager.CreateProxyObject<Skeleton>(skeletonAsset.Id, skeletonAsset.Location);
assetReferences.Add(new AssetItem(animUrl, asset));
}
private static void ImportModel(List<AssetItem> assetReferences, UFile assetSource, UFile localPath, EntityInfo entityInfo, bool shouldPostFixName, AssetItem skeletonAsset)
{
var asset = new ModelAsset { Source = assetSource };
@ -284,13 +320,19 @@ namespace Stride.Assets.Models
//}
}
private static void ImportTextures(IEnumerable<string> textureDependencies, List<AssetItem> assetReferences)
private static void ImportTextures(IEnumerable<string> textureDependencies, List<AssetItem> assetReferences, Logger logger)
{
if (textureDependencies == null)
return;
foreach (var textureFullPath in textureDependencies.Distinct(x => x))
{
if (!File.Exists(textureFullPath))
{
string texName = Path.GetFileNameWithoutExtension(textureFullPath)??"<unknown>";
logger.Error($"Texture with name {texName} not found");
continue;
}
var texturePath = new UFile(textureFullPath);
var source = texturePath;

Просмотреть файл

@ -13,9 +13,8 @@
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\tools\Stride.Importer.Assimp\Stride.Importer.Assimp.csproj" />
<ProjectReference Include="..\..\tools\Stride.Importer.Common\Stride.Importer.Common.csproj" />
<ProjectReference Include="..\..\tools\Stride.Importer.FBX\Stride.Importer.FBX.vcxproj" PrivateAssets="All" />
<ProjectReference Include="..\..\tools\Stride.Importer.3D\Stride.Importer.3D.csproj" />
<ProjectReference Include="..\Stride.Assets\Stride.Assets.csproj" />
</ItemGroup>
<ItemGroup>
@ -32,16 +31,12 @@
<ItemGroup>
<!-- Needed by .NET Core runtime to be able to load C++/CLI assemblies -->
<BuildOutputInPackage Include="$(OutputPath)ijwhost.dll" Condition="Exists('$(OutputPath)ijwhost.dll')" />
<BuildOutputInPackage Include="$(OutputPath)Stride.Importer.Assimp.dll" />
<BuildOutputInPackage Include="$(OutputPath)Stride.Importer.FBX.dll" />
<BuildOutputInPackage Include="$(OutputPath)Stride.Importer.FBX.ssdeps" />
<BuildOutputInPackage Include="$(OutputPath)Stride.Importer.Common.dll" />
</ItemGroup>
</Target>
<Target Name="_StrideIncludeNativeLibs">
<ItemGroup>
<TfmSpecificPackageFile Include="$(OutputPath)runtimes\win-x64\native\libfbxsdk.dll" PackagePath="runtimes\win-x64\native\libfbxsdk.dll" />
</ItemGroup>
</Target>
</Project>

Просмотреть файл

@ -12,10 +12,10 @@ using Stride.Importer.Common;
namespace Stride.Assets.Models
{
public class AssimpAssetImporter : ModelAssetImporter
public class ThreeDAssetImporter : ModelAssetImporter
{
// Supported file extensions for this importer
internal const string FileExtensions = ".dae;.3ds;.gltf;.glb;.obj;.blend;.x;.md2;.md3;.dxf;.ply;.stl;.stp";
internal const string FileExtensions = ".dae;.3ds;.gltf;.glb;.obj;.blend;.x;.md2;.md3;.dxf;.ply;.stl;.stp;.fbx;";
private static readonly Guid Uid = new Guid("30243FC0-CEC7-4433-977E-95DCA29D846E");
@ -28,7 +28,7 @@ namespace Stride.Assets.Models
/// <inheritdoc/>
public override EntityInfo GetEntityInfo(UFile localPath, Logger logger, AssetImporterParameters importParameters)
{
var meshConverter = new Importer.Assimp.MeshConverter(logger);
var meshConverter = new Importer.ThreeD.MeshConverter(logger);
if (!importParameters.InputParameters.TryGet(DeduplicateMaterialsKey, out var deduplicateMaterials))
deduplicateMaterials = true; // Dedupe is the default value
@ -38,10 +38,10 @@ namespace Stride.Assets.Models
}
/// <inheritdoc/>
public override void GetAnimationDuration(UFile localPath, Logger logger, AssetImporterParameters importParameters, out TimeSpan startTime, out TimeSpan endTime)
public override void GetAnimationDuration(UFile localPath, Logger logger, AssetImporterParameters importParameters, int animIndex, out TimeSpan startTime, out TimeSpan endTime)
{
var meshConverter = new Importer.Assimp.MeshConverter(logger);
var sceneData = meshConverter.ConvertAnimation(localPath.FullPath, "", 0);
var meshConverter = new Importer.ThreeD.MeshConverter(logger);
var sceneData = meshConverter.ConvertAnimation(localPath.FullPath, "", animIndex);
startTime = CompressedTimeSpan.MaxValue; // This will go down, so we start from positive infinity
endTime = CompressedTimeSpan.MinValue; // This will go up, so we start from negative infinity

Просмотреть файл

@ -1,9 +1,9 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System;
namespace Stride.Importer.Assimp.Material
namespace Stride.Importer.ThreeD.Material
{
/// <summary>
/// Enumeration of the new Assimp's flags.

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
namespace Stride.Importer.Assimp.Material
namespace Stride.Importer.ThreeD.Material
{
/// <summary>
/// Enumeration of the different mapping modes in the new Assimp's material stack.

Просмотреть файл

@ -1,9 +1,9 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System.Collections.Generic;
namespace Stride.Importer.Assimp.Material
namespace Stride.Importer.ThreeD.Material
{
/// <summary>
/// Class representing the new Assimp's material stack in c#.

Просмотреть файл

@ -1,10 +1,11 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using Silk.NET.Assimp;
using Stride.Core.Diagnostics;
using Stride.Core.Mathematics;
namespace Stride.Importer.Assimp.Material
namespace Stride.Importer.ThreeD.Material
{
public static unsafe class Materials
{
@ -76,7 +77,7 @@ namespace Stride.Importer.Assimp.Material
MappingMode.Decal // aiTextureMapMode_Decal
};
public static unsafe MaterialStack ConvertAssimpStackCppToCs(Silk.NET.Assimp.Assimp assimp, Silk.NET.Assimp.Material* material, Silk.NET.Assimp.TextureType type)
public static unsafe MaterialStack ConvertAssimpStackCppToCs(Silk.NET.Assimp.Assimp assimp, Silk.NET.Assimp.Material* material, Silk.NET.Assimp.TextureType type, Logger logger)
{
var ret = new MaterialStack();
var count = (int)assimp.GetMaterialTextureCount(material, type);
@ -110,20 +111,31 @@ namespace Stride.Importer.Assimp.Material
{
case StackElementType.Operation:
if (assimp.GetMaterialIntegerArray(material, Silk.NET.Assimp.Assimp.MaterialTexopBase, (uint)type, (uint)iEl, ref elOp, ref pMax) != Return.Success)
{
logger?.Error("Material not found");
continue; // error !
}
el = new StackOperation(ConvertAssimpStackOperationCppToCs[elOp], elAlpha, elBlend, elFlags);
break;
case StackElementType.Color:
if (assimp.GetMaterialColor(material, MatKeyTexColorBase, (uint)type, (uint)iEl, ref elColor) != Return.Success)
{
logger?.Error("Material with index not found");
continue; // error !
}
el = new StackColor(new Color3(elColor.X, elColor.Y, elColor.Z), elAlpha, elBlend, elFlags);
break;
case StackElementType.Texture:
if (assimp.GetMaterialString(material, Silk.NET.Assimp.Assimp.MaterialTextureBase, (uint)type, (uint)iEl, ref elTexPath) != Return.Success)
{
logger?.Error("Material texture item not found");
continue; // error !
}
if (assimp.GetMaterialIntegerArray(material, Silk.NET.Assimp.Assimp.MaterialUvwsrcBase, (uint)type, (uint)iEl, ref elTexChannel, ref pMax) != Return.Success)
elTexChannel = 0; // default channel
{
logger?.Error("Material integer item not found");
continue; // error !
}
if (assimp.GetMaterialIntegerArray(material, Silk.NET.Assimp.Assimp.MaterialMappingmodeUBase, (uint)type, (uint)iEl, ref elMappingModeU, ref pMax) != Return.Success)
elMappingModeU = (int)TextureMapMode.Wrap; // default mapping mode
if (assimp.GetMaterialIntegerArray(material, Silk.NET.Assimp.Assimp.MaterialMappingmodeVBase, (uint)type, (uint)iEl, ref elMappingModeV, ref pMax) != Return.Success)

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
namespace Stride.Importer.Assimp.Material
namespace Stride.Importer.ThreeD.Material
{
/// <summary>
/// Enumeration of the different operations in the new Assimp's material stack.

Просмотреть файл

@ -1,9 +1,9 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using Stride.Core.Mathematics;
namespace Stride.Importer.Assimp.Material
namespace Stride.Importer.ThreeD.Material
{
/// <summary>
/// Class representing a color in the new Assimp's material stack.

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
namespace Stride.Importer.Assimp.Material
namespace Stride.Importer.ThreeD.Material
{
/// <summary>
/// Class representing an element in the new Assimp's material stack.

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
namespace Stride.Importer.Assimp.Material
namespace Stride.Importer.ThreeD.Material
{
/// <summary>
/// Enumeration of the different types of node in the new Assimp's material stack.

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
namespace Stride.Importer.Assimp.Material
namespace Stride.Importer.ThreeD.Material
{
/// <summary>
/// Class representing an operation in the new Assimp's material stack.

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
namespace Stride.Importer.Assimp.Material
namespace Stride.Importer.ThreeD.Material
{
/// <summary>
/// Class representing a texture in the new Assimp's material stack.

Просмотреть файл

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Silk.NET.Assimp;
using Stride.Animations;
using Stride.Assets.Materials;
@ -13,6 +14,7 @@ using Stride.Core.Diagnostics;
using Stride.Core.IO;
using Stride.Core.Mathematics;
using Stride.Core.Serialization;
using Stride.Engine;
using Stride.Graphics;
using Stride.Graphics.Data;
using Stride.Importer.Common;
@ -21,11 +23,32 @@ using Stride.Rendering.Materials;
using Stride.Rendering.Materials.ComputeColors;
using Mesh = Stride.Rendering.Mesh;
using PrimitiveType = Stride.Graphics.PrimitiveType;
using Scene = Silk.NET.Assimp.Scene;
namespace Stride.Importer.Assimp
namespace Stride.Importer.ThreeD
{
public class MeshConverter
{
static class PostProcessActions
{
public const uint CalculateTangentSpace = 1;
public const uint Triangulate = 8;
public const uint GenerateNormals = 32;
public const uint JoinIdenticalVertices = 2;
public const uint LimitBoneWeights = 512;
public const uint SortByPrimitiveType = 32768;
public const uint FlipWindingOrder = 16777216;
public const uint FlipUVs = 8388608;
public const uint GenSmoothNormals = 64;
public const uint ImproveCacheLocality = 2048;
public const uint RemoveRedundantMaterials = 4096;
public const uint SplitLargeMeshes = 128;
public const uint GenUVCoords = 262144;
public const uint GlobalScaling = 134217728;
public const uint OptimizeGraph = 4194304;
}
static MeshConverter()
{
if (Platform.Type == PlatformType.Windows)
@ -42,7 +65,6 @@ namespace Stride.Importer.Assimp
public bool AllowUnsignedBlendIndices { get; set; }
// Conversion data
private string vfsInputFilename;
private string vfsOutputFilename;
@ -79,7 +101,7 @@ namespace Stride.Importer.Assimp
postProcessFlags |= PostProcessSteps.RemoveRedundantMaterials;
}
var scene = Initialize(inputFilename, outputFilename, importFlags, (uint)postProcessFlags);
var scene = Initialize(inputFilename, outputFilename, importFlags, 0);
// If scene is null, something went wrong inside Assimp
if (scene == null)
@ -113,7 +135,7 @@ namespace Stride.Importer.Assimp
return entityInfo;
}
catch(Exception ex)
catch (Exception ex)
{
Logger.Error($"Exception has occured during Entity extraction : {ex.Message}");
throw;
@ -123,31 +145,15 @@ namespace Stride.Importer.Assimp
public unsafe Model Convert(string inputFilename, string outputFilename, bool deduplicateMaterials)
{
uint importFlags = 0;
var postProcessFlags =
PostProcessSteps.CalculateTangentSpace
| PostProcessSteps.Triangulate
| PostProcessSteps.GenerateNormals
| PostProcessSteps.JoinIdenticalVertices
| PostProcessSteps.LimitBoneWeights
| PostProcessSteps.SortByPrimitiveType
| PostProcessSteps.FlipWindingOrder
| PostProcessSteps.FlipUVs;
if (deduplicateMaterials)
{
postProcessFlags |= PostProcessSteps.RemoveRedundantMaterials;
}
var scene = Initialize(inputFilename, outputFilename, importFlags, (uint)postProcessFlags);
var scene = Initialize(inputFilename, outputFilename, importFlags, 0);
return ConvertAssimpScene(scene);
}
public unsafe AnimationInfo ConvertAnimation(string inputFilename, string outputFilename, int animationIndex)
{
uint importFlags = 0;
var postProcessFlags = PostProcessSteps.None;
var scene = Initialize(inputFilename, outputFilename, importFlags, (uint)postProcessFlags);
var scene = Initialize(inputFilename, outputFilename, importFlags, 0);
return ProcessAnimations(scene, animationIndex);
}
@ -157,7 +163,7 @@ namespace Stride.Importer.Assimp
uint importFlags = 0;
var postProcessFlags = PostProcessSteps.None;
var scene = Initialize(inputFilename, outputFilename, importFlags, (uint)postProcessFlags);
var scene = Initialize(inputFilename, outputFilename, importFlags, 0);
return ProcessSkeleton(scene);
}
@ -170,9 +176,21 @@ namespace Stride.Importer.Assimp
vfsOutputFilename = outputFilename;
vfsInputPath = VirtualFileSystem.GetParentFolder(inputFilename);
var scene = assimp.ImportFile(inputFilename, importFlags);
scene = assimp.ApplyPostProcessing(scene, postProcessFlags);
var propStore = assimp.CreatePropertyStore();
assimp.SetImportPropertyInteger(propStore, "IMPORT_FBX_PRESERVE_PIVOTS", 0);
assimp.SetImportPropertyFloat(propStore, "APP_SCALE_FACTOR", .01f);
var scene = assimp.ImportFileExWithProperties(inputFilename, importFlags, null, propStore);
var postProcessFlags1 = PostProcessActions.CalculateTangentSpace
| PostProcessActions.Triangulate
| PostProcessActions.GenerateNormals
| PostProcessActions.SortByPrimitiveType
| PostProcessActions.FlipWindingOrder
| PostProcessActions.FlipUVs
| PostProcessActions.GlobalScaling;
scene = assimp.ApplyPostProcessing(scene, postProcessFlags1);
assimp.ReleasePropertyStore(propStore);
return scene;
}
@ -188,7 +206,7 @@ namespace Stride.Importer.Assimp
// register the nodes and fill hierarchy
var meshIndexToNodeIndex = new Dictionary<int, List<int>>();
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex);
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex, GetBoneList(scene));
// meshes
for (var i = 0; i < scene->MNumMeshes; ++i)
@ -204,7 +222,7 @@ namespace Stride.Importer.Assimp
Draw = meshInfo.Draw,
Name = meshInfo.Name,
MaterialIndex = meshInfo.MaterialIndex,
NodeIndex = nodeIndex
NodeIndex = nodeIndex,
};
if (meshInfo.Bones != null)
@ -221,6 +239,7 @@ namespace Stride.Importer.Assimp
if (meshInfo.HasSkinningNormal && meshInfo.TotalClusterCount > 0)
nodeMeshData.Parameters.Set(MaterialKeys.HasSkinningNormal, true);
modelData.Meshes.Add(nodeMeshData);
}
}
@ -242,7 +261,7 @@ namespace Stride.Importer.Assimp
// register the nodes and fill hierarchy
var meshIndexToNodeIndex = new Dictionary<int, List<int>>();
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex);
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex, GetBoneList(scene));
return new Rendering.Skeleton
{
@ -260,7 +279,7 @@ namespace Stride.Importer.Assimp
// register the nodes and fill hierarchy
var meshIndexToNodeIndex = new Dictionary<int, List<int>>();
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex);
RegisterNodes(scene->MRootNode, -1, nodeNames, meshIndexToNodeIndex, GetBoneList(scene));
if (scene->MNumAnimations > 0)
{
@ -287,7 +306,7 @@ namespace Stride.Importer.Assimp
// Nevertheless the second one do not seems to be usable in assimp 3.0 so it will be ignored here.
// name of the animation (dropped)
var animName = aiAnim->MName.AsString; // used only be the logger
var animName = aiAnim->MName.AsString.CleanNodeName(); // used only be the logger
// animation using meshes (not supported)
for (uint meshAnimId = 0; meshAnimId < aiAnim->MNumMeshChannels; ++meshAnimId)
@ -300,7 +319,7 @@ namespace Stride.Importer.Assimp
for (uint nodeAnimId = 0; nodeAnimId < aiAnim->MNumChannels; ++nodeAnimId)
{
var nodeAnim = aiAnim->MChannels[nodeAnimId];
var nodeName = nodeAnim->MNodeName.AsString;
var nodeName = nodeAnim->MNodeName.AsString.CleanNodeName();
if (!visitedNodeNames.Contains(nodeName))
{
@ -321,7 +340,7 @@ namespace Stride.Importer.Assimp
private unsafe void ProcessNodeAnimation(Dictionary<string, AnimationClip> animationClips, NodeAnim* nodeAnim, double ticksPerSec)
{
// Find the nodes on which the animation is performed
var nodeName = nodeAnim->MNodeName.AsString;
var nodeName = nodeAnim->MNodeName.AsString.CleanNodeName();
var animationClip = new AnimationClip();
@ -419,23 +438,7 @@ namespace Stride.Importer.Assimp
for (var i = 0; i < baseNames.Count; ++i)
{
// Clean the name by removing unwanted characters
var itemName = baseNames[i];
var itemNameSplitPosition = itemName.IndexOf('#');
if (itemNameSplitPosition != -1)
{
itemName = itemName.Substring(0, itemNameSplitPosition);
}
itemNameSplitPosition = itemName.IndexOf("__", StringComparison.Ordinal);
if (itemNameSplitPosition != -1)
{
itemName = itemName.Substring(0, itemNameSplitPosition);
}
// remove all bad characters
itemName = itemName.Replace(':', '_');
itemName = itemName.Replace(" ", string.Empty);
var itemName = baseNames[i].CleanNodeName();
tempNames.Add(itemName);
@ -465,15 +468,34 @@ namespace Stride.Importer.Assimp
}
}
private unsafe HashSet<string> GetBoneList(Scene* scene)
{
HashSet<string> bones = new HashSet<string>();
for (uint i = 0; i < scene->MNumMeshes; i++)
{
var lMesh = scene->MMeshes[i];
var boneCount = lMesh->MNumBones;
for (int j = 0; j < boneCount; j++)
{
string boneName = lMesh->MBones[j]->MName.AsString;
if(!bones.Contains(boneName))
{
bones.Add(boneName);
}
}
}
return bones;
}
private unsafe void GenerateMeshNames(Scene* scene, Dictionary<IntPtr, string> meshNames)
{
var baseNames = new List<string>();
for (uint i = 0; i < scene->MNumMeshes; i++)
{
var lMesh = scene->MMeshes[i];
baseNames.Add(lMesh->MName.AsString);
baseNames.Add(lMesh->MName.AsString.CleanNodeName());
}
GenerateUniqueNames(meshNames, baseNames, i => (IntPtr)scene->MMeshes[i]);
}
@ -483,7 +505,7 @@ namespace Stride.Importer.Assimp
for (uint i = 0; i < scene->MNumAnimations; i++)
{
var lAnimation = scene->MAnimations[i];
var animationName = lAnimation->MName.AsString;
var animationName = lAnimation->MName.AsString.CleanNodeName();
baseNames.Add(animationName);
}
@ -501,7 +523,7 @@ namespace Stride.Importer.Assimp
private unsafe void GetNodeNames(Node* node, List<string> nodeNames, List<IntPtr> orderedNodes)
{
nodeNames.Add(node->MName.AsString);
nodeNames.Add(node->MName.AsString.CleanNodeName());
orderedNodes.Add((IntPtr)node);
for (uint i = 0; i < node->MNumChildren; ++i)
@ -510,7 +532,7 @@ namespace Stride.Importer.Assimp
}
}
private unsafe void RegisterNodes(Node* fromNode, int parentIndex, Dictionary<IntPtr, string> nodeNames, Dictionary<int, List<int>> meshIndexToNodeIndex)
private unsafe void RegisterNodes(Node* fromNode, int parentIndex, Dictionary<IntPtr, string> nodeNames, Dictionary<int, List<int>> meshIndexToNodeIndex, HashSet<string> filterInNodes)
{
var nodeIndex = nodes.Count;
@ -536,8 +558,10 @@ namespace Stride.Importer.Assimp
Flags = ModelNodeFlags.Default
};
var meshes = fromNode->MMeshes;
// Extract scene scaling and rotation from the root node.
// Bake scaling into all node's positions and rotation into the 1st-level nodes.
if (parentIndex == -1)
{
rootTransform = fromNode->MTransformation.ToStrideMatrix();
@ -552,16 +576,27 @@ namespace Stride.Importer.Assimp
}
else
{
var transform = rootTransformInverse * fromNode->MTransformation.ToStrideMatrix() * rootTransform;
var transform = fromNode->MTransformation.ToStrideMatrix();
transform.Decompose(out modelNodeDefinition.Transform.Scale, out modelNodeDefinition.Transform.Rotation, out modelNodeDefinition.Transform.Position);
}
if (filterInNodes!=null
&& filterInNodes.Count>0)
{
if(!filterInNodes.Contains(fromNode->MName.AsString))
{
modelNodeDefinition.Transform.Rotation = Quaternion.Identity;
modelNodeDefinition.Transform.Scale = Vector3.One;
modelNodeDefinition.Transform.Position = Vector3.Zero;
}
}
nodes.Add(modelNodeDefinition);
// register the children
for (uint child = 0; child < fromNode->MNumChildren; ++child)
{
RegisterNodes(fromNode->MChildren[child], nodeIndex, nodeNames, meshIndexToNodeIndex);
RegisterNodes(fromNode->MChildren[child], nodeIndex, nodeNames, meshIndexToNodeIndex, filterInNodes);
}
}
@ -571,7 +606,7 @@ namespace Stride.Importer.Assimp
var hasSkinningPosition = false;
var hasSkinningNormal = false;
var totalClusterCount = 0;
var drawData = new MeshDraw();
// Build the bone's indices/weights and attach bones to NodeData
//(bones info are present in the mesh so that is why we have to perform that here)
@ -603,7 +638,11 @@ namespace Stride.Importer.Assimp
// find the node where the bone is mapped - based on the name(?)
var nodeIndex = -1;
var boneName = bone->MName.AsString;
var boneName = bone->MName.AsString.CleanNodeName();
foreach (char c in Path.GetInvalidFileNameChars())
{
boneName = boneName.Replace(c, '_');
}
for (var nodeDefId = 0; nodeDefId < nodes.Count; ++nodeDefId)
{
var nodeDef = nodes[nodeDefId];
@ -623,7 +662,8 @@ namespace Stride.Importer.Assimp
bones.Add(new MeshBoneDefinition
{
NodeIndex = nodeIndex,
LinkToMeshMatrix = rootTransformInverse * bone->MOffsetMatrix.ToStrideMatrix() * rootTransform
LinkToMeshMatrix = bone->MOffsetMatrix.ToStrideMatrix()
// LinkToMeshMatrix = rootTransformInverse * bone->MOffsetMatrix.ToStrideMatrix() * rootTransform
});
}
@ -825,6 +865,8 @@ namespace Stride.Importer.Assimp
for (int j = 0; j < 3; ++j)
{
*((uint*)ibPointer) = mesh->MFaces[(int)i].MIndices[j];
var _index = (ushort)(mesh->MFaces[(int)i].MIndices[j]);
ibPointer += sizeof(uint);
}
}
@ -833,6 +875,7 @@ namespace Stride.Importer.Assimp
for (int j = 0; j < 3; ++j)
{
*((ushort*)ibPointer) = (ushort)(mesh->MFaces[(int)i].MIndices[j]);
var _index = (ushort)(mesh->MFaces[(int)i].MIndices[j]);
ibPointer += sizeof(ushort);
}
}
@ -844,13 +887,12 @@ namespace Stride.Importer.Assimp
var vertexBufferBinding = new VertexBufferBinding(GraphicsSerializerExtensions.ToSerializableVersion(new BufferData(BufferFlags.VertexBuffer, vertexBuffer)), vertexDeclaration, (int)mesh->MNumVertices, vertexDeclaration.VertexStride, 0);
var indexBufferBinding = new IndexBufferBinding(GraphicsSerializerExtensions.ToSerializableVersion(new BufferData(BufferFlags.IndexBuffer, indexBuffer)), is32BitIndex, (int)nbIndices, 0);
var drawData = new MeshDraw
{
VertexBuffers = new VertexBufferBinding[] { vertexBufferBinding },
IndexBuffer = indexBufferBinding,
PrimitiveType = PrimitiveType.TriangleList,
DrawCount = (int)nbIndices
};
drawData.VertexBuffers = new VertexBufferBinding[] { vertexBufferBinding };
drawData.IndexBuffer = indexBufferBinding;
drawData.PrimitiveType = PrimitiveType.TriangleList;
drawData.DrawCount = (int)nbIndices;
return new MeshInfo
{
@ -862,6 +904,8 @@ namespace Stride.Importer.Assimp
HasSkinningNormal = hasSkinningNormal,
TotalClusterCount = totalClusterCount
};
}
private void NormalizeVertexWeights(List<List<(short, float)>> controlPts, int nbBoneByVertex)
@ -986,7 +1030,7 @@ namespace Stride.Importer.Assimp
}
private unsafe void SetMaterialFloatArrayFlag(Silk.NET.Assimp.Material* pMaterial, string materialBase, ref bool hasMatProperty, float matColor, bool condition)
{
if(assimp.GetMaterialFloatArray(pMaterial, materialBase, 0, 0, &matColor, (uint*)0x0) == Return.Success && condition)
if (assimp.GetMaterialFloatArray(pMaterial, materialBase, 0, 0, &matColor, (uint*)0x0) == Return.Success && condition)
{
hasMatProperty = true;
}
@ -1095,7 +1139,7 @@ namespace Stride.Importer.Assimp
private unsafe IComputeColor GenerateOneTextureTypeLayers(Silk.NET.Assimp.Material* pMat, TextureType textureType, int textureCount, MaterialAsset finalMaterial)
{
var stack = Material.Materials.ConvertAssimpStackCppToCs(assimp, pMat, textureType);
var stack = Material.Materials.ConvertAssimpStackCppToCs(assimp, pMat, textureType, Logger);
var compositionFathers = new Stack<IComputeColor>();
@ -1393,4 +1437,7 @@ namespace Stride.Importer.Assimp
public List<MaterialInstantiation> Instances = new();
public string MaterialsName;
}
}

Просмотреть файл

@ -14,6 +14,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Analysis\" />
<Folder Include="Material\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Silk.NET.Assimp" />

Просмотреть файл

@ -4,9 +4,11 @@
using Silk.NET.Assimp;
using Stride.Animations;
using Stride.Core.Mathematics;
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Stride.Importer.Assimp
namespace Stride.Importer.ThreeD
{
public static class Utils
{
@ -24,13 +26,13 @@ namespace Stride.Importer.Assimp
}
public static Core.Mathematics.Vector3 ToStrideVector3(this System.Numerics.Vector3 v)
=> new Core.Mathematics.Vector3(v.X, v.Y, v.Z);
=> Unsafe.As<System.Numerics.Vector3, Core.Mathematics.Vector3>(ref v);
public static Color ToStrideColor(this System.Numerics.Vector4 v)
=> new Color(v.X, v.Y, v.Z, v.W);
public static Core.Mathematics.Quaternion ToStrideQuaternion(this AssimpQuaternion q)
=> new Core.Mathematics.Quaternion(q.X, q.Y, q.Z, q.W);
=> new Core.Mathematics.Quaternion(q.X, q.Y, q.Z, q.W);
public static unsafe uint GetNumUVChannels(Silk.NET.Assimp.Mesh* mesh)
{
@ -59,5 +61,36 @@ namespace Stride.Importer.Assimp
var sdTime = CompressedTimeSpan.TicksPerSecond / aiTickPerSecond * time;
return new CompressedTimeSpan((int)sdTime);
}
public static string CleanNodeName(this string itemName)
{
if (string.IsNullOrWhiteSpace(itemName)) { return itemName; }
var itemNameSplitPosition = itemName.IndexOf('#');
if (itemNameSplitPosition != -1)
{
itemName = itemName.Substring(0, itemNameSplitPosition);
}
itemNameSplitPosition = itemName.IndexOf("__", StringComparison.Ordinal);
if (itemNameSplitPosition != -1)
{
itemName = itemName.Substring(0, itemNameSplitPosition);
}
itemNameSplitPosition = itemName.LastIndexOf(":", StringComparison.Ordinal);
if (itemNameSplitPosition != -1)
{
if (itemName.Length > itemNameSplitPosition + 1)
{
itemName = itemName.Substring(itemNameSplitPosition + 1);
}
}
// remove all bad characters
itemName = itemName.Replace(':', '_');
itemName = itemName.Replace(" ", string.Empty);
return itemName;
}
}
}

Просмотреть файл

@ -1,868 +0,0 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
#pragma once
#include "stdafx.h"
#include "SceneMapping.h"
using namespace System;
using namespace System::Text;
using namespace System::IO;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
using namespace Stride::Core::Mathematics;
using namespace Stride::Importer::Common;
namespace Stride {
namespace Importer {
namespace FBX {
ref class AnimationConverter
{
private:
Logger^ logger;
FbxScene* scene;
bool exportedFromMaya;
SceneMapping^ sceneMapping;
CompressedTimeSpan animStartTime;
public:
AnimationConverter(Logger^ logger, SceneMapping^ sceneMapping)
{
if (logger == nullptr) throw gcnew ArgumentNullException("logger");
if (sceneMapping == nullptr) throw gcnew ArgumentNullException("sceneMapping");
this->logger = logger;
this->sceneMapping = sceneMapping;
this->scene = sceneMapping->Scene;
auto documentInfo = scene->GetDocumentInfo();
if (documentInfo->Original_ApplicationName.Get() == "Maya")
exportedFromMaya = true;
}
bool HasAnimationData()
{
int animStackCount = scene->GetMemberCount<FbxAnimStack>();
if (animStackCount > 0)
{
bool check = true;
for (int i = 0; i < animStackCount && check; ++i)
{
FbxAnimStack* animStack = scene->GetMember<FbxAnimStack>(i);
int animLayerCount = animStack->GetMemberCount<FbxAnimLayer>();
FbxAnimLayer* animLayer = animStack->GetMember<FbxAnimLayer>(0);
check = check && CheckAnimationData(animLayer, scene->GetRootNode());
}
return check;
}
return false;
}
AnimationInfo^ ProcessAnimation(String^ inputFilename, String^ vfsOutputFilename, bool importCustomAttributeAnimations, int animationStack)
{
auto animationData = gcnew AnimationInfo();
int animStackCount = scene->GetMemberCount<FbxAnimStack>();
if (animStackCount == 0)
return animationData;
if (animationStack < 0)
{
animationStack = 0;
logger->Warning(String::Format("Animation stack specified in '{0}' less than zero, exporting first stack to '{1}",
gcnew String(inputFilename), gcnew String(vfsOutputFilename)), (CallerInfo^)nullptr);
}
if (animationStack >= animStackCount)
{
animationStack = animStackCount - 1;
logger->Warning(String::Format("Animation stack count in '{0}' greater than specified stack index, exporting last available stack to '{1}",
gcnew String(inputFilename), gcnew String(vfsOutputFilename)), (CallerInfo^)nullptr);
}
FbxAnimStack* animStack = scene->GetMember<FbxAnimStack>(animationStack);
int animLayerCount = animStack->GetMemberCount<FbxAnimLayer>();
// We support only anim layer count == 1
if (animLayerCount > 1)
{
logger->Warning(String::Format("Multiple FBX animation layers detected in '{0}', exporting only the first one to '{1}'",
gcnew String(inputFilename), gcnew String(vfsOutputFilename)), (CallerInfo^)nullptr);
}
FbxAnimLayer* animLayer = animStack->GetMember<FbxAnimLayer>(0);
FbxTime animStart, animEnd;
// Store start/end info
const FbxTakeInfo* take_info = scene->GetTakeInfo(animStack->GetName());
if (take_info)
{
animStart = take_info->mLocalTimeSpan.GetStart();
animEnd = take_info->mLocalTimeSpan.GetStop();
}
else
{
// Take the time line value.
FbxTimeSpan lTimeLineTimeSpan;
scene->GetGlobalSettings().GetTimelineDefaultTimeSpan(lTimeLineTimeSpan);
animStart = lTimeLineTimeSpan.GetStart();
animEnd = lTimeLineTimeSpan.GetStop();
}
animStartTime = FBXTimeToTimeSpan(animStart);
// Optimized code
// From http://www.the-area.com/forum/autodesk-fbx/fbx-sdk/resetpivotsetandconvertanimation-issue/page-1/
scene->GetRootNode()->ResetPivotSet(FbxNode::eDestinationPivot);
SetPivotStateRecursive(scene->GetRootNode());
scene->GetRootNode()->ConvertPivotAnimationRecursive(animStack, FbxNode::eDestinationPivot, 30.0f);
ProcessAnimationByNode(animationData->AnimationClips, animLayer, scene->GetRootNode(), importCustomAttributeAnimations);
scene->GetRootNode()->ResetPivotSet(FbxNode::eSourcePivot);
// Set duration
// Note: we can't use animEnd - animStart since some FBX has wrong data there
for each (auto animationClip in animationData->AnimationClips)
{
if (animationData->Duration < animationClip.Value->Duration)
animationData->Duration = animationClip.Value->Duration;
}
// Reference code (Uncomment Optimized code to use this part)
//scene->SetCurrentAnimationStack(animStack);
//ProcessAnimation(animationClip, animStack, scene->GetRootNode());
return animationData;
}
List<String^>^ ExtractAnimationNodesNoInit()
{
int animStackCount = scene->GetMemberCount<FbxAnimStack>();
List<String^>^ animationNodes = nullptr;
if (animStackCount > 0)
{
animationNodes = gcnew List<String^>();
for (int i = 0; i < animStackCount; ++i)
{
FbxAnimStack* animStack = scene->GetMember<FbxAnimStack>(i);
int animLayerCount = animStack->GetMemberCount<FbxAnimLayer>();
FbxAnimLayer* animLayer = animStack->GetMember<FbxAnimLayer>(0);
GetAnimationNodes(animLayer, scene->GetRootNode(), animationNodes);
}
}
return animationNodes;
}
private:
ref class CurveEvaluator
{
FbxAnimCurve* curve;
int index;
public:
CurveEvaluator(FbxAnimCurve* curve)
: curve(curve), index(0)
{
}
float Evaluate(CompressedTimeSpan time)
{
auto fbxTime = FbxTime((long long)time.Ticks * FBXSDK_TIME_ONE_SECOND.Get() / (long long)CompressedTimeSpan::TicksPerSecond);
int currentIndex = index;
auto result = curve->Evaluate(fbxTime, &currentIndex);
index = currentIndex;
return result;
}
};
template <class T>
AnimationCurve<T>^ ProcessAnimationCurveVector(AnimationClip^ animationClip, String^ name, int numCurves, FbxAnimCurve** curves, T defaultValue, bool isUserDefinedProperty)
{
auto keyFrames = ProcessAnimationCurveFloatsHelper<T>(curves, defaultValue, numCurves);
if (keyFrames == nullptr)
return nullptr;
// Add curve
auto animationCurve = gcnew AnimationCurve<T>();
// Switch to cubic implicit interpolation mode for Vector3
animationCurve->InterpolationType = AnimationCurveInterpolationType::Cubic;
// Create keys
for (int i = 0; i < keyFrames->Count; ++i)
{
animationCurve->KeyFrames->Add(keyFrames[i]);
}
animationClip->AddCurve(name, animationCurve, isUserDefinedProperty);
if (keyFrames->Count > 0)
{
auto curveDuration = keyFrames[keyFrames->Count - 1].Time;
if (animationClip->Duration < curveDuration)
animationClip->Duration = curveDuration;
}
return animationCurve;
}
template <class T> AnimationCurve<T>^ CreateCurve(AnimationClip^ animationClip, String^ name, List<KeyFrameData<T>>^ keyFrames)
{
// Add curve
auto animationCurve = gcnew AnimationCurve<T>();
if (T::typeid == Vector3::typeid)
{
// Switch to cubic implicit interpolation mode for Vector3
animationCurve->InterpolationType = AnimationCurveInterpolationType::Cubic;
}
// Create keys
for (int i = 0; i < keyFrames->Count; ++i)
{
animationCurve->KeyFrames->Add(keyFrames[i]);
}
animationClip->AddCurve(name, animationCurve, false);
if (keyFrames->Count > 0)
{
auto curveDuration = keyFrames[keyFrames->Count - 1].Time;
if (animationClip->Duration < curveDuration)
animationClip->Duration = curveDuration;
}
return animationCurve;
}
AnimationCurve<Quaternion>^ ProcessAnimationCurveRotation(AnimationClip^ animationClip, String^ name, FbxAnimCurve** curves, Vector3 defaultValue)
{
auto keyFrames = ProcessAnimationCurveFloatsHelper<Vector3>(curves, defaultValue, 3);
if (keyFrames == nullptr)
return nullptr;
// Convert euler angles to radians
for (int i = 0; i < keyFrames->Count; ++i)
{
auto keyFrame = keyFrames[i];
keyFrame.Value *= (float)Math::PI / 180.0f;
keyFrames[i] = keyFrame;
}
// Add curve
auto animationCurve = gcnew AnimationCurve<Quaternion>();
// Create keys
for (int i = 0; i < keyFrames->Count; ++i)
{
auto keyFrame = keyFrames[i];
KeyFrameData<Quaternion> newKeyFrame;
newKeyFrame.Time = keyFrame.Time;
newKeyFrame.Value = AxisRotationToQuaternion(keyFrame.Value);
animationCurve->KeyFrames->Add(newKeyFrame);
}
animationClip->AddCurve(name, animationCurve, false);
if (keyFrames->Count > 0)
{
auto curveDuration = keyFrames[keyFrames->Count - 1].Time;
if (animationClip->Duration < curveDuration)
animationClip->Duration = curveDuration;
}
return animationCurve;
}
template <typename T>
List<KeyFrameData<T>>^ ProcessAnimationCurveFloatsHelper(FbxAnimCurve** curves, T defaultValue, int numCurves)
{
FbxTime startTime = FBXSDK_TIME_INFINITE;
FbxTime endTime = FBXSDK_TIME_MINUS_INFINITE;
for (int i = 0; i < numCurves; ++i)
{
auto curve = curves[i];
if (curve == NULL)
continue;
FbxTimeSpan timeSpan;
curve->GetTimeInterval(timeSpan);
if (curve != NULL && curve->KeyGetCount() > 0)
{
auto firstKeyTime = curve->KeyGetTime(0);
auto lastKeyTime = curve->KeyGetTime(curve->KeyGetCount() - 1);
if (startTime > firstKeyTime)
startTime = firstKeyTime;
if (endTime < lastKeyTime)
endTime = lastKeyTime;
}
}
if (startTime == FBXSDK_TIME_INFINITE
|| endTime == FBXSDK_TIME_MINUS_INFINITE)
{
// No animation
return nullptr;
}
auto keyFrames = gcnew List<KeyFrameData<T>>();
const float framerate = static_cast<float>(FbxTime::GetFrameRate(scene->GetGlobalSettings().GetTimeMode()));
auto oneFrame = FbxTime::GetOneFrameValue(scene->GetGlobalSettings().GetTimeMode());
//FIX: If scene->GetGlobalSettings().GetTimeMode() returns FbxTime::eFrames30Drop then oneFrame is going to be 0.
// This is (propably) undesired since time will increment by 0 in the next second loop, resulting in a infinite loop
// that finally leads to a out-of-memory exception.
if (oneFrame <= 0)
oneFrame = FbxTime::GetOneFrameValue(FbxTime::eNTSCDropFrame); // FbxTime::eNTSCDropFrame is equivalent to FbxTime::eFrames30Drop.
//Source: (FBX Docs : http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/index.html?url=cpp_ref/class_fbx_time.html,topicNumber=cpp_ref_class_fbx_time_html29087af6-8c2c-4e9d-aede-7dc5a1c2436c)
//Refer to: enum EMode
// Step1: Pregenerate curve with discontinuities
int currentKeyIndices[4];
int currentEvaluationIndices[4];
bool isConstant[4];
for (int i = 0; i < numCurves; ++i)
{
// Start with current key at -1, so we properly advance to key 0 in the first iteration
currentKeyIndices[i] = -1;
currentEvaluationIndices[i] = 0;
isConstant[i] = false;
}
//float values[4];
auto key = KeyFrameData<T>();
float* values = (float*)&key.Value;
float* defaultValues = (float*)&defaultValue;
FbxTime time;
bool lastFrame = false;
for (time = startTime; time < endTime || !lastFrame; time += oneFrame)
{
// Last frame with time = endTime
if (time >= endTime)
{
lastFrame = true;
time = endTime;
}
key.Time = FBXTimeToTimeSpan(time) - animStartTime;
bool hasAnyDiscontinuity = false;
bool hasDiscontinuity[4];
for (int i = 0; i < numCurves; ++i)
{
auto curve = curves[i];
if (curve != nullptr)
{
int currentIndex = currentKeyIndices[i];
FbxAnimCurveKey curveKey;
// Advance to appropriate key that should be active during this frame
// (The current key is the latest key at or before the current time)
bool wasConstant = false;
while (currentIndex + 1 < curve->KeyGetCount() && curve->KeyGetTime(currentIndex + 1) <= time)
{
++currentIndex;
// If we reached a new key and the previous one was constant, we have a discontinuity
wasConstant = isConstant[i];
auto interpolation = curve->KeyGetInterpolation(currentIndex);
isConstant[i] = interpolation == FbxAnimCurveDef::eInterpolationConstant;
}
currentKeyIndices[i] = currentIndex;
hasDiscontinuity[i] = wasConstant;
hasAnyDiscontinuity |= wasConstant;
// Update non-constant values
if (!wasConstant)
{
values[i] = curve->Evaluate(time, &currentEvaluationIndices[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, &currentEvaluationIndices[i]);
}
keyFrames->Add(key);
if (hasAnyDiscontinuity)
keyFrames->Add(key);
}
return keyFrames;
}
void ConvertDegreeToRadians(AnimationCurve<float>^ channel)
{
for (int i = 0; i < channel->KeyFrames->Count; ++i)
{
auto keyFrame = channel->KeyFrames[i];
keyFrame.Value *= (float)Math::PI / 180.0f;
channel->KeyFrames[i] = keyFrame;
}
}
void ReverseChannelZ(AnimationCurve<Vector3>^ channel)
{
// Used for handedness conversion
for (int i = 0; i < channel->KeyFrames->Count; ++i)
{
auto keyFrame = channel->KeyFrames[i];
keyFrame.Value.Z = -keyFrame.Value.Z;
channel->KeyFrames[i] = keyFrame;
}
}
void ComputeFovFromFL(AnimationCurve<float>^ channel, FbxCamera* pCamera)
{
// Used for handedness conversion
for (int i = 0; i < channel->KeyFrames->Count; ++i)
{
auto keyFrame = channel->KeyFrames[i];
keyFrame.Value = (float)(FocalLengthToVerticalFov(pCamera->FilmHeight.Get(), keyFrame.Value) * 180.0 / Math::PI);
channel->KeyFrames[i] = keyFrame;
}
}
void MultiplyChannel(AnimationCurve<float>^ channel, double factor)
{
// Used for handedness conversion
for (int i = 0; i < channel->KeyFrames->Count; ++i)
{
auto keyFrame = channel->KeyFrames[i];
keyFrame.Value = (float)(factor * keyFrame.Value);
channel->KeyFrames[i] = keyFrame;
}
}
void ProcessAnimationByNode(Dictionary<String^, AnimationClip^>^ animationClips, FbxAnimLayer* animLayer, FbxNode* pNode, bool importCustomAttributeAnimations)
{
auto animationClip = gcnew AnimationClip();
auto nodeData = sceneMapping->FindNode(pNode);
FbxAnimCurve* curves[3];
auto nodeName = nodeData.Name;
auto defaultTranslation = FbxDouble3ToVector3(pNode->LclTranslation.Get());
curves[0] = pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X);
curves[1] = pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
curves[2] = pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
auto translationCurve = ProcessAnimationCurveVector<Vector3>(animationClip, "Transform.Position", 3, curves, defaultTranslation, false);
auto defaultRotation = FbxDouble3ToVector3(pNode->LclRotation.Get());
curves[0] = pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X);
curves[1] = pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
curves[2] = pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
auto rotationCurve = ProcessAnimationCurveRotation(animationClip, "Transform.Rotation", curves, defaultRotation);
auto defaultScale = FbxDouble3ToVector3(pNode->LclScaling.Get());
curves[0] = pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X);
curves[1] = pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y);
curves[2] = pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z);
auto scalingCurve = ProcessAnimationCurveVector<Vector3>(animationClip, "Transform.Scale", 3, curves, defaultScale, false);
if (translationCurve != nullptr)
{
auto keyFrames = translationCurve->KeyFrames;
for (int i = 0; i < keyFrames->Count; i++)
{
auto keyFrame = keyFrames[i];
keyFrame.Value = keyFrame.Value * sceneMapping->ScaleToMeters;
Vector3::TransformCoordinate(keyFrame.Value, sceneMapping->AxisSystemRotationMatrix, keyFrame.Value);
keyFrames[i] = keyFrame;
}
}
if (nodeData.ParentIndex == 0)
{
if (rotationCurve != nullptr)
{
auto axisSystemRotationQuaternion = Quaternion::RotationMatrix(sceneMapping->AxisSystemRotationMatrix);
auto keyFrames = rotationCurve->KeyFrames;
for (int i = 0; i < keyFrames->Count; i++)
{
auto keyFrame = keyFrames[i];
keyFrame.Value = Quaternion::Multiply(keyFrame.Value, axisSystemRotationQuaternion);
keyFrames[i] = keyFrame;
}
}
}
FbxCamera* camera = pNode->GetCamera();
if (camera != NULL)
{
String^ cameraComponentKey = "[CameraComponent.Key].";
if (camera->FieldOfViewY.GetCurve(animLayer))
{
curves[0] = camera->FieldOfViewY.GetCurve(animLayer);
float defaultValue = static_cast<float>(camera->FieldOfViewY.Get());
auto FovAnimChannel = ProcessAnimationCurveVector<float>(animationClip, cameraComponentKey+"VerticalFieldOfView", 1, curves, defaultValue, false);
// TODO: Check again Max
//if (!exportedFromMaya)
// MultiplyChannel(FovAnimChannel, 0.6); // Random factor to match what we see in 3dsmax, need to check why!
}
if (camera->FocalLength.GetCurve(animLayer))
{
curves[0] = camera->FocalLength.GetCurve(animLayer);
float defaultValue = static_cast<float>(camera->FocalLength.Get());
auto flAnimChannel = ProcessAnimationCurveVector<float>(animationClip, cameraComponentKey+"VerticalFieldOfView", 1, curves, defaultValue, false);
ComputeFovFromFL(flAnimChannel, camera);
}
if (camera->NearPlane.GetCurve(animLayer))
{
curves[0] = camera->NearPlane.GetCurve(animLayer);
float defaultValue = static_cast<float>(camera->NearPlane.Get());
ProcessAnimationCurveVector<float>(animationClip, cameraComponentKey+"NearClipPlane", 1, curves, defaultValue, false);
}
if (camera->FarPlane.GetCurve(animLayer))
{
curves[0] = camera->FarPlane.GetCurve(animLayer);
float defaultValue = static_cast<float>(camera->FarPlane.Get());
ProcessAnimationCurveVector<float>(animationClip, cameraComponentKey+"FarClipPlane", 1, curves, defaultValue, false);
}
}
if (importCustomAttributeAnimations)
{
FbxProperty lProperty = pNode->GetFirstProperty();
while (lProperty.IsValid())
{
auto isUserDefined = lProperty.GetFlag(FbxPropertyFlags::eUserDefined); // import only user custom properties
FbxAnimCurveNode* lCurveNode = lProperty.GetCurveNode(animLayer); // import only animated properties
if (!isUserDefined || !lCurveNode)
{
lProperty = pNode->GetNextProperty(lProperty);
continue;
}
auto lFbxFCurveNodeName = gcnew String(lProperty.GetName());
// extract the animation from the property
auto channelCount = lCurveNode->GetChannelsCount();
for (unsigned int c = 0; c<channelCount && c<3; ++c)
curves[c] = lCurveNode->GetCurve(c);
FbxDataType lDataType = lProperty.GetPropertyDataType();
if (lDataType.GetType() == eFbxBool ||
lDataType.GetType() == eFbxDouble || lDataType.GetType() == eFbxFloat ||
lDataType.GetType() == eFbxInt || lDataType.GetType() == eFbxUInt ||
lDataType.GetType() == eFbxChar || lDataType.GetType() == eFbxUChar ||
lDataType.GetType() == eFbxShort || lDataType.GetType() == eFbxUShort)
{
ProcessAnimationCurveVector<float>(animationClip, lFbxFCurveNodeName, channelCount, curves, 0, true);
}
if (lDataType.GetType() == eFbxDouble2)
{
ProcessAnimationCurveVector<Vector2>(animationClip, lFbxFCurveNodeName, channelCount, curves, Vector2::Zero, true);
}
else if (lDataType.GetType() == eFbxDouble3)
{
ProcessAnimationCurveVector<Vector3>(animationClip, lFbxFCurveNodeName, channelCount, curves, Vector3::Zero, true);
}
else
{
//TODO add support for the type
}
lProperty = pNode->GetNextProperty(lProperty);
} // while
}
if (animationClip->Curves->Count > 0)
{
animationClips->Add(nodeName, animationClip);
}
for (int i = 0; i < pNode->GetChildCount(); ++i)
{
ProcessAnimationByNode(animationClips, animLayer, pNode->GetChild(i), importCustomAttributeAnimations);
}
}
// This code is not used but is a reference code for code animation but less optimized than ProcessAnimationByCurve.
void ProcessAnimation(FbxTime animStart, FbxTime animEnd, AnimationClip^ animationClip, FbxAnimStack* animStack, FbxNode* pNode)
{
auto layer0 = animStack->GetMember<FbxAnimLayer>(0);
if (HasAnimation(layer0, pNode))
{
auto evaluator = scene->GetAnimationEvaluator();
auto animationName = animStack->GetName();
// Create curves
auto scalingFrames = gcnew List<KeyFrameData<Vector3>>();
auto rotationFrames = gcnew List<KeyFrameData<Quaternion>>();
auto translationFrames = gcnew List<KeyFrameData<Vector3>>();
auto nodeData = sceneMapping->FindNode(pNode);
auto parentNode = pNode->GetParent();
auto nodeName = nodeData.Name;
String^ parentNodeName = nullptr;
if (parentNode != nullptr)
{
parentNodeName = sceneMapping->FindNode(parentNode).Name;
}
FbxLongLong start = static_cast<FbxLongLong>(animStart.GetSecondDouble());
FbxLongLong end = static_cast<FbxLongLong>(animEnd.GetSecondDouble());
FbxTime sampling_period = FbxTimeSeconds(1.f / 60.0f);
bool loop_again = true;
for (FbxTime t = start; loop_again; t += sampling_period) {
if (t >= end) {
t = end;
loop_again = false;
}
// Use GlobalTransform instead of LocalTransform
auto fbxMatrix = evaluator->GetNodeGlobalTransform(pNode, t);
if (parentNode != nullptr)
{
auto parentMatrixInverse = evaluator->GetNodeGlobalTransform(parentNode, t).Inverse();
fbxMatrix = parentMatrixInverse * fbxMatrix;
}
auto matrix = sceneMapping->ConvertMatrixFromFbx(fbxMatrix);
Vector3 scaling;
Vector3 translation;
Quaternion rotation;
matrix.Decompose(scaling, rotation, translation);
auto time = FBXTimeToTimeSpan(t);
scalingFrames->Add(KeyFrameData<Vector3>(time, scaling));
translationFrames->Add(KeyFrameData<Vector3>(time, translation));
rotationFrames->Add(KeyFrameData<Quaternion>(time, rotation));
}
CreateCurve(animationClip, String::Format("Transform.Position[{0}]", nodeName), translationFrames);
CreateCurve(animationClip, String::Format("Transform.Rotation[{0}]", nodeName), rotationFrames);
CreateCurve(animationClip, String::Format("Transform.Scale[{0}]", nodeName), scalingFrames);
}
for (int i = 0; i < pNode->GetChildCount(); ++i)
{
ProcessAnimation(animStart, animEnd, animationClip, animStack, pNode->GetChild(i));
}
}
void SetPivotStateRecursive(FbxNode* pNode)
{
// From FbxNode.h
FbxVector4 lZero(0, 0, 0);
FbxVector4 lOne(1, 1, 1);
pNode->SetPivotState(FbxNode::eSourcePivot, FbxNode::ePivotActive);
pNode->SetPivotState(FbxNode::eDestinationPivot, FbxNode::ePivotActive);
EFbxRotationOrder lRotationOrder;
pNode->GetRotationOrder(FbxNode::eSourcePivot, lRotationOrder);
pNode->SetRotationOrder(FbxNode::eDestinationPivot, lRotationOrder);
//For cameras and lights (without targets) let's compensate the postrotation.
if (pNode->GetCamera() || pNode->GetLight())
{
if (!pNode->GetTarget())
{
FbxVector4 lRV(90, 0, 0);
if (pNode->GetCamera())
lRV.Set(0, 90, 0);
FbxVector4 prV = pNode->GetPostRotation(FbxNode::eSourcePivot);
FbxAMatrix lSourceR;
FbxAMatrix lR(lZero, lRV, lOne);
FbxVector4 res = prV;
// Rotation order don't affect post rotation, so just use the default XYZ order
FbxRotationOrder rOrder;
rOrder.V2M(lSourceR, res);
lR = lSourceR * lR;
rOrder.M2V(res, lR);
prV = res;
pNode->SetPostRotation(FbxNode::eSourcePivot, prV);
pNode->SetRotationActive(true);
}
// Point light do not need to be adjusted (since they radiate in all the directions).
if (pNode->GetLight() && pNode->GetLight()->LightType.Get() == FbxLight::ePoint)
{
pNode->SetPostRotation(FbxNode::eSourcePivot, FbxVector4(0, 0, 0, 0));
}
}
// apply Pre rotations only on bones / end of chains
if (pNode->GetNodeAttribute() && pNode->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eSkeleton
|| (pNode->GetMarker() && pNode->GetMarker()->GetType() == FbxMarker::eEffectorFK)
|| (pNode->GetMarker() && pNode->GetMarker()->GetType() == FbxMarker::eEffectorIK))
{
if (pNode->GetRotationActive())
{
pNode->SetPreRotation(FbxNode::eDestinationPivot, pNode->GetPreRotation(FbxNode::eSourcePivot));
}
// No pivots on bones
pNode->SetRotationPivot(FbxNode::eDestinationPivot, lZero);
pNode->SetScalingPivot(FbxNode::eDestinationPivot, lZero);
pNode->SetRotationOffset(FbxNode::eDestinationPivot, lZero);
pNode->SetScalingOffset(FbxNode::eDestinationPivot, lZero);
}
else
{
// any other type: no pre-rotation support but...
pNode->SetPreRotation(FbxNode::eDestinationPivot, lZero);
// support for rotation and scaling pivots.
pNode->SetRotationPivot(FbxNode::eDestinationPivot, pNode->GetRotationPivot(FbxNode::eSourcePivot));
pNode->SetScalingPivot(FbxNode::eDestinationPivot, pNode->GetScalingPivot(FbxNode::eSourcePivot));
// Rotation and scaling offset are supported
pNode->SetRotationOffset(FbxNode::eDestinationPivot, pNode->GetRotationOffset(FbxNode::eSourcePivot));
pNode->SetScalingOffset(FbxNode::eDestinationPivot, pNode->GetScalingOffset(FbxNode::eSourcePivot));
//
// If we don't "support" scaling pivots, we can simply do:
// pNode->SetRotationPivot(FbxNode::eDestinationPivot, lZero);
// pNode->SetScalingPivot(FbxNode::eDestinationPivot, lZero);
}
for (int i = 0; i < pNode->GetChildCount(); ++i)
{
SetPivotStateRecursive(pNode->GetChild(i));
}
}
bool CheckAnimationData(FbxAnimLayer* animLayer, FbxNode* pNode)
{
if ((pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
&& pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
&& pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL)
||
(pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
&& pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
&& pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL)
||
(pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
&& pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
&& pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL))
return true;
FbxCamera* camera = pNode->GetCamera();
if (camera != NULL)
{
if (camera->FieldOfViewY.GetCurve(animLayer))
return true;
if (camera->FocalLength.GetCurve(animLayer))
return true;
}
for (int i = 0; i < pNode->GetChildCount(); ++i)
{
if (CheckAnimationData(animLayer, pNode->GetChild(i)))
return true;
}
return false;
}
bool HasAnimation(FbxAnimLayer* animLayer, FbxNode* pNode)
{
return (pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
|| pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
|| pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL
|| pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
|| pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
|| pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL
|| pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL
|| pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL
|| pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL);
}
void GetAnimationNodes(FbxAnimLayer* animLayer, FbxNode* pNode, List<String^>^ animationNodes)
{
auto nodeData = sceneMapping->FindNode(pNode);
auto nodeName = nodeData.Name;
bool checkTranslation = pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL;
checkTranslation = checkTranslation || pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL;
checkTranslation = checkTranslation || pNode->LclTranslation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL;
bool checkRotation = pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL;
checkRotation = checkRotation || pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL;
checkRotation = checkRotation || pNode->LclRotation.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL;
bool checkScale = pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_X) != NULL;
checkScale = checkScale || pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Y) != NULL;
checkScale = checkScale || pNode->LclScaling.GetCurve(animLayer, FBXSDK_CURVENODE_COMPONENT_Z) != NULL;
if (checkTranslation || checkRotation || checkScale)
{
animationNodes->Add(nodeName);
}
else
{
bool checkCamera = true;
FbxCamera* camera = pNode->GetCamera();
if (camera != NULL)
{
if (camera->FieldOfViewY.GetCurve(animLayer))
checkCamera = checkCamera && camera->FieldOfViewY.GetCurve(animLayer) != NULL;
if (camera->FocalLength.GetCurve(animLayer))
checkCamera = checkCamera && camera->FocalLength.GetCurve(animLayer) != NULL;
if (checkCamera)
animationNodes->Add(nodeName);
}
}
for (int i = 0; i < pNode->GetChildCount(); ++i)
{
GetAnimationNodes(animLayer, pNode->GetChild(i), animationNodes);
}
}
};
}
}
}

Просмотреть файл

@ -1,39 +0,0 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
#include "stdafx.h"
using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::CompilerServices;
using namespace System::Runtime::InteropServices;
using namespace System::Security::Permissions;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly:AssemblyTitleAttribute("Stride.Importer.FBX")];
[assembly:AssemblyDescriptionAttribute("")];
[assembly:AssemblyConfigurationAttribute("")];
[assembly:AssemblyProductAttribute("Stride.Importer.FBX")];
[assembly:AssemblyCopyrightAttribute("Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)")];
[assembly:AssemblyTrademarkAttribute("")];
[assembly:AssemblyCultureAttribute("")];
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the value or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly:AssemblyVersionAttribute("1.0.*")];
[assembly:ComVisible(false)];
[assembly:CLSCompliantAttribute(true)];

Просмотреть файл

@ -1,26 +0,0 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
#ifndef __IMPORTER_UTILS_H__
#define __IMPORTER_UTILS_H__
void ReplaceCharacter(std::string& name, char c, char replacement)
{
size_t nextCharacterPos = name.find(c);
while (nextCharacterPos != std::string::npos)
{
name.replace(nextCharacterPos, 1, 1, replacement);
nextCharacterPos = name.find(c, nextCharacterPos);
}
}
void RemoveCharacter(std::string& name, char c)
{
size_t nextCharacterPos = name.find(c);
while (nextCharacterPos != std::string::npos)
{
name.erase(nextCharacterPos, 1);
nextCharacterPos = name.find(c, nextCharacterPos);
}
}
#endif // __IMPORTER_UTILS_H__

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,278 +0,0 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
#pragma once
#include "stdafx.h"
using namespace System;
using namespace System::IO;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
using namespace Stride::Core::Diagnostics;
using namespace Stride::Animations;
using namespace Stride::Rendering;
using namespace Stride::Engine;
using namespace Stride::Core::Mathematics;
namespace Stride {
namespace Importer {
namespace FBX {
/// <summary>
/// Contains mapping between FBX nodes and Stride ModelNodeDefinition
/// </summary>
ref class SceneMapping
{
private:
FbxScene* scene;
Dictionary<IntPtr, int>^ nodeMapping;
array<ModelNodeDefinition>^ nodes;
Matrix convertMatrix;
Matrix inverseConvertMatrix;
Matrix normalConvertMatrix;
public:
/// <summary>
/// Initializes a new instance of the <see cref="NodeMapping"/> class.
/// </summary>
/// <param name="sceneArg">The scene argument.</param>
SceneMapping(FbxScene* scene) : scene(scene)
{
if (scene == nullptr)
{
throw gcnew ArgumentNullException("scene");
}
nodeMapping = gcnew Dictionary<IntPtr, int>();
// Generate names for all nodes
std::map<FbxNode*, std::string> nodeNames;
GenerateNodesName(scene, nodeNames);
// Generate all ModelNodeDefinition
auto nodeList = gcnew List<ModelNodeDefinition>();
RegisterNode(scene->GetRootNode(), -1, nodeNames, nodeMapping, nodeList);
nodes = nodeList->ToArray();
// Setup the convertion
FbxGlobalSettings& settings = scene->GetGlobalSettings();
InitializeMatrix(settings.GetAxisSystem(), settings.GetSystemUnit());
}
/// <summary>
/// Gets all the nodes.
/// </summary>
property array<ModelNodeDefinition>^ Nodes
{
array<ModelNodeDefinition>^ get()
{
return nodes;
}
}
/// <summary>
/// Gets the associated FbxScene.
/// </summary>
property FbxScene* Scene
{
FbxScene* get()
{
return scene;
}
}
property Matrix MatrixModifier
{
Matrix get()
{
return convertMatrix;
}
}
property float ScaleToMeters;
property Matrix AxisSystemRotationMatrix;
/// <summary>
/// Finds the index of the FBX node in the <see cref="ModelNodeDefinition"/> from a FBX node.
/// </summary>
/// <param name="node">The node.</param>
/// <returns>Stride.Rendering.ModelNodeDefinition.</returns>
int FindNodeIndex(FbxNode* node)
{
int nodeIndex;
if (!nodeMapping->TryGetValue((IntPtr)node, nodeIndex))
{
throw gcnew ArgumentException("Invalid node not found", "node");
}
return nodeIndex;
}
/// <summary>
/// Finds a <see cref="ModelNodeDefinition"/> from a FBX node.
/// </summary>
/// <param name="node">The node.</param>
/// <returns>Stride.Rendering.ModelNodeDefinition.</returns>
ModelNodeDefinition FindNode(FbxNode* node)
{
int nodeIndex;
if (!nodeMapping->TryGetValue((IntPtr)node, nodeIndex))
{
throw gcnew ArgumentException("Invalid node not found", "node");
}
return nodes[nodeIndex];
}
Matrix ConvertMatrixFromFbx(FbxAMatrix& _m)
{
auto result = FBXMatrixToMatrix(_m);
// Adjust translation
result.M41 *= ScaleToMeters;
result.M42 *= ScaleToMeters;
result.M43 *= ScaleToMeters;
return result;
}
Vector3 ConvertPointFromFbx(const FbxVector4& _p)
{
return (Vector3)FbxDouble4ToVector4(_p) * ScaleToMeters;
}
Vector3 ConvertNormalFromFbx(const FbxVector4& _p)
{
return (Vector3)FbxDouble4ToVector4(_p);
}
private:
static void GetNodes(FbxNode* pNode, std::vector<FbxNode*>& nodes)
{
nodes.push_back(pNode);
// Recursively process the children nodes.
for (int j = 0; j < pNode->GetChildCount(); j++)
GetNodes(pNode->GetChild(j), nodes);
}
static void GenerateNodesName(FbxScene* scene, std::map<FbxNode*, std::string>& nodeNames)
{
std::vector<FbxNode*> nodes;
GetNodes(scene->GetRootNode(), nodes);
std::map<std::string, int> nodeNameTotalCount;
std::map<std::string, int> nodeNameCurrentCount;
std::map<FbxNode*, std::string> tempNames;
for (auto iter = nodes.begin(); iter != nodes.end(); ++iter)
{
auto pNode = *iter;
auto nodeName = std::string(pNode->GetName());
auto subBegin = nodeName.find_last_of(':');
if (subBegin != std::string::npos)
nodeName = nodeName.substr(subBegin + 1);
tempNames[pNode] = nodeName;
if (nodeNameTotalCount.count(nodeName) == 0)
nodeNameTotalCount[nodeName] = 1;
else
nodeNameTotalCount[nodeName] = nodeNameTotalCount[nodeName] + 1;
}
for (auto iter = nodes.begin(); iter != nodes.end(); ++iter)
{
auto pNode = *iter;
auto nodeName = tempNames[pNode];
int currentCount = 0;
if (nodeNameCurrentCount.count(nodeName) == 0)
nodeNameCurrentCount[nodeName] = 1;
else
nodeNameCurrentCount[nodeName] = nodeNameCurrentCount[nodeName] + 1;
if (nodeNameTotalCount[nodeName] > 1)
nodeName = nodeName + "_" + std::to_string(nodeNameCurrentCount[nodeName]);
nodeNames[pNode] = nodeName;
}
}
static void RegisterNode(FbxNode* pNode, int parentIndex, std::map<FbxNode*, std::string>& nodeNames, Dictionary<IntPtr, int>^ nodeMapping, List<ModelNodeDefinition>^ nodes)
{
int currentIndex = nodes->Count;
nodeMapping[(IntPtr)pNode] = currentIndex;
// Create node
ModelNodeDefinition modelNodeDefinition;
modelNodeDefinition.ParentIndex = parentIndex;
modelNodeDefinition.Transform.Scale = Vector3::One;
modelNodeDefinition.Name = ConvertToUTF8(nodeNames[pNode]);
modelNodeDefinition.Flags = ModelNodeFlags::Default;
nodes->Add(modelNodeDefinition);
// Recursively process the children nodes.
for (int j = 0; j < pNode->GetChildCount(); j++)
{
RegisterNode(pNode->GetChild(j), currentIndex, nodeNames, nodeMapping, nodes);
}
}
void InitializeMatrix(const FbxAxisSystem& axisSystem, const FbxSystemUnit& unitSystem)
{
auto fromMatrix = BuildAxisSystemMatrix(axisSystem);
fromMatrix.Invert();
//auto fromMatrix = Matrix::Identity;
// Finds unit conversion ratio to ScaleImport (usually 0.01 so 1 meter). GetScaleFactor() is in cm.
ScaleToMeters = (float)unitSystem.GetScaleFactor() * 0.01f;
// Builds conversion matrices.
AxisSystemRotationMatrix = fromMatrix;
}
static Matrix BuildAxisSystemMatrix(const FbxAxisSystem& axisSystem) {
int signUp;
int signFront;
Vector3 up = Vector3::UnitY;
Vector3 at = Vector3::UnitZ;
const auto upAxis = axisSystem.GetUpVector(signUp);
const auto frontAxisParityEven = axisSystem.GetFrontVector(signFront) == FbxAxisSystem::eParityEven;
switch (upAxis)
{
case FbxAxisSystem::eXAxis:
{
up = Vector3::UnitX;
at = frontAxisParityEven ? Vector3::UnitY : Vector3::UnitZ;
break;
}
case FbxAxisSystem::eYAxis:
{
up = Vector3::UnitY;
at = frontAxisParityEven ? Vector3::UnitX : Vector3::UnitZ;
break;
}
case FbxAxisSystem::eZAxis:
{
up = Vector3::UnitZ;
at = frontAxisParityEven ? Vector3::UnitX : Vector3::UnitY;
break;
}
}
up *= (float)signUp;
at *= (float)signFront;
auto right = axisSystem.GetCoorSystem() == FbxAxisSystem::eRightHanded ? Vector3::Cross(up, at) : Vector3::Cross(at, up);
auto matrix = Matrix::Identity;
matrix.Right = right;
matrix.Up = up;
matrix.Backward = at;
return matrix;
}
};
}
}
}

Просмотреть файл

@ -1,135 +0,0 @@
/****************************************************************************************
Copyright (C) 2011 Autodesk, Inc.
All rights reserved.
Use of this software is subject to the terms of the Autodesk license agreement
provided at the time of installation or download, or which otherwise accompanies
this software in either electronic or hard copy form.
****************************************************************************************/
#include "stdafx.h"
#include "StreamReader.h"
#include <fbxfilesdk/fbxfilesdk_nsuse.h>
StreamReader::StreamReader(KFbxSdkManager &pFbxSdkManager, int pID):
KFbxReader(pFbxSdkManager, pID),
mFilePointer(NULL),
mManager(&pFbxSdkManager)
{
}
StreamReader::~StreamReader()
{
FileClose();
}
void StreamReader::GetVersion(int& pMajor, int& pMinor, int& pRevision) const
{
pMajor = 1;
pMinor = 0;
pRevision=0;
}
bool StreamReader::FileOpen(char* pFileName)
{
if(mFilePointer != NULL)
FileClose();
mFilePointer = fopen(pFileName, "r");
if(mFilePointer == NULL)
return false;
return true;
}
bool StreamReader::FileClose()
{
if(mFilePointer!=NULL)
fclose(mFilePointer);
return true;
}
bool StreamReader::IsFileOpen()
{
if(mFilePointer != NULL)
return true;
return false;
}
bool StreamReader::GetReadOptions(bool pParseFileAsNeeded)
{
return true;
}
//Read the custom file and reconstruct node hierarchy.
bool StreamReader::Read(KFbxDocument* pDocument)
{
if (!pDocument)
{
GetError().SetLastErrorID(eINVALID_DOCUMENT_HANDLE);
return false;
}
KFbxScene* lScene = KFbxCast<KFbxScene>(pDocument);
bool lIsAScene = (lScene != NULL);
bool lResult = false;
if(lIsAScene)
{
KFbxNode* lRootNode = lScene->GetRootNode();
KFbxNodeAttribute * lRootNodeAttribute = KFbxNull::Create(lScene,"");
lRootNode->SetNodeAttribute(lRootNodeAttribute);
int lSize;
char* lBuffer = NULL;
if(mFilePointer != NULL)
{
//To obtain file size
fseek (mFilePointer , 0 , SEEK_END);
lSize = ftell (mFilePointer);
rewind (mFilePointer);
//Read file content to a string.
lBuffer = (char*) malloc (sizeof(char)*lSize + 1);
size_t lRead = fread(lBuffer, 1, lSize, mFilePointer);
lBuffer[lRead]='\0';
KString lString(lBuffer);
//Parse the string to get name and relation of Nodes.
KString lSubString, lChildName, lParentName;
KFbxNode* lChildNode;
KFbxNode* lParentNode;
KFbxNodeAttribute* lChildAttribute;
int lEndTokenCount = lString.GetTokenCount("\n");
for (int i = 0; i < lEndTokenCount; i++)
{
lSubString = lString.GetToken(i, "\n");
KString lNodeString;
lChildName = lSubString.GetToken(0, "\"");
lParentName = lSubString.GetToken(2, "\"");
//Build node hierarchy.
if(lParentName == "RootNode")
{
lChildNode = KFbxNode::Create(lScene,lChildName.Buffer());
lChildAttribute = KFbxNull::Create(mManager,"");
lChildNode->SetNodeAttribute(lChildAttribute);
lRootNode->AddChild(lChildNode);
}
else
{
lChildNode = KFbxNode::Create(lScene,lChildName.Buffer());
lChildAttribute = KFbxNull::Create(lScene,"");
lChildNode->SetNodeAttribute(lChildAttribute);
lParentNode = lRootNode->FindChild(lParentName.Buffer());
lParentNode->AddChild(lChildNode);
}
}
free(lBuffer);
}
lResult = true;
}
return lResult;
}

Просмотреть файл

@ -1,27 +0,0 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
class StreamReader : public KFbxReader
{
public:
StreamReader(KFbxSdkManager &pFbxSdkManager, int pID);
//VERY important to put the file close in the destructor
virtual ~StreamReader();
virtual void GetVersion(int& pMajor, int& pMinor, int& pRevision) const;
virtual bool FileOpen(char* pFileName);
virtual bool FileClose();
virtual bool IsFileOpen();
virtual bool GetReadOptions(bool pParseFileAsNeeded = true);
virtual bool Read(KFbxDocument* pDocument);
private:
FILE *mFilePointer;
KFbxSdkManager *mManager;
};
KFbxReader* CreateMyOwnReader(KFbxSdkManager& pManager, KFbxImporter& pImporter, int pSubID, int pPluginID);
void *GetMyOwnReaderInfo(KFbxReader::KInfoRequest pRequest, int pId);
void FillOwnReaderIOSettings(KFbxIOSettings& pIOS);

Просмотреть файл

@ -1,262 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\targets\Stride.props" />
<PropertyGroup>
<StrideProjectType>Cpp</StrideProjectType>
<TargetFramework>$(StrideEditorTargetFramework)</TargetFramework>
<StrideBuildTags>WindowsTools</StrideBuildTags>
<StrideAssemblyProcessorOptions>
</StrideAssemblyProcessorOptions>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<FbxSdkVersion>2019.0</FbxSdkVersion>
<FbxSdkUrl>https://www.autodesk.com/developer-network/platform-technologies/fbx-sdk-2019-0</FbxSdkUrl>
<FbxSdkDir>$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk FBX SDK $(FbxSdkVersion)', 'Install_Dir', null, RegistryView.Registry32))</FbxSdkDir>
<PlatformToolset>v143</PlatformToolset>
<FbxLibVersionDir>vs2015\</FbxLibVersionDir>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{0467D515-FD66-4B8A-A128-CB642C2ED03F}</ProjectGuid>
<Keyword>ManagedCProj</Keyword>
<RootNamespace>Stride.Importer.FBX</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CLRSupport>NetCore</CLRSupport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CLRSupport>NetCore</CLRSupport>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<LinkIncremental>true</LinkIncremental>
<OutDir>bin\$(TargetFramework)\$(Platform)\$(Configuration)\</OutDir>
<IntDir>obj\$(TargetFramework)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<LinkIncremental>false</LinkIncremental>
<OutDir>bin\$(TargetFramework)\$(Platform)\$(Configuration)\</OutDir>
<IntDir>obj\$(TargetFramework)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(FbxSdkDir)\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(FbxSdkDir)\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<AdditionalOptions>/wd 4945 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libfbxsdk.lib;user32.lib;advapi32.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\debug</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
<CustomBuildStep>
<Command>xcopy /D /Y "$(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\debug\libfbxsdk.dll" "$(TargetDir)x86"</Command>
<Outputs>$(TargetDir)x86\libfbxsdk.dll;%(Outputs)</Outputs>
<Inputs>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\release\libfbxsdk.dll</Inputs>
<TreatOutputAsContent>true</TreatOutputAsContent>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;NDEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(FbxSdkDir)\include</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<AdditionalOptions>/wd 4945 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libfbxsdk.lib;user32.lib;advapi32.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x86\release</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<AdditionalOptions>/wd 4945 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libfbxsdk.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\debug</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
<CustomBuildStep>
<Command>xcopy /D /Y "$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\debug\libfbxsdk.dll" "$(TargetDir)x64"</Command>
<Outputs>$(TargetDir)x64\libfbxsdk.dll;%(Outputs)</Outputs>
<Inputs>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release\libfbxsdk.dll</Inputs>
<TreatOutputAsContent>true</TreatOutputAsContent>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>NDEBUG;FBXSDK_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(FbxSdkDir)\include</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<AdditionalOptions>/wd 4945 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libfbxsdk.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release</AdditionalLibraryDirectories>
<AdditionalOptions>/ignore:4049 %(AdditionalOptions)</AdditionalOptions>
</Link>
<CustomBuildStep>
<Command>xcopy /D /Y "$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release\libfbxsdk.dll" "$(TargetDir)x64"</Command>
<Outputs>$(TargetDir)x64\libfbxsdk.dll;%(Outputs)</Outputs>
<Inputs>$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\release\libfbxsdk.dll</Inputs>
<TreatOutputAsContent>true</TreatOutputAsContent>
</CustomBuildStep>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AnimationConverter.h" />
<ClCompile Include="AssemblyInfo.h" />
<ClCompile Include="SceneMapping.h" />
<ClCompile Include="MeshConverter.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="UtilityFunctions.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ImporterUtils.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="UtilityFunctions.h" />
</ItemGroup>
<ItemGroup>
<StrideNativeLib Include="$(FbxSdkDir)\lib\$(FbxLibVersionDir)x64\debug\libfbxsdk.dll">
<Link>runtimes\win-x64\native\%(Filename)%(Extension)</Link>
<RelativePath>runtimes\win-x64\native\%(Filename)%(Extension)</RelativePath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</StrideNativeLib>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\assets\Stride.Core.Assets\Stride.Core.Assets.csproj">
<Project>{1e54a9a2-4439-4444-ae57-6d2ed3c0dc47}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\core\Stride.Core.Design\Stride.Core.Design.csproj">
<Project>{66581dad-70ad-4475-ae47-c6c0df1ec5e2}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\engine\Stride.Assets\Stride.Assets.csproj">
<Project>{39ae9c77-e94b-404f-8768-b6261b3c1e0e}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\engine\Stride.Engine\Stride.Engine.csproj">
<Project>{c121a566-555e-42b9-9b0a-1696529a9088}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\engine\Stride.Rendering\Stride.Rendering.csproj">
<Project>{ad4fdc24-b64d-4ed7-91aa-62c9eda12fa4}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\core\Stride.Core\Stride.Core.csproj">
<Project>{0e916ab7-5a6c-4820-8ab1-aa492fe66d68}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\engine\Stride.Graphics\Stride.Graphics.csproj">
<Project>{fb06c76a-6bb7-40be-9afa-fec13b045fb5}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\core\Stride.Core.IO\Stride.Core.IO.csproj">
<Project>{1de01410-22c9-489b-9796-1addab1f64e5}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\core\Stride.Core.Serialization\Stride.Core.Serialization.csproj">
<Project>{5210fb81-b807-49bb-af0d-31fb6a83a572}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\shaders\Stride.Core.Shaders\Stride.Core.Shaders.csproj">
<Project>{f2d52edb-bc17-4243-b06d-33cd20f87a7f}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\core\Stride.Core.Mathematics\Stride.Core.Mathematics.csproj">
<Project>{1677b922-ccf0-44de-b57e-1cdd3d2b8e8a}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\engine\Stride.Shaders\Stride.Shaders.csproj">
<Project>{273bdd15-7392-4078-91f0-af23594a3d7b}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\engine\Stride\Stride.csproj">
<Project>{72390339-b2a1-4f61-a800-31ed0975b515}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\buildengine\Stride.Core.BuildEngine.Common\Stride.Core.BuildEngine.Common.csproj">
<Project>{7732cb84-a39a-4adf-b740-fd32a352fa8a}</Project>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\Stride.Importer.Common\Stride.Importer.Common.csproj">
<Project>{806aa078-6070-4bb6-b05b-6ee6b21b1cde}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="BulletSharp">
<HintPath>..\..\..\deps\BulletPhysics\BulletSharp.NetStandard.dll</HintPath>
</Reference>
</ItemGroup>
<Import Project="$(StrideSdkTargets)" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<Target Name="EnsureFbxSdkInstalled" BeforeTargets="PrepareForBuild">
<Message Condition="'$(FbxSdkDir)' != ''" Importance="Normal" Text="Found FBX SDK $(FbxSdkVersion) at $(FbxSdkDir)" />
<Error Condition="'$(FbxSdkDir)' == ''" Text="FBX SDK $(FbxSdkVersion) was not found. Please download and install it from $(FbxSdkUrl) (version Windows VS2015) and reload this solution." />
</Target>
</Project>

Просмотреть файл

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
<ClCompile Include="UtilityFunctions.cpp" />
<ClCompile Include="AssemblyInfo.h" />
<ClCompile Include="AnimationConverter.h" />
<ClCompile Include="SceneMapping.h" />
<ClCompile Include="MeshConverter.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
<ClInclude Include="UtilityFunctions.h" />
<ClInclude Include="ImporterUtils.h" />
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)nuget-icon.png" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,95 +0,0 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
#include "stdafx.h"
#include <assert.h>
// Conversion functions
Quaternion AxisRotationToQuaternion(Vector3 axisRotation)
{
return Quaternion::RotationX(axisRotation.X) * Quaternion::RotationY(axisRotation.Y) * Quaternion::RotationZ(axisRotation.Z);
}
Quaternion AxisRotationToQuaternion(FbxDouble3 axisRotation)
{
return AxisRotationToQuaternion(FbxDouble3ToVector3(axisRotation));
}
Vector2 FbxDouble2ToVector2(FbxDouble2 vector)
{
return Vector2((float)vector[0], (float)vector[1]);
}
Color4 FbxDouble3ToColor4(FbxDouble3 vector, float alphaValue)
{
return Color4((float)vector[0], (float)vector[1], (float)vector[2], alphaValue);
}
Vector3 FbxDouble3ToVector3(FbxDouble3 vector)
{
return Vector3((float)vector[0], (float)vector[1], (float)vector[2]);
}
Vector4 FbxDouble3ToVector4(FbxDouble3 vector, float wValue)
{
return Vector4((float)vector[0], (float)vector[1], (float)vector[2], wValue);
}
Vector4 FbxDouble4ToVector4(FbxDouble4 vector)
{
return Vector4((float)vector[0], (float)vector[1], (float)vector[2], (float)vector[3]);
}
CompressedTimeSpan FBXTimeToTimeSpan(const FbxTime& time)
{
double resultTime = (double)time.Get();
resultTime *= (double)CompressedTimeSpan::TicksPerSecond / (double)FBXSDK_TIME_ONE_SECOND.Get();
return CompressedTimeSpan((int)resultTime);
}
Matrix FBXMatrixToMatrix(FbxAMatrix& matrix)
{
Matrix result;
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
((float*)&result)[i * 4 + j] = (float)((double*)&matrix)[j * 4 + i];
return result;
}
FbxAMatrix MatrixToFBXMatrix(Matrix& matrix)
{
FbxAMatrix result;
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
((double*)&result)[i * 4 + j] = (double)((float*)&matrix)[j * 4 + i];
return result;
}
double FocalLengthToVerticalFov(double filmHeight, double focalLength)
{
return 2.0 * Math::Atan(filmHeight * 0.5 * 10.0 * 2.54 / focalLength);
}
// Operators
FbxDouble3 operator*(double factor, FbxDouble3 vector)
{
return FbxDouble3(factor * vector[0], factor * vector[1], factor * vector[2]);
}
// string manipulation
System::String^ ConvertToUTF8(std::string str)
{
auto byteCount = str.length();
// Check `str' cannot be more than the size of a int.
assert(byteCount <= INT32_MAX);
if (byteCount <= 0)
{
return "";
}
array<Byte>^ bytes = gcnew array<Byte>((int) byteCount);
pin_ptr<Byte> p = &bytes[0];
memcpy(p, str.c_str(), byteCount);
return System::Text::Encoding::UTF8->GetString(bytes);
}

Просмотреть файл

@ -1,32 +0,0 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
#pragma once
#include "stdafx.h"
using namespace System;
using namespace Stride::Core::Mathematics;
using namespace Stride::Animations;
// conversion functions
Color4 FbxDouble3ToColor4(FbxDouble3 vector, float alphaValue = 1.0f);
Vector3 FbxDouble3ToVector3(FbxDouble3 vector);
Vector4 FbxDouble3ToVector4(FbxDouble3 vector, float wValue = 0.0f);
Vector4 FbxDouble4ToVector4(FbxDouble4 vector);
Matrix FBXMatrixToMatrix(FbxAMatrix& matrix);
FbxAMatrix MatrixToFBXMatrix(Matrix& matrix);
Quaternion AxisRotationToQuaternion(Vector3 axisRotation);
Quaternion AxisRotationToQuaternion(FbxDouble3 axisRotation);
CompressedTimeSpan FBXTimeToTimeSpan(const FbxTime& time);
double FocalLengthToVerticalFov(double filmHeight, double focalLength);
// operators
FbxDouble3 operator*(double factor, FbxDouble3 vector);
// string manipulation
System::String^ ConvertToUTF8(std::string str);

Просмотреть файл

@ -1,4 +0,0 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
#include "stdafx.h"

Просмотреть файл

@ -1,18 +0,0 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
#pragma once
#pragma warning( disable : 4945 )
#include <fbxsdk.h>
#include <vector>
#include <set>
#include <algorithm>
#include <wchar.h>
#include <algorithm>
#include <string>
#include <map>
#include "UtilityFunctions.h"