• normal-mapNormal Map

We all want more details on 3D models. Most natural solution is more vertices and more triangles. But it creates more problems than it solves: 

  • More vertices require more data to store, more processing power to manipulate it.
  • It is very easy to have more triangles in model than pixels on screen. In one pixel, you can have a few triangles. GPU will process only one sample from one triangle. You will have to use AA (Super Sampling) to get rid of aliasing artifacts.
  • You can use a few models with LOD, but it is always visible to viewer.

To avoid these problems we have "normal maps". Instead of tens (or hundreds) of triangles, we have one big triangle with additional texture. This texture has information about normal vector from model surface. It allows reproduction of many model details, saves memory and reduces aliasing artifacts.

What is stored in normal maps.

Normal vector. It is a normalized vector (lenght of vectore = 1.0). Normal vector is the set of 3 coords (x,y,z) all in range <-1,1>. BAM needs only 2 values: X and Y. Value of Z can be calculated based on X and Y.


I will not explain how to generate normal maps. If someone else wants to fill this "gap", I will happily add it to this manual.


So BAM can use additional textures. I hope you have noticed, that in one texture we can store two more values. We have "free" BLUE and ALPHA value. BAM use BLUE value as "Specular Level" modifier and ALPHA as "Height Map". To  clarify, this additional texture for every pixel in "ordinary" texture has information about:

  • Normal vector stored in RED and GREEN channel;
  • Specular Level modifier in BLUE channel. This value is interpreted as value in range <0,1>. 
    !specularLevel described  in previous lesson is multipled by this value. This way you can make some parts of model  "shine". Default value is 1.0 (=255).
  • Height Map  used to create effect visible on third video in Example what can New Renderer. Default value is 1.0 (=255).


Preparation of Normal Map for BAM

I assume, that you already have model with additional textures: normal, height or specular map. Now you need to combine it in one texture. For this task I created a tool: "tc.exe". You can find it in the download section or from this link. It is a command line tool (no gui). It processes "input file" with simple "commands". Here is the list of commands:

  • o - define size of output texture. It gets two params: width and height.
  • i - load source texture, copy selected chanels in source texture to selected chanels in output texture. You can change position of target texture and size. Input texture can be: JPG, BMP, PNG, TGA.
  • w - write output texture to file. One param: filename. This tool can save texture as 32-bit PNG or TGA. (FP can't use PNG, so write it as TGA).

 Here is an example of file:

  1.   o 2048 2048
  2.   i ed209_N.tga 0 0 1 1 rg__
  3.   i ed209_S.tga 0 0 1 1 __r1
  4.   w ed209_NS.tga

Lines explanation:

  1. Create texture with size 2048 2048
  2. Load texture "ed209_N.tga". 
    It will be stored on target texture at position defined by next 4 params.
    First two values are position of left/top corrner. "0 0" is top/left corrner on target texture. "0.5 0.5" is center of target texture. Next two params is with and height. "1 1" means 100% width and 100% height of target texture.  You can use the 4 params to change position and dimensions where loaded texture will be stored. The 4 params almost always will be "0 0 1 1"
    This texture is normal map with values X,Y,Z stored as Red, Green and Blue color. We want to copy Red and Green value from source to Red and Green on target. Last param defines where values from source will be stored. It will be always 4 letters.
    Accepted  letters are: r/g/b/a/_/0/1. "_" means "no change". "0" - "= 0", "1" - "= 255" (255 will be in shader program interpreted as 1.0).
    So this line will copy Red and Green values to Red and Green on target texture.
  3. Same as above, but: Red value from source will be copied to Blue value on target and Alpha on target will be set to 1.0
  4. Save output texture to file "ed209_NS.tga"

It seems complicated, so here is an example of what I did with my BAM-demo table. Inside this file,  you will find:

  • In "models-src"  are source models with textures. Models are downloaded from tf3dm.com.
  • In "models-fp" are: models prepared to use in FP (converted to .ms3d and to .fpm), tc.exe, source file with commands for tc.exe, textures generated by tc.exe
  • Please read "models-fp/slug.readme.txt" -instruction  on how I converted files
  • Please read "models-fp.slug.slug.txt" - it is "command" file for tc.exe. Also inside you will find additional description.

Texture Combiner: "tc.exe"

This tool will "evolve" in future. Right now it doesn't have any error checking. It can scale source texture, but only in a limited way. It can decrease size 2x or 4x or 8x ... times. For example, it can convert source image from 1024x1024 to 512x512 or 256x256..., but not to 100x100 or 512x256. It can scale "up" with bilinear filtering. For example, it can convert source from 10x10 to 1024x1024.

You can easly change resolution of output texture. In my example, I set resolution to 2048x2048. If you replace first line of example to: "o 1024 1024" output texture will be 1024x1024.

Please remember, that the texture written to disk is always 32-bit. If you don't use height map, you can load it into any paint program and save as 24-bit image. It will decrease size of output image.

If you have any trouble using it or need help with your models, just ask me. I will help.


How to use all the stuff on table

Now You have two (or three if you have Specular texture) textures for model.

  1. Import textures in Future Pinball. Remember names of all imported textures.
  2. Adding "diffuse" (ordinary) texture to object. This texture is used on table, if there is not BAM or if user isn't using New Renderer.
  3. In table script under param: !texture = diffuseTextureName and !normalMap = normalMapTextureName and if you have Specular texture !specularMap = specularTextureName. See script in my BAM-demo table.
  4. Now we have one small problem. Because "normalMapTextureName" and "specularTextureName" is not assigned to any object on table, FP will not load it and BAM will not have access to it. We have to "cheat": Create in FP surface, adding as Top or Side texture "normalMpTextureName" and "specularTextureName", uncheck "Render object (initial value)". That last step will make this surface invisible, but FP will now load the additional textures.


Height Map

When model has Height Map, BAM can distort textures to imitate additional, more complicated, geometry. Height Map stored in texture has only one value in range <0, 1> for every pixel. To use this information BAM also needs to know how to "scale" this value and "bias" of this value. You will have to deterimine these values in experiments (in BAM menu go to: [Rendering Engine] -> [DEV options] -> "!heightMap_scale" and "!heightMap_bias").  Once you find right values, you need only to add it to script.


Specular texture

When you have specular texture with different colors, you don't need to use "Specular level" in normalMap texture prepared with tc.exe. It that case you should set BLUE value to 1 (like i did for "Slug" in my BAM-demo table) and set !specularMap in script. If specular texture is "gray" (alway Red = Green = Blue), you should copy Red value from source specular texture to BLUE value in normalMap created with tc.exe. In this case, you don't need to add specular texture as separate texture to FP.