likes
comments
collection
share

React+Three.js实现一个被粒子包围的安卓机器人

作者站长头像
站长
· 阅读数 4

本篇文章已同步更新至个人公众号:Coffeeee

喜欢做动画的我很早之前就已经开始关注Threejs这个框架了,觉得这个框架老酷炫了,可以在浏览器中展示一个3D场景,奈何时间与精力关系(主要是懒)一直都没有真正花功夫去学,好在最近终于开始简单学了一点Threejs的皮毛,并且写了个安卓机器人的小demo,涉及到的知识点是一些简单的几何模型的使用,有兴趣的就来一起看下吧。

创建React项目

Threejs可以用在不同项目中,可以用纯js写,也可以用Vue来写,我这里使用的是React+ts,第一步咱先来创建个项目,使用cra创建

React+Three.js实现一个被粒子包围的安卓机器人

等待一段时间的项目初始化之后,在vscode中打开这个叫robot的工程,然后在终端里面分别执行以下命令

React+Three.js实现一个被粒子包围的安卓机器人

第一个命令是安装threejs这个库,第二个命令是安装@types/three这个库,后者是一个TypeScript的类型定义库,用于为 Three.js 库提供类型定义,库都安装好了之后我们打开项目为我们默认创建好的App.tsx文件,这个就是工程的示例页面,我们将在里面做改动

创建三要素

首先把App.tsx里面的代码都删除,换成如下代码

React+Three.js实现一个被粒子包围的安卓机器人

这里创建了一个div的Html元素containerRef,并且在div标签中引用它,而useEffect内部就是用来写我们Three的代码,在任何一个Three的工程中,有三个要素是必不可少的,那就是渲染器,相机以及场景,所以我们第一步就是将三个要素创建出来

React+Three.js实现一个被粒子包围的安卓机器人

一般都是使用透视相机PerspectiveCamera,第一个参数是fov,表示相机所成的一个四棱台远面与近面之间的夹角,夹角越小,看见的东西越少,夹角越大,看见的东西就越多,但是周围会显的比较模糊,一般取值以45~75最佳,第二个参数aspect是近裁面的一个宽高比,我们用窗口的宽除以窗口的高就可以了,第三个值near与第四个值far分别是与近面和远面的距离,这里设置的值分别为0.1与1000,调用camera.positon.set表示设置相机的位置,默认都是在(0,0,0)的位置,我们这里给相机设置的位置为(15,12,8),并且让相机正对(0,0,0)的位置,了解完了一些概念后,开始创建机器人相关的物体了

双脚

整个机器人是使用若干个几何体拼接起来的,所以我们从下往上先将双腿做出来

React+Three.js实现一个被粒子包围的安卓机器人

首先创建了一个Object3D对象robot对象,Object3D是一个基类,所有3D对象都是Object3D的子类或者衍生类,我们后面所创建的机器人身上的部位最终都会addrobot里面去,generateLegs是用来创建腿的函数,调用了两次,分别在(0,0,2)和(0,0,-2)位置创建了两个绿色的胶囊型物体,材质使用的是MeshStandardMaterial,并且设置了roughnessmetalness,让双腿有金属质感,然后用创建好的胶囊与材质生成Mesh后,腿就制作好了,添加到robot里去,并且将robot添加到场景scene里面,腿的工作就完成了,但是这个时候如果想去浏览器看下效果的话,会发现是漆黑一片的

React+Three.js实现一个被粒子包围的安卓机器人

原因是我们的材质是MeshStandardMaterial,这种材质是感光的,需要有光源照在上面才会看见,所以我们还需要在场景里面添加进去光源,这里使用平行光DirectionalLight

React+Three.js实现一个被粒子包围的安卓机器人

平行光的颜色是白色,强度设置的是5,这些可以根据自己的喜好去定义,光源所在的位置是(5,5,10),有了光源后,这样子就能看见腿了

React+Three.js实现一个被粒子包围的安卓机器人

身体

腿往上就是身体,身体是一个圆柱体,所以这里使用的是CylinderGeometry,并且在y轴方向上往上平移4个单位,看代码

React+Three.js实现一个被粒子包围的安卓机器人

CylinderGeometry第一个参数是上部分圆的半径,第二个参数是下部分圆的半径,第三个参数是高度,材质使用的跟腿一样,然后身体也出来了

React+Three.js实现一个被粒子包围的安卓机器人

手臂

两侧的手臂跟腿是差不多的做法,唯一区别就是位置不一样

React+Three.js实现一个被粒子包围的安卓机器人 React+Three.js实现一个被粒子包围的安卓机器人

