Free Support Forum - aspose.com

Exported FBX has no texture

I tried to make an fbx file.
for first practice I imported existing fbx file and get all element(vertex, normal, uv, triangle, texture) and created new scene and assigned data from existing fbx.

but result fbx(exported) has no texture.

can you tell me what did I make mistake?

here is code and sample fbx

    private void LoadAnsSave(string filePath, string exportPath)
    {
        var fullPath = Path.GetFullPath(filePath);
        var directory = Path.GetDirectoryName(fullPath);
        var scene = new Scene();
        scene.Open(filePath);

        var saveScene = new Scene();
        var rootNode = scene.RootNode;
        var childNodes = rootNode.ChildNodes;
        if ((childNodes != null) && (childNodes.Count > 0))
        {
            var nodeCount = childNodes.Count;
            for (var i = 0; i < nodeCount; i++)
            {
                var childNode = childNodes[i];
                ParseNode(childNode, directory, saveScene);
            }
        }

        saveScene.Save(exportPath, FileFormat.FBX7400ASCII);
    }

    private static void ParseNode(Node node, string directory, Scene saveScene)
    {
        var material = node.Material;
        var textures = default(Dictionary<TextureType, byte[]>);
        if (material != null)
        {
            textures = new Dictionary<TextureType, byte[]>();
            ParseMaterial(material, directory, textures);
            if (textures.Count == 0)
            {
                textures = null;
            }
        }
        foreach (var entity in node.Entities)
        {
            switch (entity)
            {
                case Mesh mesh:
                    var vertexDeclaration = new VertexDeclaration();
                    var vertexFieldForVertex = vertexDeclaration.AddField(VertexFieldDataType.FVector3, VertexFieldSemantic.Position);
                    var vertexFieldForNormal = vertexDeclaration.AddField(VertexFieldDataType.FVector3, VertexFieldSemantic.Normal);
                    var vertexFieldForUv = vertexDeclaration.AddField(VertexFieldDataType.FVector2, VertexFieldSemantic.UV);

                    var triMesh = TriMesh.FromMesh(mesh);
                    var vertices = new List<Vector3>();
                    var normals = new List<Vector3>();
                    var uvs = new List<Vector2>();
                    var triangles = new int[triMesh.IndicesCount];
                    triMesh.IndicesToArray(out triangles);

                    foreach (var vertex in triMesh)
                    {
                        var vertexRaw = vertex.ReadFVector3(vertexFieldForVertex);
                        var normalRaw = vertex.ReadFVector3(vertexFieldForNormal);
                        var uvRaw = vertex.ReadFVector2(vertexFieldForUv);
                        vertices.Add(new Vector3(vertexRaw.x, vertexRaw.y, vertexRaw.z));
                        normals.Add(new Vector3(normalRaw.x, normalRaw.y, normalRaw.z));
                        uvs.Add(new Vector2(uvRaw.x, uvRaw.y));
                    }

                    var newNode = new Node($"Mesh");
                    var newMesh = new Mesh();
                    newMesh.ControlPoints.AddRange(vertices.Select(v => new Aspose.ThreeD.Utilities.Vector4(v.x, v.y, v.z, 0)));
                    var pb = new PolygonBuilder(newMesh);
                    for (var j = 0; j < triangles.Length; j += 3)
                    {
                        pb.Begin();
                        pb.AddVertex(triangles[j]);
                        pb.AddVertex(triangles[j + 1]);
                        pb.AddVertex(triangles[j + 2]);
                        pb.End();
                    }
                    var elementNormal = newMesh.CreateElement(VertexElementType.Normal, MappingMode.ControlPoint, ReferenceMode.Direct) as VertexElementNormal;
                    elementNormal.Data.AddRange(normals.Select(v => new Aspose.ThreeD.Utilities.Vector4(v.x, v.y, v.z, 0)));
                    var elementUv = newMesh.CreateElement(VertexElementType.UV, MappingMode.ControlPoint, ReferenceMode.Direct) as VertexElementUV;
                    elementUv.Data.AddRange(uvs.Select(v => new Aspose.ThreeD.Utilities.Vector4(v.x, v.y, 0, 0)));

                    newNode.Entity = mesh;
                    saveScene.RootNode.AddChildNode(newNode);

                    if (textures != null)
                    {
                        var newMaterial = new PbrMaterial();
                        var hasTexture = false;
                        if (textures.TryGetValue(TextureType.FrontAlbedo, out var albedoMap))
                        {
                            var texture = new Texture();
                            texture.Content = albedoMap;
                            texture.FileName = $"Diffuse.png";
                            newMaterial.SetTexture(Material.MapDiffuse, texture);
                            hasTexture = true;
                        }
                        if (textures.TryGetValue(TextureType.FrontEmissive, out var emissiveMap))
                        {
                            var texture = new Texture();
                            texture.Content = albedoMap;
                            texture.FileName = $"Emissive.png";
                            newMaterial.SetTexture(Material.MapEmissive, texture);
                            hasTexture = true;
                        }
                        if (textures.TryGetValue(TextureType.FrontMetalness, out var metalnessMap))
                        {
                            var texture = new Texture();
                            texture.Content = albedoMap;
                            texture.FileName = $"Specular.png";
                            newMaterial.SetTexture(Material.MapSpecular, texture);
                            hasTexture = true;
                        }
                        if (textures.TryGetValue(TextureType.FrontNormal, out var normalMap))
                        {
                            var texture = new Texture();
                            texture.Content = albedoMap;
                            texture.FileName = $"Normal.png";
                            newMaterial.SetTexture(Material.MapNormal, texture);
                            hasTexture = true;
                        }
                        if (textures.TryGetValue(TextureType.FrontOcclusion, out var occlusionMap))
                        {
                            var texture = new Texture();
                            texture.Content = albedoMap;
                            texture.FileName = $"Ambient.png";
                            newMaterial.SetTexture(Material.MapAmbient, texture);
                            hasTexture = true;
                        }

                        if (hasTexture)
                        {
                            newMaterial.Albedo = new Vector3(1,1,1);
                            newMaterial.EmissiveColor = new Vector3(1, 1, 1);
                            newMaterial.MetallicFactor = 0.5;
                            newMaterial.OcclusionFactor = 0.5;
                            newMaterial.RoughnessFactor = 0.5;
                            newMaterial.Transparency = 1;
                            newNode.Material = newMaterial;
                        }
                    }
                    break;
                default:
                    break;
            }
        }

        var childNodes = node.ChildNodes;
        if ((childNodes != null) && (childNodes.Count > 0))
        {
            var childCount = childNodes.Count;
            for (var i = 0; i < childCount; i++)
            {
                ParseNode(childNodes[i], directory, saveScene);
            }
        }
    }

    private static void ParseMaterial(Material material, string directory, Dictionary<TextureType, byte[]> textures)
    {
        var ambientMap = material.GetTexture(Material.MapAmbient);
        var diffuseMap = material.GetTexture(Material.MapDiffuse);
        var emissiveMap = material.GetTexture(Material.MapEmissive);
        var normalMap = material.GetTexture(Material.MapNormal);
        var specularMap = material.GetTexture(Material.MapSpecular);
        if ((ambientMap != null) && diffuseMap is Texture ambientTexture)
        {
            if (GetTextureData(ambientTexture, directory, out var textureData))
            {
                textures[TextureType.FrontOcclusion] = textureData;
            }
        }
        if ((diffuseMap != null) && diffuseMap is Texture diffuseTexture)
        {
            if (GetTextureData(diffuseTexture, directory, out var textureData))
            {
                textures[TextureType.FrontAlbedo] = textureData;
                textures[TextureType.FrontDisplacement] = textureData;
            }
        }
        if ((emissiveMap != null) && emissiveMap is Texture emissiveTexture)
        {
            if (GetTextureData(emissiveTexture, directory, out var textureData))
            {
                textures[TextureType.FrontEmissive] = textureData;
            }
        }
        if ((normalMap != null) && normalMap is Texture normalTexture)
        {
            if (GetTextureData(normalTexture, directory, out var textureData))
            {
                textures[TextureType.FrontNormal] = textureData;
            }
        }
        if ((specularMap != null) && specularMap is Texture specularTexture)
        {
            if (GetTextureData(specularTexture, directory, out var textureData))
            {
                textures[TextureType.FrontMetalness] = textureData;
            }
        }
    }

    private static bool GetTextureData(Texture texture, string directory, out byte[] textureData)
    {
        try
        {
            if (texture.Content != null)
            {
                using (var ms = new MemoryStream(texture.Content))
                using (var image = Image.FromStream(ms))
                {
                    byte[] resultData = null;
                    if (image.RawFormat != ImageFormat.Png)
                    {
                        using (var convertStream = new MemoryStream())
                        {
                            image.Save(convertStream, ImageFormat.Png);
                            resultData = convertStream.ToArray();
                        }
                    }
                    else
                    {
                        resultData = ms.ToArray();
                    }

                    textureData = resultData;
                    return true;
                }
            }

            var filePath = texture.FileName;
            if (string.IsNullOrWhiteSpace(filePath))
            {
                textureData = default;
                return false;
            }

            var fileName = Path.GetFileName(texture.FileName);
            var files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
            foreach (var file in files)
            {
                if (Path.GetFileName(file) == fileName)
                {
                    using (var image = Image.FromFile(file))
                    using (var ms = new MemoryStream())
                    {
                        image.Save(ms, ImageFormat.Png);
                        var width = image.Width;
                        var height = image.Height;
                        textureData = ms.ToArray();
                        return true;
                    }
                }
            }
            textureData = default;
            return false;
        }
        catch (Exception)
        {
            textureData = default;
            return false;
        }

    }

    private enum TextureType
    {
        Preview,
        FrontAlbedo,
        FrontAlpha,
        FrontDisplacement,
        FrontNormal,
        FrontRoughness,
        FrontMetalness,
        FrontEmissive,
        FrontOcclusion,
        BackAlbedo,
        BackAlpha,
        BackDisplacement,
        BackNormal,
        BackRoughness,
        BackMetalness,
        BackEmissive,
        BackOcclusion,
    }

@HuePark

We have logged an issue as THREEDNET-807 in our issue tracking system for this scenario. We will further look into its details and keep you posted with the status of its correction. Please be patient and spare us some time.

We are sorry for the inconvenience.

@HuePark

We have investigated the ticket and found that this issue is because the current FBX exporter does not support PbrMaterial. Please use PhongMaterial/LambertMaterial instead.

The standard FBX file also does not support PBR material, tools like 3ds max/Maya implemented their own material by custom properties. We have created a ticket THREEDNET-818 for adding 3ds max compatible PBR material.

Also, there is an issue in your code, TriMesh.FromMesh(mesh) may generate a different VertexDeclaration to the manually created one. And convert Mesh to TriMesh then convert backward is very slow, modifying the Mesh can be done directly in the Mesh Class.