예제 #1
0
        /// <summary>
        /// Export the texture using the parameters of babylonTexture except its name.
        /// Write the bitmap file
        /// </summary>
        /// <param name="babylonTexture"></param>
        /// <param name="bitmap"></param>
        /// <param name="name"></param>
        /// <param name="gltf"></param>
        /// <returns></returns>
        private GLTFTextureInfo ExportBitmapTexture(GLTF gltf, BabylonTexture babylonTexture, Bitmap bitmap = null, string name = null)
        {
            if (babylonTexture != null)
            {
                if (bitmap == null)
                {
                    bitmap = babylonTexture.bitmap;
                }
                if (name == null)
                {
                    name = babylonTexture.name;
                }
            }

            return(ExportTexture(babylonTexture, gltf, name, () =>
            {
                var extension = Path.GetExtension(name);

                // Write image to output
                if (CopyTexturesToOutput)
                {
                    var absolutePath = Path.Combine(gltf.OutputFolder, name);
                    var imageFormat = extension == ".jpg" ? System.Drawing.Imaging.ImageFormat.Jpeg : System.Drawing.Imaging.ImageFormat.Png;
                    RaiseMessage($"GLTFExporter.Texture | write image '{name}' to '{absolutePath}'", 3);
                    bitmap.Save(absolutePath, imageFormat);
                }

                return extension.Substring(1); // remove the dot
            }));
        }
        void AttachMirrorPlane(BabylonTexture babylonTexture, NovaObject novaObject)
        {
            // Mirror plane
            int f1, f2, f3;

            if (novaObject.Is32bits)
            {
                f1 = novaObject.Indices32[2];
                f2 = novaObject.Indices32[1];
                f3 = novaObject.Indices32[0];
            }
            else
            {
                f1 = novaObject.Indices[2];
                f2 = novaObject.Indices[1];
                f3 = novaObject.Indices[0];
            }
            Vector3 a = novaObject.PositionOnlyVertices[f1];
            Vector3 b = novaObject.PositionOnlyVertices[f2];
            Vector3 c = novaObject.PositionOnlyVertices[f3];

            var mainPlane = new Plane(a, b, c);

            Matrix matrix = Matrix.Invert(novaObject.WorldMatrix);

            matrix = Matrix.Transpose(matrix);
            Plane plane = Plane.Transform(mainPlane, matrix);

            babylonTexture.mirrorPlane = new[] { plane.Normal.X, plane.Normal.Y, plane.Normal.Z, plane.D };
        }
        private GLTFTextureInfo ExportTexture(BabylonTexture babylonTexture, GLTF gltf)
        {
            return(ExportTexture(babylonTexture, gltf, null, () =>
            {
                var sourcePath = babylonTexture.originalPath;

                if (sourcePath == null || sourcePath == "")
                {
                    RaiseWarning("Texture path is missing.", 3);
                    return null;
                }

                var validImageFormat = GetGltfValidImageFormat(Path.GetExtension(sourcePath));

                if (validImageFormat == null)
                {
                    // Image format is not supported by the exporter
                    RaiseWarning(string.Format("Format of texture {0} is not supported by the exporter. Consider using a standard image format like jpg or png.", Path.GetFileName(sourcePath)), 3);
                    return null;
                }

                // Copy texture to output
                var destPath = Path.Combine(gltf.OutputFolder, babylonTexture.name);
                destPath = Path.ChangeExtension(destPath, validImageFormat);
                CopyGltfTexture(sourcePath, destPath);

                return validImageFormat;
            }));
        }
