Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  simple motion blur  (Read 2788 times)
0 Members and 1 Guest are viewing this topic.
Online roland
« Posted 2011-05-30 15:20:09 »

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
Offline pitbuller
« Reply #1 - Posted 2011-05-30 17:27:44 »

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.
Offline philfrei
« Reply #2 - Posted 2011-05-30 21:44:06 »

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!

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline pitbuller
« Reply #3 - Posted 2011-05-30 23:13:34 »

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.
Online roland
« Reply #4 - Posted 2011-05-31 08:22:08 »

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
Offline pitbuller
« Reply #5 - Posted 2011-05-31 08:53:42 »

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?
Online roland
« Reply #6 - Posted 2011-05-31 09:28:30 »

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.
Offline philfrei
« Reply #7 - Posted 2011-05-31 21:08:01 »

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

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.


"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline pitbuller
« Reply #8 - Posted 2011-05-31 22:46:21 »

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.

Now I see it. I could bet there was nothing at morning.
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 745
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #9 - Posted 2011-05-31 22:55:27 »

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.


Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Online roland
« Reply #10 - Posted 2011-06-01 01:04:20 »

Thanks for the replies Smiley

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

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.
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.

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.
Ok, would you happen to know a way to solve this problem?
Offline ra4king

JGO Kernel


Medals: 338
Projects: 2
Exp: 5 years


I'm the King!


« Reply #11 - Posted 2011-06-01 08:20:45 »

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.

Offline philfrei
« Reply #12 - Posted 2011-06-01 09:12:57 »

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! Clueless 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.

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline ra4king

JGO Kernel


Medals: 338
Projects: 2
Exp: 5 years


I'm the King!


« Reply #13 - Posted 2011-06-01 09:26:18 »

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

Online roland
« Reply #14 - Posted 2011-06-02 01:48:22 »

Thanks a lot philfrei!  Cheesy

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)

1  
2  
3  
4  
        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);



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.

I am not sure how to use a raster, but I tried this:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
                // 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!!! Smiley

So how would you do the blurring effect? Just a semi-transparent black rectangle drawn on top of everything?
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)


Offline philfrei
« Reply #15 - Posted 2011-06-02 03:01:23 »

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.)

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
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.

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Online roland
« Reply #16 - Posted 2011-06-02 05:34:39 »

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.)

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
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 Smiley hehe
Online roland
« Reply #17 - Posted 2011-06-02 13:28:40 »

here you can see the improvement:

www.chaosreef.com/asteroids.php

compared to the old:

www.chaosreef.com/asteroids_old.php
Offline ra4king

JGO Kernel


Medals: 338
Projects: 2
Exp: 5 years


I'm the King!


« Reply #18 - Posted 2011-06-02 17:39:28 »

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

Offline philfrei
« Reply #19 - Posted 2011-06-02 20:48:49 »

Nice!!

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Online roland
« Reply #20 - Posted 2011-06-03 02:36:11 »

