/// <summary> /// Converts a bump map to a normal map. /// </summary> /// <param name="bitmap">Source bump map image.</param> /// <param name="strength">Normal strength.</param> /// <returns>DFBitmap normal image.</returns> public static DFBitmap ConvertBumpToNormals(DFBitmap bitmap, float strength = 1) { // Must be a colour format if (bitmap.Format == DFBitmap.Formats.Indexed) { return(null); } DFBitmap newBitmap = new DFBitmap(bitmap.Width, bitmap.Height); newBitmap.Format = bitmap.Format; newBitmap.Initialise(bitmap.Width, bitmap.Height); for (int y = 0; y < bitmap.Height; y++) { for (int x = 0; x < bitmap.Width; x++) { // Look up the heights to either side of this pixel float left = GetIntensity(bitmap, x - 1, y); float right = GetIntensity(bitmap, x + 1, y); float top = GetIntensity(bitmap, x, y - 1); float bottom = GetIntensity(bitmap, x, y + 1); // Compute gradient vectors, then cross them to get the normal Vector3 dx = new Vector3(1, 0, (right - left) * strength); Vector3 dy = new Vector3(0, 1, (bottom - top) * strength); Vector3 normal = Vector3.Cross(dx, dy); normal.Normalize(); // Store result int pos = y * bitmap.Stride + x * bitmap.FormatWidth; newBitmap.Data[pos + 0] = (byte)((normal.x + 1.0f) * 127.5f); newBitmap.Data[pos + 1] = (byte)((normal.y + 1.0f) * 127.5f); newBitmap.Data[pos + 2] = (byte)((normal.z + 1.0f) * 127.5f); newBitmap.Data[pos + 3] = 0xff; } } return(newBitmap); }
/// <summary> /// Creates average intensity bitmap. /// </summary> /// <param name="bitmap">Source DFBitmap.</param> /// <returns>Average intensity DFBitmap.</returns> public static DFBitmap MakeAverageIntensityBitmap(DFBitmap bitmap) { // Must be a colour format if (bitmap.Format == DFBitmap.Formats.Indexed) { return(null); } DFBitmap newBitmap = new DFBitmap(); newBitmap.Format = bitmap.Format; newBitmap.Initialise(bitmap.Width, bitmap.Height); // Make each pixel grayscale based on average intensity int srcPos = 0, dstPos = 0; for (int i = 0; i < bitmap.Width * bitmap.Height; i++) { // Get source color byte r = bitmap.Data[srcPos++]; byte g = bitmap.Data[srcPos++]; byte b = bitmap.Data[srcPos++]; byte a = bitmap.Data[srcPos++]; // Get average intensity int intensity = (r + g + b) / 3; DFBitmap.DFColor dstColor = DFBitmap.DFColor.FromRGBA((byte)intensity, (byte)intensity, (byte)intensity, a); // Write destination pixel newBitmap.Data[dstPos++] = dstColor.r; newBitmap.Data[dstPos++] = dstColor.g; newBitmap.Data[dstPos++] = dstColor.b; newBitmap.Data[dstPos++] = dstColor.a; } return(newBitmap); }
/// <summary> /// Creates a grayscale version of bitmap based on colour theory. /// </summary> /// <param name="bitmap">Source DFBitmap.</param> /// <returns>Grayscale DFBitmap image.</returns> public static DFBitmap MakeGrayscale(DFBitmap bitmap) { // Must be a colour format if (bitmap.Format == DFBitmap.Formats.Indexed) { return(null); } DFBitmap newBitmap = new DFBitmap(); newBitmap.Format = bitmap.Format; newBitmap.Initialise(bitmap.Width, bitmap.Height); // Make each pixel grayscale int srcPos = 0, dstPos = 0; for (int i = 0; i < bitmap.Width * bitmap.Height; i++) { // Get source color byte r = bitmap.Data[srcPos++]; byte g = bitmap.Data[srcPos++]; byte b = bitmap.Data[srcPos++]; byte a = bitmap.Data[srcPos++]; // Create grayscale color int grayscale = (int)(r * 0.3f + g * 0.59f + b * 0.11f); DFBitmap.DFColor dstColor = DFBitmap.DFColor.FromRGBA((byte)grayscale, (byte)grayscale, (byte)grayscale, a); // Write destination pixel newBitmap.Data[dstPos++] = dstColor.r; newBitmap.Data[dstPos++] = dstColor.g; newBitmap.Data[dstPos++] = dstColor.b; newBitmap.Data[dstPos++] = dstColor.a; } return(newBitmap); }
/// <summary> /// Gets a bump map from the source DFBitmap. /// </summary> /// <param name="bitmap">Source colour image.</param> /// <returns>DFBitmap bump image.</returns> public static DFBitmap GetBumpMap(DFBitmap bitmap) { // Must be a colour format if (bitmap.Format == DFBitmap.Formats.Indexed) { return(null); } // Create horizontal sobel matrix Filter horizontalMatrix = new Filter(3, 3); horizontalMatrix.MyFilter[0, 0] = -1; horizontalMatrix.MyFilter[1, 0] = 0; horizontalMatrix.MyFilter[2, 0] = 1; horizontalMatrix.MyFilter[0, 1] = -2; horizontalMatrix.MyFilter[1, 1] = 0; horizontalMatrix.MyFilter[2, 1] = 2; horizontalMatrix.MyFilter[0, 2] = -1; horizontalMatrix.MyFilter[1, 2] = 0; horizontalMatrix.MyFilter[2, 2] = 1; // Create vertical sobel matrix Filter verticalMatrix = new Filter(3, 3); verticalMatrix.MyFilter[0, 0] = 1; verticalMatrix.MyFilter[1, 0] = 2; verticalMatrix.MyFilter[2, 0] = 1; verticalMatrix.MyFilter[0, 1] = 0; verticalMatrix.MyFilter[1, 1] = 0; verticalMatrix.MyFilter[2, 1] = 0; verticalMatrix.MyFilter[0, 2] = -1; verticalMatrix.MyFilter[1, 2] = -2; verticalMatrix.MyFilter[2, 2] = -1; // Get filtered images DFBitmap horz = MakeAverageIntensityBitmap(horizontalMatrix.ApplyFilter(bitmap)); DFBitmap vert = MakeAverageIntensityBitmap(verticalMatrix.ApplyFilter(bitmap)); // Create target bitmap DFBitmap result = new DFBitmap(); result.Format = bitmap.Format; result.Initialise(horz.Width, horz.Height); // Merge int pos = 0; for (int i = 0; i < bitmap.Width * bitmap.Height; i++) { // Merge average intensity int r = (horz.Data[pos + 0] + vert.Data[pos + 0]) / 2; int g = (horz.Data[pos + 1] + vert.Data[pos + 1]) / 2; int b = (horz.Data[pos + 2] + vert.Data[pos + 2]) / 2; // Write destination pixel result.Data[pos + 0] = (byte)((r > 255) ? 255 : r); result.Data[pos + 1] = (byte)((g > 255) ? 255 : g); result.Data[pos + 2] = (byte)((b > 255) ? 255 : b); result.Data[pos + 3] = 255; pos += bitmap.FormatWidth; } return(result); }