예제 #4
0
        private IStdUVGen _exportUV(IStdUVGen uvGen, BabylonTexture babylonTexture)
        {
            switch (uvGen.GetCoordMapping(0))
            {
            case 1:     //MAP_SPHERICAL
                babylonTexture.coordinatesMode = 1;
                break;

            case 2:     //MAP_PLANAR
                babylonTexture.coordinatesMode = 2;
                break;

            default:
                babylonTexture.coordinatesMode = 0;
                break;
            }

            babylonTexture.coordinatesIndex = uvGen.MapChannel - 1;
            if (uvGen.MapChannel > 2)
            {
                RaiseWarning(string.Format("Unsupported map channel, Only channel 1 and 2 are supported."), 2);
            }

            babylonTexture.uOffset = uvGen.GetUOffs(0);
            babylonTexture.vOffset = uvGen.GetVOffs(0);

            babylonTexture.uScale = uvGen.GetUScl(0);
            babylonTexture.vScale = uvGen.GetVScl(0);

            if (Path.GetExtension(babylonTexture.name).ToLower() == ".dds")
            {
                babylonTexture.vScale *= -1; // Need to invert Y-axis for DDS texture
            }

            babylonTexture.uAng = uvGen.GetUAng(0);
            babylonTexture.vAng = uvGen.GetVAng(0);
            babylonTexture.wAng = uvGen.GetWAng(0);

            babylonTexture.wrapU = BabylonTexture.AddressMode.CLAMP_ADDRESSMODE; // CLAMP
            if ((uvGen.TextureTiling & 1) != 0)                                  // WRAP
            {
                babylonTexture.wrapU = BabylonTexture.AddressMode.WRAP_ADDRESSMODE;
            }
            else if ((uvGen.TextureTiling & 4) != 0) // MIRROR
            {
                babylonTexture.wrapU = BabylonTexture.AddressMode.MIRROR_ADDRESSMODE;
            }

            babylonTexture.wrapV = BabylonTexture.AddressMode.CLAMP_ADDRESSMODE; // CLAMP
            if ((uvGen.TextureTiling & 2) != 0)                                  // WRAP
            {
                babylonTexture.wrapV = BabylonTexture.AddressMode.WRAP_ADDRESSMODE;
            }
            else if ((uvGen.TextureTiling & 8) != 0) // MIRROR
            {
                babylonTexture.wrapV = BabylonTexture.AddressMode.MIRROR_ADDRESSMODE;
            }

            return(uvGen);
        }
        private void _exportIsCube(string absolutePath, BabylonTexture babylonTexture, bool allowCube)
        {
            if (Path.GetExtension(absolutePath).ToLower() != ".dds")
            {
                babylonTexture.isCube = false;
            }
            else
            {
                try
                {
                    if (File.Exists(absolutePath))
                    {
                        babylonTexture.isCube = _isTextureCube(absolutePath);
                    }
                    else
                    {
                        RaiseWarning(string.Format("Texture {0} not found.", absolutePath), 3);
                    }
                }
                catch
                {
                    // silently fails
                }

                if (babylonTexture.isCube && !allowCube)
                {
                    RaiseWarning(string.Format("Cube texture are only supported for reflection channel"), 3);
                }
            }
        }
        /// <summary>
        /// Export the texture using the parameters of babylonTexture except its name.
        /// Write the bitmap file
        /// </summary>
        /// <param name="babylonTexture"></param>
        /// <param name="bitmap"></param>
        /// <param name="name"></param>
        /// <param name="gltf"></param>
        /// <returns></returns>
        private GLTFTextureInfo ExportBitmapTexture(GLTF gltf, BabylonTexture babylonTexture, Bitmap bitmap = null, string name = null)
        {
            if (babylonTexture != null)
            {
                if (bitmap == null)
                {
                    bitmap = babylonTexture.bitmap;
                }
                if (name == null)
                {
                    name = babylonTexture.name;
                }
            }

            return(ExportTexture(babylonTexture, gltf, name, () =>
            {
                var extension = Path.GetExtension(name).ToLower();

                // Write image to output
                if (exportParameters.writeTextures)
                {
                    var absolutePath = Path.Combine(gltf.OutputFolder, name);
                    var imageFormat = extension == ".jpg" ? System.Drawing.Imaging.ImageFormat.Jpeg : System.Drawing.Imaging.ImageFormat.Png;
                    logger.RaiseMessage($"GLTFExporter.Texture | write image '{name}' to '{absolutePath}'", 3);
                    TextureUtilities.SaveBitmap(bitmap, absolutePath, imageFormat, exportParameters.txtQuality, logger);
                }

                return extension.Substring(1); // remove the dot
            }));
        }
        private void _exportIsCube(IBitmapTex texture, BabylonTexture babylonTexture, bool allowCube)
        {
            var absolutePath = texture.Map.FullFilePath;

            try
            {
                if (File.Exists(absolutePath))
                {
                    babylonTexture.isCube = _isTextureCube(absolutePath);
                }
                else
                {
                    RaiseWarning(string.Format("Texture {0} not found.", babylonTexture.name), 2);
                }
            }
            catch
            {
                // silently fails
            }

            if (babylonTexture.isCube && !allowCube)
            {
                RaiseWarning(string.Format("Cube texture are only supported for reflection channel"), 2);
            }
        }
        private void CopyTextureCube(string texturePath, Cubemap cubemap, BabylonTexture babylonTexture)
        {
            if (!babylonScene.AddTextureCube(texturePath))
            {
                return;
            }

            try
            {
                foreach (CubemapFace face in Enum.GetValues(typeof(CubemapFace)))
                {
                    var faceTexturePath = Path.Combine(babylonScene.OutputPath, Path.GetFileNameWithoutExtension(texturePath));

                    switch (face)
                    {
                    case CubemapFace.PositiveX:
                        faceTexturePath += "_px.jpg";
                        break;

                    case CubemapFace.NegativeX:
                        faceTexturePath += "_nx.jpg";
                        break;

                    case CubemapFace.PositiveY:
                        faceTexturePath += "_py.jpg";
                        break;

                    case CubemapFace.NegativeY:
                        faceTexturePath += "_ny.jpg";
                        break;

                    case CubemapFace.PositiveZ:
                        faceTexturePath += "_pz.jpg";
                        break;

                    case CubemapFace.NegativeZ:
                        faceTexturePath += "_nz.jpg";
                        break;
                    }

                    var tempTexture = new Texture2D(cubemap.width, cubemap.height, cubemap.format, false);

                    tempTexture.SetPixels(cubemap.GetPixels(face));
                    tempTexture.Apply();

                    File.WriteAllBytes(faceTexturePath, tempTexture.EncodeToJPG());
                }
            }
            catch (Exception ex)
            {
                Debug.LogException(ex);
            }

            var textureName = Path.GetFileNameWithoutExtension(texturePath);

            babylonTexture.name            = textureName;
            babylonTexture.isCube          = true;
            babylonTexture.level           = exportationOptions.ReflectionDefaultLevel;
            babylonTexture.coordinatesMode = 3;
        }
        private void DumpCubeTexture(NovaTexture texture, BabylonTexture babylonTexture, BabylonScene babylonScene)
        {
            var textureFilename = Path.Combine(texture.LoadedTexture.Directory, texture.LoadedTexture.Filename);
            var baseName        = Path.GetFileNameWithoutExtension(texture.LoadedTexture.Filename);

            babylonTexture.isCube = true;
            babylonTexture.name   = baseName;

            baseName = Path.Combine(babylonScene.OutputPath, baseName);

            if (!File.Exists(textureFilename))
            {
                texture.LoadedTexture.SaveToDDS(false, textureFilename);
            }

            if (!alreadyExportedTextures.Contains(textureFilename))
            {
                alreadyExportedTextures.Add(textureFilename);

                // Use SharpDX to extract face images
                var form = new Form {
                    ClientSize = new Size(64, 64)
                };
                var device = new Device(new Direct3D(), 0, DeviceType.Hardware, form.Handle,
                                        CreateFlags.HardwareVertexProcessing,
                                        new PresentParameters(form.ClientSize.Width, form.ClientSize.Height));

                var cubeTexture = CubeTexture.FromFile(device, textureFilename);

                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.PositiveX, 0))
                {
                    Surface.ToFile(surface, baseName + "_px.jpg", ImageFileFormat.Jpg);
                }
                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.PositiveY, 0))
                {
                    Surface.ToFile(surface, baseName + "_py.jpg", ImageFileFormat.Jpg);
                }
                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.PositiveZ, 0))
                {
                    Surface.ToFile(surface, baseName + "_pz.jpg", ImageFileFormat.Jpg);
                }
                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.NegativeX, 0))
                {
                    Surface.ToFile(surface, baseName + "_nx.jpg", ImageFileFormat.Jpg);
                }
                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.NegativeY, 0))
                {
                    Surface.ToFile(surface, baseName + "_ny.jpg", ImageFileFormat.Jpg);
                }
                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.NegativeZ, 0))
                {
                    Surface.ToFile(surface, baseName + "_nz.jpg", ImageFileFormat.Jpg);
                }

                cubeTexture.Dispose();
                device.Dispose();
                form.Dispose();
            }
        }
        internal void RegisterBaseColorAlphaImageName(BabylonTexture texture, string imageName)
        {
            var key = new PairBaseColorAlpha(texture);

            if (!_DicoPairBaseColorAlphaImageName.ContainsKey(key))

            {
                _DicoPairBaseColorAlphaImageName.Add(key, imageName);
            }
        }
        void DumpTextureAnimation(NovaTexture texture, BabylonTexture babylonTexture)
        {
            var animations = new List <BabylonAnimation>();

            DumpInterpolator("Texture UOffset", "uOffset", texture.UOffsetInterpolator, texture.ParentScene, animations);
            DumpInterpolator("Texture VOffset", "vOffset", texture.VOffsetInterpolator, texture.ParentScene, animations);
            DumpInterpolator("Texture UScale", "uScale", texture.UScaleInterpolator, texture.ParentScene, animations);
            DumpInterpolator("Texture VScale", "vScale", texture.VScaleInterpolator, texture.ParentScene, animations);

            babylonTexture.animations = animations.ToArray();
        }
