随着元界概念的流行,3D渲染相关技术被频繁提及,而Three.js是一个基于WebGL的api封装的框架,用于简化3D场景的开发,是一个开始使用3D的良好起点。今天我们将开始使用Three.js。我们是基于Three.js实现花瓣雨效果。Three.js的基础Three.js用于渲染一个3D场景,里面包含很多物体,比如立方体、圆柱体、环形体、圆锥体等几何形状(后缀为Geometry),比如Points和Lines)surface(Sprite)和其他基本对象。如何管理所有这些对象?使用一个场景Scene来承载,所有的物体都会被添加到这个Scene中。于是就有了这样一个api:constscene=newTHREE.Scene();scene.add(xxx);scene.add(yyy);当然,也可以将对象分组,对组内的对象进行统一管理,然后添加到场景中。constscene=newTHREE.Scene();constgroup=newTHREE.Group();group.add(xxx);group.add(yyy);scene.add(group);这个场景的概念,对象,分组,在很多游戏引擎中都有类似的API,大家也是这样管理的。可以添加到Scene中的物体,除了几何体(Geometry)、点线等,还有辅助工具,比如坐标系工具(AxisHelper)。其实这些工具也封装了聚合、点、线、面,只是作为工具暂时添加到Scene中而已。constaxisHelper=newTHREE.AxisHelper(max);scene.add(axisHelper)有了场景和场景中的各种物体,如何渲染它们呢?调用Renderer,这个类专门负责渲染Scene中的各种物体。但是还有一个问题,如何将三维世界(场景)渲染到二维屏幕上?如图所示,如果你从一个角度看三维世界,或者从一个平面平行看三维世界,你看到的是二维的。在这两种方法中,第一种称为透视,第二种称为正交。生成二维图像,就像相机的功能一样,所以这个概念就叫Camera。Three.js中有PerspectiveCamera(透视相机)和OrthographicCamera(正交相机),分别对应以上两种3D转2D的方式。这两个Camera的参数挺多的,但是理解起来还是蛮简单的:在透视相机上是的,它需要看三维世界,所以必须有两个位置,最近的和最远的,然后从一个点看就会有一个视角,看到的画面有纵横比。这就是为什么PerspectCamera有near、far、fov、aspect四个参数。正交相机的参数也类似,但是因为不是从一个点来看,而是从一个面做的投影来看,那么就没有角度参数,而是上、下、左四个面位置的参数,对了。正交相机的上下左右位置不是随机的。比例应该和屏幕的纵横比一样,所以一般这样计算:constwidth=window.innerWidth;constheight=window.innerHeight;//窗口纵横比constk=width/height;//上和三维场景的下范围consts=200;//上下范围s乘以纵横比k就是左右范围,给距离设置一个数字就可以了constcamera=newTHREE.OrthographicCamera(-s*k,s*k,s,-s,1,1000);上面正交相机的参数中,距离可以设置为1和1000,上下可以设置为200,左右可以根据纵横比计算。这是相机看到的二维图片的范围。有了场景中的各种物体Scene和相机Camera,就可以使用渲染器Renderer来渲染图片了。constrenderer=newTHREE.WebGLRenderer();//设置渲染区域大小renderer.setSize(width,height)renderer.render(scene,camera)但是一般不会只渲染一帧,如果有动画效果的话,将使用requestAnimationFrame的api逐帧不间断渲染。functionrender(){renderer.render(scene,camera)requestAnimationFrame(render)}render();Three.js的大致流程是这样的:场景有Geometry、点、线、面、辅助工具等各种对象,对象也可以做分组,然后设置通过正交或透视相机看到的二维图片,然后用Renderer渲染它。如果有动画效果,使用requestAnimationFrame逐帧渲染。接下来我们来实现一下花瓣雨的效果。要实现花瓣雨,我们首先需要在场景中创建对象,即各种花瓣。需要显示的是一个平面,我们可以使用Sprite。雪碧是精灵的意思。在Three.js中,它是一个始终面向相机的二维平面。我们只是将花瓣的纹理粘贴到Sprite上。我们准备一些花瓣贴图,像这样:花瓣很多,我们生成400个,加入花瓣组,然后加入场景:constscene=newTHREE.Scene();/***花瓣组*/constpetal=newTHREE.Group();functioncreate(){vartexture1=newTHREE.TextureLoader().load("img/h1.png");vartexture2=newTHREE.TextureLoader().load("img/h2.png");vartexture3=newTHREE.TextureLoader().load("img/h3.png");vartexture4=newTHREE.TextureLoader().load("img/h4.png");vartexture5=newTHREE.TextureLoader().load("img/h5.png");varimageList=[texture1,texture2,texture3,texture4,texture5];for(leti=0;i<400;i++){varspriteMaterial=newTHREE.SpriteMaterial({map:imageList[Math.floor(Math.random()*imageList.length)],//设置精灵贴图});varsprite=newTHREE.Sprite(spriteMaterial);petal.add(sprite);sprite.scale.set(40,50,1);sprite.position.set(2000*(Math.random()-0.5),2000*Math.random(),0)}scene.add(petal)}create();400个Sprites随机贴上不同花瓣的纹理贴图,然后设置缩放比例,然后在场景中随机设置一个位置。我们在Scene中添加一个坐标系辅助工具来查看坐标:constaxisHelper=newTHREE.AxisHelper(1000);scene.add(axisHelper)红色为x轴,向右递增,绿色为y轴,向上递增。我们暂时不会使用z轴。所以,根据代码,花瓣的x范围是随机的-1000到1000,y范围是0到2000。然后,我们创建一个正交相机:constwidth=window.innerWidth;constheight=window.innerHeight;//Windowaspectratioconstk=width/height;//三维场景上下范围consts=200;constcamera=newTHREE.OrthographicCamera(-s*k,s*k,s,-s,1,1000);设置相机的位置和方向:camera.position.set(0,200,500)camera.lookAt(scene.position)我们在创建相机的时候指定二维可以显示的范围定义,相机的任意位置在这个范围内是可以的。然后创建渲染器,设置大小和背景色,将渲染后的canvas元素插入到dom中。constrenderer=newTHREE.WebGLRenderer();//设置渲染区域的大小renderer.setSize(width,height)//设置背景色renderer.setClearColor(0xFFFFFF,1)//将canvas对象插入到body元素文档中.body.appendChild(renderer.domElement)然后使用requestAnimation逐帧连续渲染。functionrender(){petal.children.forEach(sprite=>{sprite.position.y-=1;sprite.position.x+=0.5;if(sprite.position.y<-400){sprite.position.y=800;}if(sprite.position.x>1000){sprite.position.x=-1000}});renderer.render(scene,camera)requestAnimationFrame(render)}在每次重新渲染之前,我们修改位置花瓣,产生飘落的效果。如果超出范围,则移动到顶部以再次开始下降。这是不间断的花瓣雨效果。完整代码如下:
