Bump map: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
No edit summary
 
(120 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 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]


This tutorial is a step-by-step process you can go through to create a normal map for a material.
[[File:Brickwall021a normalcompare.jpg|thumb|200px|A material's [[albedo]] (left) compared to its bump map.]]


==Adding a normal map (aka bump map)==
[[File:Example of bump mapping.jpg|thumb|200px|The above material in-game.]]
[[Image:Beforenormal.jpg|thumb|Texture that the below normal map is based on.]]
[[Image:afternormal.jpg|thumb|Normal map created from above texture.]]


'''1.''' First, create the normal map. 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.  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.


'''2.''' 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 same way as before. 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.
{{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.
}}


'''3.''' Add this line to the VMT somewhere between the braces:
== Format ==


<code>"$bumpmap" "''texture name''"</code>
Each pixel in a bump map contains the (x, y, z) coordinates that define a [[normal]]ized [[vector]].


and fill in the path and name of your normal map VTF. Here's an example VMT for a normalmapped material:
Because of this each color channel in a bump map has a meaning:
<pre><nowiki>"LightmappedGeneric"
 
; 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|A flat bump map should be [128, 128, 255]. <code>dev/flat_normal</code> 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]].
 
[[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(); }
Also note that multiple materials can use the same normal map file.
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}}.


==See also==
==See also==


[[Creating Materials]]
*{{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 a Material Tutorial]]
[[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