Three.js基础入门(一)

29,684 阅读19分钟

image-20191222145622759

一、学习收获

1、OpenGL、WebGL、Canvas、Three.js四者关系

2、Three.js 三大要素

3、Three.js基本要素

4、Three.js 相关插件的使用

5、使用Three.js展示3D几何体效果

二、主要内容:

1、Three.js前提须知

讲到 Three.js,就需要先说一下 OpenGL 和 WebGL, OpenGL 是一个跨平台的3D/2D的绘图标准(规范),WebGL(Web Graphics Library)是一种3D绘图协议,它允许把JavaScript和OpenGL 结合在一起运用,但使用WebGL原生的API来写3D程序非常的复杂,同时需要相对较多的数学知识,对于前端开发者来说学习成本非常高。

1.1 WebGL

WebGL是一种Javascript的3D图形接口,把JavaScript和OpenGL ES 2.0结合在一起。

1.2 OpenGL

OpenGL是开放式图形标准,跨编程语言、跨平台,Javascript、Java 、C、C++ 、 python 等都能支持OpenGL ,OpenGL的Javascript实现就是WebGL。OpenGL ES 2.0是OpenGL的子集,针对手机、游戏主机等嵌入式设备而设计。

1.3 Canvas

Canvas是HTML5的画布元素,在使用Canvas时,需要用到Canvas的上下文,可以用2D上下文绘制二维的图像,也可以使用3D上下文绘制三维的图像,其中3D上下文就是指WebGL。

2、Three.js是什么?

官网:Javascript 3D library(JavaScript 3D 库)。Three.js是基于webGL的封装的一个易于使用且轻量级的3D库,Three.js对WebGL提供的接口进行了非常好的封装,简化了很多细节,大大降低了学习成本,极大地提高了性能,功能也非常强大,用户不需要详细地学习 WebGL,就能轻松创作出三维图形,是前端开发者研发3D绘图的主要工具。微信小游戏跳一跳也是在基于Three.js研发的,Threejs现在是独领风骚。

简言之:Three.js就是能够实现3D效果的JS库

3、OpenGL、WebGL、Canvas、Three.js四者关系

OpenGL:3D绘图标准

WebGL:OpenGL + JavaScript

Canvas:WebGL + Canvas 2D

Three.js:一个基于WebGL封装的库

类似于:

ECMAscript:脚本语言规范

JavaScript:脚本语言

jQuery: 一个基于JavaScript封装的库

简单一句话概括:WebGL和Three.js的关系,相当于JavaScript和jQuery的关系。

image-20191224104833578

4、Three.js应用场景有哪些?

(1)Web 3D游戏

image-20191220163750333

(2)3D物体模型展示

image-20191220163943163

(3)数据可视化

image-20191220165040142

(4)Web VR

image-20191220165905816

(5)其它特殊效果展示

image-20191220165237441

5、Three.js入门准备

1、支持WebGL的浏览器:

  • Google Chrome 9+
  • Firefox 4+
  • Opera 15+
  • Safari 5.1+
  • Internet Explorer 11
  • Microsoft Edge

**推荐使用Chrome浏览器 **

2、Three.js中三维坐标系

在Three.js 中,空间是基于右手笛卡尔坐标系展示的:

image-20191220173717069

Three .js中的三维坐标系:

image-20191220173914094

image-20191220173945690

3、Three.js库引入的两种方式

1、通过CDN方式引入<script src="https://cdn.bootcss.com/three.js/92/three.js"></script>

2、或者把Three.js下载到本地,直接引入<script src="./three.js"></script>

6、Three.js基础案例展示

<html>

<head>
    <title>Three.js基础案例</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }

        canvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
    <script>
       
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(
            50, 
            window.innerWidth / window.innerHeight, 
            0.1, 
            1000 
        );
        camera.position.set(5, 10, 10);
        var renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);
        var geometry = new THREE.BoxGeometry(4, 4, 4);
        var materialBasic = new THREE.MeshBasicMaterial({
            color: 0xffffff, 
            wireframe: true 
        });
        var materialNormal = new THREE.MeshNormalMaterial();
        var cube = THREE.SceneUtils.createMultiMaterialObject(geometry, [
            materialBasic,
            materialNormal
        ]);
        camera.lookAt(cube.position);
        scene.add(cube);
        var spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(0, 20, 20);
        spotLight.intensity = 5;
        scene.add(spotLight);
        var axes = new THREE.AxisHelper(6);
        scene.add(axes);
        renderer.render(scene, camera);
    </script>
</body>

</html>

想要使用三维空间,需要创建一个三维空间的容器,我们通常把这个容器叫做场景。

7、Thress.js 三大要素(核心):

场景(scene)、相机(camera)、渲染器(renderer)

相机获取到场景内显示的内容,然后再通过渲染器渲染到画布上面

