Planet textures

CubeMap is a software package for conversion of textures in a cylindrical projection to a quadrilateralized spherical cube projection (a cubemap projection for short). Supported any resolution of an input texture, any number of channels per pixel, 8-bit or 16-bit, signed or unsigned integers. The format of the input textures is raw (plain uncompressed data array). The format of the output texture is raw and/or an array of tiles of different levels of detail in the raw, tga, dds, jpg or png format.

Actual version: 1.15

Download: CubeMap 1.15

Files:

CubeMap.exe – utility for conversion of textures in a cylindrical projection to a cubemap projection
Glue.exe – utility for gluing tiles into a single raw-file
default_cub.ccf – default configuration file for the CubeMap
default_glue.gcf – default configuration file for the Glue

The configuration file and command line

All parameters for the program are described in the default_cub.ccf file in the program’s folder. It is a simple text file that contains a set of lines of the form:

var value #comment

var – a name of a parameter, value – a value of a parameter, the sign # separates comments. A comment can be either in the beginning of the line (then the entire line is a comment), or in the end of line (after the parameter’s value). The value can be of four types:

string – the string of characters without quotation marks and spaces;
int – an integer number;
float – a real number;
bool – a binary value: true or 1, false or 0.

Both utilities can work with other configuration files, in case when they are passed to them as a command line parameter:

CubeMap myconfig.ccf
Glue myconfig.ccf

In this case the file default_cub.ccf or default_glue.ccf is ignored. It is recommended to associate a .ccf files with the program CubeMap.exe in the system, then click on a *.ccf file will launch the CubeMap. A *.ccf files can be considered as a scripts for texture conversion with the CubeMap utility. The same is true for the .gcf extension used with the Glue utility.

You can specify paths to the input file and output folder in the command prompt. In this case the corresponding parameters from the configuration files are ignored:

CubeMap [myconfig.ccf] [-i InputFile] [-o OutFolder] [-o TempFolder] [-h]
Glue [myconfig.gcf] [-i InputFolder] [-o OutFile] [-h]

Option -h shows the prompt on the command line parameters.

Format of the planet textures in SpaceEngine

The path to the source cylindrical texture is specified by the InputFile parameter; the path to the output folder for the cubemap texture is specified by the OutFolder. If the path contains white spaces, it must be enclosed in quotation marks: “the path with spaces.” The TempFolder parameter specifies the path to the temporary folder, used by the utility to store a temporary files. If it is not specified, the temporary files will be stored in the OutFolder. If the folder does not exist, it is created automatically; inside it the subfolderl named neg_x, neg_y, neg_z, pos_x, pos_y, pos_z are created.

The cylindrical texture

The source cylindrical texture should be in the raw format. The raw format is a plain two-dimensional array of pixels, the size and capacity (bit-depth) of which is described by the following parameters in the configuration file:

InputWidth – width of the source image
InputHeight – height of the source image
InputChannels – number of channels (Grayscale – 1, RGB – 3, RGBA – 4, etc.)
Input16bit – capacity (bit-depth): 16 or 8 bits per channel
InputByteSwap – for 16-bit only: true for little-endian (MAC), false for big-endian
InputUnsigned – for 16-bit only: true for unsigned, false for signed value
InputLatOffset – longitude offset, in degrees

The cubic texture is a set of folders and files which are organized as follows:


cubemap ———– folder specified in the OutFolder parameter
neg_x —– folder of the neg_x face
0_0_0.jpg —– 1 tile of the level 0
1_0_0.jpg –\
1_0_1.jpg –+– 4 tiles of the level 1
1_1_0.jpg –|
1_1_1.jpg –/
2_0_0.jpg –\
2_0_1.jpg –|
2_0_2.jpg –|
2_0_3.jpg –+– 16 tiles of the level 2
2_1_0.jpg –|
2_1_1.jpg –|
2_1_2.jpg –|
2_1_3.jpg –|
………
neg_y —– folder of the neg_y face
neg_z —– folder of the neg_z face
pos_x —– folder of the pos_x face
pos_y —– folder of the pos_y face
pos_z —– folder of the pos_z face

