Jump to content
🛡️FORUMS ARE IN READ-ONLY MODE Read more... ×
Sign in to follow this  
Ardiden

Problems encountered when trying to create an island from GIS data

Recommended Posts

Hello everybody, I'm trying to create an island using various data like Digital Elevation Model, remote sensing imagery (satellite or aerial) and topographic maps. I already obtain interesting results but fail to find a satisfying way to import data other than DEM, for example the position of forest.

I'll begin by explaining my way through, then the problems encountered.

First, some few presentation words, as this is my first post on this forum : when I discovered OFP two years ago, I was struck by the realistic appearance of the landscape. The forests, especially, were the more natural looking I'd ever seen in a video game.

I began to dream of creating an island of a part of my homeland. At that time, it was just a dream, but since then I passed a degree in GIS (Geographic Information System) which gives me some knowledge that can be useful for that.

I have very little knowledge of military things, so if some weapon hasn't the proper shape or rate of fire, I probably won't notice it, but I had studied ecology and spend a lot of time in the outdoors, and a non-natural looking landscape would catch my eyes immediately. For example a fir placed on a sandy ground looks odd for me, like a PC would be in a WWII environment. There are some islands, like Freya island, which looks fine from the ground, and unnatural from a remote point of view, thought the designers have obviously spend lot of time creating them. Designing a natural looking landscape from scratch is a non trivial task. I think it is far better to use real world data. Not only the elevation, but also roads, buildings or fields could be placed from there real world position, quickly providing a basis for manual editing. GIS are softwares designed for proceeding these data. They could be useful to manage the object to place on a map in a more efficient way than the island editors. This one would only be used for the final detail tasks. This, at least, is the way I see it.

Recently Aster 30m resolution DEM's became freely available (only SRTM DEM's above 90m were previously available for free outside the USA), this decide me to start the creation of an island. I would have preferred to make it for Arma 2, but I'll have to wait some time since I'll have a PC which could handle such a game. However, some Arma's island creators may find some use in my work.

So this is a DEM of a small mountain area in the south of France, with the extension of 1024x1024 and 512x512 cells islands.

First I wrote a little script which extract a square area centered on some given coordinates and write it in the DEM format readable by WRPtool. The terrain in-game doesn't look bad :-) : mntingame27.th.jpg mntingame15.th.jpg

However, the terrain is too smoothed. This is particularly obvious in some valleys, which look like U-shaped glacier valleys while actually being torrential V-shaped valleys. The Wilbur's erosion filter could be useful to improve this. I use a basin fill slope of -1, an erosion blur of 1 and apply an amount of only 0.4. This give acceptable results, thought I may consider writing my own function for carving the river's bed.

Next step is placing the forests. They are easy to extract from satellite or aerial images as well as topographic maps. The difficulty comes when we have to import the forest layer created in a GIS into WRPtool. The only data type WRPtool can feed (except from wrp cell) is a kind of xyz files, that is, plain text files, composed of three columns, the last one displaying the elevation. No feature seems to exist for loading external data that could indicate the position of forests, roads or other objects (I haven't try Visitor 2 but had read its manual and it seems to be limited in the same way).

My first idea was to load a map giving the forest position as if it was an elevation map. So I obtained a WRPtool map were the highest ground corresponds to areas were I want to place some forest. It's now possible to use the minimum height parameter of the region tool in order to place some forest only on those cells. After that, the real DEM file can be loaded.

But this method don't work properly. Why ? Cause the elevation point correspond to the lower left corner of the cell, while the elevation used by the height parameters are the one of the center of the cell. For example, in the picture below, the cell where I wanted to place the forest is the one whose lower left corner is in yellow, but it's not the one who finally get the forest objects.

pointforet.th.jpg pointforetforet.th.jpg

So I'm stuck at this point. I'm looking for a way to display objects in a map from coordinates (listed in a text file for example) and asking the community's help for that. I can't be the only one who's try to deal with that problem, can I ?

Thanks for reading that too long french-speakers complicated English post ;-). If someone is interested by more details on how I use the DEM or the other data, I would be pleased to provide it.

Share this post


Link to post
Share on other sites

very intreseting, could you share the script?

i don't mind manually place ovjects but having problem getting nice height map

Share this post


Link to post
Share on other sites
The only data type WRPtool can feed (except from wrp cell) is a kind of xyz files, that is, plain text files, composed of three columns, the last one displaying the elevation. No feature seems to exist for loading external data that could indicate the position of forests, roads or other objects (I haven't try Visitor 2 but had read its manual and it seems to be limited in the same way).

I'd suggest to you, that you load the Wrp-file with a script (for example Python), add the objects and save the Wrp-file again.

If you don't want to wait, here's the documentation:

http://community.bistudio.com/wiki/Wrp_File_Format_-_4WVR

And a simple Python script to load and write a Wrp-file:

import sys
import struct

class WRPError:
   def __init__(self, value):
       self.value = value

   def __str__(self):
       return repr(self.value)

class WRPObject:
   def __init__(self,  rotation,  position,  index,  path):
       if self.rotation:
           self.rotation = rotation
       else:
           self.rotation = (1.0, 0.0, 0.0,  0.0, 1.0, 0.0,  0.0, 0.0, 1.0)
       self.position = position
       self.index = index
       self.path = path

   def pack(self):
       tmp = ("9f3fi76s", ) + self.rotation + self.position + (self.index,self.path)
       return struct.pack( *tmp )

   def __str__(self):
       return "WRPObject(%s, %s, %s, %s)" % (self.rotation, self.position, self.index, self.path)

   def __repr__(self):
       return "WRPObject(%r, %r, %r, %r)" % (self.rotation, self.position, self.index, self.path)


def shortToFloat(packed): return float(packed) / 22.222;
def floatToShort(number): return int( max( -1800.0, min(1800.0,  number) ) * 22.222 )

class WRPFile:
   def __init__(self):
       self.width = 1
       self.height = 1
       self.textures = []
       self.elevations = []
       self.textureIndices = []
       self.objects = []


   def readFromPath(self, path):
       file = open(path, "rb")
       self.readFromFile(file)
       file.close()


   def readFromFile(self, file, close=False):
       magic = struct.unpack("4s",  file.read(4))[0]
       if magic == "4WVR":
           self.read4WVR(file, close)
       elif magic == "8WVR":
           raise WRPError, "8WVR is not supported yet!"
       else:
           raise WRPError,  "Only 4WVR WRP files are supported, not '%s'!" % magic

   def read4WVR(self, file, close):
       self.width,  self.height = struct.unpack("2i",  file.read(8))
       if self.width != self.height:
           raise WRPError,  "Width and height are supposed to be the same, not %d x %d!" % (self.width,  self.height)

       cellcount = self.width * self.height

       elevReader = ( struct.unpack("h", file.read(2))[0] for x in xrange(cellcount) )
       self.elevations = [ float(x)/22.222 for x in elevReader ]

       # now the same number of texture indices!
       self.textureIndices = [ struct.unpack("H",  file.read(2))[0] for x in xrange(cellcount) ]

       # now the texture paths!
       # Every path is 32 byte 0-terminated/padded string; there are always 512!
       self.textures = [ struct.unpack("32s",  file.read(32))[0] for x in xrange(512) ]

       # now comes the tricky part! The objects have the following layout
       #   float[9] rotation; /// rotation matrix
       #   float x, z, y;  /// the position of the object
       #   uint index; /// the index on the map
       #   char[76] path; /// the path to the object
       #
       # those are 13*4 + 76 bytes = 128
       # now we read 128 bytes as long as
       buf = file.read(128)
       while len(buf) == 128:
           obj = struct.unpack("9f3fi76s",  buf)
           self.objects.append( WRPObject( obj[0:9],  obj[9:12],  obj[12],  obj[13] ) )
           buf = file.read(128)

       if close:
           file.close()


   def writeToPath(self, path):
       file = open(path, "wb")
       self.writeToFile(file)
       file.close()


   def writeToFile(self, file, close=False):
       file.write("4WVR")
       file.write( struct.pack("ii",  self.width,  self.height) )
       for elev in self.elevations:
           file.write( struct.pack("h",  floatToShort(elev) ) )

       for index in self.textureIndices:
           file.write( struct.pack("H",  index) )

       # first texture should be '\data\more_anim.01.pac'
       for texture in self.textures:
           file.write( struct.pack("32s", texture) )

       # if there were not enough textures, fill them up!
       for i in xrange( 512 - len(self.textures) ):
           file.write( struct.pack("32s", "") )

       # now the objects...
       for obj in self.objects:
           file.write( obj.pack() )

       if close:
           file.close()

   def generate(self, size, defaultHeight):
       self.width = size
       self.height = size
       self.textures = ['\\data\\more_anim.01.pac']
       self.elevations = [ defaultHeight for x in xrange(size*size) ]
       self.textureIndices = [ 1 for x in xrange(size*size) ]

   def printInfo(self):
       print "Size: %d x %d" % (self.width,  self.height)
       print "Number of elevations: %d" % len(self.elevations)
       print "Number of texture indices: %d" % len(self.textureIndices)
       print "Number of (non-empty) textures: %d" % len(self.textures)
       print "Number of objects: %d" % len(self.objects)

The objects you add, need to be realigned to ground in WrpTool manually, since there is some extra data from the models (the offset value) required to place the models correctly.

If you have any questions, don't hesitate to ask them!

Share this post


Link to post
Share on other sites

Was just looking through your pictures and they look great! Hope you finish and release the island!

STGN

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×