예제 #12
0
        private BabylonTexture ExportEnvironmnentTexture(ITexmap texMap, BabylonScene babylonScene)
        {
            if (texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
            {
                RaiseWarning("Failed to export environment texture. Uncheck \"Use Map\" option to fix this warning.");
                return(null);
            }

            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;

            if (texture == null)
            {
                RaiseWarning("Failed to export environment texture. Uncheck \"Use Map\" option to fix this warning.");
                return(null);
            }

            var sourcePath = texture.Map.FullFilePath;
            var fileName   = Path.GetFileName(sourcePath);

            // Allow only dds file format
            if (!fileName.EndsWith(".dds"))
            {
                RaiseWarning("Failed to export environment texture: only .dds format is supported. Uncheck \"Use map\" to fix this warning.");
                return(null);
            }

            var babylonTexture = new BabylonTexture
            {
                name = fileName
            };

            // Copy texture to output
            if (isBabylonExported)
            {
                var destPath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);

                if (CopyTexturesToOutput)
                {
                    try
                    {
                        if (File.Exists(sourcePath))
                        {
                            File.Copy(sourcePath, destPath, true);
                        }
                    }
                    catch
                    {
                        // silently fails
                    }
                }
            }

            return(babylonTexture);
        }
        void DumpTexture(NovaTexture texture, BabylonTexture babylonTexture, BabylonScene babylonScene)
        {
            babylonTexture.level           = texture.Level;
            babylonTexture.hasAlpha        = texture.HasAlpha;
            babylonTexture.coordinatesMode = (int)texture.MapType;

            if (texture.LoadedTexture.IsCube)
            {
                DumpCubeTexture(texture, babylonTexture, babylonScene);
                return;
            }

            babylonTexture.name    = texture.Name;
            babylonTexture.uOffset = texture.UOffset;
            babylonTexture.vOffset = texture.VOffset;
            babylonTexture.uScale  = texture.UScale;
            babylonTexture.vScale  = texture.VScale;
            babylonTexture.uAng    = texture.UAng;
            babylonTexture.vAng    = texture.VAng;
            babylonTexture.wAng    = texture.WAng;
            switch (texture.UAddressMode)
            {
            case NovaTextureAddress.Wrap:
                babylonTexture.wrapU = 1;
                break;

            case NovaTextureAddress.Mirror:
                babylonTexture.wrapU = 2;
                break;

            case NovaTextureAddress.Clamp:
                babylonTexture.wrapU = 0;
                break;
            }
            switch (texture.VAddressMode)
            {
            case NovaTextureAddress.Wrap:
                babylonTexture.wrapV = 1;
                break;

            case NovaTextureAddress.Mirror:
                babylonTexture.wrapV = 2;
                break;

            case NovaTextureAddress.Clamp:
                babylonTexture.wrapV = 0;
                break;
            }
            babylonTexture.coordinatesIndex = texture.MapCoordinateIndex;

            DumpTextureAnimation(texture, babylonTexture);

            babylonTexture.name = CopyTexture(texture, babylonScene);
        }
        /// <summary>
        /// Export the texture using the parameters of babylonTexture except its name.
        /// Write the bitmap file
        /// </summary>
        /// <param name="babylonTexture"></param>
        /// <param name="bitmap"></param>
        /// <param name="name"></param>
        /// <param name="gltf"></param>
        /// <returns></returns>
        private GLTFTextureInfo ExportBitmapTexture(BabylonTexture babylonTexture, Bitmap bitmap, string name, GLTF gltf)
        {
            // Copy image to output
            if (CopyTexturesToOutput)
            {
                var absolutePath = Path.Combine(gltf.OutputPath, name);
                RaiseMessage($"GLTFExporter.Texture | write image '{name}' to '{absolutePath}'", 1);
                bitmap.Save(absolutePath);
            }

            return(ExportTexture(babylonTexture, gltf, name));
        }
        /// <summary>
        /// Export the texture using the parameters of babylonTexture except its name.
        /// Write the bitmap file
        /// </summary>
        /// <param name="babylonTexture"></param>
        /// <param name="bitmap"></param>
        /// <param name="name"></param>
        /// <param name="gltf"></param>
        /// <returns></returns>
        private GLTFTextureInfo ExportBitmapTexture(BabylonTexture babylonTexture, Bitmap bitmap, string name, GLTF gltf)
        {
            // Copy image to output
            if (CopyTexturesToOutput)
            {
                var absolutePath = Path.Combine(gltf.OutputFolder, name);
                var imageFormat  = Path.GetExtension(name) == ".jpg" ? System.Drawing.Imaging.ImageFormat.Jpeg : System.Drawing.Imaging.ImageFormat.Png;
                RaiseMessage($"GLTFExporter.Texture | write image '{name}' to '{absolutePath}'", 1);
                bitmap.Save(absolutePath, imageFormat);
            }

            return(ExportTexture(babylonTexture, gltf, name));
        }
        internal string BaseColorAlphaImageNameLookup(BabylonTexture texture, string defaultName = null)
        {
            var    key       = new PairBaseColorAlpha(texture);
            string imageName = null;

            if (_DicoPairBaseColorAlphaImageName.TryGetValue(key, out imageName))
            {
                return(imageName);
            }
            key = _DicoPairBaseColorAlphaImageName.Keys.Where(k => k.baseColorPath.Equals(key.baseColorPath)).FirstOrDefault();

            return(key != null ? _DicoPairBaseColorAlphaImageName[key] : defaultName);
        }
        private void DumpRenderTargetTexture(NovaTexture texture, BabylonTexture babylonTexture, int renderSize, float level, NovaMirroredObjectsList renderList)
        {
            babylonTexture.level           = level;
            babylonTexture.hasAlpha        = false;
            babylonTexture.coordinatesMode = (int)NovaTexture.NovaTextureMapType.Projection;

            babylonTexture.name    = texture.Name;
            babylonTexture.uOffset = texture.UOffset;
            babylonTexture.vOffset = texture.VOffset;
            babylonTexture.uScale  = texture.UScale;
            babylonTexture.vScale  = texture.VScale;
            babylonTexture.uAng    = texture.UAng;
            babylonTexture.vAng    = texture.VAng;
            babylonTexture.wAng    = texture.WAng;
            switch (texture.UAddressMode)
            {
            case NovaTextureAddress.Wrap:
                babylonTexture.wrapU = 1;
                break;

            case NovaTextureAddress.Mirror:
                babylonTexture.wrapU = 2;
                break;

            case NovaTextureAddress.Clamp:
                babylonTexture.wrapU = 0;
                break;
            }
            switch (texture.VAddressMode)
            {
            case NovaTextureAddress.Wrap:
                babylonTexture.wrapV = 1;
                break;

            case NovaTextureAddress.Mirror:
                babylonTexture.wrapV = 2;
                break;

            case NovaTextureAddress.Clamp:
                babylonTexture.wrapV = 0;
                break;
            }
            babylonTexture.coordinatesIndex = texture.MapCoordinateIndex;

            DumpTextureAnimation(texture, babylonTexture);

            babylonTexture.isRenderTarget   = true;
            babylonTexture.renderTargetSize = renderSize;

            babylonTexture.renderList = renderList.Select(o => o.ID.ToString()).ToArray();
        }
