diff --git a/sources/tools/Stride.Importer.3D/Material/Materials.cs b/sources/tools/Stride.Importer.3D/Material/Materials.cs index 83d4f82f35..da2e6feb09 100644 --- a/sources/tools/Stride.Importer.3D/Material/Materials.cs +++ b/sources/tools/Stride.Importer.3D/Material/Materials.cs @@ -1,6 +1,8 @@ // 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 System; +using System.IO; using Silk.NET.Assimp; using Stride.Core.Diagnostics; using Stride.Core.Mathematics; @@ -77,7 +79,7 @@ public static unsafe class Materials MappingMode.Decal // aiTextureMapMode_Decal }; - public static unsafe MaterialStack ConvertAssimpStackCppToCs(Silk.NET.Assimp.Assimp assimp, Silk.NET.Assimp.Material* material, Silk.NET.Assimp.TextureType type, Logger logger) + public static unsafe MaterialStack ConvertAssimpStackCppToCs(Silk.NET.Assimp.Assimp assimp, Scene* scene, Silk.NET.Assimp.Material* material, Silk.NET.Assimp.TextureType type, Logger logger) { var ret = new MaterialStack(); var count = (int)assimp.GetMaterialTextureCount(material, type); @@ -141,8 +143,14 @@ public static unsafe MaterialStack ConvertAssimpStackCppToCs(Silk.NET.Assimp.Ass if (assimp.GetMaterialIntegerArray(material, Silk.NET.Assimp.Assimp.MaterialMappingmodeVBase, (uint)type, (uint)iEl, ref elMappingModeV, ref pMax) != Return.Success) elMappingModeV = (int)TextureMapMode.Wrap; // default mapping mode + // Determine the physical texture file name + if (!TryGetTextureFileName(elTexPath.AsString, scene, out var texFileName, out var errorMessage)) + { + logger?.Error(errorMessage); + continue; // error ! + } el = new StackTexture( - elTexPath.AsString, + texFileName, elTexChannel, ConvertAssimpMappingModeCppToCs[elMappingModeU], ConvertAssimpMappingModeCppToCs[elMappingModeV], @@ -160,5 +168,60 @@ public static unsafe MaterialStack ConvertAssimpStackCppToCs(Silk.NET.Assimp.Ass return ret; } + + internal static unsafe bool TryGetTextureFileName(string materialTextureFileName, Scene* scene, out string fileName, out string errorMessage) + { + var texFileName = Path.GetFileName(materialTextureFileName); + if (!texFileName.StartsWith(Assimp.EmbeddedTexnamePrefix)) + { + fileName = texFileName; + errorMessage = null; + return true; + } + // Embedded texture is denoted by '*' + index value, where the texture is accessed by scene->MTextures[index] + var texIndexStringSpan = texFileName.AsSpan().Slice(Assimp.EmbeddedTexnamePrefix.Length); + if (int.TryParse(texIndexStringSpan, out int texIndex)) + { + var texture = scene->MTextures[texIndex]; + return TryGetTextureFileName(texture, out fileName, out errorMessage); + } + else + { + fileName = null; + errorMessage = $"Invalid texture name for embedded texture: {texFileName} - Expected a number."; + return false; + } + } + + internal unsafe static bool TryGetTextureFileName(Silk.NET.Assimp.Texture* texture, out string fileName, out string errorMessage) + { + var texFileName = Path.GetFileName(texture->MFilename.AsString); + if (Path.HasExtension(texFileName)) + { + fileName = texFileName; + errorMessage = null; + return true; + } + // Formats like glTF may strip the file extension from the file name, so we need to bring this back + if (texture->MHeight != 0) + { + fileName = null; + errorMessage = $"Could not determine texture file name: Texture '{fileName}' is an embedded uncompressed texture."; + return false; + } + var fileExt = System.Text.Encoding.UTF8.GetString(texture->AchFormatHint, byteCount: Assimp.Hintmaxtexturelen).Trim('\0'); + if (!string.IsNullOrEmpty(fileExt)) + { + fileName = texFileName + '.' + fileExt; + errorMessage = null; + return true; + } + else + { + fileName = null; + errorMessage = $"Could not determine texture file name: Embedded Texture '{fileName}' has unknown file extension."; + return false; + } + } } } diff --git a/sources/tools/Stride.Importer.3D/MeshConverter.cs b/sources/tools/Stride.Importer.3D/MeshConverter.cs index 9d9ebc5bfa..86dd63aba9 100644 --- a/sources/tools/Stride.Importer.3D/MeshConverter.cs +++ b/sources/tools/Stride.Importer.3D/MeshConverter.cs @@ -869,14 +869,19 @@ private void NormalizeVertexWeights(List> controlPts, int n } } - + private unsafe void ExtractEmbededTexture(Scene* scene, string importFieName) { string dir = Path.GetDirectoryName(importFieName); for (uint i = 0; i < scene->MNumTextures; ++i) { - var texture=scene->MTextures[i]; - string fullName = Path.Combine(dir, Path.GetFileName(texture->MFilename)); + var texture = scene->MTextures[i]; + if (!Material.Materials.TryGetTextureFileName(texture, out var texFileName, out var errorMessage)) + { + Logger.Error(errorMessage); + continue; + } + string fullName = Path.Combine(dir, texFileName); CreateTextureFile(texture, fullName); } } @@ -903,7 +908,7 @@ private unsafe Dictionary ExtractMaterials(Scene* scene, { var lMaterial = scene->MMaterials[i]; var materialName = materialNames[(IntPtr)lMaterial]; - materials.Add(materialName, ProcessMeshMaterial(lMaterial)); + materials.Add(materialName, ProcessMeshMaterial(scene, lMaterial)); } return materials; } @@ -923,7 +928,7 @@ private unsafe void GenerateMaterialNames(Scene* scene, Dictionary (IntPtr)scene->MMaterials[i]); } - private unsafe MaterialAsset ProcessMeshMaterial(Silk.NET.Assimp.Material* pMaterial) + private unsafe MaterialAsset ProcessMeshMaterial(Scene* scene, Silk.NET.Assimp.Material* pMaterial) { var finalMaterial = new MaterialAsset(); @@ -955,16 +960,16 @@ private unsafe MaterialAsset ProcessMeshMaterial(Silk.NET.Assimp.Material* pMate if (hasDiffColor == false) SetMaterialColorFlag(pMaterial, Assimp.MatkeyBaseColor, ref hasDiffColor, ref diffColor, true); - BuildLayeredSurface(pMaterial, hasDiffColor, false, diffColor.ToStrideColor(), 0.0f, TextureType.Diffuse, finalMaterial); - BuildLayeredSurface(pMaterial, hasSpecColor, false, specColor.ToStrideColor(), 0.0f, TextureType.Specular, finalMaterial); - BuildLayeredSurface(pMaterial, false, false, dummyColor.ToStrideColor(), 0.0f, TextureType.Normals, finalMaterial); - BuildLayeredSurface(pMaterial, false, false, dummyColor.ToStrideColor(), 0.0f, TextureType.Displacement, finalMaterial); - BuildLayeredSurface(pMaterial, hasAmbientColor, false, ambientColor.ToStrideColor(), 0.0f, TextureType.Ambient, finalMaterial); - BuildLayeredSurface(pMaterial, false, hasOpacity, dummyColor.ToStrideColor(), opacity, TextureType.Opacity, finalMaterial); - BuildLayeredSurface(pMaterial, false, hasSpecPower, dummyColor.ToStrideColor(), specPower, TextureType.Shininess, finalMaterial); - BuildLayeredSurface(pMaterial, hasEmissiveColor, false, emissiveColor.ToStrideColor(), 0.0f, TextureType.Emissive, finalMaterial); - BuildLayeredSurface(pMaterial, false, false, dummyColor.ToStrideColor(), 0.0f, TextureType.Height, finalMaterial); - BuildLayeredSurface(pMaterial, hasReflectiveColor, false, reflectiveColor.ToStrideColor(), 0.0f, TextureType.Reflection, finalMaterial); + BuildLayeredSurface(scene, pMaterial, hasDiffColor, false, diffColor.ToStrideColor(), 0.0f, TextureType.Diffuse, finalMaterial); + BuildLayeredSurface(scene, pMaterial, hasSpecColor, false, specColor.ToStrideColor(), 0.0f, TextureType.Specular, finalMaterial); + BuildLayeredSurface(scene, pMaterial, false, false, dummyColor.ToStrideColor(), 0.0f, TextureType.Normals, finalMaterial); + BuildLayeredSurface(scene, pMaterial, false, false, dummyColor.ToStrideColor(), 0.0f, TextureType.Displacement, finalMaterial); + BuildLayeredSurface(scene, pMaterial, hasAmbientColor, false, ambientColor.ToStrideColor(), 0.0f, TextureType.Ambient, finalMaterial); + BuildLayeredSurface(scene, pMaterial, false, hasOpacity, dummyColor.ToStrideColor(), opacity, TextureType.Opacity, finalMaterial); + BuildLayeredSurface(scene, pMaterial, false, hasSpecPower, dummyColor.ToStrideColor(), specPower, TextureType.Shininess, finalMaterial); + BuildLayeredSurface(scene, pMaterial, hasEmissiveColor, false, emissiveColor.ToStrideColor(), 0.0f, TextureType.Emissive, finalMaterial); + BuildLayeredSurface(scene, pMaterial, false, false, dummyColor.ToStrideColor(), 0.0f, TextureType.Height, finalMaterial); + BuildLayeredSurface(scene, pMaterial, hasReflectiveColor, false, reflectiveColor.ToStrideColor(), 0.0f, TextureType.Reflection, finalMaterial); return finalMaterial; } @@ -989,7 +994,7 @@ private bool IsNotBlackColor(System.Numerics.Vector4 diffColor) return diffColor != System.Numerics.Vector4.Zero; } - private unsafe void BuildLayeredSurface(Silk.NET.Assimp.Material* pMat, bool hasBaseColor, bool hasBaseValue, Color4 baseColor, float baseValue, TextureType textureType, MaterialAsset finalMaterial) + private unsafe void BuildLayeredSurface(Scene* scene, Silk.NET.Assimp.Material* pMat, bool hasBaseColor, bool hasBaseValue, Color4 baseColor, float baseValue, TextureType textureType, MaterialAsset finalMaterial) { var nbTextures = assimp.GetMaterialTextureCount(pMat, textureType); @@ -1008,7 +1013,7 @@ private unsafe void BuildLayeredSurface(Silk.NET.Assimp.Material* pMat, bool has } else { - computeColorNode = GenerateOneTextureTypeLayers(pMat, textureType, textureCount, finalMaterial); + computeColorNode = GenerateOneTextureTypeLayers(scene, pMat, textureType, textureCount, finalMaterial); } if (computeColorNode == null) @@ -1020,7 +1025,7 @@ private unsafe void BuildLayeredSurface(Silk.NET.Assimp.Material* pMat, bool has { if (assimp.GetMaterialTextureCount(pMat, TextureType.Lightmap) > 0) { - var lightMap = GenerateOneTextureTypeLayers(pMat, TextureType.Lightmap, textureCount, finalMaterial); + var lightMap = GenerateOneTextureTypeLayers(scene, pMat, TextureType.Lightmap, textureCount, finalMaterial); if (lightMap != null) computeColorNode = new ComputeBinaryColor(computeColorNode, lightMap, BinaryOperator.Add); } @@ -1085,9 +1090,9 @@ private unsafe void BuildLayeredSurface(Silk.NET.Assimp.Material* pMat, bool has } } - private unsafe IComputeColor GenerateOneTextureTypeLayers(Silk.NET.Assimp.Material* pMat, TextureType textureType, int textureCount, MaterialAsset finalMaterial) + private unsafe IComputeColor GenerateOneTextureTypeLayers(Scene* scene, Silk.NET.Assimp.Material* pMat, TextureType textureType, int textureCount, MaterialAsset finalMaterial) { - var stack = Material.Materials.ConvertAssimpStackCppToCs(assimp, pMat, textureType, Logger); + var stack = Material.Materials.ConvertAssimpStackCppToCs(assimp, scene, pMat, textureType, Logger); var compositionFathers = new Stack(); @@ -1345,7 +1350,12 @@ private unsafe List ExtractTextureDependencies(Scene* scene) if (assimp.GetMaterialTexture(lMaterial, textureType, j, ref path, ref mapping, ref uvIndex, ref blend, ref textureOp, ref mapMode, ref flags) == Return.Success) { - var relFileName = Path.GetFileName(path.AsString); + if (!Material.Materials.TryGetTextureFileName(path.AsString, scene, out var texFileName, out var errorMessage)) + { + Logger.Error(errorMessage); + break; + } + var relFileName = texFileName; var fileNameToUse = Path.Combine(vfsInputPath, relFileName); textureNames.Add(fileNameToUse); break;