/// <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 GLTFBufferView WriteImageToGltfBuffer(GLTF gltf, GLTFImage gltfImage, string imageSourcePath = null, Bitmap imageBitmap = null, long textureQuality = 100) { byte[] imageBytes = null; if (imageBitmap != null) { // try our best to get extension - default will be png which is the looseless format. var extension = gltfImage.FileExtension ?? (gltfImage.uri != null ? Path.GetExtension(gltfImage.uri) : null); var outputFormat = extension != null?TextureUtilities.GetImageFormat(gltfImage.FileExtension) : ImageFormat.Png; using (MemoryStream m = new MemoryStream()) { // this use the SAME method for GLTF TextureUtilities.SaveBitmap(m, imageBitmap, outputFormat, textureQuality); imageBytes = m.ToArray(); } } else { imageBytes = File.ReadAllBytes(imageSourcePath); } // Chunk must be padded with trailing zeros (0x00) to satisfy alignment requirements imageBytes = padChunk(imageBytes, 4, 0x00); // BufferView - Image var buffer = gltf.buffer; var imageBufferView = new GLTFBufferView { name = "bufferViewImage", buffer = buffer.index, Buffer = buffer, byteOffset = buffer.byteLength }; imageBufferView.index = gltf.BufferViewsList.Count; gltf.BufferViewsList.Add(imageBufferView); imageBufferView.bytesList.AddRange(imageBytes); imageBufferView.byteLength += imageBytes.Length; imageBufferView.Buffer.byteLength += imageBytes.Length; imageBufferView.Buffer.bytesList.AddRange(imageBufferView.bytesList); return(imageBufferView); }
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); } }
/// <returns></returns> private BabylonTexture ExportBaseColorAlphaTexture(ITexmap baseColorTexMap, ITexmap alphaTexMap, float[] baseColor, float alpha, BabylonScene babylonScene, string materialName, bool isOpacity = false) { // --- Babylon texture --- var baseColorTexture = _getBitmapTex(baseColorTexMap); var alphaTexture = _getBitmapTex(alphaTexMap); var texture = baseColorTexture != null ? baseColorTexture : alphaTexture; if (texture == null) { return(null); } var baseColorTextureMapExtension = Path.GetExtension(baseColorTexture.Map.FullFilePath).ToLower(); if (alphaTexture == null && baseColorTexture != null && alpha == 1) { if (baseColorTexture.AlphaSource == 0 && (baseColorTextureMapExtension == ".tif" || baseColorTextureMapExtension == ".tiff")) { RaiseWarning($"Diffuse texture named {baseColorTexture.Map.FullFilePath} is a .tif file and its Alpha Source is 'Image Alpha' by default.", 3); RaiseWarning($"If you don't want material to be in BLEND mode, set diffuse texture Alpha Source to 'None (Opaque)'", 3); } if (baseColorTexture.AlphaSource == 3 && // 'None (Opaque)' baseColorTextureMapExtension == ".jpg" || baseColorTextureMapExtension == ".jpeg" || baseColorTextureMapExtension == ".bmp" || baseColorTextureMapExtension == ".png") { // Copy base color image return(ExportTexture(baseColorTexture, babylonScene)); } } // Use one as a reference for UVs parameters RaiseMessage("Export baseColor+Alpha texture", 2); string nameText = null; nameText = (baseColorTexture != null ? Path.GetFileNameWithoutExtension(baseColorTexture.Map.FullFilePath) : TextureUtilities.ColorToStringName(baseColor)); var textureID = texture.GetGuid().ToString(); if (textureMap.ContainsKey(textureID)) { return(textureMap[textureID]); } else { var babylonTexture = new BabylonTexture(textureID) { name = nameText // 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); // --- Merge baseColor and alpha maps --- var hasBaseColor = isTextureOk(baseColorTexMap); var hasAlpha = isTextureOk(alphaTexMap); // Alpha // If the texture file format does not traditionally support an alpha channel, export the base texture as opaque if (baseColorTextureMapExtension == ".jpg" || baseColorTextureMapExtension == ".jpeg" || baseColorTextureMapExtension == ".bmp") { babylonTexture.hasAlpha = false; } else { babylonTexture.hasAlpha = isTextureOk(alphaTexMap) || (isTextureOk(baseColorTexMap) && baseColorTexture.AlphaSource == 0) || alpha < 1.0f; } babylonTexture.getAlphaFromRGB = false; if ((!isTextureOk(alphaTexMap) && alpha == 1.0f && (isTextureOk(baseColorTexMap) && baseColorTexture.AlphaSource == 0)) && (baseColorTextureMapExtension == ".tif" || baseColorTextureMapExtension == ".tiff")) { RaiseWarning($"Diffuse texture named {baseColorTexture.Map.FullFilePath} is a .tif file and its Alpha Source is 'Image Alpha' by default.", 3); RaiseWarning($"If you don't want material to be in BLEND mode, set diffuse texture Alpha Source to 'None (Opaque)'", 3); } if (!hasBaseColor && !hasAlpha) { return(null); } // Set image format ImageFormat imageFormat = babylonTexture.hasAlpha ? ImageFormat.Png : ImageFormat.Jpeg; babylonTexture.name += imageFormat == ImageFormat.Png ? ".png" : ".jpg"; // --- Merge baseColor and alpha maps --- if (exportParameters.writeTextures) { // Load bitmaps var baseColorBitmap = _loadTexture(baseColorTexMap); var alphaBitmap = _loadTexture(alphaTexMap); // Retreive dimensions int width = 0; int height = 0; var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, baseColorBitmap, alphaBitmap); if (!haveSameDimensions) { RaiseError("Base color and transparency color maps should have same dimensions", 3); } var getAlphaFromRGB = alphaTexture != null && ((alphaTexture.AlphaSource == 2) || (alphaTexture.AlphaSource == 3)); // 'RGB intensity' or 'None (Opaque)' // Create baseColor+alpha map var _baseColor = Color.FromArgb( (int)(baseColor[0] * 255), (int)(baseColor[1] * 255), (int)(baseColor[2] * 255)); var _alpha = (int)(alpha * 255); Bitmap baseColorAlphaBitmap = new Bitmap(width, height); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { var baseColorAtPixel = baseColorBitmap != null?baseColorBitmap.GetPixel(x, y) : _baseColor; Color baseColorAlpha; if (alphaBitmap != null) { // Retreive alpha from alpha texture Color alphaColor = alphaBitmap.GetPixel(x, y); int alphaAtPixel = getAlphaFromRGB ? alphaColor.R : alphaColor.A; if (isOpacity == false) { // Convert transparency to opacity alphaAtPixel = 255 - alphaAtPixel; } baseColorAlpha = Color.FromArgb(alphaAtPixel, baseColorAtPixel); } else if (baseColorTexture != null && baseColorTexture.AlphaSource == 0) // Alpha source is 'Image Alpha' { // Use all channels from base color baseColorAlpha = baseColorAtPixel; } else { // Use RGB channels from base color and default alpha baseColorAlpha = Color.FromArgb(_alpha, baseColorAtPixel.R, baseColorAtPixel.G, baseColorAtPixel.B); } baseColorAlphaBitmap.SetPixel(x, y, baseColorAlpha); } } // Write bitmap if (isBabylonExported) { RaiseMessage($"Texture | write image '{babylonTexture.name}'", 3); TextureUtilities.SaveBitmap(baseColorAlphaBitmap, babylonScene.OutputPath, babylonTexture.name, imageFormat, exportParameters.txtQuality, this); } else { // Store created bitmap for further use in gltf export babylonTexture.bitmap = baseColorAlphaBitmap; } } return(babylonTexture); } }
private BabylonTexture ExportClearCoatTexture(ITexmap intensityTexMap, ITexmap roughnessTexMap, float coatWeight, float coatRoughness, BabylonScene babylonScene, string materialName, bool invertRoughness) { // --- Babylon texture --- var intensityTexture = _getBitmapTex(intensityTexMap); var roughnessTexture = _getBitmapTex(roughnessTexMap); var texture = intensityTexture != null ? intensityTexture : roughnessTexture; if (texture == null) { return(null); } // Use one as a reference for UVs parameters RaiseMessage("Export Clear Coat weight+roughness texture", 2); string nameText = Path.GetFileNameWithoutExtension(texture.Map.FullFilePath); var textureID = texture.GetGuid().ToString(); if (textureMap.ContainsKey(textureID)) { return(textureMap[textureID]); } else { var babylonTexture = new BabylonTexture(textureID) { name = nameText // 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); // --- Merge maps --- var hasIntensity = isTextureOk(intensityTexture); var hasRoughness = isTextureOk(roughnessTexture); if (!hasIntensity && !hasRoughness) { return(null); } // Set image format ImageFormat imageFormat = ImageFormat.Jpeg; babylonTexture.name += ".jpg"; if (exportParameters.writeTextures) { // Load bitmaps var intensityBitmap = _loadTexture(intensityTexture); var roughnessBitmap = _loadTexture(roughnessTexture); // Retreive dimensions int width = 0; int height = 0; var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, intensityBitmap, roughnessBitmap); if (!haveSameDimensions) { RaiseError("Base color and transparency color maps should have same dimensions", 3); } // Create map var _intensity = (int)(coatWeight * 255); var _roughness = (int)(coatRoughness * 255); Bitmap intensityRoughnessBitmap = new Bitmap(width, height); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { var intensityAtPixel = (intensityBitmap == null) ? _intensity : intensityBitmap.GetPixel(x, y).R; Color intensityRoughness; if (roughnessBitmap == null) { intensityRoughness = Color.FromArgb(intensityAtPixel, _roughness, 0); } else { var roughnessAtPixel = (roughnessBitmap == null) ? _roughness : invertRoughness ? 255 - roughnessBitmap.GetPixel(x, y).G : roughnessBitmap.GetPixel(x, y).G; intensityRoughness = Color.FromArgb(intensityAtPixel, roughnessAtPixel, 0); } intensityRoughnessBitmap.SetPixel(x, y, intensityRoughness); } } // Write bitmap if (isBabylonExported) { RaiseMessage($"Texture | write image '{babylonTexture.name}'", 3); TextureUtilities.SaveBitmap(intensityRoughnessBitmap, babylonScene.OutputPath, babylonTexture.name, imageFormat, exportParameters.txtQuality, this); } else { // Store created bitmap for further use in gltf export babylonTexture.bitmap = intensityRoughnessBitmap; } } return(babylonTexture); } }
private GLTFTextureInfo ExportTexture(BabylonTexture babylonTexture, GLTF gltf, string name) { 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 { var sourcePath = babylonTexture.originalPath; if (babylonTexture.bitmap != null) { sourcePath = Path.Combine(gltf.OutputFolder, name); } if (sourcePath == null || sourcePath == "") { logger.RaiseWarning("Texture path is missing.", 3); return(null); } var validImageFormat = TextureUtilities.GetValidImageFormat(Path.GetExtension(sourcePath)); if (validImageFormat == null) { // Image format is not supported by the exporter logger.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 destPath = Path.Combine(gltf.OutputFolder, name); destPath = Path.ChangeExtension(destPath, validImageFormat); 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); textureUri = Path.Combine(textureUri, name); } gltfImage = new GLTFImage { uri = textureUri }; gltfImage.index = gltf.ImagesList.Count; gltf.ImagesList.Add(gltfImage); switch (validImageFormat) { case "jpg": gltfImage.FileExtension = "jpeg"; break; case "png": gltfImage.FileExtension = "png"; break; } if (exportParameters.outputFormat == "glb") { var imageBufferView = WriteImageToGltfBuffer(gltf, gltfImage, sourcePath, babylonTexture.bitmap); gltfImage.uri = null; gltfImage.bufferView = imageBufferView.index; gltfImage.mimeType = "image/" + gltfImage.FileExtension; } else { if (exportParameters.writeTextures) { if (babylonTexture.bitmap != null) { // We may have modified this texture image, copy the buffer contents to disk var extension = Path.GetExtension(name).ToLower(); var imageFormat = extension == ".jpg" ? System.Drawing.Imaging.ImageFormat.Jpeg : System.Drawing.Imaging.ImageFormat.Png; logger.RaiseMessage($"GLTFExporter.Texture | write image '{name}' to '{destPath}'", 3); TextureUtilities.SaveBitmap(babylonTexture.bitmap, destPath, imageFormat, exportParameters.txtQuality, logger); } else { // Copy texture from source to output TextureUtilities.CopyTexture(sourcePath, destPath, exportParameters.txtQuality, logger); } } } glTFImageMap.Add(name, gltfImage); } // -------------------------- // -------- 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; if (!CheckIfImageIsRegistered(name)) { gltf.TexturesList.Add(gltfTexture); } else { gltfTexture = gltf.TexturesList[GetRegisteredTexture(gltfTexture.name).index]; } // -------------------------- // ------ 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); } }
/// <returns></returns> private BabylonTexture ExportBaseColorAlphaTexture(ITexmap baseColorTexMap, ITexmap alphaTexMap, float[] baseColor, float alpha, BabylonScene babylonScene, string materialName, bool isOpacity = false) { // --- Babylon texture --- var baseColorTexture = _getBitmapTex(baseColorTexMap); var alphaTexture = _getBitmapTex(alphaTexMap); string baseColorTextureMapExtension = null; // If we don't retrieve any textures from Max, return null. if (baseColorTexture == null && alphaTexture == null) { return(null); } // If we only have a base color texture, and we are using an opaque texture, export the base color image only. if (baseColorTexture != null && alphaTexture == null) { baseColorTextureMapExtension = Path.GetExtension(baseColorTexture.Map.FullFilePath).ToLower(); if (alpha == 1) { if (baseColorTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_FILE && (baseColorTextureMapExtension == ".tif" || baseColorTextureMapExtension == ".tiff")) { RaiseWarning($"Diffuse texture named {baseColorTexture.Map.FullFilePath} is a .tif file and its Alpha Source is 'Image Alpha' by default.", 3); RaiseWarning($"If you don't want material to be in BLEND mode, set diffuse texture Alpha Source to 'None (Opaque)'", 3); } // Copy base color image var outTexture = ExportTexture(baseColorTexture, babylonScene); textureMap[outTexture.Id] = outTexture; return(outTexture); } } // Otherwise combine base color and alpha textures to a single output texture RaiseMessage("Export baseColor+Alpha texture", 2); var hasBaseColor = baseColorTexture != null && isTextureOk(baseColorTexMap); var hasAlpha = isTextureOk(alphaTexMap); var texture = hasBaseColor ? baseColorTexture : alphaTexture; ImageFormat imageFormat = null; if (hasBaseColor) { imageFormat = TextureUtilities.GetImageFormat(Path.GetExtension(baseColorTexture.Map.FullFilePath)); } if (hasAlpha || imageFormat == null) { baseColorTextureMapExtension = ".png"; // since we are adding an alpha channel, export as png. This will convert any other input base texture format to PNG. imageFormat = ImageFormat.Png; } // since we are creating a new texture, give it a unique ID based on the base color and alpha maps. var nameText = (hasBaseColor ? Path.GetFileNameWithoutExtension(baseColorTexture.Map.FullFilePath) + (hasAlpha ? "_" + Path.GetFileNameWithoutExtension(alphaTexture.Map.FullFilePath) : "") : TextureUtilities.ColorToStringName(baseColor)); var textureID = hasBaseColor ? texture.GetGuid().ToString() + (hasAlpha ? "_" + alphaTexture.GetGuid().ToString() : "") : string.Format("{0}_{1}", texture.GetGuid().ToString(), nameText); if (textureMap.ContainsKey(textureID)) { return(textureMap[textureID]); } BabylonTexture babylonTexture = null; babylonTexture = new BabylonTexture(textureID) { name = nameText }; // Alpha babylonTexture.hasAlpha = hasAlpha || (hasBaseColor && (baseColorTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_FILE || baseColorTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_RGB)) || alpha < 1.0f; babylonTexture.getAlphaFromRGB = false; if (!hasBaseColor && !hasAlpha) { return(null); } if ((!isTextureOk(alphaTexMap) && alpha == 1.0f && (isTextureOk(baseColorTexMap) && baseColorTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_FILE)) && (baseColorTextureMapExtension == ".tif" || baseColorTextureMapExtension == ".tiff")) { RaiseWarning($"Diffuse texture named {baseColorTexture.Map.FullFilePath} is a .tif file and its Alpha Source is 'Image Alpha' by default.", 3); RaiseWarning($"If you don't want material to be in BLEND mode, set diffuse texture Alpha Source to 'None (Opaque)'", 3); } // Set image format if (hasAlpha) { babylonTexture.name += "_alpha_" + alphaTexture.Name; } if (imageFormat == ImageFormat.Jpeg) { babylonTexture.name += ".jpg"; } else { babylonTexture.name += "." + imageFormat.ToString(); } // Level babylonTexture.level = 1.0f; // UVs var uvGen = _exportUV(texture.UVGen, babylonTexture); // Is cube _exportIsCube(texture.Map.FullFilePath, babylonTexture, false); // --- Merge baseColor and alpha maps --- if (exportParameters.writeTextures && baseColorTexture != alphaTexture && alphaTexture != null) { // Load bitmaps var baseColorBitmap = _loadTexture(baseColorTexMap); var alphaBitmap = _loadTexture(alphaTexMap); // Retreive dimensions int width = 0; int height = 0; var haveSameDimensions = TextureUtilities.GetMinimalBitmapDimensions(out width, out height, baseColorBitmap, alphaBitmap); if (!haveSameDimensions) { RaiseError("Base color and transparency color maps should have same dimensions", 3); } var getAlphaFromRGB = alphaTexture != null && ((alphaTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_RGB) || (alphaTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_NONE)); // 'RGB intensity' or 'None (Opaque)' // Create baseColor+alpha map var _baseColor = Color.FromArgb( (int)(baseColor[0] * 255), (int)(baseColor[1] * 255), (int)(baseColor[2] * 255)); var _alpha = (int)(alpha * 255); Bitmap baseColorAlphaBitmap = new Bitmap(width, height); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { var baseColorAtPixel = baseColorBitmap != null?baseColorBitmap.GetPixel(x, y) : _baseColor; Color baseColorAlpha; if (alphaBitmap != null) { // Retreive alpha from alpha texture Color alphaColor = alphaBitmap.GetPixel(x, y); int alphaAtPixel = getAlphaFromRGB ? alphaColor.R : alphaColor.A; if (isOpacity == false) { // Convert transparency to opacity alphaAtPixel = 255 - alphaAtPixel; } baseColorAlpha = Color.FromArgb(alphaAtPixel, baseColorAtPixel); } else if (baseColorTexture != null && baseColorTexture.AlphaSource == MaxConstants.IMAGE_ALPHA_FILE) // Alpha source is 'Image Alpha' { // Use all channels from base color baseColorAlpha = baseColorAtPixel; } else { // Use RGB channels from base color and default alpha baseColorAlpha = Color.FromArgb(_alpha, baseColorAtPixel.R, baseColorAtPixel.G, baseColorAtPixel.B); } baseColorAlphaBitmap.SetPixel(x, y, baseColorAlpha); } } // Write bitmap if (isBabylonExported) { RaiseMessage($"Texture | write image '{babylonTexture.name}'", 3); TextureUtilities.SaveBitmap(baseColorAlphaBitmap, babylonScene.OutputPath, babylonTexture.name, imageFormat, exportParameters.txtQuality, this); } else { // Store created bitmap for further use in gltf export babylonTexture.bitmap = baseColorAlphaBitmap; } } return(babylonTexture); }