可能每个人的童年都有个时空穿梭梦,印象深刻的是第一次看《机器猫》,主角康夫卧室的抽屉就是时空隧道的入口,跳进隧道的那一刻,时间浮光掠影般从身边流过,仿佛进入了异世界。

这次我们用three.js实现一个3d隧道穿梭效果,打开异世界的大门。 它也可以是一个跑酷游戏原型,又或者是3D空间导航,具体怎么应用由你来决定,先来看下效果。

无限循环时空隧道

无限循环的隧道实际上是一个首尾无缝相连的管道,你可以将它的形状想象成一个甜甜圈。我们只要将摄像机放置在这个管道内部,并沿着管道路径运动就能实现这种穿越效果。

实现无限循环隧道

首先要实现这样一个管道我们可以借助three.js中TubeGeometry对象,TubeGeometry能够沿着一条3D曲线创建管道。我们要做的是先创建一条曲线,曲线是用坐标函数建立的,我们先拿TubeGeometry的官方示例试一下。

CustomSinCurve.prototype.getPoint = function ( t ) {
	var tx = t * 3 - 1.5
	var ty = Math.sin( 2 * Math.PI * t )
	var tz = 0
	return new THREE.Vector3( tx, ty, tz ).multiplyScalar( this.scale )
}

官方示例的getPoint函数绘制了一个烟斗状的曲线管道,看起来平淡无奇,别着急我们来逐步完善。

用官方示例绘制出的漏斗状曲线

改变下getPonit函数中的公式,我们马上得到了一个封闭的圆环管道。

CustomSinCurve.prototype.getPoint = function (t) {
  const tx = Math.cos(2 * Math.PI * t)
  const ty = Math.sin(2 * Math.PI * t)
  const tz = 0
  return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale)
}
封闭圆环隧道

为了让路径有更多变化,我们在z轴上也应用正弦函数,生成起伏状的圆环模型。

const tz = 0.1 * Math.sin(8 * Math.PI * t)
波浪状圆环隧道

为隧道添加材质

贴图是这个效果的灵魂,准备一张1024×1024尺寸的材质贴图,它会重复地显示在管道模型表面,注意贴图中明暗交替的线条,这是实现背景光线效果的关键。

隧道的材质贴图

设置材质的贴图方式和重复次数,使材质沿曲线方向重复延展,我们得到了一个贴好图的隧道模型。

material.map.wrapS = THREE.RepeatWrapping
material.map.wrapT= THREE.RepeatWrapping
material.map.repeat.set(10, 1)
贴图后的隧道

设置摄像机路径

要实现穿越效果,我们要将摄像机放在模型内部,并沿着隧道路径运动。官方的案例中也有一个相机沿曲线运动的例子,但经过试验效果并不理想,所以这里使用另外一种方法,这种方法考虑了隧道路径的法向量,使转弯处过渡效果更加自然。由于代码较长,就不贴在这里了,具体可以参考本篇教程的源文件。

沿路径添加物体

为了在隧道路径上添加物体,先要在管道路径上通过getPointAt方法上获得坐标点,然后将物体设置在坐标点处,这里的物体是一个个透明贴图的平面对象。

for(let i = 0; i < 20; i++) {
  const plane = mesh.clone()
  const pos = this.tubeGeometry.parameters.path.getPointAt(i * 0.04)
  plane.position.copy(pos)
  this.scene.add(plane)
}

最后,将这些平面对象旋转朝向摄像机,可以通过设置四元数属性和相机相同轻松搞定。四元数是3D空间旋转常用的数学方法,可以避免使用矩阵旋转时产生的万向锁问题,由于它数学原理比较复杂,这里就不做介绍了,有兴趣可以找相关资料学习。

this.planes.forEach(plane => {
  plane.quaternion.copy(this.camera.quaternion)
})

总结

我们已经掌握了如何使相机沿着自定义曲线运动,并实现了一个炫酷的空间隧道效果。接下来请发挥你的想象,做出更有趣的应用。

这里是一些建议:可以用three.js的postprocessing加入后期效果,使它更有科技感;可以加入鼠标交互,使摄像机根据鼠标滚轮向前移动;可以和cannon.js物理库结合,加入碰撞检测等等。

教程源文件:

https://github.com/imokya/threejs-tunnel-effect

关注