1、场景(scene)

场景是一个三维空间,是存放所有物品的容器,可以把场景想象成一个空房间,房间里面可以放置要呈现的物体、相机、光源等。

image-20191222114437092

场景允许在什么地方、摆放什么东西来交给three.js来进行渲染,场景也就是放置物体、灯光和相机的地方。

创建场景:要构件一个场景很简单,只需要new一个场景对象出来即可:var scene = new THREE.Scene()

var scene = new THREE.Scene(); // 创建场景

2、相机(camera)

在场景中需要添加一个相机,相机用来确定观察位置、方向、角度,相机看到的内容,就是我们最终在屏幕上看到的内容。在程序运行过程中,可以调整相机的位置、方向、角度。

想象一下,在房间里放了一个摄像机,你不在房间里面,但可以远程控制相机移动,摄像机传给远程电脑上展示出来的画面,就是Threejs在屏幕上呈现的画面。

在Three.js中有两种常用的相机:透视投影相机(perspectiveCamera)和正交投影相机(OrthographicCamera )

透视投影相机(perspectiveCamera)【重要】

特点透视相机的效果是模拟人眼看到的效果,跟人眼看到的世界是一样的,近大远小。

用途大部分场景都适合使用透视投影相机,因为跟真实世界的观测效果一样;

image-20191220183433420

创建透视投影相机:var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);

参数介绍
fov视野:表示摄像机能看到的视野。推荐默认值50
aspect指定渲染结果水平方向和竖直方向长度的比值,推荐默认值为窗口的宽高比,即window.innerWidth/window.innerHeight,如果比例设置的不对,会发现渲染出来的画面有拉伸或者压缩的感觉。
near近端渲染距离:指定从距离摄像机多近的位置开始渲染,推荐默认值0.1
far远端距离:指定摄像机从它所在的位置最远能看到多远,太小场景中的远处不会被渲染,太大会浪费资源影响性能,推荐默认值1000。

近端渲染距离和远端距离:这两个是设置相机可以看到的场景内容的范围,只有离相机的距离大于near值,小于far值,且在相机的可视角度之内,才能被相机投影到。

var camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);// 创建透视投影相机

// 设置相机位置
camera.position.x = 5;
camera.position.y = 10;
camera.position.z = 10;
// 以上设置相机位置可以简写为:
camera.position.set(5, 10, 10);

正交投影相机(OrthographicCamera )

特点正交投影则远近都是一样的大小,三维空间中平行的线,投影到二维空间也一定是平行的。

用途一般是用在制图、建模等方面,方便观察模型之间的大小比例。

image-20191220183241633

创建正交投影相机:var camera = new THREE.OrthographicCamera( left,right, top,bottom, near, far )

参数介绍
left可被渲染空间的左端面
right可被渲染空间的右端面
top可被渲染空间的上端面
bottom可被渲染空间的下端面
near基于相机所在位置,可被渲染空间的近端面
far基于相机所在位置,可被渲染空间的远端面

以上6个参数规定了相机视景体的左、右、上、下、前、后六个面的位置,这六个投影面围成的区域就是相机投影的可见区域。在三维空间内,只有在这个区域内的物体才会被相机看到。

var camera = new THREE.OrthographicCamera(-2, 2, 1, -1, 1, 10); // 创建正交投影相机

// 设置相机位置
camera.position.x = 5;
camera.position.y = 10;
camera.position.z = 10;
// 以上设置相机位置可以简写为:
camera.position.set(5, 10, 10);

正交投影和透视投影对比:

image-20191222113407660

左图是正交投影,物体反射的光平行投射到屏幕上,其大小始终不变,所以远近的物体大小一样。

右图是透视投影,符合我们平时看东西的感觉,近大远小。

3、渲染器(renderer)

渲染器的作用就是将相机拍摄出的画面在浏览器中呈现出来。渲染器决定了渲染的结果应该画在页面的什么元素上面,并且以怎样的方式来绘制。

Three.js中有很多种类的渲染器,例如webGLRenderer、canvasRenderer、SVGRenderer,通常使用的是WebGLRenderer渲染器。

创建WebGLRenderer渲染器:var renderer = new THERR.WebGLRenderer();

创建完渲染器后,需要调用render方法将之前创建好的场景和相机相结合从而渲染出来,即调用渲染器的render方法:renderer.render(scene,camera)

var renderer = new THREE.WebGLRenderer(); // 创建一个 WebGL 渲染器
renderer.setSize(window.innerWidth, window.innerHeight); // 通过调用 setSize() 方法设置渲染的长宽(设置渲染器为全屏)
document.body.appendChild(renderer.domElement); // 将渲染结果展示到页面上
renderer.render(scene, camera); // 结合场景和相机进行渲染,即用摄像机拍下此刻的场景(最后一步)

