1

我正在尝试制作一个 3D 立方体,由所有单独的小 div 组成。假设我们有一个 3*3*3 div 的立方体。关于所有 div 的内容:

  • X、Y、Z 坐标(3D 立方体的)
  • 绕 X 和 Y 轴的旋转角度

这在技术上应该足以计算立方体的 2D 透视投影。现在的问题是:如何计算每个 div 的 X 和 Y 坐标?

附言。这种多维数据集的类似示例在此链接中:http: //maettig.com/code/javascript/3d_dots.html。在这个例子中我不喜欢的两件事是:

  • 立方体如何旋转的方式。例如,如果我按下鼠标,立方体会向上旋转。此外,对于鼠标的水平移动,立方体始终围绕同一轴旋转,对于鼠标的垂直移动,立方体相对于水平旋转进行旋转。
  • 立方体的角落只有一个“+”,我想要一个填充的(巨大的)立方体。
4

1 回答 1

12

我认为您的问题有两个不同的答案:直接回答您的问题回答您的问题


到“如何计算每个 div 的 X 和 Y 坐标?”

注意 - 以下答案是我为线程Transform GPS-Points to Screen-Points with Perspective Projection in Android所做的帖子的重新表述。您还可以查看 Wikipedia 文章“ 3D 投影”以获得更通用的答案。

您将需要更多信息来执行透视投影,例如相机/眼睛的位置/方向、视角以及要在其上投影立方体的表面。

有了这一切,您应该能够循环您的div元素,然后在它们的 4 个角顶点上应用您的旋转变换并投影它们中的每一个,最终使用您获得的 2D 坐标来渲染元素。

应用旋转

让我们简化一下情况。我们有:

  • 一个顶点 A(x_0, y_0, z_0),你的一个角div
  • θδ分别定义要应用的旋转的角度。俯仰角和偏航Tayt-Brian 角

...我们想要:

  • D(x,y,z),我们旋转元素的位置

因此,您的线性化方程是:

  • x = sin(δ) * y_0 + cos(δ) * x_0
  • y = sin(θ) * z_0 + cos(θ) * (cos(δ) * y_0 − sin(δ) * x_0)
  • z = cos(θ) * z_0 i sin(θ) * (cos(δ) * y_0 − sin(δ) * x_0)

投影 - 介绍

现在我们有:

  • 我们的点 D(x,y,z)
  • w * h,您要投影的表面的尺寸(innerWidth*innerHeight例如在您的情况下)
  • 视角 α

...我们想要:

  • B 在表面平面中的坐标(我们称它们为XY

X 屏幕坐标的架构:

E 是我们的“眼睛”在这个配置中的位置,我选择它作为原点来简化。如果不是这种情况和/或如果您还想旋转相机,则需要在后续步骤之前再次将相应的平移和/或旋转变换应用于 D。

已知焦距f可以估计:

  • tan(α) = (w/2) / f (1)

一点几何

您可以在图片上看到三角形ECDEBM相似的,因此使用Side-Splitter Theorem,我们得到:

  • MB / CD = EM / EC<=> X / x = f / z (2)

使用(1)(2),我们现在有:

  • X = (x / z) * ( (w / 2) / tan(α) )

注意:Y的推理相同。

实际使用

一些备注:

  • 通常使用α = 45deg,这意味着tan(α) = 1. 这就是为什么这个术语没有出现在许多实现中的原因。
  • 如果你想保持你显示的元素的比例,保持fXY不变,即,而不是计算:

    • X = (x / z) * ( (w / 2) / tan(α) )Y = (y / z) * ( (h / 2) / tan(α) )

    ... 做:

    • X = (x / z) * ( size / 2) / tan(α) )Y = (y / z) * ( (size / 2) / tan(α) )使用size您定义的常量值(size = min(w,h)size = (w+h)/2例如经常使用的值)。它只会影响焦点,从而影响视角。
  • 正如您在上图中可能已经注意到的那样,屏幕坐标在这里定义在[-w/2 ; w/2]用于 X 和[-h/2 ;h/2]表示 Y,但您可能想要 [0 ; w][0 ; h]代替。X += w/2-Y += h/2问题解决了。


关于显示由 3D 立方体制成的问题div

正如我所看到的情况,上述方法存在缺陷。当然,您可以获得定义旋转和投影div元素的 2D 坐标,但是如何使用它来渲染它们呢?.

投影后,您div可能不再看起来是矩形的,因此很难使用简单的 CSS 进行渲染,尤其是当您的div元素包含复杂的内容时。

因此,如果您的真正目的是显示 3D DOM 立方体,带有旋转和透视,我建议您使用CSS3 3D 变换,让浏览器进行计算。

例如,您会在此处找到仅使用 HTML 和 CSS3 实现此类多维数据集的教程。

优点是多方面的:

  • 您可以从浏览器 GPU 加速中受益,使其比使用普通 JS 更流畅。
  • 它会影响你的内容div(旋转,透视)
  • 没有数学可以实现

您可能只需要担心您针对旧版本 ( http://caniuse.com/transforms3d ) 的浏览器兼容性。

如果你想动态旋转你的立方体(例如当鼠标移动时),只需使用 JS 来编辑你的 CSS 变换

例子

我很快就制作了这个JSFiddle,只需从教程中复制实现并添加一个onmousemove处理程序来更新旋转。

希望对你有帮助,再见!

于 2013-06-06T09:43:08.453 回答