| ||
Next up is coordinate rotation in 3D. This does get a bit more complex than 2D, which you saw in Chapters 10 and 11. Not only can you choose between three different axes to rotate on, you can even rotate on more than one of them at once.
In 2D coordinate rotation, the points are rotated around the z axis, as shown in Figure 15-10. Think of a Wheel of Fortune type spinning wheel with an axle through the center. The axle is the z axis. Only the x and y coordinates change.
In 3D, you can also rotate on the x or y axis. An x-axis rotation would look like a car tire rolling towards you, as shown in Figure 15-11. The axle is on the x axis. Points rotate around that and change their y and z positions .
For y-axis rotation, imagine an old record player, something like Figure 15-12. The spindle is the y axis. Points change on the x and z axes.
Thus, for 3D, when you rotate an object on one axis, its position will change on the other two axes.
If you check back to Chapter 10, youll find the following formula for 2D rotation:
x1 = cos(angle) * x sin(angle) * y; y1 = cos(angle) * y + sin(angle) * x;
In 3D, you do basically the same thing, but you need to specify which angle youre talking about: x, y, or z. Thus, you get the following three formulas:
x1 = cos(angleZ) * x sin(angleZ) * y; y1 = cos(angleZ) * y + sin(angleZ) * x; x1 = cos(angleY) * x sin(angleY) * z; z1 = cos(angleY) * z + sin(angleY) * x; y1 = cos(angleX) * y sin(angleX) * z; z1 = cos(angleX) * z + sin(angleX) * y;
Lets try a y-axis rotation. The following code can be found in ch15_11.fla . It attaches 50 movie clips and randomly positions them. Then it gets a y angle based on the mouses x position. The further right the mouse goes, the higher the number for the angle. This makes the movie clips seem to follow the mouse in their rotation.
var numBalls:Number = 50; var fl:Number = 250; var vpX:Number = Stage.width / 2; var vpY:Number = Stage.height / 2; init(); function init() { for (var i:Number = 0; i<numBalls; i++) { var ball:MovieClip = attachMovie("ball", "ball" + i, i); ball.x = Math.random() * 200 - 100; ball.y = Math.random() * 200 - 100; ball.z = Math.random() * 200 - 100; } } function onEnterFrame():Void { for (var i:Number=0;i<numBalls;i++) { var ball:MovieClip = this["ball" + i]; var angleY:Number = (_xmouse - vpX) * .001; var cosY:Number = Math.cos(angleY); var sinY:Number = Math.sin(angleY); var x1:Number = ball.x * cosY - ball.z * sinY; var z1:Number = ball.z * cosY + ball.x * sinY; ball.x = x1; ball.z = z1; if (ball.z <= -fl) { ball._visible = false; } else { ball._visible = true; var scale:Number = fl / (fl + ball.z); ball._xscale = ball._yscale = scale*100; ball._x = vpX + ball.x * scale; ball._y = vpY + ball.y * scale; ball.swapDepths(-ball.z); } } }
The important parts are in bold. You get an angle, get the sine and cosine of that angle, do the rotation, and assign x1 and z1 back to ball.x and ball.z . Figure 15-13 shows the result.
Once youve tried that, you can try switching it over to x-axis rotation. Just change the bold lines in the preceding code to the following:
var angleX:Number = (_ymouse - vpY) * .001; var cosX:Number = Math.cos(angleX); var sinX:Number = Math.sin(angleX); var y1:Number = ball.y * cosX - ball.z * sinX; var z1:Number = ball.z * cosX + ball.y * sinX; ball.y = y1; ball.z = z1;
Now, angleX is based on the mouses y position. You take the cosine and sine of that, and use them to get y1 and z1 , which are passed to the balls y and z properties.
Next, lets combine the two rotations . Heres the code ( ch15_12.fla ):
var numBalls:Number = 50; var fl:Number = 250; var vpX:Number = Stage.width / 2; var vpY:Number = Stage.height / 2; init(); function init() { for (var i:Number = 0; i<numBalls; i++) { var ball:MovieClip = attachMovie("ball", "ball" + i, i); ball.x = Math.random() * 200 - 100; ball.y = Math.random() * 200 - 100; ball.z = Math.random() * 200 - 100; } } function onEnterFrame():Void { for (var i:Number=0;i<numBalls;i++) { var ball:MovieClip = this["ball" + i]; var angleY:Number = (_xmouse - vpX) * .001; var cosY:Number = Math.cos(angleY); var sinY:Number = Math.sin(angleY); var angleX:Number = (_ymouse - vpY) * .001; var cosX:Number = Math.cos(angleX); var sinX:Number = Math.sin(angleX); var x1:Number = ball.x * cosY - ball.z * sinY; var z1:Number = ball.z * cosY + ball.x * sinY; var y1:Number = ball.y * cosX - z1 * sinX; var z2:Number = z1 * cosX + ball.y * sinX; ball.x = x1; ball.y = y1; ball.z = z2; if (ball.z <= -fl) { ball._visible = false; } else { ball._visible = true; var scale:Number = fl / (fl + ball.z); ball._xscale = ball._yscale = scale*100; ball._x = vpX + ball.x * scale; ball._y = vpY + ball.y * scale; ball.swapDepths(-ball.z); } } }
The changes from the previous example are in bold. Now, you find both angleY and angleX , and the sine and cosine of each. Then you calculate x1 and z1 , based on the y rotation as before. Next, you need to take those rotated values and rotate them again on the x axis. Because the z position is being rotated twice, you need a new variable, z2 , for the second rotation. When both rotations are done, you have new values for x, y, and z. The rest is just perspective.
Play around with this one. By combining 3D coordinate rotation with some of the concepts from the racing game examples in the "Wrapping" section earlier in this chapter, you can create some rich, interactive 3D environments.
| ||