Guest User

fs

a guest
Jul 28th, 2015
221
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // BloomComponent.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9.  
  10. #region Using Statements
  11. using System;
  12. using Microsoft.Xna.Framework;
  13. using Microsoft.Xna.Framework.Content;
  14. using Microsoft.Xna.Framework.Graphics;
  15. using System.IO;
  16. #endregion
  17.  
  18. namespace BloomPostprocess
  19. {
  20. public class BloomComponent : DrawableGameComponent
  21. {
  22. #region Fields
  23.  
  24. SpriteBatch spriteBatch;
  25.  
  26. Effect bloomExtractEffect;
  27. Effect bloomCombineEffect;
  28. Effect gaussianBlurEffect;
  29.  
  30. RenderTarget2D renderTarget1;
  31. RenderTarget2D renderTarget2;
  32.  
  33.  
  34. // Choose what display settings the bloom should use.
  35. public BloomSettings Settings
  36. {
  37. get { return settings; }
  38. set { settings = value; }
  39. }
  40.  
  41. BloomSettings settings = BloomSettings.PresetSettings[0];
  42.  
  43.  
  44. // Optionally displays one of the intermediate buffers used
  45. // by the bloom postprocess, so you can see exactly what is
  46. // being drawn into each rendertarget.
  47. public enum IntermediateBuffer
  48. {
  49. PreBloom,
  50. BlurredHorizontally,
  51. BlurredBothWays,
  52. FinalResult,
  53. }
  54.  
  55. public IntermediateBuffer ShowBuffer
  56. {
  57. get { return showBuffer; }
  58. set { showBuffer = value; }
  59. }
  60.  
  61. IntermediateBuffer showBuffer = IntermediateBuffer.FinalResult;
  62.  
  63.  
  64. #endregion
  65.  
  66. #region Initialization
  67.  
  68.  
  69. public BloomComponent(Game game)
  70. : base(game)
  71. {
  72. if (game == null)
  73. throw new ArgumentNullException("game");
  74. }
  75.  
  76.  
  77. /// <summary>
  78. /// Load your graphics content.
  79. /// </summary>
  80. public void LoadContent(GraphicsDevice g, ContentManager theContentManager)
  81. {
  82. spriteBatch = new SpriteBatch(g);
  83. bloomExtractEffect = theContentManager.Load<Effect>("BloomExtract");
  84. bloomCombineEffect = theContentManager.Load<Effect>("BloomCombine");
  85. gaussianBlurEffect = theContentManager.Load<Effect>("GaussianBlur");
  86.  
  87. // Look up the resolution and format of our main backbuffer.
  88. PresentationParameters pp = g.PresentationParameters;
  89.  
  90. int width = pp.BackBufferWidth;
  91. int height = pp.BackBufferHeight;
  92.  
  93. SurfaceFormat format = pp.BackBufferFormat;
  94.  
  95. // Create a texture for rendering the main scene, prior to applying bloom.
  96.  
  97.  
  98. // Create two rendertargets for the bloom processing. These are half the
  99. // size of the backbuffer, in order to minimize fillrate costs. Reducing
  100. // the resolution in this way doesn't hurt quality, because we are going
  101. // to be blurring the bloom images in any case.
  102. width /= 2;
  103. height /= 2;
  104.  
  105. renderTarget1 = new RenderTarget2D(g, width, height, false, format, DepthFormat.None);
  106. renderTarget2 = new RenderTarget2D(g, width, height, false, format, DepthFormat.None);
  107. }
  108.  
  109.  
  110. /// <summary>
  111. /// Unload your graphics content.
  112. /// </summary>
  113. public void UnloadContent(ContentManager theContentManager)
  114. {
  115. renderTarget1.Dispose();
  116. renderTarget2.Dispose();
  117. }
  118.  
  119.  
  120. #endregion
  121.  
  122. #region Draw
  123.  
  124.  
  125. /// <summary>
  126. /// This should be called at the very start of the scene rendering. The bloom
  127. /// component uses it to redirect drawing into its custom rendertarget, so it
  128. /// can capture the scene image in preparation for applying the bloom filter.
  129. /// </summary>
  130. public void BeginDraw(RenderTarget2D renderTarget)
  131. {
  132. if (Visible)
  133. {
  134. GraphicsDevice.SetRenderTarget(renderTarget);
  135. }
  136. }
  137.  
  138.  
  139. /// <summary>
  140. /// This is where it all happens. Grabs a scene that has already been rendered,
  141. /// and uses postprocess magic to add a glowing bloom effect over the top of it.
  142. /// </summary>
  143. public void Draw(GameTime gameTime, RenderTarget2D renderTarget)
  144. {
  145.  
  146. // Pass 1: draw the scene into rendertarget 1, using a
  147. // shader that extracts only the brightest parts of the image.
  148. bloomExtractEffect.Parameters["BloomThreshold"].SetValue(
  149. Settings.BloomThreshold);
  150.  
  151. DrawFullscreenQuad(renderTarget, renderTarget1,
  152. bloomExtractEffect,
  153. IntermediateBuffer.PreBloom);
  154.  
  155. // Pass 2: draw from rendertarget 1 into rendertarget 2,
  156. // using a shader to apply a horizontal gaussian blur filter.
  157. SetBlurEffectParameters(1.0f / (float)renderTarget1.Width, 0);
  158.  
  159. DrawFullscreenQuad(renderTarget1, renderTarget2,
  160. gaussianBlurEffect,
  161. IntermediateBuffer.BlurredHorizontally);
  162.  
  163. // Pass 3: draw from rendertarget 2 back into rendertarget 1,
  164. // using a shader to apply a vertical gaussian blur filter.
  165. SetBlurEffectParameters(0, 1.0f / (float)renderTarget1.Height);
  166.  
  167. DrawFullscreenQuad(renderTarget2, renderTarget1,
  168. gaussianBlurEffect,
  169. IntermediateBuffer.BlurredBothWays);
  170.  
  171. // Pass 4: draw both rendertarget 1 and the original scene
  172. // image back into the main backbuffer, using a shader that
  173. // combines them to produce the final bloomed result.
  174. GraphicsDevice.SetRenderTarget(null);
  175.  
  176. EffectParameterCollection parameters = bloomCombineEffect.Parameters;
  177.  
  178. parameters["BloomIntensity"].SetValue(Settings.BloomIntensity);
  179. parameters["BaseIntensity"].SetValue(Settings.BaseIntensity);
  180. parameters["BloomSaturation"].SetValue(Settings.BloomSaturation);
  181. parameters["BaseSaturation"].SetValue(Settings.BaseSaturation);
  182.  
  183. GraphicsDevice.Textures[1] = renderTarget;
  184.  
  185. Viewport viewport = GraphicsDevice.Viewport;
  186.  
  187. DrawFullscreenQuad(renderTarget1,
  188. viewport.Width, viewport.Height,
  189. bloomCombineEffect,
  190. IntermediateBuffer.FinalResult);
  191.  
  192. }
  193.  
  194.  
  195. /// <summary>
  196. /// Helper for drawing a texture into a rendertarget, using
  197. /// a custom shader to apply postprocessing effects.
  198. /// </summary>
  199. void DrawFullscreenQuad(Texture2D texture, RenderTarget2D renderTarget,
  200. Effect effect, IntermediateBuffer currentBuffer)
  201. {
  202. GraphicsDevice.SetRenderTarget(renderTarget);
  203.  
  204. DrawFullscreenQuad(texture,
  205. renderTarget.Width, renderTarget.Height,
  206. effect, currentBuffer);
  207. }
  208.  
  209.  
  210. /// <summary>
  211. /// Helper for drawing a texture into the current rendertarget,
  212. /// using a custom shader to apply postprocessing effects.
  213. /// </summary>
  214. void DrawFullscreenQuad(Texture2D texture, int width, int height,
  215. Effect effect, IntermediateBuffer currentBuffer)
  216. {
  217. // If the user has selected one of the show intermediate buffer options,
  218. // we still draw the quad to make sure the image will end up on the screen,
  219. // but might need to skip applying the custom pixel shader.
  220. if (showBuffer < currentBuffer)
  221. {
  222. effect = null;
  223. }
  224.  
  225. spriteBatch.Begin(0, BlendState.Opaque, null, null, null, effect);
  226. spriteBatch.Draw(texture, new Rectangle(0, 0, width, height), Color.White);
  227. spriteBatch.End();
  228. }
  229.  
  230.  
  231. /// <summary>
  232. /// Computes sample weightings and texture coordinate offsets
  233. /// for one pass of a separable gaussian blur filter.
  234. /// </summary>
  235. void SetBlurEffectParameters(float dx, float dy)
  236. {
  237. // Look up the sample weight and offset effect parameters.
  238. EffectParameter weightsParameter, offsetsParameter;
  239.  
  240. weightsParameter = gaussianBlurEffect.Parameters["SampleWeights"];
  241. offsetsParameter = gaussianBlurEffect.Parameters["SampleOffsets"];
  242.  
  243. // Look up how many samples our gaussian blur effect supports.
  244. int sampleCount = weightsParameter.Elements.Count;
  245.  
  246. // Create temporary arrays for computing our filter settings.
  247. float[] sampleWeights = new float[sampleCount];
  248. Vector2[] sampleOffsets = new Vector2[sampleCount];
  249.  
  250. // The first sample always has a zero offset.
  251. sampleWeights[0] = ComputeGaussian(0);
  252. sampleOffsets[0] = new Vector2(0);
  253.  
  254. // Maintain a sum of all the weighting values.
  255. float totalWeights = sampleWeights[0];
  256.  
  257. // Add pairs of additional sample taps, positioned
  258. // along a line in both directions from the center.
  259. for (int i = 0; i < sampleCount / 2; i++)
  260. {
  261. // Store weights for the positive and negative taps.
  262. float weight = ComputeGaussian(i + 1);
  263.  
  264. sampleWeights[i * 2 + 1] = weight;
  265. sampleWeights[i * 2 + 2] = weight;
  266.  
  267. totalWeights += weight * 2;
  268.  
  269. // To get the maximum amount of blurring from a limited number of
  270. // pixel shader samples, we take advantage of the bilinear filtering
  271. // hardware inside the texture fetch unit. If we position our texture
  272. // coordinates exactly halfway between two texels, the filtering unit
  273. // will average them for us, giving two samples for the price of one.
  274. // This allows us to step in units of two texels per sample, rather
  275. // than just one at a time. The 1.5 offset kicks things off by
  276. // positioning us nicely in between two texels.
  277. float sampleOffset = i * 2 + 1.5f;
  278.  
  279. Vector2 delta = new Vector2(dx, dy) * sampleOffset;
  280.  
  281. // Store texture coordinate offsets for the positive and negative taps.
  282. sampleOffsets[i * 2 + 1] = delta;
  283. sampleOffsets[i * 2 + 2] = -delta;
  284. }
  285.  
  286. // Normalize the list of sample weightings, so they will always sum to one.
  287. for (int i = 0; i < sampleWeights.Length; i++)
  288. {
  289. sampleWeights[i] /= totalWeights;
  290. }
  291.  
  292. // Tell the effect about our new filter settings.
  293. weightsParameter.SetValue(sampleWeights);
  294. offsetsParameter.SetValue(sampleOffsets);
  295. }
  296.  
  297.  
  298. /// <summary>
  299. /// Evaluates a single point on the gaussian falloff curve.
  300. /// Used for setting up the blur filter weightings.
  301. /// </summary>
  302. float ComputeGaussian(float n)
  303. {
  304. float theta = Settings.BlurAmount;
  305.  
  306. return (float)((1.0 / Math.Sqrt(2 * Math.PI * theta)) *
  307. Math.Exp(-(n * n) / (2 * theta * theta)));
  308. }
  309.  
  310.  
  311. #endregion
  312. }
  313. }
RAW Paste Data