说明:

  • setSize() 方法设置渲染的长宽。
  • renderer 的 domElement 元素,表示渲染器中的画布,所有的渲染都是画在 domElement 上,所以这里的 appendChild 表示将这个 domElement 挂接在 body 下面,这样渲染的结果就能够在页面中显示了。
  • render()方法中传递我们的场景和相机,相当于传递了一张由相机拍摄场景得到的一张底片,它将图像渲染到我们的画布中。

以上就是Three.js中完成3D绘图的三大要素(场景、相机、渲染器),利用这三大要素,我们才能够使用相机将场景渲染到网页上去。

总结:场景,相机,渲染器

场景是一个三维空间,用来存放一个物体的容器,我们可以将需要的物体放入场景中,例如苹果,葡萄。同时,物体自身也管理着其在场景中的位置。

相机相机的作用就是面对场景,在场景中取一个合适的景,把它拍下来。

渲染器渲染器的作用就是将相机拍摄下来的图片,放到浏览器中去显示。

场景,相机,渲染器之间的关系如下图所示:

image-20191222155115646

8、Three.js 基本要素

思考:我们有了场景、相机、渲染器,除了这些还需要什么,才能展示3D图像?

image-20191222121200179

这张照片就基本可以说明我们 Three.js 的 3D 设计模式:我们有了一个场景之后,我们需要将一个物体(拍摄对象)放进去。有了物体之后我们还需要设置至少一个光源,这样我们才能看到这个物体。最后,呈现在客户眼前的是一系列由相机所拍摄出的照片连续播放产生的动画,相机的参数、位置和角度直接影响着我们所拍到的图片。

结论我们需要在场景中放置:物体(拍摄对象)、光源,才能展示3D图像。

Three.js 基本要素:

  • 物体(拍摄对象)
    • 几何体模型(Geometry)
    • 材质(Material)
    • 网格(Mesh)
  • 光源

9、 Three.js 创建物体(拍摄对象)的设计模式

在计算机世界里,3D世界是由点组成,两个点能够组成一条直线,三个不在一条直线上的点就能够组成一个三角形面,在 Three.js中 将任何物体(拍摄对象)结构为一个个小三角形。无论是二维图形还是三维图形,都可以用小三角形作为结构最小单位。而结构出来的就是我们拍摄对象的一个网格。

二维平面的网格结构:

image-20191222144831523

三维球体网格结构:

image-20191222144850486

可以看到在 Three.js 中三角形是最小分割单位,这就是网格结构模型,我们通常把这种网格模型叫做Mesh模型,Mesh模型是三维开发中使用的最为广泛的模型。

总结绘制3D模型,常用的做法是用三角形组成的网格来模拟,如下图所示,用足够多的三角形时,兔子的身体看起来就足够平滑,跟真实兔子比较接近。著名的斯坦福兔子模型用了69451个三角形。

image-20191222161337724

当然有网格结构还是不够的。就像人体一样,因为网格结构就像是骨架,在其外表还需要材质。材质就是物体的纹理(皮肤),决定着几何体模型的外表。

10、Three.js中的基本要素:几何体模型(Geometry)

在Three.js中为我们预设了一些二维和三维几何体模型

二维几何体模型:

PlaneGeometry(平面几何体)

在线示例:www.webgl3d.cn/threejs/doc…

image-20191222150017496

CircleGeometry(圆形几何体)

在线示例:www.webgl3d.cn/threejs/doc…

image-20191222150459785

RingGeometry(圆环几何体)

在线示例:www.webgl3d.cn/threejs/doc…

image-20191222150424628

三维几何体模型:

BoxGeometry(立方几何体)

在线示例:www.webgl3d.cn/threejs/doc…

image-20191222150859882

SphereGeometry(球几何体)

在线示例:www.webgl3d.cn/threejs/doc…

image-20191222150936009

CylinderGeometry(圆柱几何体)

在线示例:www.webgl3d.cn/threejs/doc…

image-20191222151023221

TorusGeometry(圆环几何体)

在线示例:www.webgl3d.cn/threejs/doc…

image-20191222151106137

TubeGeometry(管道几何体)

在线示例:www.webgl3d.cn/threejs/doc…

image-20191222151133144

……

以上所举几何体模型是Three.js中内置几何体的一部分,我们在使用这些几何体的时候,我们只需要实例化(创建)相应几何体对象即可。

例如:实例化一个立方几何体

var geometry = new THREE.BoxGeometry(1, 1, 1); // 创建一个长、宽、高均为1个单位的立方体	

但是有了这么一个网格几何体是远远不够的,下一步就是给几何体添加材质(皮肤)。

11、Three.js中的基本要素:材质(Material)

Three.js 也为我们预设了几种材质对象,这里简单的介绍三种:

基础网格材质(MeshBasicMaterial)【常用】

一个以简单着色(平面或线框)方式来绘制几何体的材质,这种材质不受光照的影响。

在线示例:www.webgl3d.cn/threejs/doc…

image-20191222154347439

Lambert网格材质(MeshLambertMaterial)【常用】

一种非光泽表面的材质,没有镜面高光。这种材质可以很好地模拟一些表面(例如未经处理的木材或石材),但不能模拟具有镜面高光的光泽表面(例如涂漆木材)。

在线示例:www.webgl3d.cn/threejs/doc…

image-20191222161543799

法线网格材质(MeshNormalMaterial)【拓展:不常用】

一种RGB颜色的材质

在线示例:www.webgl3d.cn/threejs/doc…

image-20191222162114925

特殊说明:在同一个网格结构中我们可以多种材质进行叠加。

var materialBasic = new THREE.MeshBasicMaterial({
    color: 0xffffff, // 白色
    wireframe: true // //是否将几何体渲染为线框,默认值为false(即渲染为平面多边形)
}); // 创建基础网格材质
var materialNormal = new THREE.MeshNormalMaterial(); // 创建法线网格材质

12、Three.js中的基本要素:网格(Mesh)

当我们拥有了几何体模型和材质之后,我们需要通过一个网格(Mesh)将两者结合起来,创建我们正在的拍摄对象。

两种不同的拍摄对象构造方法:

  • new THREE.Mesh(geometry, material)
  • THREE.SceneUtils.createMultiMaterialObject(geometry,[materials...])

第一个参数代表物体的形状,第二个参数代表物体的材质。

以上两种都是创建拍摄对象的方法,第一个参数都是几何体模型(Geometry),唯一不同在于第二个参数。前者只能用一种材质创建拍摄对象,后者可以使用多种材质进行创建(传入一个包含多种材质的数组)。

// 创建一种网格,将材质包裹在几何体模型上
var cube = new THREE.Mesh(geometry, material); 

// 创建多种网格,将材质包裹在几何体模型上
var cube = THREE.SceneUtils.createMultiMaterialObject(geometry, [
    materialBasic,
    materialNormal
]);

// 让相机 看向(对着)物体(拍摄对象)的位置(默认状态下,相机将指向三维坐标系的原点。)
camera.lookAt(cube.position);

现在我们已经有一个拍摄对象了,这时候我们需要将我们的拍摄对象(物体)添加到场景中,就像我们在拍摄商品一样,得要把我们的商品放在拍摄空间之中。

在 Three.js 中,向场景中添加对象可以直接通过场景对象调用 add 方法实现。

// 将网格添加到场景中
scene.add(cube);

物体之所以能被人眼看见,一种是它自身的材料就能发光,不需要借助外界光源;另一种是自身材料不发光,需要反射环境中的光。对于自身不能发光的物体,需要给场景添加光源从而达到可视的效果

13、Three.js中的基本要素:光源(Light)

在Three.js中可以创建出很多不同类型的光源:

环境光(AmbientLight)

环境光是一种基本光源,它会均匀的照亮场景中的所有物体,环境光没有特定的来源方向,且不会产生阴影。

image-20191224105142465

聚光灯(SpotLight)

聚光灯(类似手电筒、舞台聚光灯)是从一个方向上的一个点发出,沿着一个圆锥体,它离光越远,它的尺寸就越大。这种光源会产生阴影。

image-20191222181047560

image-20191224105119016

平行光(DirectionalLight)

平行光是沿着特定方向发射的光。这种光的表现像是无限远,从它发出的光线都是平行的。常常用平行光来模拟太阳光 的效果; 太阳足够远,因此我们可以认为太阳的位置是无限远,所以我们认为从太阳发出的光线也都是平行的。这种光源会产生阴影。

在Three.js中创建光源实例:

// 创建光源
var spotLight = new THREE.SpotLight(0xffffff);
// 设置光源位置
spotLight.position.set(0, 20, 20);
// 设置光源照射的强度
spotLight.intensity = 5;
// 将光源添加到场景中
scene.add(spotLight);
  • position.set() 方法设置在三维空间中的位置。
  • intensity 属性用于设置光源照射的强度,默认值为 1。

14、在Three.js中添加三维坐标系对象

为了方便观察3D图像,添加三维坐标系对象

image-20191222183237879

 // 为了方便观察3D图像,添加三维坐标系对象
var axes = new THREE.AxisHelper(4); // 坐标系轴长设置为 4
//  把三维坐标系 添加到场景中
scene.add(axes);