The cubemap texture consists of six faces, with names given to them in accordance with the semi-axes of the coordinate system, which they crosses. Let the origin is in the center of the planet. Then the Y-axis is passing through the poles of the planet: the North pole is in the pos_y face, the South pole is in the neg_y face. The X-axis is passing from left to right, i.e. the left face is neg_x, the right one is pos_x. The Z axis is passing towards the observer, i.e. the further face is neg_z, the closer face is pos_z. In the original cylindrical texture, this corresponds to: the upper bound is the North pole, the lower bound is the South pole, junction of the left and right boundaries runs vertically through the neg_x face, the central meridian runs vertically through the pos_x face, and the center of the cylindrical texture is located in the center of the pos_x face. Scan of the cubemap texture is standard:

The cubemap texture

Some planetary maps are not centered on the zero meridian. For example, it may run on the left boundary of the texture. In this case, you can set the longitude offset of 180°, to “rotate” the resulting cubic texture into the correct position: InputLatOffset 180.

The resolution of cubemap faces is calculated as a quarter of the width of the original texture, rounded up to the nearest power of 2. For example if the original texture resolution is 86400 x 43200, it will give the resolution of each face of 32768 x 32768 (131072/4).

Each face is organized as a set of tiles. Resolution of the tile is determined by the parameter TileWidth and must be no more than the resolution of the face. For example, if TileWidth = 512, and the resolution of the face is 32768, then we’ll have 7 levels of tiles: Log2(32768/512) + 1 = 7. The levels are numbered from 0 to 6; the number of level is the first digit in the file name of the tile: (0_0_0.jpg, …, 6_63_63.jpg). The total resolution of each level is doubled sequentially, and the number of tile files is quadruplicating. Thus, we will have one tile of the level 0 (0_0_0.jpg) with resolution of 512 x 512. It will have the reduced image of the whole face. There will be 4 tiles of the level 1 (1_0_0.jpg … 1_1_1.jpg), each comprising a quarter of the entire face image. Resolution of each tile is again 512 x 512, thus the common resolution of the level 1 will be 1024 x 1024. The level 2 will have 16 tiles, and so on. The end (most detailed) level 6 will have 64 * 64 = 4096 tiles (512 x 512 each), with total resolution of 32768 x 32768. The second and third digits in the tile’s file name are vertical (v) and horizontal (u) indices. Indexing is carried out from the left to the right and from the top to the bottom. Here is the example picture of the first three levels (with tile resolution of 128 x 128):

level 0
Level 0

level 1
Level 1

level 2
Level 2

The CubeMap utility

Converting of the source cylindrical texture to the tiled cubemap texture is performed in several stages. It is possible to perform conversion for certain faces only. This is controlled by the following parameters in the configuration file (setting the parameter to false or 0 disables all stages for the corresponding face):

Code
Create_NEG_X 1
Create_POS_X 1
Create_NEG_Y 0 # this face will be skipped
Create_POS_Y 0 # this face will be skipped
Create_NEG_Z 1
Create_POS_Z 1

Execution of any stage can be disabled by setting the appropriate parameter in the config to false or 0 (see below):

Code
CreateBaseTex   1   # create a base texture
ComputeFaces    1   # process selected faces (compute temporary raw-files of the latest level)
DownsizeFaces   1   # compute LODs of selected faces (compute temporary raw-files of other levels back to 0)
TileFaces       1   # split temporary raw-files of the selected faces into tiles
OptimizeTiles   0   # delete homogeneous tiles

Lets look at all the steps in order.

1) Creating a base cylindrical texture

To perform this operation, the configuration file must have CreateBaseTex 1.

SpaceEngine uses a special small cylindrical texture (called “base texture”) to render a planets which are far away from the camera. Creating this texture is performed by simple downsampling of the source cylindrical texture by averaging pixels in a square blocks. Resolution of the base texture is the same as resolution of tiles (TileWidth). The BaseTexFormat parameters specifies the format of the base texture.

