KingNestor
KingNestor

Reputation: 68010

Could someone explain the math behind how this cube-rotating script works?

If you go to the following link you'll see a really cool Javascript simulation of a cube that rotates based on your mouse position.

Simulation: here.

alt text

If you view the source of the cube rotating script you'll see:

<script type="text/javascript">

/* I wrote this script in a few minutes just for fun. It's not made to win any
   competition. */

var dimension = 1, a = 0, b = 0, i = 27;
while (i--) document.write('<b id="l' + i + '">+</b>');

function f()
{
 i = 0;
 for (x = -dimension; x <= dimension; x += dimension)
  for (y = -dimension; y <= dimension; y += dimension)
   for (z = -dimension; z <= dimension; z += dimension)
   {
    u = x;
    v = y;
    w = z;
    u2 = u * Math.cos(a) - v * Math.sin(a);
    v2 = u * Math.sin(a) + v * Math.cos(a);
    w2 = w;
    u = u2; v = v2; w = w2;
    u2 = u;
    v2 = v * Math.cos(b) - w * Math.sin(b);
    w2 = v * Math.sin(b) + w * Math.cos(b);
    u = u2; v = v2; w = w2;
    var c = Math.round((w + 2) * 70);
    if (c < 0) c = 0;
    if (c > 255) c = 255;
    s = document.getElementById('l' + i).style;
    s.left = 300 + u * (w + 2) * 50;
    s.top  = 300 + v * (w + 2) * 50;
    s.color = 'rgb(' + c + ', ' + c + ', 0)';
    s.fontSize = (w + 2) * 16 + 'px';
    /* The Digg users missed depth sort, so here it is. */
    s.zIndex = Math.round((w + 2) * 10);
    i++;
   }
}

/* Using a timer instead of the onmousemove handler wastes CPU time but makes
   the animation much smoother. */
setInterval('f()', 17);

</script>

I've looked over it several times, and I still don't understand how the points for the cube are calculated. Is this using "Euler Rotations"? One of the big problems I've had is the use of single letter variable names that mean nothing to me.

Would anyone with the requisite math knowledge help explain how the math works behind rotating the cube in this simulation? I'd like to make similar things but when it comes to calculating the points positions, I'm a little lost.

Upvotes: 3

Views: 2909

Answers (2)

Peter Parker
Peter Parker

Reputation: 29725

  1. he writes 27 (3x3x3) + (in a bold html node)
  2. he iterates over x,y and z axis each from -1->0->1 (so reaching all 27 (3x3x3) points of this cube)
  3. so for each point he will do :
  4. a rotation around z-axis by a (simple 2d-rotation)
  5. a rotation around x-axis by b (simple 2d-rotation again)
  6. clamping the value c (which is just a scaled z-coord) into [0..255] (using this as color [depth-cueing]
  7. get html-nodes and place them around (300/300) with a simple perspective approach
  8. setting color and size according to the depht

The important thing you forget to mention is that global a and b are set in body tag:

<body onmousemove="a = event.clientX / 99; b = event.clientY / 99;"

variable list:

  • i is just a counter (no function) a
  • a is the angle around z-axis
  • b is angle around x-axis
  • c is color-intensity
  • x,y,z is coordinate in a space between [-1,-1,-1]-[1,1,1]
  • u,v,w are rotated points around z-axis
  • u2,v2,w2 are rotated points around x-axis
  • s is the htmlnode

He used a similar approach as euler angles, but he uses only two axis, so there are not the implicite limitations of using euler angles.

For more information about rotations in three dimensions look into wikipedia:

http://en.wikipedia.org/wiki/Rotation_matrix#Dimension_three

Also note, that his projections is not real 3d: he does not a divide by z-coordinate to project into 2d-space. So the depth is "distorted" (difficult to explain, but if you connect the crosses, they will not form a cube, but a distorted cube). In a real 2d-projection, straight lines will form to straight lines again. alt text

for correct perspective projection look into this article(do not get confused by the matrix stuff.. just the diagram and a simple intercept theorem is all you need):

http://en.wikipedia.org/wiki/Perspective_projection#Perspective_projection

x' = x * (eye_dist / eye_dist + z)
y' = y * (eye_dist / eye_dist + z)

for such a simple approach it is ok however, serious 3d will work with homogeneous coordinates.

Upvotes: 7

Nathan Fellman
Nathan Fellman

Reputation: 127578

The idea is to use a standard rotation matrix. In 2D this is:

--     --   --             -- --     --
| x_new |   | cos(a) -sin(a) | | x_old |
|       | = |               | |       |
| y_new |   | sin(a)  cos(a) | | y_old |
---    --   --             -- --     --

Where a is the angle by which you're rotating.

The idea is that you're translating each and every point to a new point using this transformatoin. To get a better picture of this, consider a unit circle (which I don't know how to draw with ASCII art), and ask yourself how you can move the point (0,1) to (sqrt(2)/2,sqrt(2)/2) (a 45 degree rotation).

x_new = x_old * cos(45) - y_old * sin(45) = 1 * sqrt(2)/2 - 0 * sqrt(2)/2 = sqrt(2)/2
y_new = x_old * sin(45) + y_old * cos(45) = 1 * sqrt(2)/2 + 0 * sqrt(2)/2 = sqrt(2)/2

Now translate this to (1,0), another 45 degree rotation:

x_new = x_old * cos(45) - y_old * sin(45) = sqrt(2)/2 * sqrt(2)/2 - sqrt(2)/2 * sqrt(2)/2 = 0
y_new = x_old * sin(45) + y_old * cos(45) = sqrt(2)/2 * sqrt(2)/2 + sqrt(2)/2 * sqrt(2)/2 = 1

Extending this to 3D is pretty straightforward, all you have to do is use another mutliplication for the rotation along the XZ plane.

Upvotes: 2

Related Questions