15、使用Three.js,在屏幕上展示 3D 图形的大概步骤:

  1. 创建一个三维空间场景( Scene );
  2. 创建一个相机( Camera ),确定一个观察点,并设置相机的观察方向和角度;
  3. 创建渲染器,设置渲染器的长宽,将渲染结果展示到页面上;
  4. 创建物体(几何体、材质、网格)、光源(同时设置光源位置),并添加到场景中去;
  5. 最后通过渲染器,把场景、相机渲染到页面上。

16、使用Three.js,实现一个基础案例

<html>

<head>
    <title>Cube</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }

        canvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <!-- 引入three.js -->
    <script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
    <script>
        // 1、创建场景
        var scene = new THREE.Scene();

        // 2、创建相机(透视投影相机)
        var camera = new THREE.PerspectiveCamera(
            50, // 相机视野
            window.innerWidth / window.innerHeight, // 水平方向和竖直方向长度的比值
            0.1, // 近端渲染距离
            1000 // 远端渲染距离
        );
        // 2.1 设置相机位置
        // camera.position.x = 5;
        // camera.position.y = 10;
        // camera.position.z = 10;
        // 2.1 设置相机位置简写方式:
        camera.position.set(5, 10, 10);

        // 3、创建渲染器
        var renderer = new THREE.WebGLRenderer();
        // 3.1 设置渲染器的大小(长宽)(设置渲染器为全屏)
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 3.2 将渲染结果展示到页面上
        document.body.appendChild(renderer.domElement);
      
        // 4、创建几何体模型(立方几何体)
        var geometry = new THREE.BoxGeometry(4, 4, 4);

        // 5、创建材质(基础网格材质和法线网格材质)
        // 5.1 创建基础网格材质
        var materialBasic = new THREE.MeshBasicMaterial({
            color: 0xffffff, // 白色
            // color: 0x00ff00, // 绿色
            wireframe: true //是否将几何体渲染为线框,默认值为false(即渲染为平面多边形)
        });
        // 5.2 创建法线网格材质
        var materialNormal = new THREE.MeshNormalMaterial();

        // 6、创建多种网格(因为有多个材质)
        // 第一个参数是几何模型,第二参数是材质
        var cube = THREE.SceneUtils.createMultiMaterialObject(geometry, [
            materialBasic,
            materialNormal
        ]);
      
      	// 6.1、将网格添加到场景中
        scene.add(cube);
        // 6.2 让相机 看向(对着)物体(拍摄对象)的位置(默认状态下,相机将指向三维坐标系的原点。)
        camera.lookAt(cube.position);
        
        // 7、创建光源
        var spotLight = new THREE.SpotLight(0xffffff);
        // 7.1 设置光源位置
        spotLight.position.set(0, 20, 20);
        // 7.2 设置光源照射的强度,默认值为 1
        spotLight.intensity = 5;
        // 7.3 将光源添加到场景中
        scene.add(spotLight);
      
        // 8、为了方便观察3D图像,添加三维坐标系对象
        var axes = new THREE.AxisHelper(6);
        scene.add(axes);
      
        // 9、 结合场景和相机进行渲染,即用摄像机拍下此刻的场景
        renderer.render(scene, camera);
    </script>
</body>

</html>

17、Three.js中的动画(Animation)

动画原理

动画实际上是由一些列的图片在一定时间内,以一定的频率播放而产生的错觉。

眼睛的一个重要特性是视觉惰性,即光象一旦在视网膜上形成,视觉将会对这个光象的感觉维持一个有限的时间,这种生理现象叫做视觉暂留性。人眼观看物体时,成像于视网膜上,并由视神经输入人脑,感觉到物体的像。一帧一帧的图像进入人脑,人脑就会将这些图像给连接起来,形成动画。对于中等亮度的光刺激,视觉暂留时间约为 0.1 至 0.4 秒。

为了让动画以连贯、平滑的方式进行过渡,一般我们以 60 帧/秒,甚至更高的速率渲染动画。

创建动画

在Three.js中使用 requestAnimationFrame()方法来创建动画。因为动画需要以一定的频率播放,所以需要创建一个循环渲染的函数,并且最后要调用这个函数。

// 动画 循环渲染的函数
function animate() {
	//循环调用函数
  requestAnimationFrame(animate);

  // (此处需要更新的属性……的代码)

  // 渲染器结合场景和相机进行渲染
  renderer.render(scene, camera);
}

以上在循环渲染的函数体内部进行相应的属性更新并渲染,并且让浏览器来控制动画帧的更新。

制作动画(在原代码基础上)

通过 requestAnimationFrame(animate)来使浏览器在每次更新页面的时候调用 animate 方法。且每调用一次,l立方体的属性就作出相应的改变:每一次调用都比上一次 X 轴、Y 轴各旋转 0.01 弧度,并且将其渲染到画布上。

function animate() {
  	//循环调用函数
    requestAnimationFrame(animate);
  	// 每一次animate函数调用,都让网格比上一次 X 轴、Y 轴各旋转增加 0.01 弧度
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    // 渲染器结合场景和相机进行渲染
    renderer.render(scene, camera);
};
animate();