2) Computing the faces of the cubemap texture

To perform this operation, the configuration file must have ComputeFaces 1.

The conversion is performed by bilinear filtering: to derive the color of the current pixel in the face, the floating-point coordinates of the corresponding point in the cylindrical texture are computed, and the color is obtained by a linear interpolation of the four pixels closest to this point. This method gives a very good result, the artifacts may be noticeable only at the poles.

The program uses a cache memory for storing parts of the original cylindrical texture. It is therefore possible to perform complete transformation of original texture without loading it into memory. This is great for large textures, such as NASA Earth texture Blue Marble Next Generation, witch has a size of 86400 x 43200 x 3 = 10.4 GiB. If system has enough free RAM at the moment of the Cubemap start to load the source texture, it will do that. Otherwise the cache will be used. Cubemap will allocate as much RAM for the cache as possible, or amount, specified by MaxMem parameter in the config, if free memory is too small. In case of using cache, processing speed will be slower, because Cubemap will load chunks of the source file multiple times.

A temporary subfolder called raw will be created in the temporary folder specified by the TempFolder parameter. Inside it, subfolders neg_x, neg_y, neg_z, pos_x, pos_y, pos_z will be created, where raw-files of the corresponding cubemap faces will be saved. In our example, each face raw-file will have a name of level6.raw (because we will have 7 levels, starting from 0), with resolution of 32768 o 32768.

If the TileBorder parameter is set to 2, a border 2 pixel-wide is added to the perimeter of each tile. This border contains pixels from adjacent tiles. The resolution of tiles remains the same, i.e. border pixels are added from inside, with corresponding scaling of the central part of the tile texture. The temporary file level*.raw will have the same resolution as well, in our example, it will be 32768 x 32768.

Additional pixels make it easy to eliminate gaps in the landscape and sharp borders at the junction of textures when rendering in SpaceEngine using linear filtering. It is important to save tiles in lossless format for elevation map texture in this case. Best of all is 16-bit png.

The elevation maps (InputChannels 1) can use normalization, i.e. changing values so they implements the full dynamic range of the bit-deepness. For example, 16-bit elevation map gebco_bathy.21601×10801.bin have a minimum and maximum pixel values of -10577 and 8430, that does not fully implements the dynamic range of a 16-bit integers (-32768 … 32767). Specifying the Normalize true enables normalization. In that case, if the parameter EnterNormData is set to false, the minimum and maximum values are searched by scanning all pixels in the source cylindrical texture. For large textures it can take considerable time, so it is enough to perform this search once, then set EnterNormData true and enter the data that the program derived in the previous launch:

Code

Normalize       true   # normalize the output image (the height map)
EnterNormData   true   # true to enter the normalization data manually, false to find them automatically
NormMinValue    -10577 # minimum pixel value
NormMaxValue    8430   # maximum pixel value
NormIgnoreValue -32768 # skip this value while reading normalization data

Some maps uses special value to mark “no data” pixels. This may break out reading of normalization data. For example, if your map is 16-bit signed integer, you may find what normalization data reading stage reports NormMinValue of -32768, while you know what real heights on this map starts from something like -10000. In this case, specify NormIgnoreValue -32768. This will tell the program to ignore this value during normalization data reading stage.

3) Computing a LODs of faces

To perform this operation, the configuration file must have DownsizeFaces 1.

A consequential 2-times downscaling of the temporary raw-file is performed, resulting in appearing of files (in our example) level5.raw, level4.raw, level3.raw, level2.raw, level1.raw, level0.raw in the temporary folder, with a resolution of 16384 x 16384 to 512 x 512 respectively.

4) Splitting the temporary raw-files into tiles

To perform this operation, the configuration file must have TileFaces 1.

The temporary files are split into the tiles with the resolution of TileWidth x TileWidth, and are saved to the folder named after face, in one of the following formats:

