For those who are newer, F-Tex is a tool that can turn large textures (like 64K) into tiles automatically. This is a tutorial for Windows users as a large number of users have Windows.
Developed by Fridger Schrempp in 2007, the usage and know how of these tools has been lost to many and a guide to installing them is not easy to find. I did some digging in the wayback machine and found a post from 2008 by Bob Hegwood on the discontinued Celestialmatters forum however it is poorly worded and asks you to download a bunch of unneeded extra stuff. There is a copy of F-Tex already posted in the forum though I will be posting a copy here too.
A lot of people may be unfamiliar to using F-Tex tools because the people using it are used to making textures on a program with flashy windows, not typing word based commands with the command prompt. I have decided to make a guide on using its basic features because it was a pain for me to figure out how to do this without an easy to find, up to date, proper guide.
NOTE: You MUST be System Administrator to use F-Tex.
STEP 1... DOWNLOAD FTEX
First step is to download F-tex in the attachment above. Then, right click the zip folder and extract to unzipped folder.
STEP 2... INSTALL FTEX
Go into the folder and open Win32_PC.bin. Within that folder is "F-TexTools-2.0pre2" as an application. Run the application and have it install, preferably in your Program Files (x86) but you can install it wherever.
STEP 3... IMPLEMENT FTEX
This is where people get confused... they go into this program and start double clicking stuff then get frustrated when it does nothing and abandon it. Or they go straight into the command prompt and also does nothing.
The reason is you have to configure Windows to use it first.
1. Go into your control panel then into "Advanced System Settings" or type it into program search at the bottom left and into "view advanced system settings"
2. Click "Environment Variables" then in "System Variables" locate "Path" and click it to highlight it.
3. Click "Edit". Now there will be a list, click the bottommost entry and click "New", then click "browse" with the cursor in a new line.
Locate the location of the Ftex install folder, usually it will be in the your Program Files (x86) in the Drive letter folder. Click on the "F-TexTools" folder and click "Ok".
The folder path should now appear in the list. With it, click "ok" out of the windows.
STEP 4... FINDING MAPS FOR FTEX
Next up, go into an image processing program and make or download a big texture in it, I used an Enceladus texture from NASA in gimp for this example upscaled and turned into a 16384 x 8192 but any texture using exponent powers of 2 will work. In Gimp, use the following settings when exporting as png (the compression level can be anything but I use 9 for saving space to share addons) Do not check any of the unchecked stuff or Ftex will glitch out:
STEP 5... USING FTEX
Now that we have an image, go into the folder you saved the png in.
click on the folder path at the top and type "cmd" and hit Enter
The command prompt will appear with the folder path specified.
Type in "png2bin" < (texture name.png) > (texture name.bin) without brackets
Example: png2bin <Enceladus.png> Enceladus.bin
The png image should then be converted to a binary file.
FINALLY THE RESULTS:
There is one FINAL STEP
Images come in a number of channels
Channel Number "1" is Grayscale
Channel number "3" is RGB color
Channel number "4" is color with transparency
Levels in Celestia You should know how they work, "2" for level2 "5" for level5 etc.
PNG compression "0" is uncompressed as in it just takes up more space but opens faster. Compression "9" is least space but opens and runs slower. This does NOT affect image quality. It can be a value from 0-9.
USE THE .BIN FILE, NOT THE .PNG FILE FOR THIS STEP OR IT WILL NOT WORK!!!
Type "txtiles" (channel number) (image width in pixels) (level number in celestia) (PNG compression number) < (texture name.bin)
For Example: txtiles 3 16384 2 9 <Enceladus.bin
Converts my 16K Enceladus.bin into a series of square color tiles that are 2K in resolution and at png compression level 9.
And Bingo! You should have yourself a series of tiles correctly labeled for your VT!!!
I hope this guide was a lot of help because hopefully this makes people regain interest in making VTs again without my prior pain of manually creating and renaming tiles. My days of wasting a whole week renaming tiles for a 64K virtual texture are over!!!
Basic Windows F-Tex Tools tutorial to make Virtual Textures
-
Topic authorShadow-Dragon-777
- Posts: 79
- Joined: 03.11.2021
- Age: 30
- With us: 3 years
- Location: A Galaxy Far Far Away....
-
Topic authorShadow-Dragon-777
- Posts: 79
- Joined: 03.11.2021
- Age: 30
- With us: 3 years
- Location: A Galaxy Far Far Away....
There is also nmtools, however, I have not been able to get it working without it causing artifacts. The tool is set up the same way as steps 1-3 with Ftex.
The tools requires you to save a bumpmap at 16 bit integer in B/W with no gamma.
You can do this in GIMP with a bumpmap by going to "image - precision - 16 bit integer" then "image - mode - B/W" and with only a single layer, right click it and "remove alpha channel" if available.
Then you use png2bin to convert the image to binary.
Then you type in:
"nms" (object radius) (image width) (exaggeration) <(image name.png)> (image name.ppm)
Again, I have had plenty of trouble with this and the poles seem to have induced artifacts occur and I am leaving here for others to experiment on and perhaps figure out.
The tools requires you to save a bumpmap at 16 bit integer in B/W with no gamma.
You can do this in GIMP with a bumpmap by going to "image - precision - 16 bit integer" then "image - mode - B/W" and with only a single layer, right click it and "remove alpha channel" if available.
Then you use png2bin to convert the image to binary.
Then you type in:
"nms" (object radius) (image width) (exaggeration) <(image name.png)> (image name.ppm)
Again, I have had plenty of trouble with this and the poles seem to have induced artifacts occur and I am leaving here for others to experiment on and perhaps figure out.
- John Van Vliet
- Posts: 2944
- Joined: 28.08.2002
- With us: 22 years 2 months
- John Van Vliet
- Posts: 2944
- Joined: 28.08.2002
- With us: 22 years 2 months
Here is a small hack of nms to use 16 bit UNSIGNED integer raw image
this should make using it a bit easier
you will need to compile it as " nms.u16 ( or nms.u16.exe ) "
this should make using it a bit easier
Code: Select all
//
// Authors: Chris Laurel, Fridger Schrempp & Robert Skuridin & John Van Vliet
//
// claurel@gmail.com
// fridger.schrempp@desy.de
// skuridin1@mail.ru
// john.k.vanvliet@gmail.com
// The program reads an elevation map in unsigned 16-bit raw format
// from STDIN. It outputs to STDOUT a normalmap (PNG format),
// corrected for spherical geometry.
#include <iostream>
#include <cstdio>
#include <math.h>
#include <string>
#include <vector>
#include <ctime>
#include <png.h>
#include <iomanip>
#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#endif
#if _MSC_VER >= 1400 // MSVC 2005/8
#define SSCANF sscanf_s
#else
#define SSCANF sscanf
#endif
using namespace std;
const string version = "2.0, November 2008, authors: C. Laurel, F. Schrempp and R. Skuridin J. Van Vliet\n";
int byteSwap = 0;
int kernelSize = 2;
int halfKernelSize = 1;
int IsLittleEndian()
{
ushort word = 0;
if((*(char *)& word) != 0x21 )
return 0;
else
return 1;
}
ushort readu16(FILE *in)
{
ushort b2;
fread(&b2, 2, 1, in);
if (byteSwap == 1)
b2 = ((b2 & 0xff00) >> 8) | ((b2 & 0x00ff) << 8);
return (ushort) b2;
}
ushort* readRowU16(FILE* in, int width)
{
ushort* row = new ushort[width];
for (int i = 0; i < width; i++)
row[i] = readu16(in);
return row;
}
int main(int argc, char* argv[])
{
const double pi = 3.1415926535897932385;
int width = 0;
int height = 0;
double radius = 0.0;
double exag = 1.0;
double heightmapunit = 1.0;
vector<string> pcOrder(2);
pcOrder[0] = "Big-endian (PPC-MAC,...)";
pcOrder[1] = "Little-endian (Intel-PC, Intel-MAC,...)";
if (argc < 3 || argc > 6)
{
cerr << "\nUsage: nms.u16 <bodyradius> <width> [<exag> [<byteswap> [ <heightmapunit> OutputImage.png]]]\n\n";
cerr << "Version "<< version << endl;
cerr << "-------------------------------------------------------\n";
cerr << "The program reads an elevation map in unsigned 16-bit integer \n";
cerr << "raw format from STDIN. It outputs to STDOUT a normalmap (PNG),\n";
cerr << "corrected for spherical geometry\n\n";
cerr << "Units : bodyradius[km], width[pixel]\n";
cerr << "Assume : aspect ratio = width : height = 2 : 1\n\n";
cerr << "Defaults : exag = 1.0 (exaggeration factor, recommended: exag ~ 2.5)\n";
cerr << " byteswap = 0 <=> byte ordering of input file and computer are equal\n";
cerr << " heightmapunit = 1.0 (length of one heightmap unit in meters)\n\n";
cerr << "-------------------------------------------------------\n\n";
cerr << "You computer uses +++ "<<pcOrder[IsLittleEndian()]<<" +++ byte order!\n";
cerr << "If different from byte order of input file, use byteswap = 1\n\n";
cerr << "Reference: bodyradius = 6378.140 (Earth)\n";
cerr << " = 3396.0 (Mars)\n\n";
return 1;
}
else
{
if (SSCANF(argv[1], "%lf", &radius) != 1)
{
cerr<<"Read error: body_radius\n";
return 1;
}
if (SSCANF(argv[2], "%d", &width) != 1)
{
cerr << "Bad image dimensions.\n";
return 1;
}
height = width / 2;
if (argc > 3)
{
if (SSCANF(argv[3], "%lf", &exag) != 1)
{
cerr<<"Read error: exag\n";
return 1;
}
if (argc > 4)
{
if (SSCANF(argv[4], "%d", &byteSwap) != 1)
{
cerr << "Bad byteorder specs.\n";
return 1;
};
if (argc == 6)
{
if (SSCANF(argv[5], "%lf", &heightmapunit) != 1)
{
cerr<<"Read error: heightmapunit\n";
return 1;
}
}
}
}
}
#ifdef _WIN32
if (_setmode(_fileno(stdin), _O_BINARY) == -1 )
{
cerr<<"Binary read mode from STDIN failed\n";
return 1;
}
if (_setmode(_fileno(stdout), _O_BINARY) == -1 )
{
cerr<<"Binary write mode via STDOUT failed\n";
return 1;
}
#endif
//
// Output to STDOUT in PNG format
//
png_structp png;
png_infop info;
if ((png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL,NULL)) == NULL)
{
fprintf(stderr, "Failed creating PNG write structure (out of memory?)");
exit(99);
}
// Allocate image info
if ((info = png_create_info_struct (png)) == NULL)
{
fprintf(stderr, "Failed creating PNG info structure (out of memory?)");
exit(99);
}
if (setjmp (png_jmpbuf (png)))
{
fprintf(stderr, "Failed setting the PNG jump value (errors)");
exit(99);
}
png_init_io(png, stdout);
png_set_IHDR (png, info, width, height, 8, PNG_COLOR_TYPE_RGB,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
png_set_compression_level(png, 4);
cerr<<"[nms ]: Input file is a 16 bit elevation map:"<< setw(6)<<width<<" x"<< setw(6)<<height<<"\n\n";
cerr<<" Generating a normalmap for spherical geometry in PNG format"<<"\n\n";
clock_t start = clock(), end;
//write header
png_write_info (png, info);
ushort** h = new ushort* [height+1];
unsigned char* rgb = new unsigned char[width * 3];
for (int i = 0; i < kernelSize - 1; i++)
h[i] = readRowU16(stdin, width);
double bumpheight = heightmapunit * exag * width / (2000 * pi * radius);
double hp = pi / (double) height;
for (int y = 0; y < height; y++)
{
// Out with the old . . .
if (y > halfKernelSize)
delete[] h[y - halfKernelSize - 1];
// . . . and in with the new.
if (y < height - halfKernelSize)
h[y + halfKernelSize] = readRowU16(stdin, width);
double spherecorr = 1.0 / sin(hp * (y + 0.5));
for (int x = 0; x < width; x++)
{
double dx, dy;
// use forward differences throughout!
dx = (double)(h[y][x] - h[y][(x + 1) % width]);
// the pixel x in the row nearest to South pole uses the
// pixel across the pole at position width/2 + x for the dy gradient
if (y == height - 1)
dy = (double)(h[y][x] - h[y][((width >> 1) + x) % width]);
else
dy = (double)(h[y][x] - h[y + 1][x]);
dx *= bumpheight * spherecorr;
dy *= bumpheight;
double mag = sqrt(dx * dx + dy * dy + 1.0);
double rmag = 127.0 / mag;
rgb[x * 3 + 0] = (unsigned char) (128.5 + dx * rmag);
rgb[x * 3 + 1] = (unsigned char) (128.5 + dy * rmag);
rgb[x * 3 + 2] = (unsigned char) (128.5 + rmag);
}
png_bytep row_pointer = rgb;
// Write a row of the image
png_write_row(png, row_pointer);
if ((y + 1) % 1024 == 0 )
{
end = clock();
double duration = ( double )( end - start ) / CLOCKS_PER_SEC;
cerr << "nms ["<< setw(6) << y + 1 << " rows of " << setw(5) << height << " -> " << setw(6) << fixed << setprecision(2) << duration << " s] \n";
}
}
png_write_end (png, info);
png_destroy_write_struct (&png, &info);
return 0;
}
you will need to compile it as " nms.u16 ( or nms.u16.exe ) "
Code: Select all
g++ -O3 -Wall -D_LINUX nms.u16.cpp -o ../Linux_PC.bin/nms.u16 -lpng
- culturediff
- Posts: 10
- Joined: 04.08.2022
- With us: 2 years 3 months
- Location: France
- Contact:
- John Van Vliet
- Posts: 2944
- Joined: 28.08.2002
- With us: 22 years 2 months
if you use " G'Mic " to convert a tiff to raw , the terminal code has changed in the current release
Code: Select all
gmic 4k.Ariel.DEM.inpaint.16s.tiff -o 4k.Ariel.DEM.inpaint.16s.raw,int16
- culturediff
- Posts: 10
- Joined: 04.08.2022
- With us: 2 years 3 months
- Location: France
- Contact:
To easily convert a Tiff image into raw format, you can also use XnConvert : https://www.xnview.com/fr/xnconvert/#downloads
Very easy to use and very quick conversion - less than 1 second for a 21600x10800 pixels image.
Have a nice evening ...
Very easy to use and very quick conversion - less than 1 second for a 21600x10800 pixels image.
Have a nice evening ...