有人可以解释一下这个立方体旋转脚本如何工作背后的数学原理吗?

发布于 2024-08-04 11:32:02 字数 1749 浏览 10 评论 0原文

如果您访问以下链接,您将看到一个非常酷的 Javascript 模拟立方体,该立方体根据您的鼠标位置旋转。

模拟:此处。

alt text

如果你查看立方体旋转脚本的源代码,你会看到:

<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>

我已经看过好几次了,但我仍然不明白立方体的点是如何的计算出来的。这是使用“欧拉旋转”吗?我遇到的大问题之一是使用对我来说毫无意义的单字母变量名。

具有必要数学知识的任何人都可以帮助解释在此模拟中旋转立方体背后的数学原理吗?我想做类似的事情,但在计算点位置时,我有点迷失。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

兔小萌 2024-08-11 11:32:02
  1. 他写了 27 (3x3x3) + (在
    粗体 html 节点)
  2. 他从 -1->0->1 迭代 x、y 和 z 轴(因此到达该立方体的所有 27 (3x3x3) 点),
  3. 因此对于每个点,他将执行以下操作:
  4. 围绕 z 旋转-axis 通过 a (简单的 2d 旋转)
  5. 绕 x 轴旋转 b (再次简单的 2d 旋转)
  6. 将值 c (这只是缩放的 z 坐标)钳位到 [0..255] (将其用作color [深度提示]
  7. 获取 html 节点并使用简单的透视方法将它们放置在 (300/300) 左右,
  8. 根据深度设置颜色和大小

您忘记提及的重要事情是全局 a 和 b 在 body 标记中设置:

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

变量列表:

  • i 只是一个计数器(无功能) a
  • a 是绕 z 轴的角度
  • b 是绕 x 轴的角度
  • c 是颜色强度
  • x,y,z 是 [-1,- 之间的空间中的坐标1,-1]-[1,1,1]
  • u,v,w 是绕 z 轴旋转的点
  • u2,v2,w2 是绕 x 轴旋转的点
  • s 是 htmlnode

他使用了与欧拉角类似的方法,但他只使用两个轴,因此不存在使用欧拉角的隐含限制。

有关三维旋转的更多信息,请参阅维基百科:

http://en.wikipedia.org/wiki/Rotation_matrix#Dimension_ Three

另请注意,他的投影不是真正的 3d:他没有除以 z 坐标来投影进入二维空间。所以深度是“扭曲的”(很难解释,但是如果你把十字连接起来,它们就不会形成一个立方体,而是一个扭曲的立方体)。在真实的二维投影中,直线将再次形成直线。
alt text

要获得正确的透视投影,请查看这篇文章(不要被矩阵的东西弄糊涂了..只是图表和一个简单的截距定理就足够了):

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

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

对于这样一个简单的方法来说是可以的,但是,严肃的 3d 可以使用齐次坐标。

  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.

稀香 2024-08-11 11:32:02

这个想法是使用标准旋转矩阵。在 2D 中,这是:

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

其中 a 是旋转的角度。

这个想法是,您使用此转换将每个点转换为一个新点。为了更好地了解这一点,请考虑一个单位圆(我不知道如何用 ASCII 艺术来绘制它),并问问自己如何将点 (0,1) 移动到 (sqrt(2) /2,sqrt(2)/2)(45 度旋转)。

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

现在将其转换为 (1,0),另一个 45 度旋转:

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

将其扩展到 3D 非常简单,您所要做的就是使用另一个乘法来沿 XZ 平面旋转。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文