raw – 8 or 16 bits, any number of channels, no compression
tga – 8 bits, 1, 3, 4 channels, no compression
dds – 8 bits, 1, 3, 4 channels, no compression
jpg – 8 bits, 1, 3, channels, lossy compression
tif – 8 or 16 bits, 1, 3, 4 channels, lossy compression
png – 8 or 16 bits, 1, 3, 4 channels, lossless compression

The tile format is described by the following parameters:

OutFormat – the tile format (raw, tga, dds, jpg, tif, png)
OutFormat2 – the tile format (raw, tga, dds, jpg, tif, png) for the low-byte, or for the alpha-channel (see SeparateHiLo and SeparateRGBA)
TileWidth – the tile resolution, default for SE: 256
TileBorder – the width of a border with additional pixels, default for SE: 2
Out16bit – capacity (bit-depth): 16 or 8 bits per channel (16 is allowed only for raw and png)
OutByteSwap – for 16-bit only: true for little-endian (MAC), false for big-endian
OutUnsigned – for 16-bit only: true for unsigned, false for signed value
OutInvertAlpha – invert the alpha channel for the RGBA images
OutJPEGquality – the quality of saving into JPEG (0…100)
SeparateRGBA – save RGBA tiles as a two separate files: RGB and alpha
SeparateHiLo – save 16-bit tiles as a two separate files: the high-byte and the low-byte
MaxOversampling – don’t save tiles of the last level it its oversampling rate is greater than this value

The MaxOversampling parameter is used to avoid generating of tiles with excessive resolution. This saves conversion time and disk space. For example, if the original texture had a resolution of 36000×18000, it will be effectively upscaled to the nearest power of two upwards, i.e. 65536х32768. This will make the last level look very blurry; its oversampling rate will be 65536/36000 = 1.82. If it is higher than the MaxOversampling value, raw files and tiles of this level will not be created (although internally CubeMap will work in the resolution of 65536).

Another possible scenario for using this option is converting a texture with exact power-of-two dimensions (for example 32768×16384) and using a non-zero TileBorder. In this case, CubeMap will slightly stretch the original texture to a resolution of 32768 + 4 * (32768/256) = 33280 to take into account the slight compression of the tile area visible in SpaceEngine (256 – 2 * 2 = 252 pixels). Therefore, the working resolution will be 65536 (the nearest greater power-of-two), and the oversampling value will be 65536/33280 = 1.969. Without the use of MaxOversampling, these would create the last level of tiles that would look very blurry.

To disable this limiting and save tiles of all levels, simply specify MaxOversampling 2.

It is necessary to dwell on the parameters OutFormat2, SeparateRGBA and SeparateHiLo. SpaceEngine supports a special way to store RGBA texture of the planetary surface in the form of two separate texture files – a color files for the RGB components and a black-and-white files for the alpha channel. This can be used to save disk space. For example, the Earth surface requires RGBA textures with color specified in the RGB channels, and a water mask specified in the alpha channel. The compressed texture formats which support 4 channels (RGBA) are only png and tif. But files of these formats are quite large, while the color information in could be compressed in jpg with a sufficiently good quality, and the water mask could be compressed in the lossless png very well. Such a combined set of two textures jpg + png takes much less space than a single 4-channel png. To use this method, set the SeparateRGBA true, and specify the format for the RGB texture by the OutFormat, and for the alpha texture by the OutFormat2:

Code
OutFormat    jpg
OutFormat2   png
SeparateRGBA true


With this configuration, the CubeMap will save two files for each tile: the RGB file with the suffix _c and the alpha file with the suffix _a, for example:
3_2_16_c.jpg
3_2_16_a.png

For the 16-bit elevation maps, it is also can be used the separation of the 16-bit tile image into two files: a low-byte and a high-byte. Sometimes saving them separately into a 8-bit files gives an advantage in size compared to saving in a single 16-bit image (png or tif). To do this, set the SeparateHiLo true, and specify the format for the high-byte texture by the OutFormat, and for the low-byte texture by the OutFormat2:

Code
OutFormat    png
OutFormat2   jpg
SeparateHiLo true


