simple motion blur

Hi, I made a simple motion blur effect by instead of clearing the screen each frame, I just draw a black rectangle over the whole screen which has, say 10 alpha.
It seems to work perfectly, except when you look closer, the black rect never fully overwrites the other colours, no matter how many times it is drawn. Is there a way I can fix this?
Thanks,
roland

I have used exactly same principle but instead of black rectangle I use background image. There is still some artefacts if alpha is too low as seen my game when it slowed down alpha go also down. I was pretty happy for results.
http://www.students.tut.fi/~hamala26/shapetronic.html

You could also paint almoust black rect but hint of grey on it.

I haven’t done this myself. But first, I’d try fiddling with the opacity value, try making it just a bit higher and see if that works. The above idea of making it grey also makes a certain sense, is definitely a worthy experiment.

A more involved course of action would be to manage one or more buffered images of the entire screen in various stages, and rotate them. But that would lead to a LOT of redundant activity if most of the screen is stationary. So I don’t know. It probably makes more sense to manage multiple copies of the moving sprite, print them with varying degrees of alpha.

For example, maintain an array of the last 10 (or however many) locations, and print the sprite at each location with a different alpha. I’ve done something similar to make a smoke/flame effect. There’s an Applet example embedded near the bottom of a blog, the July 2010 entry–the “SmokeGenie” http://www.hexara.com/.

Each frame, you would bump the locations up through the array, but always draw at the first location with, say, 50% alpha, the second at 25%, the third at 13% etc or some gradually disappearing formula.

With my “SmokeGenie”, I’m using 50 stages, and have premade all 50 graphics (each with its own alpha), as I don’t know a quick way to print an image with varying alpha without going in and touching every pixel. But you wouldn’t need so many stages for a blur effect.

Hope that helps!

Tested with black or very dark grey rectangle. Black didn’t leave any trace byt greyish leaved very ugly and visible dirt marks. Test was with slick2d and Shapetronic.

Thanks for the replies, pitbuller and philfrei.
Heres my applet: www.chaosreef.com/asteroids.php
you can see the effect really clearly. I am using just plain java awt graphics instead of OpenGL, because a computer I am working on does not support hardware accelerated graphics. So there must be something different about how java renders transparent shapes. I tried clearing the screen grey, and that was worse than black, as pitbuller found out. Clearing the whole screen white is about the same as clearing it black. Also I would rather not draw a sequence of images that decrease in alpha, because it is likely to slow my program down a lot when I have many things on the screen. (maybe 10x as much drawing?)
I hope there is another way to fix this.
Does anyone have any more ideas?
Thanks

I didn’t notice any jittter. Everything was solid and working as intented. Maybe it’s problem with your computer spec?

Thanks for the reply.
I tested it on 3 computers: my laptop, and 2 desktops with large moniters.
One of the desktop moniters showed almost no “dirty” trails, but my laptop and the other moniter did.
It could be something to do with specs, but I would like there to be no dirty trails on any computer.

Can you look again? : try moving your head up/down, looking from different angles, angle the moniter into the dark or the light.
There’s a high chance you will see a small amount of dirty colours not being cleared.

I got a 404-error when I tried to look at your website! ???

If done right, Java can support thousands of object updates in a single game cycle. So you might reconsider. But sure, if the black with low alpha background works or a reasonable variant works, that is a very convenient solution! With variations in implementation between computers, though, it would be good to take more control of what is happening to the data.

Now I see it. I could bet there was nothing at morning.

This is a plain and simple mathematical problem…

Your colors are represented by 8 bit values (bytes) per channel (R,G,B).

If you have a very low value in your channel, and you blend it very lightly, absolutely nothing will happen as the result of the blend equals the value you started with.

Thanks for the replies :slight_smile:

strange… my website is woking for me and other people. maybe it was down(free webhosting is average, right?)
True. I am going to try out the way you described, and use that instead unless there is a good way to easily do it my way and make it actually work properly.

Ok, would you happen to know a way to solve this problem?

At first I didn’t know what you mean by dirty trails since the game worked fine for me and the trails seemed to disappear. Yet I moved my laptop screen down a bit, and I could seen very faintly every single trail that used to be there.

Yes, it works for me now. The leftover “trails” are very subtle. But the blur itself is a neat effect!

I’m guessing that the math being used to calculate the pixel color has problems such as some sort of round-off error (or “feature”). For example, if the color that is left is RGB: 0,0,50 and a RGBA 0,0,0,10 is applied to it, 245/255ths of the color would remain in the next iteration (say, perhaps–I admit I am making this up). That’s (50 * 245)/255 = 48 which represents a reduction towards the target.