查看动画效果(动画版完整代码)

<html>

<head>
    <title>Cube</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }

        canvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
  	<!-- 引入three.js -->
    <script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
    <script>
        // 1、创建场景
        var scene = new THREE.Scene();

        // 2、创建相机(透视投影相机)
        var camera = new THREE.PerspectiveCamera(
            50, // 相机视野
            window.innerWidth / window.innerHeight, // 水平方向和竖直方向长度的比值
            0.1, // 近端渲染距离
            1000 // 远端渲染距离
        );
        // 2.1 设置相机位置
        // camera.position.x = 5;
        // camera.position.y = 10;
        // camera.position.z = 10;
        // 2.1 设置相机位置简写方式:
        camera.position.set(5, 10, 10);

        // 3、创建渲染器
        var renderer = new THREE.WebGLRenderer();
        // 3.1 设置渲染器的大小(长宽)(设置渲染器为全屏)
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 3.2 将渲染结果展示到页面上
        document.body.appendChild(renderer.domElement);
      
        // 4、创建几何体模型(立方几何体)
        var geometry = new THREE.BoxGeometry(4, 4, 4);

        // 5、创建材质(基础网格材质和法线网格材质)
        // 5.1 创建基础网格材质
        var materialBasic = new THREE.MeshBasicMaterial({
            color: 0xffffff, // 白色
            wireframe: true //是否将几何体渲染为线框,默认值为false(即渲染为平面多边形)
        });
        // 5.2 创建法线网格材质
        var materialNormal = new THREE.MeshNormalMaterial();

        // 6、创建多种网格(因为有多个材质)
        // 第一个参数是几何模型,第二参数是材质
        var cube = new THREE.Mesh(geometry, materialNormal);
        // 6.1 让相机 看向(对着)物体(拍摄对象)的位置(默认状态下,相机将指向三维坐标系的原点。)
        camera.lookAt(cube.position);
        // 6.2、将网格添加到场景中
        scene.add(cube);
        // 7、创建光源
        var spotLight = new THREE.SpotLight(0xffffff);
        // 7.1 设置光源位置
        spotLight.position.set(0, 20, 20);
        // 7.2 设置光源照射的强度,默认值为 1
        spotLight.intensity = 5;
        // 7.3 将光源添加到场景中
        scene.add(spotLight);
        // 8、为了方便观察3D图像,添加三维坐标系对象
        var axes = new THREE.AxisHelper(6);
        scene.add(axes);
        // 9、创建动画循环渲染函数
        function animate() {
            // 9.1 循环调用函数
            requestAnimationFrame(animate);
            // 每一次animate函数调用,都让网格比上一次 X 轴、Y 轴各旋转增加 0.01 弧度
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;
            // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景
            renderer.render(scene, camera);
        };
        // 调用动画函数
        animate();
    </script>
</body>

</html>

18、Three.js相关插件介绍

有些时候,我们需要调整模型的位置或者大小,需要每次都去场景内进行调试,不是很方便和直观。那有没有一款插件能解决这个问题呢?

1、dat.GUI

dat.GUI链接:github.com/dataarts/da…

dat.GUI 是一个用于在 JavaScript 中修改变量的轻量级图形用户界面的插件,使用这个插件可以很容易地创建出能够改变代码变量的界面组件,从而实现一些实时交互效果。

使用dat.GUI

1.引入dat.GUI 插件

<script src="https://cdn.bootcss.com/dat-gui/0.7.1/dat.gui.min.js"></script>

2.定义一个对象,在里面设置我们需要修改的一些数据:

// 定义对象,设置需要修改的数据
var controls = {
    positionX:0,
    positionY:0,
    positionZ:0
};

3.实例化dat.GUI对象,将需要修改的配置添加对象中,并监听变化回调:

// 实例化dat.GUI对象
var gui = new dat.GUI();
// 把需要修改的配置添加dat.GUI对象中
//gui.add(修改的配置对象, 配置对象中修改的数据名称, 修改数据边界的起始点, 修改数据边界的终止点)
// onChange: 只要数据发生了变化 就会触发onchange方法
gui.add(controls, "positionX", -10, 10).onChange(updatePosition);
gui.add(controls, "positionY", -1, 1).onChange(updatePosition);
gui.add(controls, "positionZ", -1, 1).onChange(updatePosition);

// 定义更新模型位置函数
function updatePosition() {
  	 // 设置网格在页面中的位置
    cube.position.set(controls.positionX, controls.positionY, controls.positionZ);
}

这样,只要我们每次都修改对象里面的值以后,都会触发updatePosition回调,来更新模型的位置。

加入dat.GUI插件后的完整代码