With this configuration, the CubeMap will save two files for each tile: the high-bytes file with the suffix _h and the low-bytes file with the suffix _l, for example:
3_2_16_h.png
3_2_16_l.jpg

Note: the high-bytes must be saved in a lossless format, such as png. Otherwise, the terrain will have large artifacts! The lower-bytes may be saved in a format with lossy compression, such as jpg, but it also leads to artifacts. Only the combination of png + png does not gives the artifacts, and sometimes it makes an advantage in a file size; in this case when this method is recommended to use.

SpaceEngine automatically detects and loads the dual-file textures, no additional tweaking of the planet script is required.

WARNING: if the tile files already exist in the folder, they will be overwritten!.

6) Optimizing tiles

To perform this operation, the configuration file must have OptimizeTiles 1.

SpaceEngine supports the tiled cubemap textures with any level of detail in any place. This means that you can, for example, have an Earth texture with resolution of 6 x 32768 x 32768 (obtained from Blue Marble Next Generation), and in some places such as the Grand Canyon, the level detail can be improved by adding an additional tiles with higher levels. Or vice versa, the large homogeneous areas with no detail – the oceans – can have only lower-level tiles (from 0 to 2) with the rest removed, which saves the disk space and improves loading time. The Cubemap can try to identify such homogeneous areas and remove them. Thus, it is recommended to use this optimization only with texture with large homogeneous areas such as the oceans; it is not recommended to do that for other textures.

Detecting of homogeneity is doing by calculating the variation of the pixel colors across the tile (the weighted sum of the absolute value of the difference between the color of a pixel and the average color of the tile). If this variation is less than the value specified by the parameter MinVar in the configuration file, the tile is considered homogeneous and is moved to a temporary location.

The subfolder called optimized is created in the temporary folder specified by the TempFolder parameter. Inside it, the subfolders called neg_x, neg_y, neg_z, pos_x, pos_y, pos_z are created. A detected homogeneous tiles are moved into that subfolders. They are candidates for removal.

A general guidelines for optimization are the next. After generating the tiles without optimization (OptimizeTiles false), start from some value MinVar and run CubeMap with OptimizeTiles true while the rest stages are disabled (parameters CreateBaseTex to TileBaces are set to false). It is better to do that for only one face, choosing it by the parameters Create_NEG_X … Create_POS_Z. Next, look which tiles were moved to a temporary folder. If not satisfyingly, move the tiles back (manually), adjust the MinVar value, and repeat until you get an acceptable result. Then do the optimization of the other faces using the optimal value of the MinVar you have found.

The MinOptLevel specifies from which level the optimization process should start. SpaceEngine requires at least 2-3 levels of textures even in flat areas like oceans to maintain sphere tessellation at a good level to prevent visual artifacts.

The current version (1.15) does not use a good algorithm, so errors are possible – e.g. tile with a small island and homogeneous ocean around it can be considered as homogeneous, while the tile with a slight color gradient can be considered as heterogeneous. Therefore it is recommended to look at all the tiles in the temporary folder and move back those which seems to be not suitable for removal. It is also recommended to save these removed tiles somewhere, so you can quickly restore incorrectly deleted tiles, without launching again a full conversion process with the CubeMap (especially if the source cylindrical texture is large).

Optimization is not supported for the dual-file tiles (SeparateRGBA or SeparateHiLo).

The Glue utility

The Glue utility is designed for glueing up the tiles back to a single raw-file. The utility has its own configuration file with the following parameters:

InputFolder – path to a folder with tiles
OutFile – path to an output raw-file
TilePrefix – string, a prefix in the file names of a tiles (the level number)
TileExt – string, an file name extension of a tiles
StartU – initial U (horizontal) tile index
StartV – initial V (vertical) index
EndU – final U (horizontal) tile index
EndV – final V (vertical) tile index
SwapUV – swap U and V indices
TileWidth – tile width
TileHeight – tile height
TileBorderWidth – width of border in pixels, which Glue will skip
TileBorderHeight – height of border in pixels, which Glue will skip
ChannelsPerPixel – number of channels (Grayscale – 1, RGB – 3, RGBA – 4, etc.)
BytesPerChannel – bytes per channel: 1 for 8-bit, 2 for 16-bit, etc.)