But maybe when you get down to a low int, the calculation keeps rounding back up to the number you started with. For example, (5 * 245)/255 = 4.8 rounds to 5. This is circular and never decrements further!

This is just speculation, as I don’t know the exact formula as to how the colors are calculated.

[EDIT: Doh! :clue: I just realized Riven already pointed this out.]

Here is a possible solution: after drawing everything on your Graphics Object, iterate through it and set any color value less than some threshold (10?) to 0. You should be able to do this with a BufferedImage and a Raster. And, it could work very efficiently if you are doing your own double buffering.

So how would you do the blurring effect? Just a semi-transparent black rectangle drawn on top of everything?

Thanks a lot philfrei! :smiley:

even if you did say the same thing as riven, you explained it a lot better so I could understand what he meant.
I was indeed clearing the screen with a colour (0,0,0,10) all integers. So there must have been some rounding errors.
If I clear with (0,0,0,0.1f) there are less dirt marks.
Also,
if i clear with a value of alpha depending on the frames per second, eg. the length of time the last frame took, it clears a lot better. Because if there is a slow frame,
a less transparent rectangle is drawn causing the marks to be cleared. (this seems to happen quite a lot)


        float fBlur = CLOCK.GetDeltaTick() * 5; //time of last frame * random factor depending on how much motion blur you want
        if (fBlur < 0) fBlur = 0; if (fBlur > 1) fBlur = 1;
        m_graphics.setColor(new Color(0,0,0,fBlur));
    	m_graphics.fillRect(0, 0, m_iWidth, m_iHeight);

I am not sure how to use a raster, but I tried this:


                // Get all the pixels
    		int w = m_mainBackBuffer.getWidth(null);
    		int h = m_mainBackBuffer.getHeight(null);
    		int[] rgbs = new int[w*h];
    		m_mainBackBuffer.getRGB(0, 0, w, h, rgbs, 0, w);
    		for (int i = 0; i < rgbs.length; i++)
    		{
    			Color pixel = new Color(rgbs[i]);
    			if ((pixel.getRed() < 50) && (pixel.getGreen() < 50)&& (pixel.getBlue() < 50))
    			{
                                //will clear the pixel to solid black if the pixel is almost black
    				pixel = new Color(0,0,0,255);
    				rgbs[i] = pixel.getRGB();
    			}
    		}
    		
    		m_mainBackBuffer.setRGB(0, 0, w, h, rgbs, 0, w);

    		
    		m_appletGraphics.drawImage(m_mainBackBuffer,0,0, m_iWidth,m_iHeight, this);

This works perfectly although it is very slow. With a raster there is probably a much faster way to do it, but it will be still slower than not using a raster at all.

By using a combination of setting float colour values instead of integer values and using the fps to set the alpha, there is no longer any dirt marks. (unless you use a really really really big amount of motion blur.)
I will upload a new version of my applet later today, so you can see the difference.
Thanks everyone!!! :slight_smile:

Instead of clearing the screen(by using a function, or drawing a coloured rectangle or background image over the screen) each frame before you draw anything, instead you draw a semi transparent black rectangle or semi transparent image.) The more transparent the rectangle/image is, the more motion blur. Each frame, the transparent image/rectangle slowly makes all the pixels clear unless something is being drawn on them that frame. I hope this helps.

If anyone needs help, please reply (and if i don’t answer, email me at chaosreef@gmail.com)

Cool. Glad I could help.
By the way, you should be able to work directly on the BufferedImage, not a copy. That alone should be a big savings in time. (I’m assuming m_mainBackBuffer is a BufferedImage.)

WritableRaster raster = m_mainBackBuffer.getRaster();
int[] pixel = new int[4];  // r,g,b,a
int[] blackPixel = {0,0,0,255};
int height = raster.height();
int width = raster.width(); 

for (int x=0; x<width; x++)
{
	for (int y=0; y<height; y++)
	{
		pixel = raster.getPixel(x,y,pixel);

		if ((pixel[0]< 50) && (pixel[1] < 50) && etc.
		{
			setPixel(x, y, blackPixel);
		}
	}
}

Maybe there is even a for-each construction for the raster. I really don’t know what the quickest way would be to iterate through the complete raster. But, I do think you only have to make the raster once, maybe when you make m_MainBackBuffer, and you can reuse it.

yep m_mainBackBuffer is a BufferedImage. Thanks for that example, I will use this raster for other things such as destructible terrain as it does look a lot faster :slight_smile: hehe

here you can see the improvement:

www.chaosreef.com/asteroids.php

compared to the old:

www.chaosreef.com/asteroids_old.php

Wow I love it! Could you release the source code?

Nice!!