void InitializeBloomFilter() { BloomEnabled = true; // A bloom filter makes graphics appear to be bright and glowing by adding blur around only // the brightest parts of the image. This approximates the look of HDR (high dynamic range) // rendering, in which the color of the brightest light sources spills over onto surrounding // pixels. // // Many different visual styles can be achieved by adjusting these settings: // // Intensity = how much bloom is added // 0 = none // // Threshold = how bright does a pixel have to be in order for it to bloom // 0 = the entire image blooms equally // // Blur = how much the glow spreads sideways around bright areas BloomIntensity = 200; BloomThreshold = 80; BloomBlur = 48; // Before drawing, properties of these effects will be adjusted to match the // current settings (see ApplyBloomFilter), and an input image connected to // extractBrightAreas.Source and bloomResult.Background (see DemandCreateBloomRenderTarget). // Step 1: use a transfer effect to extract only pixels brighter than the threshold. extractBrightAreas = new LinearTransferEffect { ClampOutput = true, }; // Step 2: blur these bright pixels. blurBrightAreas = new GaussianBlurEffect { Source = extractBrightAreas, }; // Step 3: adjust how much bloom is wanted. adjustBloomIntensity = new LinearTransferEffect { Source = blurBrightAreas, }; // Step 4: blend the bloom over the top of the original image. bloomResult = new BlendEffect { Foreground = adjustBloomIntensity, Mode = BlendEffectMode.Screen, }; }
public BloomRendering() { extractBrightAreas = new LinearTransferEffect { ClampOutput = true, }; blurBrightAreas = new GaussianBlurEffect { Source = extractBrightAreas, }; adjustBloomIntensity = new LinearTransferEffect { Source = blurBrightAreas, }; result = new BlendEffect { Foreground = adjustBloomIntensity, Mode = BlendEffectMode.Screen, }; }
private ICanvasImage CreateLuminanceToAlpha() { var contrastAdjustedTiger = new LinearTransferEffect { Source = bitmapTiger, RedOffset = -3, GreenOffset = -3, BlueOffset = -3, }; var tigerAlpha = new LuminanceToAlphaEffect { Source = contrastAdjustedTiger }; var tigerAlphaWithWhiteRgb = new LinearTransferEffect { Source = tigerAlpha, RedOffset = 1, GreenOffset = 1, BlueOffset = 1, RedSlope = 0, GreenSlope = 0, BlueSlope = 0, }; var recombinedRgbAndAlpha = new ArithmeticCompositeEffect { Source1 = tigerAlphaWithWhiteRgb, Source2 = bitmapTiger, }; var movedTiger = new Transform2DEffect { Source = recombinedRgbAndAlpha }; const float turbulenceSize = 128; var backgroundImage = new CropEffect { Source = new TileEffect { Source = new TurbulenceEffect { Octaves = 8, Size = new Vector2(turbulenceSize), Tileable = true }, SourceRectangle= new Rect(0, 0, turbulenceSize, turbulenceSize) }, SourceRectangle = new Rect((bitmapTiger.Size.ToVector2() * -0.5f).ToPoint(), (bitmapTiger.Size.ToVector2() * 1.5f).ToPoint()) }; var tigerOnBackground = new BlendEffect { Foreground = movedTiger, Background = backgroundImage }; // Animation moves the alpha bitmap around, and alters color transfer settings to change how solid it is. animationFunction = elapsedTime => { contrastAdjustedTiger.RedSlope = contrastAdjustedTiger.GreenSlope = contrastAdjustedTiger.BlueSlope = ((float)Math.Sin(elapsedTime * 0.9) + 2) * 3; var dx = (float)Math.Cos(elapsedTime) * 50; var dy = (float)Math.Sin(elapsedTime) * 50; movedTiger.TransformMatrix = Matrix3x2.CreateTranslation(dx, dy); }; return tigerOnBackground; }
void CreateEffects() { // The Game of Life is a cellular automaton with very simple rules. // Each cell (pixel) can be either alive (white) or dead (black). // The state is updated by: // // - for each cell, count how many of its 8 neighbors are alive // - if less than two, the cell dies from loneliness // - if exactly two, the cell keeps its current state // - if exactly three, the cell become alive // - if more than three, the cell dies from overcrowding // Step 1: use a convolve matrix to count how many neighbors are alive. This filter // also includes the state of the current cell, but with a lower weighting. The result // is an arithmetic encoding where (value / 2) indicates how many neighbors are alive, // and (value % 2) is the state of the cell itself. This is divided by 18 to make it // fit within 0-1 color range. countNeighborsEffect = new ConvolveMatrixEffect { KernelMatrix = new float[] { 2, 2, 2, 2, 1, 2, 2, 2, 2 }, Divisor = 18, BorderMode = EffectBorderMode.Hard, }; // Step 2: use a color transfer table to map the different states produced by the // convolve matrix to whether the cell should live or die. Each pair of entries in // this table corresponds to a certain number of live neighbors. The first of the // pair is the result if the current cell is dead, or the second if it is alive. float[] transferTable = { 0, 0, // 0 live neighbors -> dead cell 0, 0, // 1 live neighbors -> dead cell 0, 1, // 2 live neighbors -> cell keeps its current state 1, 1, // 3 live neighbors -> live cell 0, 0, // 4 live neighbors -> dead cell 0, 0, // 5 live neighbors -> dead cell 0, 0, // 6 live neighbors -> dead cell 0, 0, // 7 live neighbors -> dead cell 0, 0, // 8 live neighbors -> dead cell }; liveOrDieEffect = new DiscreteTransferEffect { Source = countNeighborsEffect, RedTable = transferTable, GreenTable = transferTable, BlueTable = transferTable, }; // Step 3: the algorithm is implemented in terms of white = live, // black = dead, but we invert these colors before displaying the // result, just 'cause I think it looks better that way. invertEffect = new LinearTransferEffect { RedSlope = -1, RedOffset = 1, GreenSlope = -1, GreenOffset = 1, BlueSlope = -1, BlueOffset = 1, }; // Step 4: insert our own DPI compensation effect to stop the system trying to // automatically convert DPI for us. The Game of Life simulation always works // in pixels (96 DPI) regardless of display DPI. Normally, the system would // handle this mismatch automatically and scale the image up as needed to fit // higher DPI displays. We don't want that behavior here, because it would use // a linear filter while we want nearest neighbor. So we insert a no-op DPI // converter of our own. This overrides the default adjustment by telling the // system the source image is already the same DPI as the destination canvas // (even though it really isn't). We'll handle any necessary scaling later // ourselves, using Transform2DEffect to control the interpolation mode. var dpiCompensationEffect = new DpiCompensationEffect { Source = invertEffect, SourceDpi = new Vector2(canvas.Dpi), }; // Step 5: a transform matrix scales up the simulation rendertarget and moves // it to the right part of the screen. This uses nearest neighbor filtering // to avoid unwanted blurring of the cell shapes. transformEffect = new Transform2DEffect { Source = dpiCompensationEffect, InterpolationMode = CanvasImageInterpolation.NearestNeighbor, }; }
private ICanvasImage CreateLuminanceToAlpha() { var contrastAdjustedTiger = new LinearTransferEffect { Source = bitmapTiger, RedOffset = -3, GreenOffset = -3, BlueOffset = -3, }; var tigerAlpha = new LuminanceToAlphaEffect { Source = contrastAdjustedTiger }; var tigerAlphaWithWhiteRgb = new LinearTransferEffect { Source = tigerAlpha, RedOffset = 1, GreenOffset = 1, BlueOffset = 1, RedSlope = 0, GreenSlope = 0, BlueSlope = 0, }; var recombinedRgbAndAlpha = new ArithmeticCompositeEffect { Source1 = tigerAlphaWithWhiteRgb, Source2 = bitmapTiger, }; var movedTiger = new Transform2DEffect { Source = recombinedRgbAndAlpha }; const float turbulenceSize = 128; var backgroundImage = new CropEffect { Source = new TileEffect { Source = new TurbulenceEffect { Octaves = 8, Size = new Vector2(turbulenceSize), Tileable = true }, SourceRectangle = new Rect(0, 0, turbulenceSize, turbulenceSize) }, SourceRectangle = new Rect((bitmapTiger.Size.ToVector2() * -0.5f).ToPoint(), (bitmapTiger.Size.ToVector2() * 1.5f).ToPoint()) }; var tigerOnBackground = new BlendEffect { Foreground = movedTiger, Background = backgroundImage }; // Animation moves the alpha bitmap around, and alters color transfer settings to change how solid it is. animationFunction = elapsedTime => { contrastAdjustedTiger.RedSlope = contrastAdjustedTiger.GreenSlope = contrastAdjustedTiger.BlueSlope = ((float)Math.Sin(elapsedTime * 0.9) + 2) * 3; var dx = (float)Math.Cos(elapsedTime) * 50; var dy = (float)Math.Sin(elapsedTime) * 50; movedTiger.TransformMatrix = Matrix3x2.CreateTranslation(dx, dy); }; return(tigerOnBackground); }