Bump Map Creation Using C#
I've been posting a lot of C# code with regard to image manipulation. Half of the reason for this is that at work, I'm working on the initial planning/setup of a SharePoint project (lots of planning, not much programming involved at the moment). The other half is that one of my personal projects is nearing completion and I plan on putting out that code all at once. So I'm left with code that gets added to my utility library as I work on my personal projects... In this case, it's an update to my procedural texture generator (that has been shelved for a bit). Specifically I created a class to help with the generation of bump maps.
For those of you that don't know what a bump map is, it is a height map of sorts that is applied to 3D geometry prior to lighting that gives the impression that there is more detail than there actually is on the object. There are a few different techniques for creating bump maps (as there are a few different types of bump maps), but the easiest to create is the 1D bump map. If you've seen them, they're the grey images that look like they have some depth to them. And as always, I've created some code for creating them, which is why you're here:
/\*
Copyright (c) 2010 <a href="http://www.gutgames.com">James Craig</a>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.\*/
#region Usings
using System.Drawing;
#endregion
namespace Utilities.Media.Image
{
/// <summary>
/// Used for creating bump maps
/// </summary>
public class BumpMap
{
#region Constructors
/// <summary>
/// Constructor
/// </summary>
public BumpMap()
{
Invert = false;
Direction = Direction.TopBottom;
}
#endregion
#region Protected Properties
protected Filter EdgeDetectionFilter { get; set; }
#endregion
#region Public Properties
/// <summary>
/// Determines the direction of the bump map
/// </summary>
public bool Invert { get; set; }
/// <summary>
/// Determines the direction of the bump map
/// </summary>
public Direction Direction { get; set; }
#endregion
#region Protected Functions
/// <summary>
/// Sets up the edge detection filter
/// </summary>
protected void CreateFilter()
{
EdgeDetectionFilter = new Filter(3, 3);
if (Direction == Direction.TopBottom)
{
if (!Invert)
{
EdgeDetectionFilter.MyFilter\[0, 0\] = 1;
EdgeDetectionFilter.MyFilter\[1, 0\] = 2;
EdgeDetectionFilter.MyFilter\[2, 0\] = 1;
EdgeDetectionFilter.MyFilter\[0, 1\] = 0;
EdgeDetectionFilter.MyFilter\[1, 1\] = 0;
EdgeDetectionFilter.MyFilter\[2, 1\] = 0;
EdgeDetectionFilter.MyFilter\[0, 2\] = -1;
EdgeDetectionFilter.MyFilter\[1, 2\] = -2;
EdgeDetectionFilter.MyFilter\[2, 2\] = -1;
}
else
{
EdgeDetectionFilter.MyFilter\[0, 0\] = -1;
EdgeDetectionFilter.MyFilter\[1, 0\] = -2;
EdgeDetectionFilter.MyFilter\[2, 0\] = -1;
EdgeDetectionFilter.MyFilter\[0, 1\] = 0;
EdgeDetectionFilter.MyFilter\[1, 1\] = 0;
EdgeDetectionFilter.MyFilter\[2, 1\] = 0;
EdgeDetectionFilter.MyFilter\[0, 2\] = 1;
EdgeDetectionFilter.MyFilter\[1, 2\] = 2;
EdgeDetectionFilter.MyFilter\[2, 2\] = 1;
}
}
else
{
if (!Invert)
{
EdgeDetectionFilter.MyFilter\[0, 0\] = -1;
EdgeDetectionFilter.MyFilter\[0, 1\] = -2;
EdgeDetectionFilter.MyFilter\[0, 2\] = -1;
EdgeDetectionFilter.MyFilter\[1, 0\] = 0;
EdgeDetectionFilter.MyFilter\[1, 1\] = 0;
EdgeDetectionFilter.MyFilter\[1, 2\] = 0;
EdgeDetectionFilter.MyFilter\[2, 0\] = 1;
EdgeDetectionFilter.MyFilter\[2, 1\] = 2;
EdgeDetectionFilter.MyFilter\[2, 2\] = 1;
}
else
{
EdgeDetectionFilter.MyFilter\[0, 0\] = 1;
EdgeDetectionFilter.MyFilter\[0, 1\] = 2;
EdgeDetectionFilter.MyFilter\[0, 2\] = 1;
EdgeDetectionFilter.MyFilter\[1, 0\] = 0;
EdgeDetectionFilter.MyFilter\[1, 1\] = 0;
EdgeDetectionFilter.MyFilter\[1, 2\] = 0;
EdgeDetectionFilter.MyFilter\[2, 0\] = -1;
EdgeDetectionFilter.MyFilter\[2, 1\] = -2;
EdgeDetectionFilter.MyFilter\[2, 2\] = -1;
}
}
EdgeDetectionFilter.Offset = 127;
}
#endregion
#region Public Functions
/// <summary>
/// Creates the bump map
/// </summary>
public Bitmap Create(Bitmap Image)
{
CreateFilter();
using (Bitmap TempImage = EdgeDetectionFilter.ApplyFilter(Image))
{
return Media.Image.Image.ConvertBlackAndWhite(TempImage);
}
}
#endregion
}
#region Enum
/// <summary>
/// Direction
/// </summary>
public enum Direction
{
TopBottom = 0,
LeftRight
};
#endregion
}
The code above really doesn't have much to it. It simply uses the Filter class that I showed a little bit ago, so you're going to need that in order to create the bump map. Also a function from my utility library to convert the image to black and white is used. Other than that, all the code does, is it sets up a sobel emboss filter:
1 2 1
0 0 0
-1 -2 -1
And runs it on the image. Please note that you can tell it to flip the filter, go left to right instead of top to bottom, etc. so it does have some flexibility. The image, after the filter is applied, then goes through a grey scale process so we end up with the correct image (otherwise you'll notice some artifacts from the color image). From there the Image property will contain your bump map. But that's all there is to it. So give it a try, leave feedback, and happy coding.
Sign up for More Posts
I have no idea why you'd put yourself through that but if you'd like more posts from me then how about using my RSS feed? Take a look.
- Previous: Symmetric Nearest Neighbor in C#
- Next: Normal Map Creation Using C#