Texture Series
Bump and Normal Channel Deep Dive
Version 1.0, Updated Aug 2024 using Octane 2023.1.3 and Cinema 4D 2024.4.1
About this guide
Both the bump and normal channels exist in every material type in Octane (and most other render engines out there). They serve as cheap and fast ways to add extra surface detail to a model without increasing the polygon count.
This guide goes into a little bit of detail about how these channels actually work, what kind of textures they’re expecting, as well as some pointers on what to use when. It also includes a few setups for Octane in Cinema 4D to help the process along.
This guide is meant to replace about half of the current Fun with Normal Maps guide (the portion of it that explains how they work). The second half (walkthrough of building your own) will be rebuilt at a later date.
PDF Version of this guide can be found here
Part I: Polygon Normals
Both the bump and normal channels work by messing with normals, so it’s important to understand a bit about what they are and what they do. Every polygon also has a property called a “polygon normal”, which in this guide we’re just going to refer to as a “normal” to keep things easy (there are also vertex normals which we won’t address here).
Every polygon has a front side and a back side. In C4D, if we select a polygon, the front is orange and the back is blue. If we imagine a sphere around the polygon that’s split in half, anything pointing out from the center of the polygon from the front will go into the front hemisphere, and anything pointing out from the back goes into the back hemisphere.
Technically, a normal is the direction vector that is perpendicular to the polygon and points into the same hemisphere as the front of the polygon (shown above in orange). It describes the orientation of a polygon in space, and is used in a variety of calculations in 3D.
In C4D, if we hit Shift-V in the perspective viewport and turn on Polygon Normals in the View tab, we can see the normal represented when an editable sheet of polygons is selected.
When light hits a polygon, a render engine uses its normal to determine how to shade it. If we rotate the polygon toward or away from a light source, the normal remains perpendicular to the surface, but the angle the light is hitting it changes relative to the normal, so the shading changes.
If we were to alter just the normal and not rotate the polygon, we’d essentially “fool” the engine and get the same shading effects without altering the geometry itself.
This principle was used first in bump mapping, and then later in normal mapping. Both of these technologies take it a step further by overlaying a texture across a set of polygons and using the color values for each pixel to nudge the polygon normal on that particular part of the polygon a different way.
Part II: The Bump Channel
Bump mapping uses a grayscale texture to determine which parts of each polygon should be shaded to appear “higher” or “lower” and altering the shading normals accordingly to fake depth. The normals that map to lighter pixels on the texture are tilted to appear higher, and ones that are mapped to darker pixels appear lower. Great.
Here’s the confusing part: Even though bump uses a height map, we do not have precise control over the exact “height” of every pixel like most other channels. Rather than one pixel telling one normal how to tilt, bump samples two other points near the pixel in question and then uses the local gradient (the ramp of grays between them) to determine how the surrounding normals tilt without affecting the position of the original point (yep, confusing). Fortunately we don’t need to truly understand it to get good results.
Because of the way the effect works, not every bump texture is going to look good (or as we expect), and there are a few gotchas that we need to watch out for. Generally speaking, the smoother and more continuous the gray transitions are from point to point, the more convincing the effect is going to look. It starts to break down with high contrast sharp edges and/or isolated islands in the texture.
The three maps on the left produce good results because they’re using reasonable height values, and there are a lot of smooth intermediate grays and small details so the channel has a lot of data to work with.
The three on the right don’t work so well. High contrast images like the bricks or logos don’t give the channel enough of a local gradient between black and white to tilt the normals nicely, and the large linear gradient is too regular and doesn’t have enough small detail to add any value to the render. It’s not actually displacing geometry, so it can’t make a wedge shape across the whole polygon like we might expect.
Bump Setup
The bump channel will happily take nearly anything we try to feed into it, making it easy to use. Any grayscale image texture or procedural shader will produce some kind of effect. If we pick a color image, the value (the V in HSV) of the color of each pixel will be used. Once we have the texture hooked up, we just need to adjust the bump height parameter in the bump channel of the material until it looks good. We can invert our source file using an Invert node if we want it to go “down” instead of “up” or vice versa.
File types
One of the nice things about bump is that it’s not super picky about the file type. The most accurate possible results would be had with a 16- or 32-bit linear encoded image created by a texture set generator, but in nearly all cases, an 8-bit PNG (linear or even sRGB) is fine. JPG can even work in some cases as long as we don’t have a geometric pattern or a recognizable shape where the lossy artifacts would look crunchy. Again, bump relies on the neighboring pixels to work, so it’s not high accuracy per pixel we’re after as much as something that has enough variation to look good when fed into the channel.
Important: If we’re using a bump map created by a texture set generator, we want to load it into an Image Texture node and make sure it’s set to non-color data (Legacy Gamma is overridden with this setting).
Resolution is probably the biggest factor to consider. Usually 1k or 2k is the sweet spot. For more organic lumpy shapes, we can often get away with a lower resolution image (256px even, like we see in the example above. For precise shapes like a logo, we will probably have to go higher res (2k or 4k+)
Important: Depth maps can’t be antialiased to smooth out 2D curves, because those intermediate antialiasing pixels would read as different heights in bump (seen in panel 1 above), so the only way to make a 2D curve smoother in bump is to up the resolution and/or back the camera out so it’s not as close.
Bump Height
Bump height strengthens or weakens the effect by tilting the surrounding normals more. Since there are no polygons being displaced, there are hard limits on how much we can expect from this. We can see this pretty clearly by building a height map with sharp squares of different gray tones separated by a neutral 50% gray. If we feed this map into the displacement channel, the value of the gray drives the actual height of the displacement and the areas sink in or extrude out like we’d expect.
If we feed the same map into the bump channel, all the squares appear to sink in or bump out about the same amount. This is due to a combination of not giving the channel enough data to work with, having sharp delineations between the shaded areas (islands), and the limitations of how high areas can appear to be raised or lowered just by tilting the normals. It’s pretty much the perfect storm of a bad bump map. There actually is a tiny bit of variation in the effect from square to square which we can see a touch more clearly if we crank the bump height and zoom in, but it’s never going to look convincing like it does with displacement, and overdoing the height causes other visual artifacts and issues.
On the other hand, if we smooth the image out a bit with gradients and reduce the amount of islands, we get a far more successful bump map. This method gives us tapered indentations and bumps as opposed to steep dropoffs, so it does change the look. There’s also a hard limit on the apparent height we can get, but if we can live with all that, we can save ourselves the headache and resource needs of displacement.
It’s also worth noting that the bump height here only had to be 0.02 to be convincing because of the gradients, where we had to push the bump height to 0.1 or even 0.5 to notice the effect using the high contrast map in the previous section. A good rule of thumb is that the less we have to change the height from default (0.02), the better we’re doing at giving the bump channel a map it likes.
If our surface is always facing toward the main light source and not wrapping around away from it, we can help the effect along further by feeding the same map into the Albedo channel as seen in the right panel. This trick breaks pretty easily in an animated piece or if we’re reusing the texture in other parts of the model because the lighting won’t appear to be correct anymore, so we need to be careful with that.
Contrast/Blur
If we have a texture that’s super high contrast like a logo or an icon, we get a weak effect at the default height (0.02) like in panel 2. If we push it too much, we get this steppy look like in panel 3.
Adding blur to the edges creates a grayscale ramp which gives the channel more information to work with and helps smooth out the height transition. It also essentially rounds the sharp corners of the texture which stops the stepping effect because the normals can tilt at more angles around a rounded transition.
We can either blur the map in our 2D editor prior to bringing it in, or we can use an OSL Gaussian Blur node in the material to do it procedurally. The OSL blur can give us a little more of a chiseled look on the corners which is mostly noticeable if we get super close (panel 4), but his method is far more convenient because it’s adjustable on the fly. Using an external image editor to blur the texture itself (panels 5-6) gives us a little smoother corners, but we have to keep round tripping to the 2D app and trying different blur amounts.
OSL Gaussian Blur setup
The easiest way to find the built-in Gaussian Blur OSL node is to search with spacebar or shift-C while the node editor is active and start typing “Gaussian”. We just need to make sure to grab the Gaussian blur node and not Gaussian Spectrum which is a completely different thing. That node goes between the texture and the material input. “Iterations” makes the blur larger or smaller, “steps” makes it smoother (lower values).
Important: Whatever texture is being fed in must have a Texture Projection node attached to it which is set to OSL delayed UV, or the OSL blur node will not do anything.
Part III: The Normal Channel
The normal channel is similar to the bump channel in that they both mess with normals to produce extra detail on a surface without creating new geometry. The way it goes about it is different though.
Unlike the bump channel, every pixel in the normal channel can have a unique normal direction. This makes the system a lot more powerful and accurate. Unlike height maps where each slice of depth has to have a solid color, normal maps can just tilt intermediate pixels used for antialiasing to produce smoother 2D curves, allowing us to get a lot closer to the model without seeing jagged edges or other artifacts. It can also be used to do effects like galvanizing and faux anisotropy that the bump channel simply can’t do.
The tradeoff is that the system is more complex and more often than not we need specialized tools to build the maps properly. For example, if we want to bevel the edges of a “raised” surface, we have to create the right 2D shapes that translate to each bevel, AND know which RGB values to assign to each, rather than throwing a gaussian blur on the shape and calling it a day like we can in bump. Most of the time, it’s just easier to have a texture set generator make them for us rather than trying to draw them out by hand.
The normal channel uses the R, G, & B channels of a color image. The 0-1 value it pulls from the red channel tells a render engine how much to tilt the normal for that pixel “left” or “right”, and the 0-1 value taken from the green channel tells it to tilt it “top” or “bottom”. The blue channel deals with the height of the normal itself, so it can be thought of as “inward” or “outward”.
The amount of tilt has to be relative to something, and that something most of the time is either the polygon’s normal or the object’s coordinate space.
Tangent Space vs. Object Space Normal maps
There are a few ways normal maps can be encoded, the difference having to do with the coordinate system that the normals in the map are tilted (technical term is “perturbed”) relative to. The two most common spaces we come across in the wild are Tangent Space and Object Space.
A Tangent Space normal map is meant to be used on any model. They’re most often used in general purpose texture sets where we may want to use the same set on several objects and add in surface detail like we would with the bump channel, only with more accuracy. The normals in this type of map are tilted relative to the surface of the geometry, using each polygon normal as the main reference object.
A tangent space map appears to us as mostly a cornflower blue-dominant image because it only needs to calculate normals that point “outward” from the front face of the polygon. “Inward” and “outward” are mapped to the blue channel, and ones that are facing directly out (unmodified) are R:0.5, G:0.5, B:1, or light blue. Red and green are added or subtracted to tilt the normal “left”, “right”, “up”, or “down”.
An Object Space normal map is custom-built for one specific model. They’re most often used in video games or other applications where polycount is at a premium and the models are not likely to change after they’re finished. After a high polygon model is created, a normal map is produced by a process called baking. This baked map can then be applied to a chunkier, lower polygon version of the model, and the normals will help smooth out the faceting that occurs because of the low polycount, as well as add in smaller detailed areas that have been sculpted into the surface of the model.
Object space normals are tilted relative to the object’s XYZ coordinate system (x for red, y for green, z for blue), not each polygon’s normal. This is a much simpler calculation, but ties the map to that particular object. As we can see in the face example above, light blue is the front (-Z in C4D), yellow is the back (+Z), green is up, magenta is down (Y axis), red is right, dark cyan is left.
Because the normals are relative to the entire object, more colors are used, and the resulting map has more of a rainbow-ish look than a light blue one. This makes it easier for us to tell at a glance that it’s an Object Space map and should only be used with the model it came with.
World Space and Camera Space are also terms that exist in the normal world, but these are typically found in the process of baking or generating normal maps, not using them in materials.
Normal Map Setup
Similar to bump we can just put anything we want directly into the Normal channel. It’ll produce some kind of effect no matter what we feed in, but if we really want to use it as intended, we want to give it a linear RGB texture that was purpose-built to be a normal map.
We can use the Power slider to reduce the “strength” of the normal map, but we’ll start to lose detail if we do this which may or may not be desirable. We can also mix normal maps as we’ll see later.
File types
Resolution is important - unless the normal channel isn’t contributing a lot, the camera is never close, or the material is a tiny repeating pattern, we’ll typically want to start with 1K and work our way up as needed.
For the file format, we want to avoid JPG and stick with PNG or EXR, because compression artifacts will be very noticeable. This is less of an issue with 8k textures, but given the choice, lossless is always better.
When choosing bit depth, 8-bit files will usually suffice for most tangent space maps. In some cases, moving to 16-bit will make a noticeable difference, especially in highly detailed object space maps where we need more individual normal directions (each one represented by a unique color) to get smoother transitions. If we’re getting what looks like a topographic hiking map, we probably need to go 16-bit.
Important: Most normal maps are encoded with a linear transfer function (gamma=1), even lower bit depth files like PNG. We need to make sure that we set the color space in the Image Texture node properly for this by either setting the Legacy Gamma to 1 or setting the mode to non-color data.
GL vs. DX
Normal maps can be encoded as GL (OpenGL) or DX (DirectX). Most of the time we get a choice when downloading or exporting a texture set. Octane uses GL maps, which means green is “up”. If we are only given a DX map where green is “down”, we can fix it with a Channel Inverter node by inverting the green channel only.
Mixing Normal Maps
Mixing normal maps requires a Composite Texture node. Once we have one of these in our node graph, we can add one purple texture node per texture we want to use in the Composite Texture Node’s Shader tab (Add Layer button>Texture).
Each normal map gets fed into a Texture node’s Texture input. Then we can select all the Texture Nodes, and in the Shader tab, we need to make sure the blend mode is set to Reoriented normal (not just regular Normal or anything else).
To make an individual input stronger or weaker, we can use the Opacity slider in the corresponding purple Texture node (not in the ImageTexture node).
When to use what
If we have a normal map, we use that. If we have a bump map, we use that. If we have both as part of a texture set, we use both. Texture sets are kind of a no-brainer - the generator already did all the deciding for us. When we’re building materials by hand, however, we really need to consider which to use.
Bump mapping is easier and more forgiving than normal mapping at the expense of precision. We have far more options when it comes to built-in procedural effects and height maps that already exist in the wild, and some grayscale images not even meant for bump will work ok. With quick-fix tools at our disposal like gaussian blur, bump mapping can be fine in a lot of cases if we’re not getting too close to the model.
Normal mapping can effectively do everything bump mapping can, though getting 1:1 results between the two is often hard because of how the two different technologies work. If the results of the bump map are acceptable, we should just use that. If we have sharp transitions between areas in the texture and/or need to get pretty close to the model, we should consider switching to normal mapping for more detailed bump-like effects.
The normal channel is also capable of things bump simply can’t do. It’s great for effects where the surface needs to look flat, but bits of it catch the light in different ways as the environment shifts like in the case of flakes or galvanizing. We can even get a quick faux anisotropy effect (different from the anisotropy channel which is a modification of the BRDF model). Normal mapping is also our only choice between the two for baking object-space maps to smooth out a low-poly version of a model.
Sometimes we can use both - if we want a pitted galvanized metal, we can do the galvanizing in the normal channel pretty easily with Cell Voronoi noise and a gradient to recolor it to random rgb values, and then add the pits and damage using a grayscale noise in the bump channel.
Part IV: Specific issues
Small bump map patterns combined with strong, small light sources can produce hot pixels (fireflies). Making the pattern or area light larger or introducing blur can help with this. There are also other kernel settings that can be adjusted to counter it.
Converting bump to normal: Depth/height maps can’t be antialiased (since the antialiasing pixels would produce different heights), so using a height-to-normal conversion method will produce jaggy curves if we get too close. Normal maps that are generated from geometry or programmatically (not converted) are capable of antialiasing - they just tilt the normals, so they’ll look better when we get close to the model.
Neither bump nor normal affects the silhouette of the object because they aren’t pushing the polygons themselves around like displacement. This means the illusion will break if we look at a sharp edge of the model from too severe of an angle or at the or the texture abruptly stops and the surface should be casting a shadow on another one. If this effect is needed, displacement or adding geometry to the model is the only way to get it.
Wrap Up
If you made it through this guide, you probably have a much better understanding of how to work with the bump and normal channels than you did before, and you’re aware of all the gotchas and idiosyncrasies involved.