|
The second part of high resolution terrain model in FU3 is the large
file in the regions geos folder named geotiles.tag. Inside this file,
there are 303 distinct subfiles for the Seattle region and 252 for the Sanfran region.
After all subfiles there is a table of content for each subfile entry.
The Seattle region has 100 megatiles going from aaaa to ajaj with 3 subfiles per megatile plus the blank megatile. The Sanfran region has 84 megatiles going from aaaa to ajak also with 3 subfiles but many of the megatile of the seaside are substituted by the blank megatile. In the Seattle region blank megatiles are never used inside the highres area. the 3 .geo subfiles for each megatile are named L0aaaa.geo, L2aaaa.geo and L5aaaa.geo for the megatile aaaa. There is also 1 set of .geo subfiles for the blank megatile named L0blank.geo, L2blank.geo and L5blank.geo This blank megatile is used to simulate the north of the Seattle region looking towards Vancouvert and this megatile is the reason why when flying to the north, you see land in the sea area that desapear when comming nearer. I think this megatile should be modified for better results. The level of detail for .geo is opposite that of textures .bin, .cpd (0 is lowest resolution, not highest) There are not distinct .geo files for every level but level sharing
All these subfiles contains the elevations and classifications info of the megatiles. Level 0 has 25 height fields ranged in a 5x5 matrix. The top (north) row and right (east) column are values copied from the megatiles next to the north, north-east and east of the current megatile. The remaining left-bottom part as 4x4 matrix has the data of the actual megatile. The index sequence of the height fields start always in the bottom-left corner going from there to the right and then up to the top row. The first Quad of the Quad array is the main quad of the entire megatile. The next 4 Quads divides the megatile in a 2x2 matrix and the next 16 Quads is the 4x4 split of the megatile. this is the same in all levels. In level 2 only, there is an additional split of the megatile in a 8x8 matrix requiring 64 Quads more.
In level 0 the heights of the megatile are defined by 4x4 squares, first as mean of the 64x64 original values from level 5 of a square area, but the world looks to flat and I change this to select the maximum value. Doing this the sight to distant mountains becomes better and for the near area, level 5 heights are used and the valleys are back again. Height fields alone are not enough to define the terrain elevation in FU3. The Level 0 has also 21 Quads defining bounding boxes around a set of height squares defining the min, max and the max lod height error squared and inverted - but actually unknown how to compute it. There is not clear to what the height error is related, to the mean height ? For a tottaly flat area the value is set to 1.00e12 and the bounding box min = height field value - 3 and max = height field value + 3. Computing back 1 / SQR(1.00e12) you get a value near 0 (1.00e-6) but not 0. If this value is set to 0, you get strange pictures in the 3-D-view of FU3. The QuadLevel structure points to the Quads for the start of the 1x1, 2x2, 4x4 and 8x8 matrix. The pointer addresses are unusable, but computed back to the virtual address of the subfile, then all the pointers are correct, but in reality not at this addresses. I have changed it to relative pointers with 000000 as start of the subfile. FU3 don't care about this. Raster of the Geos structures for a megatile:
Still open questions concerning the GeoTiles.tag file data:
|
|
|
Address |
The Structure of the GeoTiles.tag file |
|
0x0000 0x010f |
Header: 272 bytes from 0x0000 to 0x010f Pointer to the Start of Geos-Table (4 bytes) unused space 0x00 (264 bytes) 4 unknown bytes 0xde 0xad 0xbe 0xef |
|
0x0110 |
Geos files: levels 0, 2 and 5 for each megatile in any order
a level 0-2-5 set for 1 megatile has a size of 401776 bytes |
|
Size in bytes 34 24 24 50 168 |
Level 0 Geos - 1 subfile per megatile Size: 266 data bytes Total size with the header: 1*266+34=300 bytes Name padded with 0x00 l0blank.geo : level 0 for the blank megatile l0aaaa.geo : level 0 for megatile aaaa TileInfo
typedef struct _TileInfo
{
WORD *hfield; // pointer to height field, unused addr.
// Region Seattle Sanfran
// pointer 0x00EB0ED0 0x005735E0
long row; // row posts for hfield = 5
long xdel; // startpoint x inside region, negative for blank tiles
// for aiah xdel=8, for blank xdel=-1
long ydel; // startpoint y inside region, negative for blank tiles
// for aiah ydel=7, for blank ydel=-1
long lod; // base level of detail = 0
long num_levs; // number of levs = 4
} TileInfo;
QuadLevel (4 entries at 6 bytes)
typedef struct _QuadEntry
{
QuadInfo *quads; // pointer to quad array, unused addr.
WORD post; // post separation
} QuadLevel[4];
Region Seattle Sanfran
pointer 0x00EB0F02 0x00573612
posts 4 4
pointer 0x00EB0F0A 0x0057361A
posts 2 2
pointer 0x00EB0F2A 0x0057363A
posts 1 0
pointer 0x00000000 0x00000000
posts 0 0
height fields (5 * 5 entries at 2 bytes)
WORD heightfld[25]; // (height in ft + region sealevel) * 4 + classification bits
// classification bits: 0 land, 1 water, 2 urban
// 1 ft = 0.3048 m and 1 m = 3.28 ft
QuadInfos (1+4+16 = 21 entries at 8 bytes)
typedef struct _QuadInfo
{(\) or topright-bottomleft(/)
float inv_err2; // max lod height error squared and inverted ?!?!?!
// for a totaly flat area the value = 1.00000e+012
// The lowest bit of the QuadInfo inv_err2 field is the
// "split direction" bit which determines if the quad is split
// into triangles topleft-bottomright(\) or topright-bottomleft(/)
WORD min; // min height for boundingbox, for the blank flat area: heightsfld-3
WORD max; // max height for boundingbox, for the blank flat area: heightsfld+3
} QuadInfo[21];
// for a blank megatile with a totaly flat area
// all height fields have the same sealevel value of:
// Region Seattle aaaj Sanfran blank
// const. value 0x01B1 433 0x439 classification is water
// min height 0x01AE 430 0x436
// max height 0x01B4 436 0x43C
// Sealevel -1 ft 270 ft
|
|
Size in bytes 34 24 30 162 680 |
Level 2 Geos - 16 subfiles per megatile Size: 896 data bytes per subfile Total size with the header: 16*896=14336+34=14370 bytes Name padded with 0x00 l2blank.geo : level 2 for the blank megatile l2aaaa.geo : level 2 for megatile aaaa TileInfo from this point the data structure will repeat 16 times dividing the megatile in 4 x 4 subsquares
typedef struct _TileInfo
{
WORD *hfield; // pointer to height field, unused addr.
// Region Seattle Sanfran
// pointer 0x00E285F2 0x00000000
long row; // row posts for hfield = 9
long xdel; // startpoint x inside region for the 16 subfiles
// aiah ai is tile 9 xdel=(9-1)*4 + m_lsx[i]= 32 + m_lsx[i]
// m_lsx[16]={0,0,1,1,2,2,3,3,0,0,1,1,2,2,3,3};
// negative for blank tiles xdel=m_blsx[i]
// m_blsx[16]={-4,-4,-3,-3,-2,-2,-1,-1,-4,-4,-3,-3,-2,-2,-1,-1};
long ydel; // startpoint y inside region for the 16 subfiles
// aiah, ah is tile 8, ydel=(8-1)*4 + m_lsy[i]=28 + m_lsy[i]
// m_lsy[16]={0,1,0,1,0,1,0,1,2,3,2,3,2,3,2,3};
// negative for blank tiles ydel=m_blsy[i]
// m_blsy[16]={-4,-3,-4,-3,-4,-3,-4,-3,-2,-1,-2,-1,-2,-1,-2,-1};
long lod; // base level of detail = 2
long num_levs; // number of levs = 5
} TileInfo;
QuadLevel (5 entries at 6 bytes)
typedef struct _QuadEntry
{
QuadInfo *quads; // pointer to quad array, unused addr.
WORD post; // post separation
} QuadLevel[5];
Region Seattle Sanfran
pointer 0x00E28694 0x00000000
posts 8 8
pointer 0x00E2869C 0x00000000
posts 4 4
pointer 0x00E286BC 0x00000000
posts 2 2
pointer 0x00E2873C 0x00000000
posts 1 1
pointer 0x00000000 0x00000000
posts 0 0
height fields (9 * 9 entries at 2 bytes)
WORD heightfld[81]; // (height in ft + region sealevel) * 4 + classification bits
// classification bits: 0 land, 1 water, 2 urban
// 1 ft = 0.3048 m and 1 m = 3.28 ft
QuadInfos (1+4+16+64 = 85 entries at 8 bytes)
typedef struct _QuadInfo
{
float inv_err2; // max lod height error squared and inverted ?!?!?!
// for a totaly flat area the value = 1.00000e+012
// The lowest bit of the QuadInfo inv_err2 field is the
// "split direction" bit which determines if the quad is split
// into triangles topleft-bottomright(\) or topright-bottomleft(/)
WORD min; // min height for boundingbox, for the blank flat area: heightsfld-3
WORD max; // max height for boundingbox, for the blank flat area: heightsfld+3
} QuadInfo[85];
|
|
Size in bytes 34 24 24 162 168 |
Level 5 Geos - 1024 subfiles per megatile Size: 378 data bytes per subfile Total size with the header: 1024*378=387072+34=387106 bytes Name padded with 0x00 l5blank.geo : level 5 for the blank megatile l5aaaa.geo : level 5 for megatile aaaa TileInfo from this point the data structure will repeat 1024 times dividing the megatile in 32 x 32 subsquares
typedef struct _TileInfo
{
WORD *hfield; // pointer to height field, unused addr.
// Region Seattle Sanfran
// pointer 0x00EB1550 0x00000000
long row; // row posts for hfield = 9
long xdel; // startpoint x inside region for the 1024 subfiles
// aiah ai is tile 9 xdel=(9-1)*32 + m_hsx[i]= 256 + m_hsx[i]
// m_hsx[1024]=4*{4*{ 0, 0, 1, 1, 2, 2, 3, 3},
// 4*{ 4, 4, 5, 5, 6, 6, 7, 7},
// 4*{ 8, 8, 9, 9,10,10,11,11},
// 4*{12,12,13,13,14,14,15,15} },
// 4*{4*{16,16,17,17,18,18,19,19},
// 4*{20,20,21,21,22,22,23,23},
// 4*{24,24,25,25,26,26,27,27},
// 4*{28,28,29,29,30,30,31,31} };
// negative for blank tiles xdel=m_bhsx[i]
// m_bhsx[1024]=4*{4*{-32,-32,-31,-31,-30,-30,-29,-29},
// 4*{-28,-28,-27,-27,-26,-26,-25,-25},
// 4*{-24,-24,-23,-23,-22,-22,-21,-21},
// 4*{-20,-20,-19,-19,-18,-18,-17,-17} },
// 4*{4*{-16,-16,-15,-15,-14,-14,-13,-13},
// 4*{-12,-12,-11,-11,-10,-10,- 9,- 9},
// 4*{- 8,- 8,- 7,- 7,- 6,- 6,- 5,- 5},
// 4*{- 4,- 4,- 3,- 3,- 2,- 2,- 1,- 1} };
long ydel; // startpoint y inside region for the 1024 subfiles
// aiah, ah is tile 8, ydel=(8-1)*32 + m_hsy[i]=224 + m_hsy[i]
// m_hsy[1024]=4*{4*{ 0, 1},4*{ 2, 3},4*{ 4, 5},4*{ 6, 7}},
// 4*{4*{ 8, 9},4*{10,11},4*{12,13},4*{14,15}},
// 4*{4*{16,17},4*{18,19},4*{20,21},4*{22,23}},
// 4*{4*{24,25},4*{26,27},4*{28,29},4*{30,31}},
// 4*{4*{ 0, 1},4*{ 2, 3},4*{ 4, 5},4*{ 6, 7}},
// 4*{4*{ 8, 9},4*{10,11},4*{12,13},4*{14,15}},
// 4*{4*{16,17},4*{18,19},4*{20,21},4*{22,23}},
// 4*{4*{24,25},4*{26,27},4*{28,29},4*{30,31}};
// negative for blank tiles ydel=m_bhsy[i]
// m_bhsy[1024]=4*{4*{-32,-31},4*{-30,-29},4*{-28,-27},4*{-26,-25}},
// 4*{4*{-24,-23},4*{-22,-21},4*{-20,-19},4*{-18,-17}},
// 4*{4*{-16,-15},4*{-14,-13},4*{-12,-11},4*{-10,- 9}},
// 4*{4*{- 8,- 7},4*{- 6,- 5},4*{- 4,- 3},4*{- 2,- 1}},
// 4*{4*{-32,-31},4*{-30,-29},4*{-28,-27},4*{-26,-25}},
// 4*{4*{-24,-23},4*{-22,-21},4*{-20,-19},4*{-18,-17}},
// 4*{4*{-16,-15},4*{-14,-13},4*{-12,-11},4*{-10,- 9}},
// 4*{4*{- 8,- 7},4*{- 6,- 5},4*{- 4,- 3},4*{- 2,- 1}};
long lod; // base level of detail = 5
long num_levs; // number of levs = 4
} TileInfo;
QuadLevel (4 entries at 6 bytes)
typedef struct _QuadEntry
{
QuadInfo *quads; // pointer to quad array, unused addr.
WORD post; // post separation
} QuadLevel[4];
Region Seattle Sanfran
pointer 0x00EB15F2 0x00000000
posts 8 8
pointer 0x00EB15FA 0x00000000
posts 4 4
pointer 0x00EB161A 0x00000000
posts 2 2
pointer 0x00000000 0x00000000
posts 1 1
height fields (9 * 9 entries at 2 bytes)
WORD heightfld[81]; // (height in ft + region sealevel) * 4 + classification bits
// classification bits: 0 land, 1 water, 2 urban
// 1 ft = 0.3048 m and 1 m = 3.28 ft
QuadInfos (1+4+16 = 21 entries at 8 bytes)
typedef struct _QuadInfo
{
float inv_err2; // max lod height error squared and inverted ?!?!?!
// for a totaly flat area the value = 1.00000e+012
// The lowest bit of the QuadInfo inv_err2 field is the
// "split direction" bit which determines if the quad is split
// into triangles topleft-bottomright(\) or topright-bottomleft(/)
WORD min; // min height for boundingbox, for the blank flat area: heightsfld-3
WORD max; // max height for boundingbox, for the blank flat area: heightsfld+3
} QuadInfo[21];
|
|
Start of Geos-Table |
Geos-Table: 3 entries at 30 bytes per megatile
int number of entries // 3 * megatiles defined in this file
struct GEO_TABENTRY
{ // GeoTiles table
BYTE Tilename[22]; // Tilename Lnaxay.geo, padded with 0x00
int Offset; // Offset in GeoTiles.tag file
int Size; // Tilesize level0=266, level2=14336, level5=387072
} m_GeoTabEntry[3*megatiles];
|
Information: André Meystre
back to FU3 Terrain Workshop
next to Using the GeoTilesViewer tool