ShadowDragon Posted February 24, 2008 Share Posted February 24, 2008 Hey guys, I LOVE your program! I work at a school for video game programming and I recommend your tool to all the students when they are working on their games. I'm having difficulty finding information on how to do a pixelation filter (which you guys have working in your program under Effects->Distort->Pixelate). I'm working on my own game and would really LOVE to get that effect going in real time using a post process pixel shader. Can you tell me the algorithm you are using or point me to somewhere I can find that information? Thanks in advance! Quote Link to comment Share on other sites More sharing options...
david.atwell Posted February 24, 2008 Share Posted February 24, 2008 Moved to General Coding Quote The Doctor: There was a goblin, or a trickster, or a warrior... A nameless, terrible thing, soaked in the blood of a billion galaxies. The most feared being in all the cosmos. And nothing could stop it, or hold it, or reason with it. One day it would just drop out of the sky and tear down your world.Amy: But how did it end up in there?The Doctor: You know fairy tales. A good wizard tricked it.River Song: I hate good wizards in fairy tales; they always turn out to be him. Link to comment Share on other sites More sharing options...
I Like Pi Posted February 24, 2008 Share Posted February 24, 2008 src\Effects\PixelateEffect.cs ///////////////////////////////////////////////////////////////////////////////// // Paint.NET // // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. // // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. // // See src/Resources/Files/License.txt for full licensing and attribution // // details. // // . // ///////////////////////////////////////////////////////////////////////////////// using PaintDotNet.IndirectUI; using PaintDotNet.PropertySystem; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; namespace PaintDotNet.Effects { [EffectTypeHint(EffectTypeHint.Fast)] public sealed class PixelateEffect : PropertyBasedEffect { public static string StaticName { get { return PdnResources.GetString("PixelateEffect.Name"); } } public PixelateEffect() : base(StaticName, PdnResources.GetImageResource("Icons.PixelateEffect.png").Reference, SubmenuNames.Distort, EffectFlags.Configurable) { } public enum PropertyNames { CellSize } protected override PropertyCollection OnCreatePropertyCollection() { List props = new List(); props.Add(new Int32Property(PropertyNames.CellSize, 2, 1, 100)); return new PropertyCollection(props); } protected override ControlInfo OnCreateConfigUI(PropertyCollection props) { ControlInfo configUI = CreateDefaultConfigUI(props); configUI.SetPropertyControlValue(PropertyNames.CellSize, ControlInfoPropertyNames.DisplayName, PdnResources.GetString("PixelateEffect.ConfigDialog.SliderLabel")); // TODO: units label? //aecg.SliderUnitsName = PdnResources.GetString("PixelateEffect.ConfigDialog.SliderUnitsName"); return configUI; } private ColorBgra ComputeCellColor(int x, int y, RenderArgs src, int cellSize) { Rectangle cell = GetCellBox(x, y, cellSize); cell.Intersect(src.Bounds); int left = cell.Left; int right = cell.Right - 1; int bottom = cell.Bottom - 1; int top = cell.Top; ColorBgra colorTopLeft = src.Surface[left, top]; ColorBgra colorTopRight = src.Surface[right, top]; ColorBgra colorBottomLeft = src.Surface[left, bottom]; ColorBgra colorBottomRight = src.Surface[right, bottom]; ColorBgra c = ColorBgra.BlendColors4W16IP(colorTopLeft, 16384, colorTopRight, 16384, colorBottomLeft, 16384, colorBottomRight, 16384); return c; } private Rectangle GetCellBox(int x, int y, int cellSize) { int widthBoxNum = x % cellSize; int heightBoxNum = y % cellSize; Point leftUpper = new Point(x - widthBoxNum, y - heightBoxNum); Rectangle returnMe = new Rectangle(leftUpper, new Size(cellSize, cellSize)); return returnMe; } private int cellSize; protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs) { this.cellSize = newToken.GetProperty(PropertyNames.CellSize).Value; base.OnSetRenderInfo(newToken, dstArgs, srcArgs); } protected unsafe override void OnRender(Rectangle[] rois, int startIndex, int length) { for (int i = startIndex; i < startIndex + length; ++i) { Rectangle rect = rois[i]; for (int y = rect.Top; y < rect.Bottom; ++y) { int yEnd = y + 1; for (int x = rect.Left; x < rect.Right; ++x) { Rectangle cellRect = GetCellBox(x, y, this.cellSize); cellRect.Intersect(DstArgs.Bounds); ColorBgra color = ComputeCellColor(x, y, SrcArgs, this.cellSize); int xEnd = Math.Min(rect.Right, cellRect.Right); yEnd = Math.Min(rect.Bottom, cellRect.Bottom); for (int y2 = y; y2 < yEnd; ++y2) { ColorBgra *ptr = DstArgs.Surface.GetPointAddressUnchecked(x, y2); for (int x2 = x; x2 < xEnd; ++x2) { ptr->Bgra = color.Bgra; ++ptr; } } x = xEnd - 1; } y = yEnd - 1; } } } } } Quote Link to comment Share on other sites More sharing options...
ShadowDragon Posted February 26, 2008 Author Share Posted February 26, 2008 Thank you but I have the source code. What I'm not understanding is the technique behind the instructions. The reason certain things are being done and why. Can you run me through the algorithm in pseudo code or point me to the resource you learned the technique from? Quote Link to comment Share on other sites More sharing options...
Simon Brown Posted February 29, 2008 Share Posted February 29, 2008 The easiest way is probably to create a new resized Bitmap object and draw rectangles on a new Bitmap object for each pixel (If you just lower the resolution and increase it it will blur it). Edit: Not from the pdn code - but try editing this for your purposes: int factor = 10; Bitmap bpic = new Bitmap(Properties.Resources.sbavi08, Properties.Resources.sbavi08.Width/factor,Properties.Resources.sbavi08.Height/factor); Bitmap b = new Bitmap(Properties.Resources.sbavi08.Width, Properties.Resources.sbavi08.Height); Graphics g = Graphics.FromImage(; for (int county = 0; county < bpic.Height; county++) { for (int countx = 0; countx < bpic.Width; countx++) { g.FillRectangle(new SolidBrush(bpic.GetPixel(countx, county)), countx*factor, county*factor, factor, factor); } } pictureBox1.Image = b; Quote Link to comment Share on other sites More sharing options...
aphillips Posted March 1, 2008 Share Posted March 1, 2008 I must be missing something but isn't this almost trivial. Each pixelation cell has a number of pixels in it, eg 2x2. For each cell find the average of the colours of the pixels in it and set the colour of all the pixels to this colour. Quote Link to comment Share on other sites More sharing options...
pyrochild Posted March 1, 2008 Share Posted March 1, 2008 Each pixelation cell has a number of pixels in it, eg 2x2. For each cell find the average of the colours of the pixels in it and set the colour of all the pixels to this colour. That's the way GIMP does it, yes. But Paint.NET only takes the average of the four corner pixels of the cell. Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
Simon Brown Posted March 1, 2008 Share Posted March 1, 2008 Each pixelation cell has a number of pixels in it, eg 2x2. For each cell find the average of the colours of the pixels in it and set the colour of all the pixels to this colour. That's the way GIMP does it, yes. But Paint.NET only takes the average of the four corner pixels of the cell. The advantage of the code I published it that its faster because it uses lower-level functions which do the job much more quickly. Quote Link to comment Share on other sites More sharing options...
pyrochild Posted March 1, 2008 Share Posted March 1, 2008 Yeeeahhh.... no. If you're doing it all at once (single-threaded render, not using Paint.NET's plugin architecture) yours will be about the same render time as Paint.NET's. If you're sticking that in a Paint.NET effect, well, lord have mercy. And really, does your post really have anything to do with what you quoted? Nope... Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
Simon Brown Posted March 1, 2008 Share Posted March 1, 2008 Yeeeahhh.... no.If you're doing it all at once (single-threaded render, not using Paint.NET's plugin architecture) yours will be about the same render time as Paint.NET's. If you're sticking that in a Paint.NET effect, well, lord have mercy. And really, does your post really have anything to do with what you quoted? Nope... At the risk of looking stupid again, if you use the inbuilt .NET functions then it probably averages the whole box - leaving better quality. IMHO it also makes the code cleaner. Quote Link to comment Share on other sites More sharing options...
pyrochild Posted March 1, 2008 Share Posted March 1, 2008 Say you have a 10x10 cell. Getting the values of 4 pixels from that -- unless you are some insanely brilliant God-Of-Optimization (and the people behind the .NET Framework are smart, but not that smart) -- will always be faster than getting the values of 100. Not only is there the drag of memory access in a non-linear order (unless your image is exactly 10 pixels wide and you're using pointers), but you need to allocate more of your own memory space to accommodate the larger sample size, which will also slow you down. Not a lot, but it's still there. And as for being "better quality," well it's a bloody Pixelation filter. Using a different algorithm might result in different-looking results, but better results? You're making a bunch of big single-colored squares, for cryin' out loud! Someone would have to be all kinds of stupid to make a Pixelizer that looked "bad." Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
Simon Brown Posted March 1, 2008 Share Posted March 1, 2008 There should be a quality setting - but I guess you are right in this case as its a game. Quote Link to comment Share on other sites More sharing options...
harold Posted March 7, 2008 Share Posted March 7, 2008 how about drawing to a somewhat smaller render target first and then drawing (screen-aligned quad) that with pointsampling? that's a pixelation algorithm for free (well, free.. you would have to draw to a render target first..) simple, easy, no coding involved If you'd do it as fullscreen effect it would also require a render target - you have to sample neighboring pixels after all. It would also be harder since for each pixel you first have to find out what block they are in anyway (simply taking the average of 3 texels '1 pixel away' and the current one will only blur) edit: we are talking about hardware shaders here right? (not C# code) Quote I would write plugins, if I knew what kind of plugins were needed.. Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.