Saturday 30 August 2008

Adventures in 3D: Part II - Round We Go

[The next in a series on simple 3D graphics in Java. You might want to read the Intro, and Part I - The Basics]

In Part I, we got some spots. Not too impressive, and certainly not very 3D. But let's build on that, and start making those spots move. Our aim is to have something rotating when we move the mouse, so let's look at rotation.

If you want to talk rotation, you need to talk sine and cosine. Remembering back to school days and trigonometry, sine and cosine together describe a circle. If you want to know the x,y of any point around a circle of unit radius, you just need to look at the angle from the horizontal - the cosine of that angle tells you x, and the sine of the angle gives you y. If the circle is not unit radius, you just multiply accordingly. In simple terms:

x = r cos t
y = r sin t

where t is the angle. That's all very well, but if we're going to do arbitrary rotations, you need to talk in terms of the delta i.e. the change in angle, and not just an absolute angle. Thankfully, that's not overly difficult either. I know I said I wouldn't delve too much into the maths, but this is useful to know. You have a point x,y, which with the equations above you can talk about in terms of an (unknown) angle t. Now, you want to rotate that point around an axis (the Z axis) by an arbitrary angle, which we'll call dt, and that will give you a new point x',y'. That new point you can talk about in terms of an (unknown) angle t'. Put all that together, and you come up with:

x' = r cos t'
y' = r sin t'

But t' is just t + dt, so:

x' = r cos (t + dt)
y' = r sin (t + dt)

Naturally, your maths teacher forced you to constantly chant the formulas:

cos (t + dt) = cos t * cos dt - sin t * sin dt
sin (t + dt) = sin t * cos dt + cos t * sin dt

With a little bit of substitution and refactoring, you arrive at:

x' = x * cos dt - y * sin dt
y' = y * cos dt + x * sin dt

and before you know it, you can talk about x' and y' purely in terms of the old position (x,y) and the angle you've rotated through (dt).

Let's plug that into our Point class. We'll create a method called rotateZ() which will accept an angle as a parameter. The method will then move the point from x,y to x', y' by applying the formulas above.

public void rotateZ(double angle){
double x0 = x;
x = (x0 * Math.cos(angle) - y * Math.sin(angle));
y = (y * Math.cos(angle) + x0 * Math.sin(angle));
}


Notice that we save the initial value of x in another variable beforehand. Otherwise, we modify x in the first formula, and the formula for y will be messed up. If your scene appears to shrink as you rotate it, you've probably made that mistake.

Sweet. Now we just have to do something to invoke this method and get our points moving. We're going to do this fairly simply, by adding a MouseMotionListener to the panel. When the mouse is dragged i.e. the button is down, we'll measure how far the mouse has travelled from it's last position, and then rotate all the points in our scene that number of degrees. Naturally we'll convert it into radians first (you are working in radians, right? Right??).

public void mouseDragged(MouseEvent e) {
int x = e.getX();
int dx = x - oldX;
oldX = x;
double angle = dx * radian;
for(Drawable d : scene){
Point p = (Point) d;
p.rotateZ(angle);
}
panel.repaint();
}


Of course, don't forget to a) store the last known X position for next time, and more importantly b) repaint the panel once the rotation is done so you can see the result of your hard work.

If it all works, you should now have a bunch of spots that rotate when you drag the mouse left and right! It gets better. Let's say that when you move up and down, we should rotate around the X axis. Well, that's easy peasy - we just shift the axes so Y becomes Z and X becomes Y, and then reuse the same equation (think about the Right Hand Rule). So you can plug that formula in as well and link that to the mouse movement in the y direction. If you're lazy, you could just download the source

Wait, what's that? It looks like it's rotating in 3D? Well sure it does! Congrats space cadet, you're well on the way. Best take a look at Part III - Poly Filler before you explode with excitement.

No comments: