Import Heightmap for nameshing with 3dsmax

**Import Heightmap for Nameshing with 3dsmax**

By Mschoeldgen

**LEVEL:** Advanced

**Tools:** 3ds Max 9, BF2 plugin for 3ds Max 9  (This is the last version that has plugins
for 3ds Max), notepad or another text editor

This is an expansion
to the original plugin 3ds max 9 tools for importing the heightmap of the map.   This
comes in very handy for adjusting navmeshes to the exact terrain as we all know
that maps with smooth valleys and hills are often victims of the 'over-optimizing'
in navmesh.exe, in which vehicles are abandoned in valleys and bots stand
around there, or even game crashes.

You'll need 3DSMax and the appropriate BF2 toolset for your version of the
program. A text editor is needed to modify the scripts.

The scripts are located in **<3DSMax>/scripts/bf2**

Ok, first open the 'BF2\_UI.mcr' file with a texteditor and add the following
lines (between two other menu entries) :

> macroScript BF2Import\_Heightmap
>
>
>
>     buttontext:"BF2 Import Heightmap"
>
>     category:"Game Tools BF2"
>
>     toolTip:"BF2 Import Heightmap"
>
> (
>
>     bf2ImportScaledHeightmap()
>
>
>
>
> )
>
>

I put those lines between **BF2GameTools\_LMs** and **BF2GameTools\_Batch**
when using the PoE2 toolset in Max9.

Scroll further down in that file and add the line in the middle:

> append ItemsTemp (menuMan.createActionItem
>
>
> "BF2GameTools\_LMs" "Game Tools BF2")
>
> append ItemsTemp (menuMan.createActionItem "BF2Import\_Heightmap"
> "Game Tools BF2")
>
> append ItemsTemp (menuMan.createActionItem "BF2GameTools\_Batch"
>
>
>
> "Game Tools BF2")
>
>

Save the file and close it. Now we need to find the heightmap import function
used for the lightmapping toolchain and clone it. Go to **/scripts/bf2/levels/Heightmap\_Import.ms**
and open it with your texteditor. Add the following code at the end. ( Rexman
has left in a 'TEST' section at the end of the file , insert the code before

that section ) :

