/// <summary> /// <para>Set the filter format of the blur filter.</para> /// <para>Note: Some filter formats require the graphics device support texture filtering for the given format</para> /// </summary> /// <param name="filterFormat"></param> /// <param name="bellCurveExponent"> /// <para>A scale value to infulence the bell curve used to generate the filter kernel.</para> /// <para>A value of 1.0 generates a standard blur filter kernels. Larger values will produce a tighter curve, and less blur.</para> /// <para>Smaller values will produce a wider curve, and a larger blur - but may produce a visible edge as the curve more rapidly ends.</para> /// </param> public void SetFilterFormat(BlurFilterFormat filterFormat, float bellCurveExponent) { //IsFilterFormat bool filteringSupported = DrawTargetTexture2D.SupportsFormatFiltering(source.SurfaceFormat); if (filteringSupported == false && filterFormat == BlurFilterFormat.ThirtyOneSampleBlur_FilteredTextureFormat) { throw new ArgumentException("BlurFilterFormat.ThirtyOneSampleBlurFiltered is not supported, Hardware does not support texture filter for " + source.SurfaceFormat.ToString()); } FilterGenerator.SetFilter(filterFormat, true, this.filterH, filteringSupported, bellCurveExponent); FilterGenerator.SetFilter(filterFormat, false, this.filterV, filteringSupported, bellCurveExponent); }
public static void SetFilter(BlurFilterFormat format, bool xAxis, SinglePassTextureFilter target, bool supportsFiltering, float bellExponent) { lock (weights) { int kernel = GenerateFilter(format, supportsFiltering, bellExponent); Vector2 axis = new Vector2(xAxis ? 1 : 0, xAxis ? 0 : 1); for (int i = 0; i < 16; i++) { offsetsV[i] = axis * offset[i]; } target.SetFilter(offsetsV, weights, kernel); } }
/// <summary> /// Blur the source horizontally to the <paramref name="intermediate"/> target, then blur vertically to <paramref name="target"/>. /// </summary> /// <param name="source"></param> /// <param name="filterFormat">format of the blur filter</param> /// <param name="intermediate">draw target to use as a temporary, intermediate target for blurring</param> /// <param name="target"></param> /// <param name="bellCurveExponent"> /// <para>A scale value to infulence the bell curve used to generate the filter kernel.</para> /// <para>A value of 1.0 generates a standard blur filter kernels. Larger values will produce a tighter curve, and less blur.</para> /// <para>Smaller values will produce a wider curve, and a larger blur - but may produce a visible edge as the curve more rapidly ends.</para> /// </param> public BlurFilter(BlurFilterFormat filterFormat, float bellCurveExponent, DrawTargetTexture2D source, DrawTargetTexture2D intermediate, DrawTargetTexture2D target) { if (target == null || source == null) { throw new ArgumentNullException(); } if (intermediate != null && source.SurfaceFormat != intermediate.SurfaceFormat) { throw new ArgumentException("source.SurfaceFormat != intermediate.SurfaceFormat"); } if (intermediate != null && target.SurfaceFormat != intermediate.SurfaceFormat) { throw new ArgumentException("target.SurfaceFormat != intermediate.SurfaceFormat"); } this.source = source; #if XBOX360 //if the surface will fit into EDRAM then the intermediate can be skipped if (source.Width * source.Height * DrawTarget.FormatSize(source.SurfaceFormat) < 1000 * 1000 * 10) //approx { this.filterV = new SinglePassTextureFilter(source, target); this.filterH = new SinglePassTextureFilter(target, target); } else { this.filterV = new SinglePassTextureFilter(source, intermediate); this.filterH = new SinglePassTextureFilter(intermediate, source); } #else this.filterV = new SinglePassTextureFilter(source, intermediate); this.filterH = new SinglePassTextureFilter(intermediate, target); #endif SetFilterFormat(filterFormat, bellCurveExponent); }
/// <summary> /// Blur the source horizontally to the <paramref name="intermediate"/> target, then blur vertically back to <paramref name="source"/>. (Xbox360 may specify null for <paramref name="intermediate"/> if the render target will fit in 10mib) /// </summary> /// <param name="source"></param> /// <param name="filterFormat">format of the blur filter</param> /// <param name="intermediate">draw target to use as a temporary, intermediate target for blurring</param> /// <param name="bellCurveExponent"> /// <para>A scale value to infulence the bell curve used to generate the filter kernel.</para> /// <para>A value of 1.0 generates a standard blur filter kernels. Larger values will produce a tighter curve, and less blur.</para> /// <para>Smaller values will produce a wider curve, and a larger blur - but may produce a visible edge as the curve more rapidly ends.</para> /// </param> public BlurFilter(BlurFilterFormat filterFormat, float bellCurveExponent, DrawTargetTexture2D source, DrawTargetTexture2D intermediate) : this(filterFormat, bellCurveExponent, source, intermediate, source) { }
//generates weight and offset value for bell curve filters private static int GenerateFilter(BlurFilterFormat format, bool filtered, float bellExponent) { int samples = 0; switch (format) { case BlurFilterFormat.ThreeSampleBlur: samples = 3; break; case BlurFilterFormat.FiveSampleBlur: samples = 5; break; case BlurFilterFormat.SevenSampleBlur: samples = 7; break; case BlurFilterFormat.FifteenSampleBlur: samples = 15; break; case BlurFilterFormat.ThirtyOneSampleBlur_FilteredTextureFormat: if (!filtered) { throw new ArgumentException(); } samples = 31; break; } int actualSamples = samples; if (filtered) { actualSamples = samples / 2 + 1; } if (!filtered) { //centre sample samples the 0 offset pixel int centre = actualSamples / 2; weights[centre] = 1; offset[centre] = 0; double total = 1; for (int i = 1; i <= centre; i++) { //bell curve //~ exp(- x^2 ) double x = (i / (double)(centre + 1)); double bell = Math.Exp(-(x * x) * 3 * bellExponent); total += bell * 2; offset[centre - i] = -i; offset[centre + i] = i; weights[centre - i] = (float)bell; weights[centre + i] = (float)bell; } float inv = 1.0f / (float)total; for (int i = 0; i < actualSamples; i++) { weights[i] *= inv; } } else { bool isOdd = (actualSamples & 1) == 1; //if it's odd, there is a centre sample int count = actualSamples / 2; double total = 0; if (isOdd) { weights[count] = 2; offset[count] = 0; total = 2; } for (int i = 0; i < count; i++) { //bell curve //~ exp(- x^2 ) //each is made up of two combined samples (filter) double x1, x2; if (isOdd) { x1 = ((i * 2 + 1) / (double)(actualSamples)); x2 = ((i * 2 + 2) / (double)(actualSamples)); } else { x1 = ((i * 2) / (double)(actualSamples)); x2 = ((i * 2 + 1) / (double)(actualSamples)); } double bell1 = Math.Exp(-(x1 * x1) * 3 * bellExponent); double bell2 = Math.Exp(-(x2 * x2) * 3 * bellExponent); if (!isOdd && i == 0) { bell1 *= 0.5; //two samples on the centre } double bias; if (isOdd) { bias = ((i * 2 + 1) * bell1 + (i * 2 + 2) * bell2) / (bell1 + bell2); } else { bias = (i * 2 * bell1 + (i * 2 + 1) * bell2) / (bell1 + bell2); } double weight = bell1 + bell2; total += weight * 2; int p = isOdd ? 1 : 0; offset[count - i - 1] = -(float)bias; offset[count + i + p] = (float)bias; weights[count - i - 1] = (float)weight; weights[count + i + p] = (float)weight; } float inv = 1.0f / (float)total; for (int i = 0; i < actualSamples; i++) { weights[i] *= inv; } } return(actualSamples); }
//generates weight and offset value for bell curve filters private static int GenerateFilter(BlurFilterFormat format, bool filtered, float bellExponent) { int samples = 0; switch (format) { case BlurFilterFormat.ThreeSampleBlur: samples = 3; break; case BlurFilterFormat.FiveSampleBlur: samples = 5; break; case BlurFilterFormat.SevenSampleBlur: samples = 7; break; case BlurFilterFormat.FifteenSampleBlur: samples = 15; break; case BlurFilterFormat.ThirtyOneSampleBlur_FilteredTextureFormat: if (!filtered) throw new ArgumentException(); samples = 31; break; } int actualSamples = samples; if (filtered) actualSamples = samples / 2 + 1; if (!filtered) { //centre sample samples the 0 offset pixel int centre = actualSamples / 2; weights[centre] = 1; offset[centre] = 0; double total = 1; for (int i = 1; i <= centre; i++) { //bell curve //~ exp(- x^2 ) double x = (i / (double)(centre + 1)); double bell = Math.Exp(-(x * x) * 3 * bellExponent); total += bell * 2; offset[centre - i] = -i; offset[centre + i] = i; weights[centre - i] = (float)bell; weights[centre + i] = (float)bell; } float inv = 1.0f / (float)total; for (int i = 0; i < actualSamples; i++) weights[i] *= inv; } else { bool isOdd = (actualSamples & 1) == 1; //if it's odd, there is a centre sample int count = actualSamples/2; double total = 0; if (isOdd) { weights[count] = 2; offset[count] = 0; total = 2; } for (int i = 0; i < count; i++) { //bell curve //~ exp(- x^2 ) //each is made up of two combined samples (filter) double x1,x2; if (isOdd) { x1 = ((i * 2 + 1) / (double)(actualSamples)); x2 = ((i * 2 + 2) / (double)(actualSamples)); } else { x1 = ((i * 2) / (double)(actualSamples)); x2 = ((i * 2 + 1) / (double)(actualSamples)); } double bell1 = Math.Exp(-(x1 * x1) * 3 * bellExponent); double bell2 = Math.Exp(-(x2 * x2) * 3 * bellExponent); if (!isOdd && i == 0) bell1 *= 0.5; //two samples on the centre double bias; if (isOdd) bias = ((i*2 + 1) * bell1 + (i*2 + 2) * bell2) / (bell1 + bell2); else bias = (i*2 * bell1 + (i*2 + 1) * bell2) / (bell1 + bell2); double weight = bell1 + bell2; total += weight * 2; int p = isOdd ? 1 : 0; offset[count - i - 1] = -(float)bias; offset[count + i + p] = (float)bias; weights[count - i - 1] = (float)weight; weights[count + i + p] = (float)weight; } float inv = 1.0f / (float)total; for (int i = 0; i < actualSamples; i++) weights[i] *= inv; } return actualSamples; }
/// <summary> /// <para>Set the filter format of the blur filter.</para> /// <para>Note: Some filter formats require the graphics device support texture filtering for the given format</para> /// </summary> /// <param name="filterFormat"></param> /// <param name="bellCurveExponent"> /// <para>A scale value to infulence the bell curve used to generate the filter kernel.</para> /// <para>A value of 1.0 generates a standard blur filter kernels. Larger values will produce a tighter curve, and less blur.</para> /// <para>Smaller values will produce a wider curve, and a larger blur - but may produce a visible edge as the curve more rapidly ends.</para> /// </param> public void SetFilterFormat(BlurFilterFormat filterFormat, float bellCurveExponent) { //IsFilterFormat bool filteringSupported = DrawTargetTexture2D.SupportsFormatFiltering(source.SurfaceFormat); if (filteringSupported == false && filterFormat == BlurFilterFormat.ThirtyOneSampleBlur_FilteredTextureFormat) throw new ArgumentException("BlurFilterFormat.ThirtyOneSampleBlurFiltered is not supported, Hardware does not support texture filter for " + source.SurfaceFormat.ToString()); FilterGenerator.SetFilter(filterFormat, true, this.filterH, filteringSupported, bellCurveExponent); FilterGenerator.SetFilter(filterFormat, false, this.filterV, filteringSupported, bellCurveExponent); }
/// <summary> /// Blur the source horizontally to the <paramref name="intermediate"/> target, then blur vertically to <paramref name="target"/>. /// </summary> /// <param name="source"></param> /// <param name="filterFormat">format of the blur filter</param> /// <param name="intermediate">draw target to use as a temporary, intermediate target for blurring</param> /// <param name="target"></param> /// <param name="bellCurveExponent"> /// <para>A scale value to infulence the bell curve used to generate the filter kernel.</para> /// <para>A value of 1.0 generates a standard blur filter kernels. Larger values will produce a tighter curve, and less blur.</para> /// <para>Smaller values will produce a wider curve, and a larger blur - but may produce a visible edge as the curve more rapidly ends.</para> /// </param> public BlurFilter(BlurFilterFormat filterFormat, float bellCurveExponent, DrawTargetTexture2D source, DrawTargetTexture2D intermediate, DrawTargetTexture2D target) { if (target == null || source == null) throw new ArgumentNullException(); if (intermediate != null && source.SurfaceFormat != intermediate.SurfaceFormat) throw new ArgumentException("source.SurfaceFormat != intermediate.SurfaceFormat"); if (intermediate != null && target.SurfaceFormat != intermediate.SurfaceFormat) throw new ArgumentException("target.SurfaceFormat != intermediate.SurfaceFormat"); this.source = source; this.filterV = new SinglePassTextureFilter(source, intermediate); this.filterH = new SinglePassTextureFilter(intermediate, target); SetFilterFormat(filterFormat, bellCurveExponent); }
/// <summary> /// Blur the source horizontally to the <paramref name="intermediate"/> target, then blur vertically back to <paramref name="source"/>. /// </summary> /// <param name="source"></param> /// <param name="filterFormat">format of the blur filter</param> /// <param name="intermediate">draw target to use as a temporary, intermediate target for blurring</param> /// <param name="bellCurveExponent"> /// <para>A scale value to infulence the bell curve used to generate the filter kernel.</para> /// <para>A value of 1.0 generates a standard blur filter kernels. Larger values will produce a tighter curve, and less blur.</para> /// <para>Smaller values will produce a wider curve, and a larger blur - but may produce a visible edge as the curve more rapidly ends.</para> /// </param> public BlurFilter(BlurFilterFormat filterFormat, float bellCurveExponent, DrawTargetTexture2D source, DrawTargetTexture2D intermediate) : this(filterFormat, bellCurveExponent, source, intermediate, source) { }
public static void SetFilter(BlurFilterFormat format, bool xAxis, SinglePassTextureFilter target, bool supportsFiltering, float bellExponent) { lock (weights) { int kernel = GenerateFilter(format, supportsFiltering, bellExponent); Vector2 axis = new Vector2(xAxis ? 1 : 0, xAxis ? 0 : 1); for (int i = 0; i < 16; i++) offsetsV[i] = axis * offset[i]; target.SetFilter(offsetsV, weights, kernel); } }