The tile file name has a form of: TilePrefix_v_u.TileExt; for example, for this configuration file:

Code

TilePrefix 5_
TileExt    png
StartU     2
StartV     3
SwapUV     false

the first tile will have a name 5_3_2.png; the names of the next tiles will be obtained by increasing the indices u and v until values specified by EndU/EndV is reached. Extension of * indicates that the program should look for a tiles in any of the supported formats, in the following order: dds, png, jpg, jpeg, tif, tiff, tga, raw. For example, if the folder contains the two files 3_1_2.jpg and 3_1_2.tga, the first one will be loaded.

If the extension does not match one of the above, the tool switches to the raw-mode: the input tiles are considered to have the raw format, i.e. a simple uncompressed pixel arrays without a title. The extension can be .raw, .img or any other, renaming of the tiles to the .raw is not required. In the raw-mode, the number of channels (ChannelsPerPixel) and capacity (BytesPerChannel) are not limited. It can be used for glueing of arbitrary arrays of data (not necessarily a textures), as if they are a rectangular blocks. Tiles do not necessarily have to be square-shaped – thus the separate parameters TileWidth and TileHeight are provided.

The Glue tool can skip borders on sides of the tiles (useful for merging back tile of some maps, processed by Cubemap before). The parameter TileBorderWidth defines width of the border, which will be skipped on both left and right sides of the tile; TileBorderHeight do the same for top and bottom sides.

The RawConv utility

The RawConv utility is a simple tool useful for preprocessing of the raw files. Usage:


RawConv [options] -i input_file -o out_file [-a alpha_file]

Options determines what operation are performed over the input_file:

-t: insert 8-bit grayscale image alpha_file into 8-bit RGB image input_file as an alpha channel.
-s: convert signed 16-bit image to unsigned 16-bit image or back.
-b: swap byte order of 16-bit image (convert between Mac and Windows format).

The result is saved to out_file. All input and output files must be in raw format. Options -s and -b can be used together; their order defines order of operations performed on every 16-bit word of the input file.

General recommendations

1) Placing the source texture, the temporary folder and output folder on a different physical drives can significantly increase performance. Performance is also increased if the source file and temporary raw-files are defragmented.

2) Write the information about the format of the source raw-texture in its name, for example: Earth-surface-32k-RGBA.raw is a RGBA texture of 32768 x 16384; Mars-bump-16k-16bit.raw is a 16-bit elevation map of 16384 x 8192. This will help to avoid confusion.

3) Conversion of the texture of any format to the raw format can be done in the Photoshop, IrfanView and other programs. Using them can also view the temporary raw-files (if you have enough RAM so these programs were able to load large raw-files). Graphic editors do not understand images in the signed 16-bit format, therefore, it makes sense to convert such textures to unsigned 16-bit using RawConv.

4) Save the configuration files for each converted texture, they can by useful in the future. Associate the .ccf file extension with the program CubeMap.exe, and the .gcf with the Glue.exe in the system, then double-click on a configuration file will automatically launch the corresponding utility. You can also drag and drop the configuration file on the shortcut of the CubeMap or Glue.

5) It is recommended to view the result of conversion of the polar faces pos_y and neg_y, and, if there are noticeable artifacts present, edit the raw-files of the polar faces in the graphics editor. To do this, run the ComputeFaces, edit the raw-files, disable ComputeFaces and perform the rest operations.

6) In order to avoid the loss of precision it is not recommended to normalize the height map, the dynamic range of which is “almost implemented”, for example (1 … 252) for the 8-bit and (-32000 … 32000) for the 16-bit.

7) If you want to save the tiles into a format not supported by the Cubemap, it is necessary to perform the conversion into a lossless format such as tga, and then perform a batch conversion of all tiles into the desired format using third-party software such as IrfanView or ImageMagic.