Thanks  Smiley
i will not release the source code because I want to make a really good game with it Smiley (atleast not until after its done), but you should look at this code here:
http://www.java-gaming.org/index.php?topic=22773.0
This gives a basic applet and motion blur example working (beware that there will be dirt trails in this one: just set colour with float values instead of integer values, and set it depending on the last frame time (as i said above).

A good tutorial on asteroids is here: although the collision detection is not good (distance not pixel perfect), so use mine (see below)
http://www.giosoft.net/Development/Java-Asteroids-Tutorial.html

For the ship: it is a java polygon: http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Polygon.html
it has 4 points (in counter clockwise order). Draw the polygon with graphics.fillPolygon() method.

start with a list of points, (java arraylist or something similar), and each frame reset your Polygon and add the rotated vertices.
(this needs javax.vecmath library for vectors by the way)

1  
2  
3  
4  
5  
6  
7  
Sorry for my c++ style naming conventions:
//m_ = class member variable
//m_i... = int variable
//m_f... = float variable
//m_list... = Java util ArrayList
//m_vec2... javax.vecmath Vector2f
//CLOCK.GetDeltaTick() //get the time (milliseconds) of the last frame


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
for (Vector2f point: m_listPoints)
      {
         Vector2f rotated = RotatePoint(point);
         int x = (int)(rotated.x*m_fSize + m_vec2Position.x);
         int y = (int)(rotated.y*m_fSize + m_vec2Position.y);
         m_polygon.addPoint(x, y);
         iPoint++;
      }
private Vector2f RotatePoint(Vector2f point)
   {
      Vector2f result = new Vector2f();
      result.x = (float) (point.x*Math.cos(m_fRotation) - point.y*Math.sin(m_fRotation));
      result.y = (float) (point.x*Math.sin(m_fRotation) + point.y*Math.cos(m_fRotation));
      return result;
   }


for moving the ship:
1  
2  
3  
4  
5  
6  
public void Forward()
   {
               
      m_vec2Velocity.x += m_fSpeed * Math.cos(m_fRotation-Math.PI/2) * CLOCK.GetDeltaTick();
      m_vec2Velocity.y += m_fSpeed * Math.sin(m_fRotation-Math.PI/2) * CLOCK.GetDeltaTick();
   }


Asteroids and particles are also made out of polygons.
The points in the polygon seem random,
each point is made like this:
where i is a for loop variable (for (int i = 0; i < iNumPoints; i++)
1  
2  
3  
float angle = (float) ((Math.PI*2) / iNumPoints)*i;
         vec2Pos.x += fRandomSize * Math.cos(angle);
         vec2Pos.y += fRandomSize * Math.sin(angle);


for collisions:
you have 2 Java Polygons.
Loop through one of the polygon's points.
for each point, see if the other polygon contains that point http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Polygon.html#contains(int,%20int)
if it does, you have a collision.

hope that helps  Wink







Offline ra4king

JGO Kernel


Medals: 338
Projects: 2
Exp: 5 years


I'm the King!


« Reply #21 - Posted 2011-06-03 03:36:49 »

Ah I just wanted to see how you do the physics and explosion Cheesy

Online roland
« Reply #22 - Posted 2011-06-03 04:07:30 »

ok. Smiley My physics are using polygon collision as I showed above, and the javax.vecmath library (for vectors).
my explosions are just a list of polygons, that have a certain amount of life. Their alpha = currentLife / initialLife.
i decrease their life by the last frame (ms), and their colour is:
red = 1;
green = random.nextfloat();
blue = 0;
if their life <= 0 then remove. When I create them I give them a random x & y velocity

something like this: http://paraschopra.com/tutorials/particle-systems/
Offline ra4king

JGO Kernel


Medals: 338
Projects: 2
Exp: 5 years


I'm the King!


« Reply #23 - Posted 2011-06-03 05:00:43 »

And how did you do the physics when two entities collide? Like when the player and a rock hit each other, how would you figure out the resulting velocities?

Online roland
« Reply #24 - Posted 2011-06-03 05:26:05 »

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
//When collision between player and asteroid happens, player.Recoil(asteroid.getPosition(), 100) is called.
//_vec2Object = position of asteroid
//speed = how fast the player should be pushed back
public void Recoil(Vector2f _vec2Object, float _fSpeed)
   {
                //reverse players speed and divide by 2
     m_vec2Velocity.x *= -0.5f;
      m_vec2Velocity.y *= -0.5f;
     
                //get direction between player and asteroid
     Vector2f vec2Direction = new Vector2f();
      vec2Direction.x = _vec2Object.x-m_vec2Position.x;
      vec2Direction.y = _vec2Object.y-m_vec2Position.y;
      vec2Direction.normalize();
                //change the players velocity by the recoil speed and the direction between the player and the asteroid
     m_vec2Velocity.x -= _fSpeed * vec2Direction.x;
      m_vec2Velocity.y -= _fSpeed * vec2Direction.y;
   }


as to the asteroid: it splits apart into a random amount of smaller ones which all have random velocities.
after the collision between the player and the asteroid, the player becomes invincible for a second (so it can't collide with the new asteroids)  Grin
Offline ra4king

JGO Kernel


Medals: 338
Projects: 2
Exp: 5 years


I'm the King!


« Reply #25 - Posted 2011-06-03 05:34:50 »

Ohhh....I thought it would be more complicated than that. Hahaha thanks that helps Cheesy

Online roland
« Reply #26 - Posted 2011-06-03 05:46:42 »

no problem  Wink
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Riven (18 views)
2014-07-29 18:09:19

Riven (13 views)
2014-07-29 18:08:52

Dwinin (12 views)
2014-07-29 10:59:34

E.R. Fleming (31 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (42 views)
2014-07-24 01:59:36

Riven (41 views)
2014-07-23 21:16:32

Riven (28 views)
2014-07-23 21:07:15

Riven (29 views)
2014-07-23 20:56:16

ctomni231 (60 views)
2014-07-18 06:55:21
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!