张春成

V2

2023/03/06阅读:24主题:默认主题

THREEJS 的三阶魔方

THREEJS 的三阶魔方

春去江花红胜火,春来江水绿如蓝,能不忆江南。这个周末气温回暖,草木发芽,于是在家有前端做了个虚拟化的三阶魔方。本文的开源代码可见我的前端笔记本

Rolling magic cube with THREE.js[1]


  • THREEJS 的三阶魔方[2]
    • 圆角方块[3]
    • 方块分组[4]
    • 定轴旋转[5]
    • 操作链表[6]
    • 平滑曲线[7]

圆角方块

圆角方块类是继承自 THREEJS 的 BoxGeometry,与基类的区别在于它是圆角的。通过简单地在每个面上贴上对应颜色的贴纸,我们就可以生成一个仿真性挺强的魔方。

Untitled
Untitled
Untitled
Untitled

方块分组

三阶魔方的旋转是一种挺复杂的东西。它包括 27 个块,从三个方向(axis)来看,它们分别组成三个面(level),每个面都有两个可能的旋转方向(dir),因此我们可以认为它的旋转自由度是 。对于如此大量的旋转动作来说,每个旋转动作都对应九个块。由于魔方的排列组合数量过多,因此这九个块是随机的。这就导致了一个问题,这个问题来自 THREE.js 的运行逻辑。

对于 THREE.js 来说,它的旋转操作是针对 Mesh 或 Mesh 的组合(Group),而为了提高执行效率起见,这些操作的对象都是事先定义好的。也就是说,如果要对某个面执行旋转动作,需要将它操作的九个块合并成一个组,再对这个组做旋转。而这样做显然是不经济的,因为每次旋转的块和面的关系无法事先确定。

因此,为了解决面的旋转问题,就需要程序根据要旋转的面“找到”它对应的九个块,再将这九个块进行同步旋转。找到九个块可以做到,而让它们进行同步旋转时就遇到另一个问题,那就是旋转轴不是块的中心。

定轴旋转

接下来要解决的问题是对块进行旋转,并且旋转轴不是块的中心,它甚至都不在块的内部。为了解决这个问题,我将全部块的转动轴都设置在魔方的中心,再将转动轴作为虚拟成员与每个块进行绑定,由于核心代码很短,因此誊写如下。接下来,只要将这些块所在的组进行旋转,就可以实现块沿着转动轴而不是自己的中心进行旋转。从使用者的角度来看,就是某个平面的九个块进行整体旋转的效果。

/**
 * Generate pivot and bound it with the cube,
 * the combination is a group.
 */


const pivot = new THREE.Group();

// The sub-cube
const material = new THREE.MeshNormalMaterial(),
  size = 0.95,
  geometry = new RoundedBoxGeometry(size, size, size, 200.1),
  cube = new THREE.Mesh(geometry, material);

Object.assign(cube.position, position);
pivot.add(cube);

操作链表

对于魔方来说,我们希望它旋转,但不希望它自由旋转。也就是说,每个面的每次旋转经过的弧度必须是 ,否则就会出现物理干涉的情况。另外,我们还需要实现一定的动效,让魔方看上去像是正常旋转的样子。这就要求它每次都精确地旋转一定角度,而某次旋转完成之前不应进行其他旋转。

为了满足上述要求,我建立了一个“操作链表”,它当然是 FIFO 的,链表中的元素是每个时间切片的旋转操作。在每个时间切片中,魔方的某个面只旋转一个较小的角度。而一次完整的 旋转则由多次时间切片构成。由于链表具有 FIFO 特性,因此它总能保证旋转操作的完整性。

平滑曲线

最后,为了使得旋转过程更像真实的物理旋转场景,我将每个时间切片的旋转角度进行映射,映射函数如下图所示。它代表开始和结束时的变化率较小,而中段的变化率较大。体现在旋转动作上,它代表开始和结束转动时的速度变化较小,而中段的旋转速度变化较大,即角速度呈现先增大后减小的规律性变化。

Untitled
Untitled

参考资料

[1]

Rolling magic cube with THREE.js: https://observablehq.com/@listenzcc/rolling-magic-cube-with-three-js

[2]

THREEJS 的三阶魔方: #threejs-的三阶魔方

[3]

圆角方块: #圆角方块

[4]

方块分组: #方块分组

[5]

定轴旋转: #定轴旋转

[6]

操作链表: #操作链表

[7]

平滑曲线: #平滑曲线

分类:

后端

标签:

后端

作者介绍

张春成
V2