gknpezgssb

使用Three.js制作无穷隧道

gknpezgssb · 2017-05-16翻译 · 914阅读 原文链接

一些有WebGL体验的页面,浏览者有种在一个带有材质的隧道中穿梭的感受。这有赖于Three.js以及由fornasetti.com带来的灵感。

InfiniteTubesWithThreeJS_Featured

例子地址 下载资源

WebGL变得原来越流行,我们可以看到一些列的网站使用WebGL来达到惊艳且具创造力的效果。 Fornasetti 近期发布了一个网站,其中借助WebGL达到了极好的效果:让我们身临穿梭于带有不断变换背景的隧道之中的运动。最有趣的莫过于可以通过鼠标控制我们穿梭的方向。本文将分享一些类似的Three.js管道运动。 注意: 你的浏览器需要支持WebGL(> IE10)以便可以浏览这些例子。

Screenshot of Fornasetti's website

Fornasetti的网站截图

起步

在例子中我们会使用Three.js这个常用的库,来使构建WebGL效果更为便捷。在生成隧道前,我们先需要创建渲染器(renderer),场景(scene)以及相机(camera)。

当你对于使用Three.js不是那么顺畅,我建议你先阅读一些入门课程。这里提供一个Rachel Smith写的三部分的入门课程

一旦创建好了场景(scene)我们就可以继续下面的流程:

  1. 创建一条曲线来确定隧道的形状

  2. 生成基于曲线的隧道

  3. 向前移动

  4. 增添交互

曲线

有赖于Three.js,我们有好用的函数用来基于一组点去创建曲线。我们首先需要计算这些点的位置,一旦完成这一步骤,我们可以用如下方法创建曲线:

// 穿建空数组来储存点
var points = [];

// 点沿z轴方向定义
for (var i = 0; i < 5; i += 1) {
    points.push(new THREE.Vector3(0, 0, 2.5 * (i / 4)));
}

// 创建基于点的曲线
var curve = new THREE.CatmullRomCurve3(points)

在实际过程中,我们会改变曲线来保证管道形状变化。如你所见,所有的点都有相同的x,y值。目前,这条曲线还只是简单的直线。

隧道

现在我们有了一条曲线(一点也不弯),我们可以使用Three.js来创建一个隧道。为此我们需要:何体模型(用来描述管道的形状),材质(用来展示管道的视觉效果)以及最终的将几何体与材质结合成网格(mesh)。

// 基于曲线创建一个隧道几何模型
// 每个值的含义: 
// 70 : 隧道模型的轴向片段数
// 0.02 : 曲率(虽然是个小隧道)
// 50 : 隧道模型径向片段数
// false : 用来决定隧道模型是否闭合
var tubeGeometry = new THREE.TubeGeometry(this.curve, 70, 0.02, 50, false);

// 用一张纹理贴图而非单一的颜色来作为隧道呈现的材质
var tubeMaterial = new THREE.MeshStandardMaterial({
    side: THREE.BackSide, // Since the camera will be inside the tube we need to reverse the faces
    map: rockPattern // rockPattern is a texture previously loaded
});
// 使用重复图案填充以防止纹理被拉伸Repeat the pattern to prevent the texture being stretched
tubeMaterial.map.wrapS = THREE.RepeatWrapping;
tubeMaterial.map.wrapT = THREE.RepeatWrapping;
tubeMaterial.map.repeat.set(30, 6);

// 基于tubeGeometry与tubeMaterial创建网格(mesh)
var tube = new THREE.Mesh(tubeGeometry, tubeMaterial);

// 将隧道添加进场景(sence)
scene.add(this.tubeMesh);

向前移动

由于运动的原理并非我最初所想,这震撼到了我,因此这是我最喜欢的部分。我最初认为隧道实际上沿相机的方向运动,之后我觉得因该让相机移动进隧道中。但这两种想法都是错误的。

实际的解决方案非常巧妙: 场景中没有任何物体发生了实际的运动,发生的仅仅只是隧道贴图位置的移动.

为此,我们需要对每一帧的贴图都定义一个偏移量从而实现视觉上的运动

function updateMaterialOffset() {
  // 以定义的速度来更新材质的偏移量
  tubeMaterial.map.offset.x += speed;
};

用户交互

没有用户交互的例子不是好例子。当你的鼠标在浏览器上移动的时候,你可以控制隧道的形状。这里的小技巧去更新我们在第一个步骤中创建的曲线。一旦曲线改变了,我们便可以借由一些过渡来更新隧道。

// 更新第三个的在x轴及y轴上的位置
curve.points[2].x = -mouse.position.x * 0.1;
curve.points[2].y = mouse.position.y * 0.1;

// 更新最后一个点的x轴位置
curve.points[4].x = -mouse.position.x * 0.1;

万事大吉?

其实并没有,实际的代码会比文章中提到的更复杂一点。但是如果你理解了以上的步骤,那么对例子是如何运作的原理会有大致的认识。如果你希望更深入地理解,查看第一个例子的源码。我已收到大量的评论。如果你依然有困惑,不要犹豫来Twitter上找我吧。

例子

一旦你有了基础的隧道模型,你可以不同的方向来改造它。浏览一下例子可以给你一些启发!

InfiniteTubes_01

上文中介绍过的砖块图案。

Screenshot of a low poly particles demo - Infinite Tubes with Three.js

点击你的鼠标或者是点按屏幕来释放粒子彩虹!

Screenshot of an hyperspace demo - Infinite Tubes with Three.js

这个例子灵感来源于科幻电影的时空穿梭。

Screenshot of a blood vessel demo

进入你的身体,观察一下血管吧:)

Screenshot of a demo with a triangle tube - Infinite Tubes with Three.js

为何所有的隧道都是圆的?是时候让我们穿梭在三角形的隧道中了。

InfiniteTubes_06 - Infinite Tubes with Three.js

在手机或平板上尝试这个例子,并通过设备朝向来控制方向!

感谢您阅读本文!

有任何问题欢迎到原文讨论

引用

译者gknpezgssb尚未开通打赏功能

相关文章