private DirectBitmap[] ResizeAndConverCubeToDirectBitmap(CubemapImages images) { Bitmap[] processedFaces = new Bitmap[6]; bool resize = false; if (resize) { processedFaces[0] = ResizeImage(images.Back, images.Back.Width * 2, images.Back.Height * 2); processedFaces[1] = ResizeImage(images.Bottom, images.Bottom.Width * 2, images.Bottom.Height * 2); processedFaces[2] = ResizeImage(images.Front, images.Front.Width * 2, images.Front.Height * 2); processedFaces[3] = ResizeImage(images.Left, images.Left.Width * 2, images.Left.Height * 2); processedFaces[4] = ResizeImage(images.Right, images.Right.Width * 2, images.Right.Height * 2); processedFaces[5] = ResizeImage(images.Top, images.Top.Width * 2, images.Top.Height * 2); } else { processedFaces[0] = images.Back; processedFaces[1] = images.Bottom; processedFaces[2] = images.Front; processedFaces[3] = images.Left; processedFaces[4] = images.Right; processedFaces[5] = images.Top; } DirectBitmap[] faces = new DirectBitmap[6]; faces[0] = CopyImageToDirectBitmap(processedFaces[0]); faces[1] = CopyImageToDirectBitmap(processedFaces[1]); faces[2] = CopyImageToDirectBitmap(processedFaces[2]); faces[3] = CopyImageToDirectBitmap(processedFaces[3]); faces[4] = CopyImageToDirectBitmap(processedFaces[4]); faces[5] = CopyImageToDirectBitmap(processedFaces[5]); return(faces); }
public void ExportCubemapAsFaces(string fileSavePath, CubemapImages images) { var filenames = GetCubeFileNames(fileSavePath); ImageSaveService.Save(filenames[0], images.Back); ImageSaveService.Save(filenames[1], images.Bottom); ImageSaveService.Save(filenames[2], images.Front); ImageSaveService.Save(filenames[3], images.Left); ImageSaveService.Save(filenames[4], images.Right); ImageSaveService.Save(filenames[5], images.Top); }
public void ExportCubemap(string fileSavePath, Node node, bool saveSeparately = false, bool exportAsSphericalProjection = false) { CubeMapImageSet imageSet; if (node.DepthMap != null) { imageSet = node.DepthMap; } else { imageSet = node.CubeMap; } CubemapImages images = GetCubemapImagesForImageSet(node, imageSet); if (!saveSeparately) { Bitmap finalImage; if (exportAsSphericalProjection) { MessageBox.Show("Exporting as spherical projection may take up to around a minute to finish."); finalImage = new SphericalProjectionService().ConstructProjection(images); } else { finalImage = new CubeMapBuilder().ConstructCubemap(images); } ImageSaveService.Save(fileSavePath, finalImage); if (exportAsSphericalProjection) { MessageBox.Show("Exporting as spherical projection has completed!"); } } else { // with Revelation images need assembly, which create bitmaps in memory // the best output for images manipulated by the program as png files // that way they retain detail, without creating output files that are gigantic // saving as jpg would be too lossy // With Exile the original jpg image data can be saved directly from the original files // this avoids un-needed conversion and loss of detail or increase the output file size if (SelectedGame == "Exile") { ExportCubemapDataDirectly(fileSavePath, node); } else { ExportCubemapAsFaces(fileSavePath, images); } } }
public CubemapImages GetCubemapImagesForImageSet(Node node, CubeMapImageSet imageSet) { var data = new CubemapImages(); data.Back = BitmapUtils.LoadBitmapFromMemory(this.LookupFileImageData(node, imageSet.Back.File)); data.Bottom = BitmapUtils.LoadBitmapFromMemory(this.LookupFileImageData(node, imageSet.Bottom.File)); data.Front = BitmapUtils.LoadBitmapFromMemory(this.LookupFileImageData(node, imageSet.Front.File)); data.Left = BitmapUtils.LoadBitmapFromMemory(this.LookupFileImageData(node, imageSet.Left.File)); data.Right = BitmapUtils.LoadBitmapFromMemory(this.LookupFileImageData(node, imageSet.Right.File)); data.Top = BitmapUtils.LoadBitmapFromMemory(this.LookupFileImageData(node, imageSet.Top.File)); return(data); }
public void PopulateImages(Node node) { if (node == null) { return; } CubeMapImageSet imageSet = node.CubeMap; //if (mapTypeIsColor == true) // imageSet = node.CubeMap; //else // imageSet = node.CubeMaps.Depth; // some kind of check to validate images? CubemapImages data = App.GetCubemapImagesForImageSet(node, imageSet); var blank = Properties.Resources.picture_icon_large; backImage.BackgroundImage = data.Back != null ? data.Back : blank; bottomImage.BackgroundImage = data.Bottom != null ? data.Bottom : blank; frontImage.BackgroundImage = data.Front != null ? data.Front : blank; leftImage.BackgroundImage = data.Left != null ? data.Left : blank; rightImage.BackgroundImage = data.Right != null ? data.Right : blank; topImage.BackgroundImage = data.Top != null ? data.Top : blank; backImage.Tag = imageSet.Back.File; bottomImage.Tag = imageSet.Bottom.File; frontImage.Tag = imageSet.Front.File; leftImage.Tag = imageSet.Left.File; rightImage.Tag = imageSet.Right.File; topImage.Tag = imageSet.Top.File; fileNameLabel_Back.Text = "Back: " + imageSet.Back.File; fileNameLabel_Bottom.Text = "Bottom: " + imageSet.Bottom.File; fileNameLabel_Front.Text = "Front: " + imageSet.Front.File; fileNameLabel_Left.Text = "Left: " + imageSet.Left.File; fileNameLabel_Right.Text = "Right: " + imageSet.Right.File; fileNameLabel_Top.Text = "Top: " + imageSet.Top.File; }
private Texture GetCubeMapTexture() { var cubeMapImages = new CubemapImages( new Bitmap(@"Resources\data\water_pos_x.png"), new Bitmap(@"Resources\data\water_neg_x.png"), new Bitmap(@"Resources\data\water_pos_y.png"), new Bitmap(@"Resources\data\water_neg_y.png"), new Bitmap(@"Resources\data\water_pos_z.png"), new Bitmap(@"Resources\data\water_neg_z.png")); var cubemapFiller = new CubemapImageFiller(cubeMapImages, 0, OpenGL.GL_RGBA, 0, OpenGL.GL_BGRA, OpenGL.GL_UNSIGNED_BYTE); var cubemapTexture = new Texture(TextureTarget.TextureCubeMap, cubemapFiller, new SamplerParameters( TextureWrapping.ClampToEdge, TextureWrapping.ClampToEdge, TextureWrapping.ClampToEdge, TextureFilter.Linear, TextureFilter.Linear)); cubemapTexture.Initialize(); cubeMapImages.Dispose(); return(cubemapTexture); }
//https://stackoverflow.com/questions/34250742/converting-a-cubemap-into-equirectangular-panorama //https://github.com/adamb70/Python-Spherical-Projection/blob/master/cube2equi.py //https://stackoverflow.com/questions/11504584/cubic-to-equirectangular-projection-algorithm private Bitmap ConvertToEquirectangular(CubemapImages cubeMap) { CubemapHelper.FillAnyNullWithBlanks(cubeMap); CubemapHelper.UpsizeAnyPartials(cubeMap); DirectBitmap[] faces = ResizeAndConverCubeToDirectBitmap(cubeMap); int cubeFaceWidth = faces[0].Width; int cubeFaceHeight = cubeFaceWidth; // this block is to calculate a size that has a comparable pixel density to that of the combined input images int factor = 256; int nearestMultiple = 0; { int cubePixelCount = cubeFaceHeight * cubeFaceWidth; int totalCubePixelCount = cubePixelCount * 6; int sizeToGetComparablePixelDensity = (int)Math.Sqrt(totalCubePixelCount / 2); nearestMultiple = (int)Math.Round( (sizeToGetComparablePixelDensity / (double)factor), MidpointRounding.AwayFromZero ) * factor; } int outputHeight = nearestMultiple + factor; // round it up int outputWidth = outputHeight * 2; // make the projection a multiple of the width of the combined images int scale_factor = 4; int projectionWidth = (cubeFaceWidth * 4) * scale_factor; int projectionHeight = projectionWidth / 2; DirectBitmap equiTexture = new DirectBitmap(projectionWidth, projectionHeight); //Normalised UV texture coordinates, from 0 to 1, starting at lower left corner double u_coordinate; double v_coordinate; //Polar coordinates double latitude; double longitude; //Unit vector double x, y, z; double xAxis, yAxis, zAxis; double largestComponent; double[] vector = new double[3]; Color color; Point pixelCoord; double normX; double normY; //int modulousFactorX = outputWidth / 16; //int modulousFactorY = outputHeight / 8; //bool horizontalMarker = false; //bool verticalMarker = false; for (int heightIndex = 0; heightIndex < equiTexture.Height; heightIndex++) { //verticalMarker = heightIndex % modulousFactorX == 0; v_coordinate = 1 - ((double)heightIndex / equiTexture.Height); latitude = v_coordinate * Math.PI; for (int widthIndex = 0; widthIndex < equiTexture.Width; widthIndex++) { //horizontalMarker = widthIndex % modulousFactorY == 0; u_coordinate = ((double)widthIndex / equiTexture.Width); longitude = u_coordinate * 2 * Math.PI; //assuming Y+ is up, X+ is right, Z+ is front //Calculate unit vector x = Math.Sin(longitude) * Math.Sin(latitude) * -1; y = Math.Cos(latitude); z = Math.Cos(longitude) * Math.Sin(latitude) * -1; vector[0] = Math.Abs(x); vector[1] = Math.Abs(y); vector[2] = Math.Abs(z); largestComponent = vector.Max(); // PROBLEM : there are cases where the vertical boundary between cube faces // results in both the x and z components to be equivalent // so both axis return a 1, which //Vector Parallel to the unit vector that lies on one of the cube faces xAxis = x / largestComponent; yAxis = y / largestComponent; zAxis = z / largestComponent; //bool debug = true; //if (debug && verticalMarker && horizontalMarker) //{ // MessageBox.Show( // "h:" + heightIndex + " w:" + widthIndex + // "\r\nlat:" + latitude + " long:" + longitude + // "\r\nx:" + x + " y:" + y + " z:" + z // ); // color = Color.Purple; //} if (xAxis == 1) { //Right normX = (((zAxis + 1f) / 2f) - 1f); normY = (((yAxis + 1f) / 2f)); pixelCoord = GetPixelCoordinates(normX, normY, faces[4].Width, faces[4].Height); color = faces[4].GetPixel(pixelCoord.X, pixelCoord.Y); } else if (xAxis == -1) { //Left normX = ((zAxis + 1) / 2); normY = ((yAxis + 1) / 2); pixelCoord = GetPixelCoordinates(normX, normY, faces[3].Width, faces[3].Height); color = faces[3].GetPixel(pixelCoord.X, pixelCoord.Y); } else if (yAxis == -1) { //Up normX = ((xAxis + 1f) / 2f); normY = ((zAxis + 1f) / 2f); pixelCoord = GetPixelCoordinates(normX, normY, faces[5].Width, faces[5].Height); color = faces[5].GetPixel(pixelCoord.X, pixelCoord.Y); } else if (yAxis == 1) { //Down normX = ((xAxis + 1f) / 2f); normY = (((zAxis + 1f) / 2f) - 1f); pixelCoord = GetPixelCoordinates(normX, normY, faces[1].Width, faces[1].Height); color = faces[1].GetPixel(pixelCoord.X, pixelCoord.Y); } else if (zAxis == 1) { //Front normX = ((xAxis + 1f) / 2f); normY = ((yAxis + 1f) / 2f); pixelCoord = GetPixelCoordinates(normX, normY, faces[2].Width, faces[2].Height); color = faces[2].GetPixel(pixelCoord.X, pixelCoord.Y); } else if (zAxis == -1) { //Back normX = (((xAxis + 1f) / 2f) - 1f); normY = ((yAxis + 1f) / 2f); pixelCoord = GetPixelCoordinates(normX, normY, faces[0].Width, faces[0].Height); color = faces[0].GetPixel(pixelCoord.X, pixelCoord.Y); } else { throw new Exception("Unknown face, something went wrong"); } equiTexture.SetPixel(widthIndex, heightIndex, color); } } var downscaled = ResizeImage(equiTexture.Bitmap, equiTexture.Width / scale_factor, equiTexture.Height / scale_factor); return(downscaled); }
public Bitmap ConstructProjection(CubemapImages images) { return(ConvertToEquirectangular(images)); }