AS3: Polar inversion/black hole effect

Hey, i want to create a dynamic effect where a starry sky turns into a black hole sorta thing.
The effect looks exactly like something i managed to make in paint.net with the effect tool: polar inversion.
Heres what i made in paint.net: http://imgur.com/qOd3kk0

Do you want it to be animated in some fashion? Would the stars always be moving or only the ones near the black hole?

I want the stars to be moving behind the black hole, so that it looks like a simplified version of this: https://youtu.be/eI9CvipHl_c?t=3m15s

Hmm, well, you could check out the source of something like this: http://moorem27.github.io/BlackHole/

Or you could look at the source of Paint.NET’s PolarInversion: https://github.com/wangdeshui/paint.net/blob/cadf8f6d5d76cfa36d6fddf6ef9d0159d141c55a/src/Effects/PolarInversionEffect.cs

… though it’s hard to extract unless you know a lot about Paint.NET’s underlying drawing model.


Edit: Or, since I was thinking about Box2D, you could follow this person’s trail: http://www.box2d.org/forum/viewtopic.php?f=8&t=3977

Neither of your examples look like what i want, and i dont understand the Paint.NET one. I dont want the effect to actually interact with the stars and throw them away as if its an actual physics simulator, i just want it to displace and stretch the stars when the stars are near the black hole and move the stars back to their original position once theyre are out of it range.

For the lens effect of a black hole on a static 2d image, you could use bitmapdata and the displacementmap. I suppose the most difficult part would be to create the displacementmap?

It is possible to create displacementmaps by hand, in for example photoshop, with different gradients in each rgb channel.

1 Like

Using displacement maps sounds like a good idea, do you know of any kind of tutorial or helpful information i would need to draw this by hand?

To construct a multicolored, and advanced gradient, you just need to create a new image with the colormode RGB. Select the Channels window and make sure only one channel-layer is selected while creating a black and white gradient at the appropriate direction, select another colorchannel and create a gradient in another direction(+90 degrees).

Don’t forget to mark the RGB channel in the channel window, to view the final result.

If I remember correctly, there is a grey color at 127 that has no influence at all, so you make a new layer with this grey and mask a hole for you gradient underneath, flatten the image and blur it some to get a soft edge between the grey and the advanced multicolored gradient.

If I get time this weekend, I will perhaps make a more thorough investigation into this, since I noticed that Photoshop CC has a filter for dicplacementmaps, and that could perhaps also be useful for me?

The best result would be to calculate the discplacementmap, but photoshoped maps will give you the ability to test and play, and they will probably be good enough for most cases.

The image should look somehting like this, depending on what channels you will use, size etc.

Wow, awesome explanation man! I really appreciate it! This sounds like the perfect opportunity to learn photoshop!

Edit; If you change scaleX and scaleY to about 300-350 in the fla file, ie make a larger discplacement than the map itself, you get a somewhat convincing black hole :smile:

--------- end edit

I made some tests in an old as2 file I had laying around, in flash cs6. You can poke around with the mouse to test different maps.
dispclament.fla.zip (195.4 KB)

If you want to mimic the lens effect of a black hole, you probably don’t want to use the ordinary displacement map commonly used to create a lens effect in flash. Black holes in the sky are detected, not because they enlarge things, but because they produce illusions of twin stars and twin galaxies. So you probably want to use a map that looks slightly different.

I did try with a different displacementmap, and it is included in the file, with the property of “doubling” what is seen in the background.

The raw image is here:displacer.png.zip (64.3 KB)
I blurred and edited it some in the fla file, to soften the center some, and the grey is apparently 128 and not 127, so I adjusted for that too.

The script to calculate the map is here, maybe you could use it? I tried to use a sigmoid function to calculate the displacement, I’m not sure I got it right?

package
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	
	public class createDisplacebitmap extends MovieClip
	{
		//math vars
		//using logistic s-curve: 
		//http://en.wikipedia.org/wiki/Logistic_function
		//http://en.wikipedia.org/wiki/Sigmoid_function
		public var e:Number = Math.E;
		
		//bitmap vars
		private var bitmapH:Number = 500;
		private var bitmapW:Number = 500;
		public var myBitmapData:BitmapData;
		public var bit:Bitmap;
		
		//color vars
		private var r:Number;
		private var g:Number;
		private var b:Number;
		
		public function createDisplacebitmap()
		{
			//create bitmapdata
			myBitmapData = new BitmapData(bitmapW,bitmapH,false);
			
			//centerpoint
			var cx:Number = bitmapW/2;
			var cy:Number = bitmapH/2;
			
			//loop over pixels and use a formula to calculate pixelvalue
			for (var i:Number = 0; i < bitmapW; i++) 
			{
				for (var j:Number = 0; j < bitmapH; j++) 
				{
					//I want to know distance to center from current pixel and caculate that as force for x and y component
					var dist:Number = DistanceTwoPoints(i,cx, j, cy);
					
					
					//I want to normalize distance from center from 0 to 6
					//normalize distance to half width and half height(since we use centerpoint)
					var ndx:Number = 6*(dist/cx);
					var ndy:Number = 6*(dist/cy);
					
					var dirx:Number = 1;
					var diry:Number = 1;
					if(i<cx){dirx =-1};
					if(j<cy){diry =-1};
					
					//get color
					var rcolor:Number = 127+255*sigmoidf(ndx*dirx);//127-dirx*127*sigmoidf(ndx);
					var gcolor:Number = 127+255*sigmoidf(ndy*diry);//127-diry*127*sigmoidf(ndy);
						
					myBitmapData.setPixel(i,j,getColor(rcolor,gcolor,127));
					
				}
			}
			
			//add bitmapdata to bitmap 
			bit = new Bitmap(myBitmapData);
			
			//add bitmap to stage
			addChild(bit);
		}
		
		private function sigmoidf(val:Number):Number
		{
			//https://www.wolframalpha.com/input/?i=Plot%5B1%2F%281%2Be%5E-x%29%2C%7Bx%2C-6%2C6%7D%5D
			//returns from 0 to 1 in the range -6 to 6
			var  nmb:Number = 1.0/(1.0 + Math.pow(Math.E, -val));
			return nmb;
		}
		
		private function getColor(r:Number,g:Number,b:Number):uint{
			var resultColor:uint;
			r = Math.round(r);
			g = Math.round(g);
			b = Math.round(b);
			
			resultColor = r<<16 | g<<8 | b;
			return resultColor;
		}
		
		private function DistanceTwoPoints(x1:Number, x2:Number,  y1:Number, y2:Number):Number {
			var dx:Number = x1-x2;
			var dy:Number = y1-y2;
			return Math.sqrt(dx * dx + dy * dy);
		}
	}
}
1 Like

Dude, your help is so much appreciated and you have helped me unbelievably much. Thank you so much! The displacement map you made is exactly what im looking for!

One last question though, is it possible to increase the quality of the effect? Or is the only way to increase the size of the displacement map?

Heres a picure of what i mean: http://i.imgur.com/B4iZttq.png . As i understand it the dots in the middle of the black hole should just be enlarged stars, but they look very weird.

I’m not sure how good quality you can get from the displacement? They probably traded of quality for speed and animation.

There are a few things you could try that will have some effect I think.

-restrict motion to full pixels.
-double the pixeldimendions and scale down presentation with 50% so you give room for sharper enlargements.
-blur the discplacementmap, there might be artifacts in the image.

I let you know if I can think of anything else.