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); }
/// <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); }