Bump map: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
No edit summary
 
(114 intermediate revisions by 53 users not shown)
Line 1: Line 1:
[[category:material system]][[category:tutorials]]
{{LanguageBar}}
If your texture is supposed to have depth to it, adding a '''normal map''' (aka bump map) will make the lighting on it far more realistic. (This is perhaps the main reason Doom3, FarCry, and HL2 are able to look so much better than previous games.) The normal map tells the game what direction each pixel would be facing if your texture were in 3D instead of being a flat image. A normal map is kind of useless for really flat surfaces like smooth concrete or metal. But even rough concrete sometimes has enough depth to it to make a normal map worthwhile. This is an old article but explains the concept well: [http://members.shaw.ca/jimht03/normal.html Normal Maps]


The normal map should be created in the same dimensions as the image texture (color map) it will go with.  There are a few options for how to create one, depending on the quality you want, your skill with various programs, or your patience.
[[File:Brickwall021a normalcompare.jpg|thumb|200px|A material's [[albedo]] (left) compared to its bump map.]]


==One-Step Normal Map Creation==
[[File:Example of bump mapping.jpg|thumb|200px|The above material in-game.]]


If you have Photoshop or PaintShop Pro, you can use Nvidia's normal map tools, available [http://developer.nvidia.com/object/photoshop_dds_plugins.html here]. There are also tools for those who use the GIMP [http://nifelheim.dyndns.org/%7ecocidius/normalmap/ here], but we will focus on the Photoshop tools. To use them, open a copy of the texture and apply the Normal Map filter. Fiddle with the settings until you get something that you feel will be bumpy enough for your texture. The greater the range of colors, the greater the range of angles on the surface.  A very flat surface will look that medium blue color all over.  If you want to have more control over it, change the image to grayscale and fiddle with brightness and contrast to make certain details stand out before applying the filter- however, be sure to change the texture back to RGB mode, or else the normal map tool will not work.  Do this step multiple times to get different details to stand out, and then put the images together in layers with the blend mode set to overlay.
Textures often called '''Bump Maps''', or '''Normal Maps''' are used to simulate three-dimensional details on a two-dimensional surface by manipulating its lighting.


{{note|
* Static props using bump maps can not be lit per-vertex, except in {{csgobranch}}. [[$lightmap]] is also incompatible with [[$bumpmap]].
* Bump maps cannot be used on normal [[decals]] and [[overlay]]s, except in {{csgobranch}}. In order for these to function properly, the surface that they are placed on must also have a bumpmap. Bumped "decals" can be created in any engine branch, regardless of underlying geometry, by using a [[Decals#brush_decals|brush or displacement with a $decal material]] instead.
}}


[[Image:afternormal.jpg|thumb|Normal map created from texture on left using nVidia's filter.]]
== Format ==
[[Image:Beforenormal.jpg|thumb|none|Image texture (color map).]]


==Normal Map from a Height Map==
Each pixel in a bump map contains the (x, y, z) coordinates that define a [[normal]]ized [[vector]].


==Normal Map from a 3D program==
Because of this each color channel in a bump map has a meaning:


==Getting the Normal Map in the Game==
; Red
: Horizontal facing (X axis)
:* 0 = left
:* 128 = forward, or facing viewer
:* 255 = right
; Green
: Vertical facing (Y axis)
:* 0 = up
:* 128 = forward, or facing viewer
:* 255 = down
; Blue
: Height (Z axis).
:* 0 = facing 'in' to the texture, away from the viewer. This is a 'bad' value. Anything under 128 means that the surface should be facing away from the player, which is not possible.
:* 128 = maximum depth capable of receiving dynamic light. It's a bad idea to go under this.
:* 255 = facing 'out' of the texture towards the viewer.


'''1.''' Save your normal map as a [[TGA]] in the same resolution as the original texture. Give it a name that ends in _normal. Then convert it to a VTF. The _normal at the end of the name will affect how [[Vtex]] converts it. For the brick wall example, we would name the file <code>brickwall_normal.tga</code>. Place the new VTF in the same place as your original texture.


'''2.''' Add this line to the VMT somewhere between the braces:
{{note|A flat bump map should be [128, 128, 255]. <code>dev/flat_normal</code> is a flat bump map present in every game.}}


<code>"$bumpmap" "''texture name''"</code>
The three channels represent a normal vector for every pixel which represents the direction that the pixel is facing in 3D space. This allows the engine to generate shadows and highlights on a two-dimensional surface, or give a 3D model more detail.


and fill in the path and name of your normal map VTF. Here's an example VMT for a normal-mapped material:
A bump map is largely useless for really flat surfaces like smooth concrete or metal, but even smooth concrete sometimes has enough depth to it to make one worthwhile, especially if used in conjunction with a [[cubemap]].
<pre><nowiki>"LightmappedGeneric"
 
[[file:normalmap.gif]]
 
== Creation ==
 
A bump map should be rendered in Tangent space and use vector directions X+ Y- Z+.
 
{{note|There are basically two sets of rules for normal maps: [[DirectX]] and [[OpenGL]]. Their interpretation of green channels are opposite. [[Source]] takes the former, whereas [[Source 2]] (even with DX11) takes the latter. Thus, the green channel may need to be inverted depending on the software used to create it. }}
 
=== Programs ===
 
[[File:Test_bump.jpg|thumb|600px|Bump maps as created by various programs.]]
 
Various programs can automate the creation of bump maps, either by image analysis or by using 3D geometry the user provides.
 
;2D
:[[Normal Map Creation in Photoshop or Paint Shop Pro|Photoshop or Paint Shop Pro]]
:[http://www.youtube.com/watch?v=WsFe-E-33IQ Substance Designer]
:[[Normal Map Creation in The GIMP|The GIMP]]
:[http://www.youtube.com/watch?v=xDZDWvTUz-c nDo]
:[http://filterforge.com/filters/8774.html Filter Forge]
:{{Xblahmt|4}}
:[https://charles.hollemeersch.net/njob/ nJob]
;3D
:[[Normal Map Creation in XSI|XSI]]
:[[Normal Map Creation in ZBrush|ZBrush]]
:[[Normal Map Creation in Lightwave|Lightwave]]
:[[Normal Map Creation in 3ds Max|3ds Max]]
:[[Normal Map Creation in Maya|Maya]]
:[[Normal Map Creation in Blender|Blender]]
:[[Materialize]]
:[http://www.nvidia.com/object/melody_home.html NVIDIA Melody]
:[http://planetpixelemporium.com/tutorialpages/normal2.html Cinema 4D]
:[[NormalMapper]]
:[http://xnormal.net/ xNormal]
;Other
:[https://cpetry.github.io/NormalMap-Online/ NormalMap Online]: A website for generating normal maps online.
:[https://sourceforge.net/projects/ssbumpgenerator/ SSBump Generator 5.3]: Despite the name, it can also be used to generate bumpmaps, not just [[$ssbump|self-shadowing bump maps]].
:[http://store.steampowered.com/app/325910/ Substance B2M3]: Previously known as BitMap2Material.
:[https://sites.google.com/site/ccdsurgeon/download/ InsaneBump]: Specifically made to be a free alternative to the now-superseded software "CrazyBump" (may trip antiviruses due to incompatibility)
 
=== Conversion ===
 
==== In [[VTFEdit]] ====
 
When converting your texture:
 
# Choose your image format. Uncompressed formats like BGR888 are higher-quality than compressed formats like DXT1, but be wary of file size.
# Check the "Normal map" box in the texture's flags list after the import is complete. It's about 1/5 of the way down the list.
 
{{tip|VTFEdit can automatically generate bump maps. See the bottom-right of the import screen.}}
 
==== In [[Vtex (Source 1)|Vtex]] ====
 
# Save your normal map as a [[TGA]]. Give it a name that ends in ''_normal''. The ''_normal'' at the end of the name will affect how [[Vtex (Source 1)|Vtex]] converts it. For the brick wall example, we would name the file <code>brickwall_normal.tga</code>.
# Add <code>nocompress 1</code> and <code>normal 1</code> to <texture filename>.txt in the same folder as your texture, then compile.
 
=== Implementation ===
 
Normal maps can be generated from a basetexture, using the Sobel Operator, by sampling the HSB Brightness of each pixel and adjoining pixel to determine the scale of the output Hue and Saturation values that are subsequently converted to RGB for the SetPixel operation.
<syntaxhighlight lang=cpp>
Bitmap image = (Bitmap) Bitmap.FromFile(@"yourpath/yourimage.jpg");
int w = image.Width - 1;
int h = image.Height - 1;
float sample_l;
float sample_r;
float sample_u;
float sample_d;
float x_vector;
float y_vector;
Bitmap normal = new Bitmap(image.Width, image.Height);
for (int y = 0; y < w + 1; y++)
{
{
    "$basetexture" "walls/brickwall"
for (int x = 0; x < h + 1; x++)
    "$surfaceprop" "brick"
{
    "$bumpmap" "walls/brickwall_normal"
if (x > 0) { sample_l = image.GetPixel(x - 1, y).GetBrightness(); }
}</nowiki></pre>
else { sample_l = image.GetPixel(x, y).GetBrightness(); }
if (x < w) { sample_r = image.GetPixel(x + 1, y).GetBrightness(); }
else { sample_r = image.GetPixel(x, y).GetBrightness(); }
if (y > 1) { sample_u = image.GetPixel(x, y - 1).GetBrightness(); }
else { sample_u = image.GetPixel(x, y).GetBrightness(); }
if (y < h) { sample_d = image.GetPixel(x, y + 1).GetBrightness(); }
else { sample_d = image.GetPixel(x, y).GetBrightness(); }
x_vector = (((sample_l - sample_r) + 1) * .5f) * 255;
y_vector = (((sample_u - sample_d) + 1) * .5f) * 255;
Color col = Color.FromArgb(255, (int)x_vector, (int)y_vector, 255);
normal.SetPixel(x, y, col);
}
}
</syntaxhighlight>
See {{ent|$bumpmap}}.


Also note that multiple materials can use the same normal map file.
==See also==


==See also==
*{{ent|$ssbump}}: creation and usage of Valve's new self-shadowing bump maps.
*[http://planetpixelemporium.com/tutorialpages/normal.html An old article that explains normal mapping quite well]
*[http://wiki.polycount.com/wiki/Normal_map Polycount wiki page about normal maps]
*[[Creating a Material]]


[[Creating Materials]]
[[Category:Material System]]
[[Category:Glossary]]
[[Category:Tutorials]]

Latest revision as of 08:47, 14 April 2025

English (en)Español (es)Français (fr)Português do Brasil (pt-br)Русский (ru)中文 (zh)Translate (Translate)
A material's albedo (left) compared to its bump map.
The above material in-game.

Textures often called Bump Maps, or Normal Maps are used to simulate three-dimensional details on a two-dimensional surface by manipulating its lighting.

Note.pngNote:
  • Static props using bump maps can not be lit per-vertex, except in CS:GO engine branch. $lightmap is also incompatible with $bumpmap.
  • Bump maps cannot be used on normal decals and overlays, except in CS:GO engine branch. In order for these to function properly, the surface that they are placed on must also have a bumpmap. Bumped "decals" can be created in any engine branch, regardless of underlying geometry, by using a brush or displacement with a $decal material instead.

Format

Each pixel in a bump map contains the (x, y, z) coordinates that define a normalized vector.

Because of this each color channel in a bump map has a meaning:

Red
Horizontal facing (X axis)
  • 0 = left
  • 128 = forward, or facing viewer
  • 255 = right
Green
Vertical facing (Y axis)
  • 0 = up
  • 128 = forward, or facing viewer
  • 255 = down
Blue
Height (Z axis).
  • 0 = facing 'in' to the texture, away from the viewer. This is a 'bad' value. Anything under 128 means that the surface should be facing away from the player, which is not possible.
  • 128 = maximum depth capable of receiving dynamic light. It's a bad idea to go under this.
  • 255 = facing 'out' of the texture towards the viewer.


Note.pngNote:A flat bump map should be [128, 128, 255]. dev/flat_normal is a flat bump map present in every game.

The three channels represent a normal vector for every pixel which represents the direction that the pixel is facing in 3D space. This allows the engine to generate shadows and highlights on a two-dimensional surface, or give a 3D model more detail.

A bump map is largely useless for really flat surfaces like smooth concrete or metal, but even smooth concrete sometimes has enough depth to it to make one worthwhile, especially if used in conjunction with a cubemap.

Normalmap.gif

Creation

A bump map should be rendered in Tangent space and use vector directions X+ Y- Z+.

Note.pngNote:There are basically two sets of rules for normal maps: DirectX and OpenGL. Their interpretation of green channels are opposite. Source takes the former, whereas Source 2 (even with DX11) takes the latter. Thus, the green channel may need to be inverted depending on the software used to create it.

Programs

Bump maps as created by various programs.

Various programs can automate the creation of bump maps, either by image analysis or by using 3D geometry the user provides.

2D
Photoshop or Paint Shop Pro
Substance Designer
The GIMP
nDo
Filter Forge
XBLAH's Modding Tool XBLAH's Modding Tool
nJob
3D
XSI
ZBrush
Lightwave
3ds Max
Maya
Blender
Materialize
NVIDIA Melody
Cinema 4D
NormalMapper
xNormal
Other
NormalMap Online: A website for generating normal maps online.
SSBump Generator 5.3: Despite the name, it can also be used to generate bumpmaps, not just self-shadowing bump maps.
Substance B2M3: Previously known as BitMap2Material.
InsaneBump: Specifically made to be a free alternative to the now-superseded software "CrazyBump" (may trip antiviruses due to incompatibility)

Conversion

In VTFEdit

When converting your texture:

  1. Choose your image format. Uncompressed formats like BGR888 are higher-quality than compressed formats like DXT1, but be wary of file size.
  2. Check the "Normal map" box in the texture's flags list after the import is complete. It's about 1/5 of the way down the list.
Tip.pngTip:VTFEdit can automatically generate bump maps. See the bottom-right of the import screen.

In Vtex

  1. Save your normal map as a TGA. Give it a name that ends in _normal. The _normal at the end of the name will affect how Vtex converts it. For the brick wall example, we would name the file brickwall_normal.tga.
  2. Add nocompress 1 and normal 1 to <texture filename>.txt in the same folder as your texture, then compile.

Implementation

Normal maps can be generated from a basetexture, using the Sobel Operator, by sampling the HSB Brightness of each pixel and adjoining pixel to determine the scale of the output Hue and Saturation values that are subsequently converted to RGB for the SetPixel operation.

Bitmap image = (Bitmap) Bitmap.FromFile(@"yourpath/yourimage.jpg");
int w = image.Width - 1;
int h = image.Height - 1;
float sample_l;
float sample_r;
float sample_u;
float sample_d;
float x_vector;
float y_vector;
Bitmap normal = new Bitmap(image.Width, image.Height);
for (int y = 0; y < w + 1; y++)
{
	for (int x = 0; x < h + 1; x++)
	{
		if (x > 0) { sample_l = image.GetPixel(x - 1, y).GetBrightness(); }
		else { sample_l = image.GetPixel(x, y).GetBrightness(); }
		if (x < w) { sample_r = image.GetPixel(x + 1, y).GetBrightness(); }
		else { sample_r = image.GetPixel(x, y).GetBrightness(); }
		if (y > 1) { sample_u = image.GetPixel(x, y - 1).GetBrightness(); }
		else { sample_u = image.GetPixel(x, y).GetBrightness(); }
		if (y < h) { sample_d = image.GetPixel(x, y + 1).GetBrightness(); }
		else { sample_d = image.GetPixel(x, y).GetBrightness(); }
		x_vector = (((sample_l - sample_r) + 1) * .5f) * 255;
		y_vector = (((sample_u - sample_d) + 1) * .5f) * 255;
		Color col = Color.FromArgb(255, (int)x_vector, (int)y_vector, 255);
		normal.SetPixel(x, y, col);
		}
	}

See $bumpmap.

See also