/// <summary> /// Create Normal Map Texture. /// </summary> /// <param name="img">Reference FloatImage.</param> /// <param name="wm">Texture Wrap Mode.</param> /// <param name="heightWeights">float[4]-> Color Weights.</param> /// <param name="kdu">Kernel U.</param> /// <param name="kdv">Kernel V.</param> /// <returns></returns> public static FloatImage CreateNormalMap(FloatImage img, WrapMode wm, float[] heightWeights, Kernel2 kdu, Kernel2 kdv, ParsePixelEventHandler pixelParseEvent) { int w = (int)img.Width; int h = (int)img.Height; bool canceled = false; FloatImage fimage = new FloatImage(); fimage.Allocate(4, w, h); unsafe { float* alphaChannel = fimage.Channel(3); int x = 0, y = 0; for (uint i = 0; i < w * h; i++) { float r = img.Pixel((uint)x, (uint)y, 0); float g = img.Pixel((uint)x, (uint)y, 1); float b = img.Pixel((uint)x, (uint)y, 2); float a = img.ComponentCount > 3 ? img.Pixel((uint)x, (uint)y, 3) : 255f; float[] color = ColorToVector4(r, g, b, a); alphaChannel[i] = Float4Dot(color, heightWeights); if (!pixelParseEvent()) { canceled = true; break; } x++; if (x >= w) { x = 0; y++; } } float heightScale = 1.0f / 16.0f; // @@ Use a user defined factor. for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { float du = fimage.ApplyKernel(kdu, x, y, 3, wm); float dv = fimage.ApplyKernel(kdv, x, y, 3, wm); float[] n = Float3Normalize(new float[] { du, dv, heightScale }); fimage.SetPixel(0.5f * n[0] + 0.5f, (uint)x, (uint)y, 0); fimage.SetPixel(0.5f * n[1] + 0.5f, (uint)x, (uint)y, 1); fimage.SetPixel(0.5f * n[2] + 0.5f, (uint)x, (uint)y, 2); if (canceled) break; if (!pixelParseEvent()) { canceled = true; break; } } if (canceled) break; } } return fimage; }
/// <summary> /// Create a new Instance of Kernel Filter. /// </summary> /// <param name="k">Base Kernel to Copy.</param> public Kernel2(Kernel2 k) { m_windowSize = k.m_windowSize; m_data = new float[m_windowSize * m_windowSize]; for (uint i = 0; i < m_windowSize * m_windowSize; i++) { m_data[i] = k.m_data[i]; } }
/// <summary> /// Apply Kernel Filter to Image. /// </summary> /// <param name="k">Kernel Filter.</param> /// <param name="x">X Position.</param> /// <param name="y">Y Position.</param> /// <param name="c">Channel.</param> /// <param name="wm">Wrap Mode.</param> /// <returns></returns> public float ApplyKernel(Kernel2 k, int x, int y, uint c, WrapMode wm) { uint kernelWindow = k.windowSize(); int kernelOffset = (int)(kernelWindow / 2) - 1; float sum = 0.0f; unsafe { float* channel = this.Channel(c); for (uint i = 0; i < kernelWindow; i++) { int src_y = (int)(y + i) - kernelOffset; for (uint e = 0; e < kernelWindow; e++) { int src_x = (int)(x + e) - kernelOffset; int idx = (int)this.Index(src_x, src_y, wm); sum += k.valueAt(e, i) * channel[idx]; } } } return sum; }
/// <summary> /// Create Normal Map Texture. /// </summary> /// <param name="img">Reference FloatImage.</param> /// <param name="wm">Texture Wrap Mode.</param> /// <param name="heightWeights">float[4]-> Color Weights.</param> /// <param name="filterWeights">float[4]-> Filter Weights.</param> /// <returns></returns> public static FloatImage CreateNormalMap(FloatImage img, WrapMode wm, float[] heightWeights, float[] filterWeights, ParsePixelEventHandler pixelParseEvent) { Kernel2 kdu; Kernel2 kdv; kdu = new Kernel2(9); kdu.initBlendedSobel(filterWeights); kdu.normalize(); kdv = new Kernel2(kdu); kdv.transpose(); return CreateNormalMap(img, wm, heightWeights, kdu, kdv, pixelParseEvent); }
/// <summary> /// Create Normal Map Texture. /// </summary> /// <param name="img">Reference Bitmap.</param> /// <param name="wm">Texture Wrap Mode.</param> /// <param name="heightWeights">float[4]-> Color Weights.</param> /// <param name="kdu">Kernel U.</param> /// <param name="kdv">Kernel V.</param> /// <returns></returns> public static FloatImage CreateNormalMap(Bitmap img, WrapMode wm, float[] heightWeights, Kernel2 kdu, Kernel2 kdv, ParsePixelEventHandler pixelParseEvent) { FloatImage tmp = new FloatImage(); tmp.InitFrom(img); return CreateNormalMap(tmp, wm, heightWeights, kdu, kdv, pixelParseEvent); }