> ----------------------------------------------------------
>
>
>
> -- Creates the scaled terrain mesh with same scale as navmeshes
>
> -- heightmap is flipped added by mschoeldgen aug 2008
>
> fn BF2generatescaledHM worldSize:4096 values:#(1,2,3,4,5,6,7,8,9) =
>
> (
>
>       undo off
>
>       (
>
>             local res = sqrt values.count
>
>             local evenRes = res - 1
>
>
>
>             local t = mesh width:evenRes
> length:evenRes lengthSegs:evenRes widthSegs:evenRes
>
>
>
>             format " res: %\n"
> res
>
>
>
>             -- set vertex positions
>
>             local tmpYOffset
>
>             for y = 0 to evenRes do
>
>             (
>
>                   tmpYOffset = y \* res + 1
>
>
>
>                   for x=0 to evenRes do
>
>                   (
>
>                         setVert t
> (tmpYOffset + x) [ x, y, values[ tmpYOffset + x ] ]
>
>                   )
>
>             )
>
>
>
>       )
>
>
>
>       return t
>
> )
>
>
>
>
>
>
>
>
> ---
>
>
>
>
>
> fn BF2\_ImportscaledHeightmapRaw fname tScale:[1,1,1] s:1.0 =
>
> (
>
>       format "HeightmapFile:
> %\n" fname
>
>       local f = fopen fname "rb"
>
>       if f == undefined then
>
>       (
>
>             format "ERROR! Could not
> open file: %\n" fname
>
>             return false
>
>       )
>
>
>
>       fseek f 0 #seek\_end
>
>       local theFileSize = ftell f
>
>       format "  FileSize: %\n" theFileSize
>
>
>
>       fseek f 0 #seek\_set
>
>       local hmRes = (sqrt (theFileSize /
> 2)) as integer
>
>       format "  Heightmap res: %\n" hmRes
>
>
>
>
>
>       local hmVals = #()
>
>       for y=1 to hmRes do
>
>       (
>
>             for x=1 to hmRes do
>
>             (
>
>                   append hmVals (readShort
> f #unsigned)
>
>             )
>
>       )
>
>
>
>       fclose f
>
>
>
>
>
>
>
>       local t = BF2generatescaledHM
> worldsize:(hmRes \* s) values:hmVals
>
>
>
>       if isValidNode t then
>
>       (
>
>             t.scale = tScale \* s
>
>       )
>
>
>
>       return t
>
> )
>
>
>
>
>
> fn bf2ImportScaledHeightmap fname:undefined s:1.0=
>
> (
>
>       if fname == undefined then
>
>       (
>
>              fname = getOpenFileName
>
>       )
>
>
>
>       if fname == undefined then return
> false
>
>
>
>
>
>       local heightData =
> bf2parseConData\_HeightData fname
>
>
>
>       local tScale = heightData[2]
>
>       local tRawFile = heightData[3]
>
>
>
>       if tScale == undefined then
>
>       (
>
>             format "ERROR! heightmap
> has no scale value!\n"
>
>             return false
>
>       )
>
>       if tRawFile == undefined then
>
>       (
>
>             format "ERROR! heightmap
> has no .raw filename!\n"
>
>             return false
>
>       )
>
>
>
>       local findPos = findString fname
> "\\levels\\"
>
>       if findPos == undefined then
>
>       (
>
>             format "Error Could not
> find Levels in path!\n"
>
>             return false
>
>       )
>
>       local gamePath = substring fname 1
> findPos
>
>
>
>       format "tScale.y: %\n"
> tScale.y
>
>       tScale = [ tScale.x, tScale.z ,
> tScale[2] ]
>
>       local t =
> BF2\_ImportscaledHeightmapRaw (gamePath + tRawFile) tScale:tScale s:s
>
>       addModifier t (uvwmap())
>
>       t = convertToMesh t
>
>       t.wirecolor = brown
>
>       -- bf2 has the origin at the bottom
> center of the terrain
>
>       t.pos.x = -0.5 \* t.max.x
>
>       t.pos.y = -0.5 \* t.max.y
>
> -- but the pivot is in the center
>
>     t.pivot = [0,0,0]
>
>     bf2AddMirrorMod t
>
>       t.Mirror.mirror\_axis = 1
>
>       t.Mirror.mirror\_center.position =
> [0,0,0]
>
>       t.Mirror.mirror\_center.position.x =
> 0
>
>       t.Mirror.mirror\_center.position.y =
> 0
>
>       t.Mirror.mirror\_center.position.z =
> 0
>
>       return t
>
>
>
>
> )
>
>

You'll probably note that most of these functiosn are nearly identical to the existing functions but with a different scale ( 1 instead of 10 ) and that the
function adds a mirror modifier to the imported heightmap. This comes in handy later on.

* Save the file and quit the text editor.

After Max has been started you'll notice a new entry in the Battlefield 2 menu : 'BF2 Import Heightmap'

Now to import the navmesh you're currently working on:

[navmesh\_example1]

* Go to the new menu entry and select it.
* Browse to the heightdata.con of your level and open it.

Heightmaps are mostly large objects so from that point on your Max will probably be a bit slower. Unfortunately, there's a bug in Maxscript which ignores setting the center of the mirror modifier, so we need to do that manually once the heightmap is imported.

* Select it (it's called 'Object01') and select the 'Mirror Center' property of its mirror modifier ( Step 1 in the image below ) .

* Select Max' 'Move' tool and find the three coordinates for the mirror center on the bottom status line .

* It currently says something like X = -1024.0 Y=-1024 Z=0 if you imported a 1024 scale 2 map.

[heightmap\_navmesh1]

* Enter a 0 ( zero, that is ) into the X and the Y coordinate and the heightmap is exactly where you want it.

* As the final step collapse the Mirror modifier on the heightmap mesh

[heightmap\_navmesh2]

Now edit your navmesh as usual.

For best results:

* ·vehicle navmeshes should be set between 0 and 1 meter above the ground

* ·infantry navmeshes should follow the terrain as close as possible.

* ·tesselating a polygon (set the 'explode' value to 0 before tesselating ) enables you to add detail in critical spots.