예제 #18
0
        /// <summary>
        /// Export the texture using the parameters of babylonTexture except its name.
        /// Write the bitmap file
        /// </summary>
        /// <param name="babylonTexture"></param>
        /// <param name="bitmap"></param>
        /// <param name="name"></param>
        /// <param name="gltf"></param>
        /// <returns></returns>
        private GLTFTextureInfo ExportBitmapTexture(GLTF gltf, BabylonTexture babylonTexture, Bitmap bitmap = null, string name = null)
        {
            if (babylonTexture != null)
            {
                if (bitmap == null)
                {
                    bitmap = babylonTexture.bitmap;
                }
                if (name == null)
                {
                    name = babylonTexture.name;
                }
            }

            return(ExportTexture(babylonTexture, gltf, name));
        }
예제 #19
0
        private void ConvertUnitySkyboxToBabylon(Camera camera, float progress)
        {
            // Skybox
            if ((camera.clearFlags & CameraClearFlags.Skybox) == CameraClearFlags.Skybox)
            {
                if (RenderSettings.skybox != null)
                {
                    if (RenderSettings.skybox.shader.name == "Skybox/Cubemap")
                    {
                        var cubeMap = RenderSettings.skybox.GetTexture("_Tex") as Cubemap;
                        if (cubeMap != null)
                        {
                            var skytex = new BabylonTexture();
                            CopyTextureCube("sceneSkybox.hdr", cubeMap, skytex);
                            skytex.coordinatesMode = 5;
                            skytex.level           = RenderSettings.reflectionIntensity;

                            BabylonMesh skybox = new BabylonMesh();
                            skybox.indices   = new[] { 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23 };
                            skybox.positions = new[] { 50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, 50.0f, 50.0f, 50.0f, 50.0f, 50.0f, 50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, 50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, 50.0f, 50.0f, 50.0f, 50.0f, -50.0f, 50.0f, 50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, -50.0f, -50.0f, 50.0f, -50.0f, -50.0f, 50.0f, 50.0f, -50.0f, 50.0f, -50.0f, 50.0f, 50.0f, -50.0f, 50.0f, 50.0f, 50.0f, 50.0f, -50.0f, 50.0f, 50.0f, -50.0f, -50.0f, -50.0f, -50.0f, -50.0f, -50.0f, -50.0f, 50.0f };
                            skybox.uvs       = new[] { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
                            skybox.normals   = new[] { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0, 0f };

                            var skyboxMaterial = new BabylonPBRMaterial()
                            {
                                name                 = "sceneSkyboxMaterial",
                                id                   = Guid.NewGuid().ToString(),
                                albedo               = new[] { 1.0f, 1.0f, 1.0f, 1.0f },
                                reflectivity         = new[] { 0.0f, 0.0f, 0.0f },
                                microSurface         = 1.0f,
                                directIntensity      = 0.0f,
                                specularIntensity    = 0.0f,
                                environmentIntensity = 1.0f
                            };
                            skyboxMaterial.backFaceCulling = false;
                            skybox.materialId                = skyboxMaterial.id;
                            skybox.infiniteDistance          = true;
                            skyboxMaterial.reflectionTexture = skytex;

                            babylonScene.MeshesList.Add(skybox);
                            babylonScene.MaterialsList.Add(skyboxMaterial);
                            babylonScene.AddTextureCube("sceneSkyboxMaterial");
                        }
                    }
                }
            }
        }
예제 #20
0
        private BabylonTexture ExportEnvironmnentTexture(ITexmap texMap, BabylonScene babylonScene)
        {
            if (texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
            {
                return(null);
            }

            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;

            if (texture == null)
            {
                return(null);
            }

            var sourcePath = texture.Map.FullFilePath;

            var babylonTexture = new BabylonTexture
            {
                name = Path.GetFileName(sourcePath)
            };

            // Copy texture to output
            if (isBabylonExported)
            {
                var destPath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);

                if (CopyTexturesToOutput)
                {
                    try
                    {
                        if (File.Exists(sourcePath))
                        {
                            File.Copy(sourcePath, destPath, true);
                        }
                    }
                    catch
                    {
                        // silently fails
                    }
                }
            }

            return(babylonTexture);
        }
예제 #21
0
        private BabylonFurMaterial ExportFurModifier(IModifier modifier, String sourceMeshName, BabylonScene babylonScene)
        {
            RaiseMessage("Export Fur Modifier", 2);
            var paramBlock = modifier.GetParamBlock(0);

            // 3dsMax "Cut Length" is in percentages - "100%" will be "20" babylon spacing
            // (babylon Fur length means the distance from the obj, while the length of the hair is the spacing)
            var cutLength = paramBlock.GetFloat(CUT_LENGTH_PARAM_ID, 0, 0);
            var spacing   = (int)Math.Round(cutLength / 5);

            // 3dsMax "Root Thick" is in percentages - "100%" will be "1" babylon density
            // (lower density in babylon is thicker hair - lower root thick in 3dsMax is thinner)
            var rootThickness = paramBlock.GetFloat(ROOT_THICKNESS_PARAM_ID, 0, 0);
            var density       = (int)Math.Ceiling((100.1f - rootThickness) / 5);

            var rootColor = paramBlock.GetColor(ROOT_COLOR_PARAM_ID, 0, 0);
            var furColor  = new float[] { rootColor.R, rootColor.G, rootColor.B };

            if (paramBlock.GetTexmap(MAPS_PARAM_ID, 0, 11) != null)
            {
                RaiseWarning("Tip texture is not supported. Use root texture instead", 2);
            }

            BabylonTexture diffuseTexture  = null;
            ITexmap        rootColorTexmap = paramBlock.GetTexmap(MAPS_PARAM_ID, 0, 14);

            if (rootColorTexmap != null)
            {
                diffuseTexture       = ExportTexture(rootColorTexmap, 0f, babylonScene);
                diffuseTexture.level = 1;
            }

            return(new BabylonFurMaterial
            {
                id = modifier.GetGuid().ToString(),
                name = modifier.GetGuid().ToString(),
                sourceMeshName = sourceMeshName,
                furDensity = density,
                furSpacing = spacing,
                diffuseTexture = diffuseTexture,
                furColor = furColor,
            });
        }
        private BabylonTexture DumpTexture(Texture texture, Material material = null, string name = "", bool isLightmap = false)
        {
            if (texture == null)
            {
                return(null);
            }

            var texturePath    = AssetDatabase.GetAssetPath(texture);
            var textureName    = Path.GetFileName(texturePath);
            var babylonTexture = new BabylonTexture {
                name = textureName
            };

            if (material != null)
            {
                var textureScale = material.GetTextureScale(name);
                babylonTexture.uScale = textureScale.x;
                babylonTexture.vScale = textureScale.y;

                var textureOffset = material.GetTextureOffset(name);
                babylonTexture.uOffset = textureOffset.x;
                babylonTexture.vOffset = textureOffset.y;
            }

            var texture2D = texture as Texture2D;

            if (texture2D)
            {
                babylonTexture.hasAlpha = texture2D.alphaIsTransparency;

                CopyTexture(texturePath, texture2D, babylonTexture, isLightmap);
            }
            else
            {
                var cubemap = texture as Cubemap;
                if (cubemap != null)
                {
                    CopyTextureCube(texturePath, cubemap, babylonTexture);
                }
            }

            return(babylonTexture);
        }
예제 #23
0
        private BabylonTexture DumpReflectionTexture()
        {
            if (sceneReflectionTexture != null)
            {
                return(sceneReflectionTexture);
            }

            // Take only reflection source currently and not the RenderSettings.ambientMode
            if (RenderSettings.defaultReflectionMode == UnityEngine.Rendering.DefaultReflectionMode.Skybox)
            {
                var skybox = RenderSettings.skybox;
                if (skybox != null)
                {
                    if (skybox.shader.name == "Skybox/Cubemap")
                    {
                        var cubeMap = skybox.GetTexture("_Tex") as Cubemap;
                        if (cubeMap != null)
                        {
                            sceneReflectionTexture = new BabylonTexture();
                            CopyTextureCube("sceneReflectionTexture.hdr", cubeMap, sceneReflectionTexture);
                            sceneReflectionTexture.level = RenderSettings.reflectionIntensity;
                        }
                    }
                    //else if (skybox.shader.name == "Skybox/6 Sided")
                    //{
                    //    // TODO. HDR faces.
                    //}
                }
            }
            else if (RenderSettings.customReflection != null)
            {
                var cubeMap = RenderSettings.customReflection;
                sceneReflectionTexture = new BabylonTexture();
                CopyTextureCube("sceneReflectionTexture.hdr", cubeMap, sceneReflectionTexture);
                sceneReflectionTexture.level = RenderSettings.reflectionIntensity;
            }

            return(sceneReflectionTexture);
        }
        private GLTFTextureInfo ExportTexture(BabylonTexture babylonTexture, GLTF gltf, string name, Func <string> writeImageFunc)
        {
            if (babylonTexture == null)
            {
                return(null);
            }

            if (name == null)
            {
                name = babylonTexture.name;
            }


            logger.RaiseMessage("GLTFExporter.Texture | Export texture named: " + name, 2);

            if (glTFTextureInfoMap.ContainsKey(babylonTexture.Id))
            {
                return(glTFTextureInfoMap[babylonTexture.Id]);
            }
            else
            {
                string validImageFormat = writeImageFunc.Invoke();
                if (validImageFormat == null)
                {
                    return(null);
                }

                name = Path.ChangeExtension(name, validImageFormat);

                // --------------------------
                // -------- Sampler ---------
                // --------------------------
                logger.RaiseMessage("GLTFExporter.Texture | create sampler", 3);
                GLTFSampler gltfSampler = new GLTFSampler();
                gltfSampler.index = gltf.SamplersList.Count;

                // --- Retrieve info from babylon texture ---
                // Mag and min filters
                GLTFSampler.TextureMagFilter?magFilter;
                GLTFSampler.TextureMinFilter?minFilter;
                getSamplingParameters(babylonTexture.samplingMode, out magFilter, out minFilter);
                gltfSampler.magFilter = magFilter;
                gltfSampler.minFilter = minFilter;
                // WrapS and wrapT
                gltfSampler.wrapS = getWrapMode(babylonTexture.wrapU);
                gltfSampler.wrapT = getWrapMode(babylonTexture.wrapV);

                var matchingSampler = gltf.SamplersList.FirstOrDefault(sampler => sampler.wrapS == gltfSampler.wrapS && sampler.wrapT == gltfSampler.wrapT && sampler.magFilter == gltfSampler.magFilter && sampler.minFilter == gltfSampler.minFilter);
                if (matchingSampler != null)
                {
                    gltfSampler = matchingSampler;
                }
                else
                {
                    gltf.SamplersList.Add(gltfSampler);
                }


                // --------------------------
                // --------- Image ----------
                // --------------------------

                logger.RaiseMessage("GLTFExporter.Texture | create image", 3);
                GLTFImage gltfImage = null;
                if (glTFImageMap.ContainsKey(name))
                {
                    gltfImage = glTFImageMap[name];
                }
                else
                {
                    string textureUri = name;
                    if (!string.IsNullOrWhiteSpace(exportParameters.textureFolder))
                    {
                        textureUri = PathUtilities.GetRelativePath(exportParameters.outputPath, exportParameters.textureFolder) + "/" + name;
                    }
                    gltfImage = new GLTFImage
                    {
                        uri = textureUri
                    };
                    gltfImage.index = gltf.ImagesList.Count;
                    gltf.ImagesList.Add(gltfImage);
                    glTFImageMap.Add(name, gltfImage);
                    switch (validImageFormat)
                    {
                    case "jpg":
                        gltfImage.FileExtension = "jpeg";
                        break;

                    case "png":
                        gltfImage.FileExtension = "png";
                        break;
                    }
                }

                // --------------------------
                // -------- Texture ---------
                // --------------------------

                logger.RaiseMessage("GLTFExporter.Texture | create texture", 3);
                var gltfTexture = new GLTFTexture
                {
                    name    = name,
                    sampler = gltfSampler.index,
                    source  = gltfImage.index
                };
                gltfTexture.index = gltf.TexturesList.Count;
                gltf.TexturesList.Add(gltfTexture);


                // --------------------------
                // ------ TextureInfo -------
                // --------------------------
                var gltfTextureInfo = new GLTFTextureInfo
                {
                    index    = gltfTexture.index,
                    texCoord = babylonTexture.coordinatesIndex
                };

                if (!(babylonTexture.uOffset == 0) || !(babylonTexture.vOffset == 0) || !(babylonTexture.uScale == 1) || !(babylonTexture.vScale == -1) || !(babylonTexture.wAng == 0))
                {
                    // Add texture extension if enabled in the export settings
                    if (exportParameters.enableKHRTextureTransform)
                    {
                        AddTextureTransformExtension(ref gltf, ref gltfTextureInfo, babylonTexture);
                    }
                    else
                    {
                        logger.RaiseWarning("GLTFExporter.Texture | KHR_texture_transform is not enabled, so the texture may look incorrect at runtime!", 3);
                        logger.RaiseWarning("GLTFExporter.Texture | KHR_texture_transform is not enabled, so the texture may look incorrect at runtime!", 3);
                    }
                }
                var textureID = name + TextureTransformID(gltfTextureInfo);
                // Check for texture optimization.  This is done here after the texture transform has been potentially applied to the texture extension
                if (CheckIfImageIsRegistered(textureID))
                {
                    var textureComponent = GetRegisteredTexture(textureID);

                    return(textureComponent);
                }

                // Add the texture in the dictionary
                RegisterTexture(gltfTextureInfo, textureID);
                glTFTextureInfoMap[babylonTexture.Id] = gltfTextureInfo;

                return(gltfTextureInfo);
            }
        }
 private GLTFTextureInfo ExportTexture(BabylonTexture babylonTexture, GLTF gltf)
 {
     return(ExportTexture(babylonTexture, gltf, null,
                          () => { return TryWriteImage(gltf, babylonTexture.originalPath, babylonTexture.name); }));
 }
        /// <summary>
        /// Add the KHR_texture_transform to the glTF file
        /// </summary>
        /// <param name="gltf"></param>
        /// <param name="babylonMaterial"></param>
        private void AddTextureTransformExtension(ref GLTF gltf, ref GLTFTextureInfo gltfTextureInfo, BabylonTexture babylonTexture)
        {
            if (!gltf.extensionsUsed.Contains(KHR_texture_transform))
            {
                gltf.extensionsUsed.Add(KHR_texture_transform);
            }
            if (!gltf.extensionsRequired.Contains(KHR_texture_transform))
            {
                gltf.extensionsRequired.Add(KHR_texture_transform);
            }

            float angle       = babylonTexture.wAng;
            float angleDirect = -babylonTexture.wAng;

            KHR_texture_transform textureTransform = new KHR_texture_transform
            {
                offset   = new float[] { babylonTexture.uOffset, -babylonTexture.vOffset },
                rotation = angle,
                scale    = new float[] { babylonTexture.uScale, -babylonTexture.vScale },
                texCoord = babylonTexture.coordinatesIndex
            };


            if (gltfTextureInfo.extensions == null)
            {
                gltfTextureInfo.extensions = new GLTFExtensions();
            }
            gltfTextureInfo.extensions[KHR_texture_transform] = textureTransform;
        }
        private IStdUVGen _exportUV(IStdUVGen uvGen, BabylonTexture babylonTexture)
        {
            switch (uvGen.GetCoordMapping(0))
            {
            case 1:     //MAP_SPHERICAL
                babylonTexture.coordinatesMode = BabylonTexture.CoordinatesMode.SPHERICAL_MODE;
                break;

            case 2:     //MAP_PLANAR
                babylonTexture.coordinatesMode = BabylonTexture.CoordinatesMode.PLANAR_MODE;
                break;

            default:
                babylonTexture.coordinatesMode = BabylonTexture.CoordinatesMode.EXPLICIT_MODE;
                break;
            }

            babylonTexture.coordinatesIndex = uvGen.MapChannel - 1;
            if (uvGen.MapChannel > 2)
            {
                RaiseWarning(string.Format("Unsupported map channel, Only channel 1 and 2 are supported."), 3);
            }

            babylonTexture.uOffset = uvGen.GetUOffs(0);
            babylonTexture.vOffset = -uvGen.GetVOffs(0);

            babylonTexture.uScale = uvGen.GetUScl(0);
            babylonTexture.vScale = uvGen.GetVScl(0);

            var offset          = new BabylonVector3(babylonTexture.uOffset, -babylonTexture.vOffset, 0);
            var scale           = new BabylonVector3(babylonTexture.uScale, babylonTexture.vScale, 1);
            var rotationEuler   = new BabylonVector3(uvGen.GetUAng(0), uvGen.GetVAng(0), uvGen.GetWAng(0));
            var rotation        = BabylonQuaternion.FromEulerAngles(rotationEuler.X, rotationEuler.Y, rotationEuler.Z);
            var pivotCenter     = new BabylonVector3(-0.5f, -0.5f, 0);
            var transformMatrix = MathUtilities.ComputeTextureTransformMatrix(pivotCenter, offset, rotation, scale);

            transformMatrix.decompose(scale, rotation, offset);
            var texTransformRotationEuler = rotation.toEulerAngles();

            babylonTexture.uOffset         = -offset.X;
            babylonTexture.vOffset         = -offset.Y;
            babylonTexture.uScale          = scale.X;
            babylonTexture.vScale          = -scale.Y;
            babylonTexture.uRotationCenter = 0.0f;
            babylonTexture.vRotationCenter = 0.0f;
            babylonTexture.invertY         = false;
            babylonTexture.uAng            = texTransformRotationEuler.X;
            babylonTexture.vAng            = texTransformRotationEuler.Y;
            babylonTexture.wAng            = texTransformRotationEuler.Z;

            if (Path.GetExtension(babylonTexture.name).ToLower() == ".dds")
            {
                babylonTexture.vScale *= -1; // Need to invert Y-axis for DDS texture
            }

            if (babylonTexture.wAng != 0f &&
                (babylonTexture.uScale != 1f || babylonTexture.vScale != 1f) &&
                (Math.Abs(babylonTexture.uScale) - Math.Abs(babylonTexture.vScale)) > float.Epsilon)
            {
                RaiseWarning("Rotation and non-uniform tiling (scale) on a texture is not supported as it will cause texture shearing. You can use the map UV of the mesh for those transformations.", 3);
            }


            babylonTexture.wrapU = BabylonTexture.AddressMode.CLAMP_ADDRESSMODE; // CLAMP
            if ((uvGen.TextureTiling & 1) != 0)                                  // WRAP
            {
                babylonTexture.wrapU = BabylonTexture.AddressMode.WRAP_ADDRESSMODE;
            }
            else if ((uvGen.TextureTiling & 4) != 0) // MIRROR
            {
                babylonTexture.wrapU = BabylonTexture.AddressMode.MIRROR_ADDRESSMODE;
            }

            babylonTexture.wrapV = BabylonTexture.AddressMode.CLAMP_ADDRESSMODE; // CLAMP
            if ((uvGen.TextureTiling & 2) != 0)                                  // WRAP
            {
                babylonTexture.wrapV = BabylonTexture.AddressMode.WRAP_ADDRESSMODE;
            }
            else if ((uvGen.TextureTiling & 8) != 0) // MIRROR
            {
                babylonTexture.wrapV = BabylonTexture.AddressMode.MIRROR_ADDRESSMODE;
            }

            return(uvGen);
        }
        private BabylonTexture ExportTexture(ITexmap texMap, BabylonScene babylonScene, float amount = 1.0f, bool allowCube = false, bool forceAlpha = false)
        {
            IBitmapTex texture = _getBitmapTex(texMap, false);

            if (texture == null)
            {
                float specialAmount;
                var   specialTexMap = _getSpecialTexmap(texMap, out specialAmount);
                texture = _getBitmapTex(specialTexMap, false);
                amount *= specialAmount;
            }

            if (texture == null)
            {
                return(null);
            }

            var sourcePath = texture.Map.FullFilePath;

            if (sourcePath == null || sourcePath == "")
            {
                RaiseWarning("Texture path is missing.", 2);
                return(null);
            }

            RaiseMessage("Export texture named: " + Path.GetFileName(sourcePath), 2);

            var validImageFormat = TextureUtilities.GetValidImageFormat(Path.GetExtension(sourcePath));

            if (validImageFormat == null)
            {
                // Image format is not supported by the exporter
                RaiseWarning(string.Format("Format of texture {0} is not supported by the exporter. Consider using a standard image format like jpg or png.", Path.GetFileName(sourcePath)), 3);
                return(null);
            }
            var textureID = texture.GetGuid().ToString();

            if (textureMap.ContainsKey(textureID))
            {
                return(textureMap[textureID]);
            }
            else
            {
                var babylonTexture = new BabylonTexture(textureID)
                {
                    name = Path.GetFileNameWithoutExtension(texture.MapName) + "." + validImageFormat
                };
                RaiseMessage($"texture id = {babylonTexture.Id}", 2);

                // Level
                babylonTexture.level = amount;

                // Alpha
                if (forceAlpha)
                {
                    babylonTexture.hasAlpha        = true;
                    babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2) || (texture.AlphaSource == 3); // 'RGB intensity' or 'None (Opaque)'
                }
                else
                {
                    babylonTexture.hasAlpha        = (texture.AlphaSource != 3); // Not 'None (Opaque)'
                    babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2); // 'RGB intensity'
                }

                // UVs
                var uvGen = _exportUV(texture.UVGen, babylonTexture);

                // Animations
                var animations = new List <BabylonAnimation>();
                ExportFloatAnimation("uOffset", animations, key => new[] { uvGen.GetUOffs(key) });
                ExportFloatAnimation("vOffset", animations, key => new[] { -uvGen.GetVOffs(key) });
                ExportFloatAnimation("uScale", animations, key => new[] { uvGen.GetUScl(key) });
                ExportFloatAnimation("vScale", animations, key => new[] { uvGen.GetVScl(key) });
                ExportFloatAnimation("uAng", animations, key => new[] { uvGen.GetUAng(key) });
                ExportFloatAnimation("vAng", animations, key => new[] { uvGen.GetVAng(key) });
                ExportFloatAnimation("wAng", animations, key => new[] { uvGen.GetWAng(key) });
                babylonTexture.animations = animations.ToArray();

                // Copy texture to output
                if (isBabylonExported)
                {
                    var destPath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);
                    TextureUtilities.CopyTexture(sourcePath, destPath, exportParameters.txtQuality, this);

                    // Is cube
                    _exportIsCube(Path.Combine(babylonScene.OutputPath, babylonTexture.name), babylonTexture, allowCube);
                }
                else
                {
                    babylonTexture.isCube = false;
                }
                babylonTexture.originalPath = sourcePath;

                return(babylonTexture);
            }
        }
        private BabylonTexture ExportSpecularTexture(IIGameMaterial materialNode, float[] specularColor, BabylonScene babylonScene)
        {
            ITexmap specularColorTexMap = _getTexMap(materialNode, 2);
            ITexmap specularLevelTexMap = _getTexMap(materialNode, 3);

            // --- Babylon texture ---

            var specularColorTexture = _getBitmapTex(specularColorTexMap);
            var specularLevelTexture = _getBitmapTex(specularLevelTexMap);

            if (specularLevelTexture == null)
            {
                // Copy specular color image
                // Assume specular color texture is already pre-multiplied by a global specular level value
                // So do not use global specular level
                return(ExportTexture(specularColorTexture, babylonScene));
            }

            // Use one as a reference for UVs parameters
            var texture = specularColorTexture != null ? specularColorTexture : specularLevelTexture;

            if (texture == null)
            {
                return(null);
            }

            RaiseMessage("Multiply specular color and level textures", 2);

            string nameText = null;

            nameText = (specularColorTexture != null ? Path.GetFileNameWithoutExtension(specularColorTexture.Map.FullFilePath) : TextureUtilities.ColorToStringName(specularColor)) +
                       Path.GetFileNameWithoutExtension(specularLevelTexture.Map.FullFilePath) + "_specularColor";

            var textureID = texture.GetGuid().ToString();

            if (textureMap.ContainsKey(textureID))
            {
                return(textureMap[textureID]);
            }
            else
            {
                var babylonTexture = new BabylonTexture(textureID)
                {
                    name = nameText + ".jpg" // TODO - unsafe name, may conflict with another texture name
                };

                // Level
                babylonTexture.level = 1.0f;

                // UVs
                var uvGen = _exportUV(texture.UVGen, babylonTexture);

                // Is cube
                _exportIsCube(texture.Map.FullFilePath, babylonTexture, false);


                // --- Multiply specular color and level maps ---

                // Alpha
                babylonTexture.hasAlpha        = false;
                babylonTexture.getAlphaFromRGB = false;

                if (exportParameters.writeTextures)
                {
                    // Load bitmaps
                    var specularColorBitmap = _loadTexture(specularColorTexMap);
                    var specularLevelBitmap = _loadTexture(specularLevelTexMap);

                    if (specularLevelBitmap == null)
                    {
                        // Copy specular color image
                        RaiseError("Failed to load specular level texture. Specular color is exported alone.", 3);
                        return(ExportTexture(specularColorTexture, babylonScene));
                    }

                    // Retreive dimensions
                    int width              = 0;
                    int height             = 0;
                    var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, specularColorBitmap, specularLevelBitmap);
                    if (!haveSameDimensions)
                    {
                        RaiseError("Specular color and specular level maps should have same dimensions", 3);
                    }

                    // Create pre-multiplied specular color map
                    var _specularColor = Color.FromArgb(
                        (int)(specularColor[0] * 255),
                        (int)(specularColor[1] * 255),
                        (int)(specularColor[2] * 255));
                    Bitmap specularColorPreMultipliedBitmap = new Bitmap(width, height);
                    for (int x = 0; x < width; x++)
                    {
                        for (int y = 0; y < height; y++)
                        {
                            var specularColorAtPixel = specularColorBitmap != null?specularColorBitmap.GetPixel(x, y) : _specularColor;

                            var specularLevelAtPixel = specularLevelBitmap.GetPixel(x, y);

                            var specularColorPreMultipliedAtPixel = specularColorAtPixel.multiply(specularLevelAtPixel);

                            specularColorPreMultipliedBitmap.SetPixel(x, y, specularColorPreMultipliedAtPixel);
                        }
                    }

                    // Write bitmap
                    if (isBabylonExported)
                    {
                        RaiseMessage($"Texture | write image '{babylonTexture.name}'", 3);
                        TextureUtilities.SaveBitmap(specularColorPreMultipliedBitmap, babylonScene.OutputPath, babylonTexture.name, ImageFormat.Jpeg, exportParameters.txtQuality, this);
                    }
                    else
                    {
                        // Store created bitmap for further use in gltf export
                        babylonTexture.bitmap = specularColorPreMultipliedBitmap;
                    }
                }
                textureMap.Add(babylonTexture.Id, babylonTexture);
                return(babylonTexture);
            }
        }
        private BabylonTexture ExportORMTexture(ITexmap ambientOcclusionTexMap, ITexmap roughnessTexMap, ITexmap metallicTexMap, float metallic, float roughness, BabylonScene babylonScene, bool invertRoughness)
        {
            // --- Babylon texture ---

            var metallicTexture         = _getBitmapTex(metallicTexMap);
            var roughnessTexture        = _getBitmapTex(roughnessTexMap);
            var ambientOcclusionTexture = _getBitmapTex(ambientOcclusionTexMap);

            // Use metallic or roughness texture as a reference for UVs parameters
            var texture = metallicTexture != null ? metallicTexture : roughnessTexture;

            if (texture == null)
            {
                return(null);
            }

            RaiseMessage("Export ORM texture", 2);

            var textureID = texture.GetGuid().ToString();

            if (textureMap.ContainsKey(textureID))
            {
                return(textureMap[textureID]);
            }
            else
            {
                var babylonTexture = new BabylonTexture(textureID)
                {
                    name = (ambientOcclusionTexMap != null ? Path.GetFileNameWithoutExtension(ambientOcclusionTexture.Map.FileName) : "") +
                           (roughnessTexMap != null ? Path.GetFileNameWithoutExtension(roughnessTexture.Map.FileName) : ("" + (int)(roughness * 255))) +
                           (metallicTexMap != null ? Path.GetFileNameWithoutExtension(metallicTexture.Map.FileName) : ("" + (int)(metallic * 255))) + ".jpg" // TODO - unsafe name, may conflict with another texture name
                };

                // UVs
                var uvGen = _exportUV(texture.UVGen, babylonTexture);

                // Is cube
                _exportIsCube(texture.Map.FullFilePath, babylonTexture, false);


                // --- Merge metallic and roughness maps ---

                if (!isTextureOk(metallicTexMap) && !isTextureOk(roughnessTexMap))
                {
                    return(null);
                }

                if (exportParameters.writeTextures)
                {
                    // Load bitmaps
                    var metallicBitmap         = _loadTexture(metallicTexMap);
                    var roughnessBitmap        = _loadTexture(roughnessTexMap);
                    var ambientOcclusionBitmap = _loadTexture(ambientOcclusionTexMap);

                    // Retreive dimensions
                    int width              = 0;
                    int height             = 0;
                    var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, metallicBitmap, roughnessBitmap, ambientOcclusionBitmap);
                    if (!haveSameDimensions)
                    {
                        RaiseError((ambientOcclusionBitmap != null ? "Occlusion, roughness and metallic " : "Metallic and roughness") + " maps should have same dimensions", 3);
                    }

                    // Create ORM map
                    Bitmap ormBitmap = new Bitmap(width, height);
                    for (int x = 0; x < width; x++)
                    {
                        for (int y = 0; y < height; y++)
                        {
                            int _occlusion = ambientOcclusionBitmap != null?ambientOcclusionBitmap.GetPixel(x, y).R : 0;

                            int _roughness = roughnessBitmap != null ? (invertRoughness ? 255 - roughnessBitmap.GetPixel(x, y).G : roughnessBitmap.GetPixel(x, y).G) : (int)(roughness * 255.0f);
                            int _metallic  = metallicBitmap != null?metallicBitmap.GetPixel(x, y).B : (int)(metallic * 255.0f);

                            // The occlusion values are sampled from the R channel.
                            // The roughness values are sampled from the G channel.
                            // The metalness values are sampled from the B channel.
                            Color colorMetallicRoughness = Color.FromArgb(_occlusion, _roughness, _metallic);
                            ormBitmap.SetPixel(x, y, colorMetallicRoughness);
                        }
                    }

                    // Write bitmap
                    if (isBabylonExported)
                    {
                        RaiseMessage($"Texture | write image '{babylonTexture.name}'", 3);
                        TextureUtilities.SaveBitmap(ormBitmap, babylonScene.OutputPath, babylonTexture.name, ImageFormat.Jpeg, exportParameters.txtQuality, this);
                    }
                    else
                    {
                        // Store created bitmap for further use in gltf export
                        babylonTexture.bitmap = ormBitmap;
                    }
                }
                textureMap[babylonTexture.Id] = babylonTexture;
                return(babylonTexture);
            }
        }