Source : Better Flash 10 3D interaction : ArcBall

With the addition of the 2.5d API in Flash 10, lot’s of developers now have even easier access to basic 2.5D environments. But with those new capabilities and API’s new challenges for developers arise. Famously, Flash 10 doesn’t do the Z-Sorting natively. When Lee Brimelow asked me if I could send him an easy solution for that, I sent him the SimpleZSorter. Which he in turn used to paste my profile picture on as much as possible planes, but more significantly, use for this tutorial.

Althought the name Simple would imply something a bit away from a PerfectZSorter (which, technically, has some challenges considering the 2.5D API and the player performance, don’t ask), the thing which astounded me was the amount of feedback. Sure, more people had asked me for such a solution and this simple little tool did it for them most of the time.

But considering the simplicity of the SimpleZSorter and the amount of feedback I got on it (even if I didn’t publish on it myself) made clear that although the 2.5D API of Flash 10 opened up loads of opportunities for developers and designers a like, some of the simpler issues aren’t addressed by it, whist there is clearly a need for it. That need can be addressed and with this post I’m hoping to do a another small part.

The ArcBall

One of the questions which people have been asking me about for in relation to using the 2.5D API, is (loosely combined) “How do I rotate things in 3D correctly with the mouse”.As this question came more and more, I’ve also realized how fundamental this is to our community. With Flash 10 we have native realtime (2.5D) 3D, but with realtime comes interactivity. And what use is it for users to have a 3D interface, while the controls are not intuitive ? At that point 3D becomes a worse experience, rather then a better. While this solution won’t address every issue with that, it most certainly addresses one, 3D rotation dragging.

Native 3D interaction might be new to Flash, but it certainly isn’t new to Flash 3D, or 3D in general for that matter. And the problem of having a user rotate an object with a mouse has been addressed before in numerous different ways. So luckily the wheel doesn’t need any inventing. The wheel I chose for to address this problem is called an ArcBall, first proposed by Ken Shoemake. Now if you want to read that paper go ahead, but let me define this in flashers layman terms.

The Problem

Let’s first have a look at the problem as I’ve seen examples of code of people and derived it to this “problem” example. Drag the cube to rotate it.

Although the mouse dragging does offer some feeling of control, you’ll find it difficult to rotate it in a natural intuitive way, to let’s say to the front of one of those colored planes. Here’s what’s happening here in that code, and what I’ve been seeing most.

This is example is the most common and is responsible for the example above. Now, the problem here is that it doesn’t take into account the local object transformation, as well as the dragging coordinates. As the object rotates around it’s axis, so do it’s axis change. Also, as the dragging goes on, we don’t take into account the 2D coordinate versus it’s 3D transformation dragging start and final output. All in all it ends up being a bit messy.

As you can see / feel, object rotations now feel much more direct and natural. But what is this magic ? First off all, the class is fully Flash 10, and uses it’s native methods and features, where available for this solution. To explain it as simple as possible, as you click and start dragging on the cube, a sphere is established. This virtual sphere, around the object is then used to establish a point in 3D space on the sphere. As you are dragging, your actually rotating other points on the sphere. From these angular differences on the sphere, we can derive a new transform matrix for the object.

The hard part is in the establishing the rotational angles from those 2 coordinates on a sphere. A well proven way to do that (and the only form I have seen in ArcBall implementations, so far), is using Quaternions (go ahead, read it now, all of it, I dare you). Quaternions are complex things (pun intended). Now Quaternions are a bit daunting to start at and at this point I would be lying if I said I fully understand them. I’m not the only one who finds them scary, quoting Keith Peters / Bit-101 ; “Oh no. Vector3D’s w is the second most scary w in the world.” (I wonder what the first is, Keith ?).

Quaternions and Flash 10

If you are looking for the clearcut solution and implementation of my class for it, skip this part, otherwise, read on, enjoy.

The reference to the w in that quote is also a reference to the complex component real component of the quaternion, where the xyz are complex numbers. Yes, complex numbers (I dare you again) and their appliance is where stuff does get scary for most of us. The great thing about the Flash 10 3D and geom API is that there is a partial native support for quaternions, next to having a vector with x,y,z and w components. For instance, this:

matrix3D.decompose(OrientationStyle.QUATERNION);

Which will return a Vector of 3 Vector3D’s, which are in order translation, rotation, and scale. When using the quaternion orientation style, the rotation will be filled with a Vector3D with it’s x,y,z,w values nicely filled; a quaternion. While this is something we could have handled ourselves (decomposing a matrix to it’s components using quaternions), it’s great Flash 10 has it. Less code, less size and it’s faster then doing it with your own defined functions.

This ArcBall implementation relies heavily on that piece of code and some added code to do some additional stuff with the quaternions (multiply doesn’t seem to be available native). Now while I’m not enough of an authority to try and explain quaternions, the applications for them in 3D rotation are numerous, most famously, the first thing which will get mentioned when talking about the topic of Gimbal lock, which is a problem most encountered by astronauts and people developing 3D applications (see! us developers do have something in common with astronauts, we’re now doing rocket science!).

That being said, on a wider look on Quaternions, for example, Both Andy Zupko and John Lindquist have done some nice articles on the subject and it’s appliances in Papervision3D. Papervision3D, running from Flash 9 and higher, has it’s own Quaternion implementation, as Flash 9 doesn’t support it natively.

Deriving an easy solution for all

While the solution to ArcBalls using Quaternions isn’t even that hard, I still felt the problem should be abstracted a bit more, with an easy one stop solution for all. After all, the reason I got that much feedback on the SimpleZSorter, is clearly because people actually use it. Why do people use it ? My estimate is, it addresses a real problem and it’s simple to implement. And while that might cause a little overhead, and make it less flexible, it works for people looking for a simple solution. Here’s how that was implemented.

SimpleZSorter.sortClips(boxSprite,true);

Simple enough right ? So for the abstraction of the ArcBall something similar made sense.
Using the ArcBall class (and getting your correct dragging rotations up and running in no time) works like this.

arcBall = new ArcBall(boxSprite);

Now you can drag this object, and get nice, intuive rotations from it. There are a bunch of options to use;

arcBall = new ArcBall(boxSprite, useRadius, radius);

If you set the useRadius argument to true, and set radius to a specific value for that object (think about a sphere which completely encapsulates the object you have, it’s bounding sphere, see my beautiful artistic rendering at the top of this post), the bounding sphere used per dragging action is the same size. When that option is left set to false, the point on the sphere is derived from the click in 3D space on that object and thus speed might vary, depending where the user start the drag.

Because the ArcBall class automatically adds listeners to the object, and automatically enables dragging on it, you need a way to switch it off when it’s not wanted.

arcBall.enabled = false;
//To enable it again
arcBall.enabled = true;

So, that’s it. I hope it helps you in getting a better experience for the end user. Since this is an abstraction for ease of use and much more can be done, the entire code base for both examples and the ArcBall under the MIT License; essentially, do with it what you want, if it breaks anything, it’s not my fault. Let me know what you think.

Thanks Ralph, it’s amazing to keep seeing how you create solutions for complex stuff like this and making it usefull to a much broader audiance. Now I can keep ignoring what the hell Quaternions are and move on.

@boblemarin Although the solutions look the same, because of the use of Euler angles in your example, there is a subtle but UI wise notable difference. With the Quaternions you get true 6 dof, with the use of eulers in your example you don’t. Although both are an implementation of an arcball which works, there is a subtle difference, which doesn’t make it the same.

Here’s a good way to see that difference. With one of the faces of the cube facing directly to the viewer, try and rotate the plane around it’s Z axis (the axis coming directly towards you. For clarity sake, let’s called it the effect of an old .rotation property). Now, if you try and rotate around that axis 180 degrees with the quaternion approach, although it does take a couple of steps going back and forth of pulling one of the corners down, and then the opposite corner up, you can do a full rotation with that, without actually getting an unexpected rotation, or having to do a full flip.

Try that with your example of using euler angles. You’ll see it’s not truly direct 6DOF, and it’s harder to get the same result. It will feel somewhat like one of the angles is “locked”, or you have got less control over it. It’s subtle, but to me a big difference.

I’ve done something similar to @boblemarin ‘s version in the past. For me, the problem is the cube will get rotated when you press and drag it in circular motion… For example, dragging it clockwise will make the cube move anti-clockwise…