Classic Battlefield Modding Wikia
Advertisement

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 types:"HeightData.con(*.con)|HeightData.con|All(*.*)|*.*|"
      )
     
      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.
Advertisement