This was a fun quickie. I’ve always wanted to try creating Northern Lights with Actionscript, and here was a good excuse. I’ve seen the real deal in Finland, and though my demo doesn’t act (or look) exactly like aurora borealis, it does use the Circular Wander Class I blogged about last week The code is pretty straight forward, the “trick” being that I take the y value of the “leader” (an instance of CircularWander), and cast that to the Z value of all the following particles. A little Blur, and voila. Then for lack of inspiration, I made it into a sound visualizer.
I used this random Image from Flickr as my source of inspiration:
Here’s a screenshot of the demo.
Click image to see demo WARNING: 3megs… there’s an embedded sound file…
That’s the only working version I could find. There is an FLA, but I dare not open it.
Unfortunately, the loader never saw the light of day, as Sony rebranded within weeks of me finishing the code
The most interesting aspect of the loader was the random movement of the blobs. It’s not what I wanted. I wanted the circular wander motion. Time just ran out back then. Every now and then I’ve pondered going back to the problem. I was inspired to finally get off my ass by Grant Skinners recent post about his Wander Class. So it took me 7 years…
The basic premise is simple:
Any particle travelling along the perimeter of a circle, can “smoothly” switch circles, as long as the next ones center is along a line perpendicular to the particles current moving direction.
The problem is, how do you restrict this movement to stay within a given rectangle?
The solution is easy to see when visualizing it:
There are a few “maximum circle sizes” along the blue “axis line” which fit the wandering bounds. Once the radii of those circles are discovered, it’s just a matter of randomly selecting a point along the line, between the “maximums”.
But how to find those magical maximum radii?
There are probably several ways. After blankly staring at a few sketches, I was suddenly reminded of my Highschool Math teacher Mr. Rosko. He would say the term “Isosceles Triangle” in a tone of voice, that sounded like it was something that could get you laid.
Needless to say I never tried that one on the ladies, but for this baby, it did just the trick.
Not only do isosceles triangles have two equal angles, they also have two sides that are the same length.
Now, let’s look at another mindblowing illustration:
In other words, due to the nature of a circle, an isosceles triangle appears between the current position of the particle, the maximum radius center, and the edge of a boundary. So at this point, here’s what we know about that triangle:
All the angles in the triangle. These can be deciphered with simple arithmetic.
The point currently occupied by the particle.
The equation of the line between the particle, and the new center.
The X (or y) of the point which intersects with the bounds.
In a nutshell, we pwn that sob.
There was some trials and tribulations with maintaining the correct direction when switching circles, and choosing the best circle for the job… more about that if you look at the code
I figured that by converting an “O” into a “C” leaves me with two polygons which are easy to triangulate. Allow me to elaborate:
So the idea is just to cut out a rectangle (two triangles), which connects the polygon and the hole. Triangulate the “cut shape” and then concat the extra two triangles to it. But which rectangle to choose?
I wrote a class called PolygonWithHoles.as . This contains a polygon (Vector.<Point>), and holes (Vector.<Vector.<Point>>). The idea is too loop through the “holes” one at a time (cue beavis and butthead). The safest bet is to find the shortest “connection” between a point on the main polygon and the hole (done by looping and using Point.dist()).
This too has one stipulation. In order to have a rectangle, the code has to find the “shortest connection” either before or after our initially picked “shortest connection”.
Once the “cut out rectangle” has been discovered, the perimeter of the main polygon and the hole are merged through a few loops. If there are more holes, the now modified main shape is chopped again and again, eventually resulting in a “hole free” polygon. This can then be triangulated, and the “removed rectangles” are appended as sets of triangles.
This approach seems to work well over 90% of the time. A few characters in some fonts do throw an error… not sure why. The triangulation is pretty fast, you can see this in the tracebox in the demo. The vectorization of the text is the slow bit.
The next step, of course, is to extrude the characters using textures Maybe even add shading some day…
The code is more or less legible this time, eventually I hope to clean this up into some sort of an API… Once again, the download is a zip of my always expanding “FindBitmapPixelOutline” project… download it’s latest incarnation here. The project you want to look at is “TriangulationTest.mxml”. Warning, it’s 6 megs with tons of crap you probably don’t want
For some reason the demo doesn't start everytime. Just refresh a few times and you should be STOKED! Also, the specular lights go black sometimes. I'm convinced this is just due to my happy go lucky texture generation, but David claims he needs to look at his code.
Here's a demo I made for my presentation at multi-mania. I played around with verlet integrationbefore and have long wanted to try this technique on text. Once I got the vectorization going, it was just a matter of connecting all the points to "Verlet Sticks".
This turned out to be a little tougher than expected. The tricky thing about Verlet Sticks, is that if you connect the same Verlet Point to multiple Verlet Points, the calculations go berzerk, and your shape quickly vanishes from the canvas into the ether. So the challenge was to find a way to connect all the points of a vector shape, with a minimum number of "individual connections", yet in a way that maintains the integrity of the shape. Keyboard cat played me off multiple times in my attempts .
Finally, the solution I landed on, was to create a grid out of all the points. The idea is to create a boundary rectangle, which maintains it's shape via "cross sticks":
Then, create a grid using all the points of your vector shape(s), in such a way that each point connects to a subdivision of the outlines of that "boundary Rectangle":
In the image above you can see the "boundary rectangle" surrounding the vector shape. Then, each point is connected with a vertical and horizontal line. These verticals and horizontals are then connected to a "subdivided" boundary rectangle.
In the demo you can turn "render sticks" on and off to visualize the trick.
Can handle pretty much any set of shapes and subshapes
Due to the "Boundary Rectangle" the shapes "bouncing" is limited, a "T" for instance can't lie diagonally, it always ends up on one of the four sides of the rectangle.
The vertical and horizontal lines shouldn't have more than two subdivisions. To fix this, the code first checks for all points along the same x and y, then shifts any instances above 2 by .5 pixels each. It's practically invisible, but it's there.
Doesn't support transparency, I guess this could be done with a blendmode or so...
More complex shapes can still spazz out and disappear
RENDER : renders the input text with the selected font
UPDATE : update one frame of animation (when stopped)
PLAY : updates the animation on an enter frame
BOUNCE : when the characters are just skidding the floor, spice things up by clicking this button
The code is DIRTY, but does the trick. I've uploaded the source for the brave (or desperate ). It's the same project that I've been using for my last 5 or so blog posts, so there's a lot of redundant code in there. Download it here.
compose a clean "all purpose" class for generating such a grid
Render shapes with curves, using the drawing api
Use nicopteres vectorization code to do this with photos...
Improve the curves and optimization, again I think I can use some code from nicopetre
I just wanted to put this out there because, well, it's kind of nifty... More to come, enjoy!