脑袋

脑袋是个半球体,这里使用SphereGeometry创建个球体,半径设置为4,widthSegmentheightSegment都使用默认值,phiStartphiLength分别是水平方向上的起始角度与跨度,由于水平方向上是整个圆,所以phiLength设置为Math.PI * 2,相对的垂直方向上的跨度就是90度,这里给thetaLength设置为Math.PI * 0.5

React+Three.js实现一个被粒子包围的安卓机器人

脑袋在y轴方向上平移了6.5个单位,这个时候浏览器上面机器人的脑袋就已经出来了

React+Three.js实现一个被粒子包围的安卓机器人

触角

触角的位置要比脑袋还要高,同时它也要有点角度,所以创建个generateHorn函数,除了接受位置参数之外,还要接受角度参数,代码如下

React+Three.js实现一个被粒子包围的安卓机器人 React+Three.js实现一个被粒子包围的安卓机器人

眼睛

眼睛是两个黑色的球体,所以还是使用SphereGeometry,位于脑袋的内部,从脑袋里面露出来个半圆作为眼睛,代码如下

React+Three.js实现一个被粒子包围的安卓机器人 React+Three.js实现一个被粒子包围的安卓机器人

增加页面互动

我们看到整个机器人都已经出来了,但是目前页面还是不能够操作的,比如现在我们只看到机器人的一侧,另一侧是看不到的,当然这与我们相机摆放的位置有关,调整下相机的位置就好了,不过也可以使用轨道控制器OrbitControls,让页面可以跟着鼠标的操作360度移动,代码很简单,生成个轨道对象,再调用update方法

React+Three.js实现一个被粒子包围的安卓机器人

不过加了上述代码后,我们会发现页面还是动不了,因为我们还必须刷新页面,创建个update函数,内部调用requestAnimationFrame,这个函数的执行时机与浏览器的刷新频率是一致的,所以只需要在浏览器刷新的时候,再渲染一次页面,就能完成页面上的动画效果了,代码如下

React+Three.js实现一个被粒子包围的安卓机器人

现在我们的页面就可以操作了,来看下

React+Three.js实现一个被粒子包围的安卓机器人

我们还可以在update方法中,让机器人自己可以转动起来,比如让它绕着y轴转动,就可以这样写

React+Three.js实现一个被粒子包围的安卓机器人

可以看到只需要给robot在y轴上不断减少0.005的角度,机器人就可以自己转动起来了,效果如下

React+Three.js实现一个被粒子包围的安卓机器人

我们还可以让机器人变小一些,只需要在robotscale属性上,分别给x,y,z轴方向都设置上缩放比例,机器人的大小就改变了,这里设置了0.3的缩放比例

React+Three.js实现一个被粒子包围的安卓机器人

我们看下现在机器人的大小是不是改变了

React+Three.js实现一个被粒子包围的安卓机器人

的确是变小了,下面来给机器人周围加上一些粒子

制作粒子

这里粒子的原型其实就是一个个小球体,所以几何模型依然使用SphereGeometry,然后由于我们需要制作多个球体,所以还要创建一个Object3D,将所有粒子都放在Object3D里面,至于如何创建多个粒子,这里就用到了copy函数,看代码

React+Three.js实现一个被粒子包围的安卓机器人

给球体设置了widthSegmentheightSegment让球体带点棱角,其他的同上面设置的一样,最终生成一个物体mesh,在for循环内每次都会新生成一个targetMesh对象,通过调用copy函数,将mesh复制给target,那么target就拥有mesh的所有属性了,后面只需要给新的target设置新的位置就可以了,编译完之后,我们的机器人周围已经都是小粒子了

React+Three.js实现一个被粒子包围的安卓机器人

现在这些粒子看起来还不太美观,这里再稍作修改,把上面的金属质感metalness设置为5,粗糙程度roughness设置为0.1,改变一下粒子受光照的效果

React+Three.js实现一个被粒子包围的安卓机器人

再看下效果,粒子就变得好看些了

React+Three.js实现一个被粒子包围的安卓机器人

现在再让粒子360无死角转动起来,给stars的x,y,z上都加上旋转增量,更新一下update函数内的代码

React+Three.js实现一个被粒子包围的安卓机器人

最终效果就做好了

React+Three.js实现一个被粒子包围的安卓机器人

总结

文章到这里就结束了,用的东西都是比较入门的,诸如一些纹理图的加载,GLTF模型的加载等这样的知识点,我仍旧在学习摸索的过程中,后面也会通过一个个小的demo分享出来。