<html>

<head>
    <title>Cube</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }

        canvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <!-- 引入three.js -->
    <script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
    <!-- 引入 dat.gui -->
    <script src="https://cdn.bootcss.com/dat-gui/0.7.1/dat.gui.min.js"></script>
    <script>
        // 1、创建场景
        var scene = new THREE.Scene();

        // 2、创建相机(透视投影相机)
        var camera = new THREE.PerspectiveCamera(
            50, // 相机视野
            window.innerWidth / window.innerHeight, // 水平方向和竖直方向长度的比值
            0.1, // 近端渲染距离
            1000 // 远端渲染距离
        );
        // 2.1 设置相机位置
        // camera.position.x = 5;
        // camera.position.y = 10;
        // camera.position.z = 10;
        // 2.1 设置相机位置简写方式:
        camera.position.set(5, 10, 10);

        // 3、创建渲染器
        var renderer = new THREE.WebGLRenderer();
        // 3.1 设置渲染器的大小(长宽)(设置渲染器为全屏)
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 3.2 将渲染结果展示到页面上
        document.body.appendChild(renderer.domElement);
        // 10.1 定义对象,设置需要修改的数据
        var controls = {
            positionX: 0,
            positionY: 0,
            positionZ: 0
        };
        // 4、创建几何体模型(立方几何体)
        var geometry = new THREE.BoxGeometry(4, 4, 4);

        // 5、创建材质(基础网格材质和法线网格材质)
        // 5.1 创建基础网格材质
        var materialBasic = new THREE.MeshBasicMaterial({
            color: 0xffffff, // 白色
            wireframe: true //是否将几何体渲染为线框,默认值为false(即渲染为平面多边形)
        });
        // 5.2 创建法线网格材质
        var materialNormal = new THREE.MeshNormalMaterial();

        // 6、创建多种网格(因为有多个材质)
        // 第一个参数是几何模型,第二参数是材质
        var cube = THREE.SceneUtils.createMultiMaterialObject(geometry, [
            materialBasic,
            materialNormal
        ]);
        // 6.1 让相机 看向(对着)物体(拍摄对象)的位置(默认状态下,相机将指向三维坐标系的原点。)
        camera.lookAt(cube.position);
        // 6.2、将网格添加到场景中
        scene.add(cube);
        // 7、创建光源
        var spotLight = new THREE.SpotLight(0xffffff);
        // 7.1 设置光源位置
        spotLight.position.set(0, 20, 20);
        // 7.2 设置光源照射的强度,默认值为 1
        spotLight.intensity = 5;
        // 7.3 将光源添加到场景中
        scene.add(spotLight);
        // 8、为了方便观察3D图像,添加三维坐标系对象
        // var axes = new THREE.AxisHelper(6);
        // scene.add(axes);
        // 9、创建动画循环渲染函数
        function animate() {
            // 9.1 循环调用函数
            requestAnimationFrame(animate);
            // 每一次animate函数调用,都让网格比上一次 X 轴、Y 轴各旋转增加 0.01 弧度
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;
            // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景
            renderer.render(scene, camera);
        };
        // 调用动画函数
        animate();

        // 10.2 实例化dat.GUI对象
        var gui = new dat.GUI();
        // 10.3 把需要修改的配置添加dat.GUI对象中
        gui.add(controls, "positionX", -10, 10).onChange(updatePosition);
        gui.add(controls, "positionY", -10, 10).onChange(updatePosition);
        gui.add(controls, "positionZ", -1, 1).onChange(updatePosition);
        // 10.4 定义更新模型位置函数
        function updatePosition() {
            cube.position.set(controls.positionX, controls.positionY, controls.positionZ);
        }
    </script>
</body>

</html>

Three.js里面,遇到的最多的问题就是性能问题,所以我们需要时刻检测当前的Three.js的性能,那是否有一款插件来帮助我们检测Three.js性能问题呢?

毫无疑问,帧数越高,画面的感觉就会越好。所以大多数游戏都会有超过30的FPS。为了监视FPS,看看你的程序哪里占用了很多的CPU时间,就需要学习一下性能监视器。

image-20191223163751619

2、stats.js

关于性能:在3D世界里,经常使用帧数来测试一个程序性能上是否有瓶颈。

stats.js链接github.com/mrdoob/stat…

stats.js 是一个JavaScript性能监视器,可以帮助监视代码的性能,主要用于检测动画运行时的帧数。

  • 帧数(FPS):图形处理器每秒钟能够刷新几次,通常用FPS(Frames Per Second)来表示,越高的数字越好。

  • 毫秒(MS):渲染一个帧所需的 MS 毫秒,数字越小越好.

  • MB :已分配内存的 MB 字节(占用的内存大小)

image-20191227212303424

使用stats.js

  1. 引入
