3

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

模拟:这里。

替代文字

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

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

我看了好几遍,还是不明白立方体的点是怎么计算的。这是使用“欧拉旋转”吗?我遇到的一个大问题是使用对我来说毫无意义的单字母变量名。

有必要的数学知识的人会帮助解释在这个模拟中旋转立方体背后的数学是如何工作的吗?我想做类似的事情,但是在计算积分位置时,我有点迷茫。

4

2 回答 2

7
  1. 他写了 27 (3x3x3) +(在一个粗体的 html 节点中)
  2. 他从 -1->0->1 遍历 x、y 和 z 轴(因此到达这个立方体的所有 27 个(3x3x3)点)
  3. 所以对于每一点他都会做:
  4. 绕 z 轴旋转 a(简单的 2d 旋转)
  5. a 绕 x 轴旋转 b (再次简单的 2d 旋转)
  6. 将值 c (这只是一个缩放的 z 坐标)限制为 [0..255] (使用它作为颜色 [深度提示]
  7. 获取 html-nodes 并使用简单的透视方法将它们放置在 (300/300) 周围
  8. 根据深度设置颜色和尺寸

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

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

变量列表:

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

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

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

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

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

要获得正确的透视投影,请查看本文(不要被矩阵的东西弄糊涂了。只需要图表和简单的截距定理就可以了):

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

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

对于这种简单的方法,它是可以的,但是,严肃的 3d 将使用齐次坐标。

于 2009-09-09T18:47:44.607 回答
2

这个想法是使用标准的旋转矩阵。在 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 平面进行旋转。

于 2009-09-09T18:40:32.407 回答