<script src="http://www.wjceo.com/lib/js/libs/stats.min.js"></script>
  1. 实例化stats对象,然后把对象内生成的dom添加到页面当中。
var stats = new Stats();
document.body.appendChild(stats.dom);
  1. requestAnimationFrame的回调里面进行更新每次渲染的时间:
function animate() {
    requestAnimationFrame(animate); //循环调用函数
    stats.update(); //更新性能插件
		renderer.render( scene, camera ); //渲染界面
}
animate();

加入stats.js插件后的完整代码

<html>

<head>
    <title>Cube</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }

        canvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <!-- 引入three.js -->
    <script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
    <!-- 引入 dat.gui -->
    <script src="https://cdn.bootcss.com/dat-gui/0.7.1/dat.gui.min.js"></script>
    <!-- 引入stats.js  -->
    <script src="http://www.wjceo.com/lib/js/libs/stats.min.js"></script>
    <script>
        // 1、创建场景
        var scene = new THREE.Scene();

        // 2、创建相机(透视投影相机)
        var camera = new THREE.PerspectiveCamera(
            50, // 相机视野
            window.innerWidth / window.innerHeight, // 水平方向和竖直方向长度的比值
            0.1, // 近端渲染距离
            1000 // 远端渲染距离
        );
        // 2.1 设置相机位置
        // camera.position.x = 5;
        // camera.position.y = 10;
        // camera.position.z = 10;
        // 2.1 设置相机位置简写方式:
        camera.position.set(5, 10, 10);

        // 3、创建渲染器
        var renderer = new THREE.WebGLRenderer();
        // 3.1 设置渲染器的大小(长宽)(设置渲染器为全屏)
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 3.2 将渲染结果展示到页面上
        document.body.appendChild(renderer.domElement);
        // 还有3.3步骤(今后会把3.3步骤放到后面去),结合场景和相机进行渲染,即用摄像机拍下此刻的场景
        // renderer.render(scene, camera);
        // 10.1 定义对象,设置需要修改的数据
        var controls = {
            positionX: 0,
            positionY: 0,
            positionZ: 0
        };
        // 4、创建几何体模型(立方几何体)
        var geometry = new THREE.BoxGeometry(4, 4, 4);

        // 5、创建材质(基础网格材质和法线网格材质)
        // 5.1 创建基础网格材质
        var materialBasic = new THREE.MeshBasicMaterial({
            color: 0xffffff, // 白色
            wireframe: true //是否将几何体渲染为线框,默认值为false(即渲染为平面多边形)
        });
        // 5.2 创建法线网格材质
        var materialNormal = new THREE.MeshNormalMaterial();

        // 6、创建多种网格(因为有多个材质)
        // 第一个参数是几何模型,第二参数是材质
        var cube = THREE.SceneUtils.createMultiMaterialObject(geometry, [
            materialBasic,
            materialNormal
        ]);
        // 6.1 让相机 看向(对着)物体(拍摄对象)的位置(默认状态下,相机将指向三维坐标系的原点。)
        camera.lookAt(cube.position);
        // 6.2、将网格添加到场景中
        scene.add(cube);
        // 7、创建光源
        var spotLight = new THREE.SpotLight(0xffffff);
        // 7.1 设置光源位置
        spotLight.position.set(0, 20, 20);
        // 7.2 设置光源照射的强度,默认值为 1
        spotLight.intensity = 5;
        // 7.3 将光源添加到场景中
        scene.add(spotLight);
        // 8、为了方便观察3D图像,添加三维坐标系对象
        var axes = new THREE.AxisHelper(6);
        scene.add(axes);
        // 11、实例化性能监视插件
        var stats = new Stats();
        // 11.1 把stats对象生成的dom,添加到页面中(这样就能在页面中看到性能监视器了)
        document.body.appendChild(stats.dom);
        // 9、创建动画循环渲染函数
        function animate() {
            // 9.1 循环调用函数
            requestAnimationFrame(animate);
            // 每一次animate函数调用,都让网格比上一次 X 轴、Y 轴各旋转增加 0.01 弧度
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;
            // 11.2 更新性能插件
            stats.update();
            // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景
            renderer.render(scene, camera);
        };
        // 调用动画函数
        animate();

        // 10.2 实例化dat.GUI对象
        var gui = new dat.GUI();
        // 10.3 把需要修改的配置添加dat.GUI对象中
        gui.add(controls, "positionX", -10, 10).onChange(updatePosition);
        gui.add(controls, "positionY", -10, 10).onChange(updatePosition);
        gui.add(controls, "positionZ", -1, 1).onChange(updatePosition);
        // 10.4 定义更新模型位置函数
        function updatePosition() {
            cube.position.set(controls.positionX, controls.positionY, controls.positionZ);
        }
    </script>
</body>

</html>