阅读 935

Three.js基础+案例(二)

一、学习收获

1、Three.js 相机插件的使用

2、Three.js 基本元素 :精灵(Sprite)

3、Three.js 导出和导入JSON格式的3D模型

4、Three.js 导出和导入glTF格式的3D模型

5、Three.js 代码封装

二、主要内容:

1、Three.js中的相机插件

src=http___pic2.zhimg.com_v2-c5cb61c51efa03c52ab5e1e8129454ad_r.jpg&refer=http___pic2.zhimg.jpeg

通过Three.js的相机控件OrbitControls.js可以对Threejs的三维场景进行缩放、平移、旋转操作,本质上改变的并不是场景,而是相机的参数,相机的位置角度不同,同一个场景的渲染效果是不一样,比如一个相机绕着一个场景旋转,就像场景旋转一样。OrbitControls.js是对Three.js中正交投影相机和透视投影相机对象进行了封装。

简言之:在Three.js中能够使用OrbitControls.js进行自由视角观察。

OrbitControls.js链接: github.com/mrdoob/thre…

使用OrbitControls.js

  1. 引入OrbitControls.js插件

<script src="./OrbitControls.js"></script> 复制代码

  1. 实例化相机插件对象

var control = new THREE.OrbitControls(camera, renderer.domElement); 复制代码

  1. 在每一帧执行update(可以实时更新一下网格的位置,这样效果更好)

function animate() {     //  循环调用函数     requestAnimationFrame(animate);     // 每一次animate函数调用,都让网格比上一次 X 轴、Y 轴各旋转增加 0.01 弧度     cube.rotation.x += 0.01;     cube.rotation.y += 0.01;     //  更新性能插件     stats.update();    // cube.position.x = 3; //将模型的位置调整到x正轴距离原点为3的位置。    // cube.position.y += 5; //将模型的y轴位置以当前的位置向上移动5个单位。     // cube.position.z -= 6; //将模型的Z轴位置以当前的位置向后移动5个单位。    // 更新网格的位置     cube.position.set(2, 5, -6);    // 更新相机插件     control.update();     // 结合场景和相机进行渲染,即用摄像机拍下此刻的场景     renderer.render(scene, camera); }; // 调用动画函数 animate(); 复制代码

  1. 案例截图:

image-20191226203029273

  1. 完整代码如下:

<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>     <!-- 引入 stats.js  -->     <script src="http://www.wjceo.com/lib/js/libs/stats.min.js"></script>     <!-- 引入相机插件 OrbitControls.js-->     <script src="./OrbitControls.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);         // 实例化相机插件对象         var control = new THREE.OrbitControls(camera, 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 = 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);         // 10、实例化性能监视插件         var stats = new Stats();         // 10.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;             // 10.2 更新性能插件             stats.update();             // cube.position.x = 3; //将模型的位置调整到x正轴距离原点为3的位置。             // cube.position.y += 5; //将模型的y轴位置以当前的位置向上移动5个单位。             // cube.position.z -= 6; //将模型的Z轴位置以当前的位置向后移动5个单位。             cube.position.set(2, 5, -6);             // 更新相机插件             control.update();             // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景             renderer.render(scene, camera);         };         // 调用动画函数         animate();     </script> </body> </html> 复制代码

2、THREE.Object3D

为了方便操作,Three.js将每个能够直接添加到场景内的对象都继承至一个基类-THREE.Object3D,以后我们将继承至这个基类的对象称为3d对象。Object3D是ThreeJS中大部分物体的基类,它包含了物体的位移,旋转,缩放,以及各个物体父子关系的js实现。

判断一个对象是否是继承至THREE.Object3D,我们可以这么判断:

obj instanceof THREE.Object3D //如果一个对象继承至THREE.Object3D,则返回 true 否则返回false 复制代码

image-20191224151339286

添加一个3d对象:

将一个网格添加到场景中进行使用

scene.add(cube);; //将网格添加到场景 复制代码

删除一个3d对象

如果一个模型不再被使用到,需要彻底删除掉,我们可以使用remove方法进行删除:

scene.remove(mesh); //将一个模型从场景中删除 复制代码

3、Three.js内容补充

3.1、修改位置的3种方式

  1. 单独设置

camera.position.x = 5; camera.position.y = 10; camera.position.z = 10; 复制代码

  1. 使用set方法,一次性设置所有

camera.position.set(5, 10, 10); 复制代码

  1. 通过三维向量一次性设置

    Three.js的模型的位置属性是一个THREE.Vector3(三维向量)的对象,

    一个三维向量表示的是一个有顺序的、三个为一组的数字组合(标记为x、y和z), 可被用来表示很多事物,例如:

    • 一个位于三维空间中的点。

    • 一个在三维空间中的方向与长度的定义。在three.js中,长度总是从(0, 0, 0)到(x, y, z)的直线距离,方向也是从(0, 0, 0)到(x, y, z)的方向。

camera.position = new THREE.Vector3(5, 10, 10); //上面的设置位置也可以通过这样设置。 复制代码

3.2、修改大小的3种方式

  1. 单独设置

cube.scale.x = 2; //模型沿x轴放大一倍 cube.scale.y = 0.5; //模型沿y轴缩小一倍 cube.scale.z = 1; //模型沿z轴保持不变 复制代码

  1. 使用set方法,一次性设置所有

cube.scale.set(2, 2, 2); //每个方向等比放大一倍 复制代码

  1. 由于scale属性也是一个三维向量,通过三维向量一次性设置

cube.scale = new THREE.Vector3(2, 2, 2); //每个方向都放大一倍 复制代码

3.3 修改模型转向(旋转)的3种方式

  1. 单独设置每个轴的旋转:

cube.rotation.x = Math.PI; //模型沿x旋转180度 cube.rotation.y = Math.PI * 2; //模型沿y轴旋转360度,跟没旋转一样的效果。。。 cube.rotation.z = - Math.PI / 2; //模型沿z轴逆时针旋转90度 复制代码

  1. 使用set方法,一次性设置所有

cube.rotation.set(Math.PI, 0, - Math.PI / 2); //旋转效果和第一种显示的效果相同 复制代码

  1. 通过重新赋值一个欧拉角对象来实现旋转调整【了解即可】

    模型的rotation属性其实是一个欧拉角对象(THREE.Euler),欧拉角描述一个旋转变换,通过指定轴顺序和其各个轴向上的指定旋转角度来旋转一个物体。

cube.rotation = new THREE.Euler(Math.PI, 0, - Math.PI / 2, 'XYZ');  复制代码

3、Three.js 基本元素 :精灵(Sprite)和 粒子(Points)

1、精灵(Sprite)

精灵(Sprite )属于Three.js中的物体,但是我们通过相机查看它时,始终看到的是它的正面,它总是朝向相机。通过它的这种特性,我们可以实现广告牌的效果,或实现更多的比如雨雪、烟雾等更加绚丽的特效。

注意:人有正面、背面、侧面的,但是雨、雪、烟雾等物体是不分正面、背面、侧面的,它们只有一个面。

**精灵(Sprite)**由于一直正对着相机的特性,一般使用在模型的提示信息当中。通过THREE.Sprite创建生成,由于THREE.Sprite和THREE.Mesh都属于THREE.Object3D的子类,所以,我们操作模型网格的相关属性和方法大部分对于精灵都适用。和精灵一起使用的还有一个THREE.SpriteMaterial对象,它是专门配合精灵的材质。注意:精灵没有阴影效果。

  1. 普通方式的精灵(Sprite)

// 创建精灵材质 var spriteMaterialNormal = new THREE.SpriteMaterial({color: 0x00ffff}); // 实例化精灵对象 var spriteNormal = new THREE.Sprite(spriteMaterialNormal); //设置精灵对象的位置 spriteNormal.position.set(-30, 10, 0);  //设置精灵对象的缩放大小 spriteNormal.scale.set(5, 5, 1);   // 在场景中添加精灵 scene.add(spriteNormal); 复制代码

1.0 案例截图:

image-20191226202415603

1.1 完整代码如下:

<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>     <!-- 引入 stats.js  -->     <script src="http://www.wjceo.com/lib/js/libs/stats.min.js"></script>     <!-- 引入相机插件 OrbitControls.js-->     <script src="./OrbitControls.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);         // 实例化相机插件对象         var control = new THREE.OrbitControls(camera, 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 = 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);         // 10、实例化性能监视插件         var stats = new Stats();         // 10.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;             // 10.2 更新性能插件             stats.update();             // cube.position.x = 3; //将模型的位置调整到x正轴距离原点为3的位置。             // cube.position.y += 5; //将模型的y轴位置以当前的位置向上移动5个单位。             // cube.position.z -= 6; //将模型的Z轴位置以当前的位置向后移动5个单位。             cube.position.set(2, 5, -6);             // 更新相机插件             control.update();             // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景             renderer.render(scene, camera);         };         // 调用动画函数         animate();         // 11 创建精灵材质         var spriteMaterialNormal = new THREE.SpriteMaterial({             color: 0x00ffff         });         // 11.1 实例化精灵对象         var spriteNormal = new THREE.Sprite(spriteMaterialNormal);         //11.2 设置精灵对象的位置         spriteNormal.position.set(-30, 0, 0);         //11.3 设置精灵对象的缩放大小         spriteNormal.scale.set(5, 5, 1);         // 11.4 在场景中添加精灵         scene.add(spriteNormal);     </script> </body> </html> 复制代码

  1. 图片(TextureLoader)导入的方式

    (TextureLoader内部使用ImageLoader来加载文件)。

    此导入方式需要借助Canvas来实现。

     //创建canvas对象(封装Canvas画布)         function drawCanvas(options) {             // 创建Canvas画布             var canvas = document.createElement("canvas");             // 设置Canvas画布的宽度和高度             canvas.width = options.width;             canvas.height = options.height;             // 设置 在Canvas画布上的绘图环境为2D绘图             var ctx = canvas.getContext("2d");             // 设置 绘图环境的背景颜色填充颜色为黑色             ctx.fillStyle = "rgba(0, 0, 0, 0)";             // 绘制“被填充”的矩形(绘制矩形,该矩形的填充颜色为黑色)             ctx.fillRect(0, 0, canvas.width, canvas.height);             // ctx.fillRect(x,y,width,height);             // 参数    描述             // x      矩形左上角的 x 坐标             // y      矩形左上角的 y 坐标             // width  矩形的宽度, 以像素计             // height 矩形的高度, 以像素计             // 设置绘图环境的字体大小和字体(Verdana 为无衬线字体)             ctx.font = "60px Verdana";             // 设置绘图中物体的颜色为白色(在此处设置的是文本的颜色)             ctx.fillStyle = "#fff";             // 在画布上绘制填色的文本             ctx.fillText(options.text, 0, 56, options.width);             // ctx.fillText(text,x,y,maxWidth);             // 参数       描述             // text      规定在画布上输出的文本。             // x         开始绘制文本的 x 坐标位置( 相对于画布)。             // y         开始绘制文本的 y 坐标位置( 相对于画布)。             // maxWidth  可选。 允许的最大文本宽度, 以像素计。             return canvas; // 返回画布给封装好的drawCanvas函数         } 复制代码
// 通过TextureLoader将图片转为base64格式(为了减小图片的体积) var spriteMap = new THREE.TextureLoader().load(drawCanvas({text: "文本内容", width: 64, height: 64}).toDataURL());  // 创建精灵材质 var spriteMaterial = new THREE.SpriteMaterial({map: spriteMap, color: 0xffffff}); // 实例化精灵对象 var sprite = new THREE.Sprite(spriteMaterial); //设置精灵对象的位置 sprite.position.set(0, 10, 0); //设置位置 //设置精灵对象的缩放大小 sprite.scale.set(5, 5, 1); //设置scale进行大小设置 // 在场景中添加精灵 scene.add(sprite); 复制代码

2.0 案例截图:

image-20191226202549239

2.1完整代码:

<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>     <!-- 引入 stats.js  -->     <script src="http://www.wjceo.com/lib/js/libs/stats.min.js"></script>     <!-- 引入相机插件 OrbitControls.js-->     <script src="./OrbitControls.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);         // 实例化相机插件对象         var control = new THREE.OrbitControls(camera, 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 = 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);         // 10、实例化性能监视插件         var stats = new Stats();         // 10.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;             // 10.2 更新性能插件             stats.update();             // cube.position.x = 3; //将模型的位置调整到x正轴距离原点为3的位置。             // cube.position.y += 5; //将模型的y轴位置以当前的位置向上移动5个单位。             // cube.position.z -= 6; //将模型的Z轴位置以当前的位置向后移动5个单位。             cube.position.set(2, 5, -6);             // 更新相机插件             control.update();             // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景             renderer.render(scene, camera);         };         // 调用动画函数         animate();         //创建canvas对象         function drawCanvas(options) {             // 创建Canvas画布             var canvas = document.createElement("canvas");             // 设置Canvas画布的宽度和高度             canvas.width = options.width;             canvas.height = options.height;             // 设置 在Canvas画布上的绘图环境为2D绘图             var ctx = canvas.getContext("2d");             // 设置 绘图环境的背景颜色填充颜色为黑色             ctx.fillStyle = "rgba(0, 0, 0, 0)";             // 绘制“被填充”的矩形(绘制矩形,该矩形的填充颜色为黑色)             ctx.fillRect(0, 0, canvas.width, canvas.height);             // ctx.fillRect(x,y,width,height);             // 参数    描述             // x      矩形左上角的 x 坐标             // y      矩形左上角的 y 坐标             // width  矩形的宽度, 以像素计             // height 矩形的高度, 以像素计             // 设置绘图环境的字体大小和字体(Verdana 为无衬线字体)             ctx.font = "60px Verdana";             // 设置绘图中物体的颜色为白色(在此处设置的是文本的颜色)             ctx.fillStyle = "#fff";             // 在画布上绘制填色的文本             ctx.fillText(options.text, 0, 56, options.width);             // ctx.fillText(text,x,y,maxWidth);             // 参数       描述             // text      规定在画布上输出的文本。             // x         开始绘制文本的 x 坐标位置( 相对于画布)。             // y         开始绘制文本的 y 坐标位置( 相对于画布)。             // maxWidth  可选。 允许的最大文本宽度, 以像素计。             return canvas; // 返回画布给封装好的drawCanvas函数         }         // 通过TextureLoader将图片转为base64格式(为了减小图片的体积)         var spriteMap = new THREE.TextureLoader().load(drawCanvas({             text: "文本内容",             width: 64,             height: 64         }).toDataURL());         // 创建精灵材质         var spriteMaterial = new THREE.SpriteMaterial({             map: spriteMap,             color: 0xffffff         });         // 实例化精灵对象         var sprite = new THREE.Sprite(spriteMaterial);         //设置精灵对象的位置         sprite.position.set(0, 10, 0); //设置位置         //设置精灵对象的缩放大小         sprite.scale.set(5, 5, 1); //设置scale进行大小设置         // 在场景中添加精灵         scene.add(sprite);     </script> </body> </html> 复制代码

  1. canvas导入的方式

    需要结合使用纹理对象(Texture),用途是:创建一个纹理贴图,将其应用到一个表面。

 //创建canvas对象(封装Canvas画布)      function drawCanvas(options) {          // 创建Canvas画布          var canvas = document.createElement("canvas");          // 设置Canvas画布的宽度和高度          canvas.width = options.width;          canvas.height = options.height;          // 设置 在Canvas画布上的绘图环境为2D绘图          var ctx = canvas.getContext("2d");          // 设置 绘图环境的背景颜色填充颜色为黑色          ctx.fillStyle = "rgba(0, 0, 0, 0)";          // 绘制“被填充”的矩形(绘制矩形,该矩形的填充颜色为黑色)          ctx.fillRect(0, 0, canvas.width, canvas.height);          // ctx.fillRect(x,y,width,height);          // 参数    描述          // x      矩形左上角的 x 坐标          // y      矩形左上角的 y 坐标          // width  矩形的宽度, 以像素计          // height 矩形的高度, 以像素计          // 设置绘图环境的字体大小和字体(Verdana 为无衬线字体)          ctx.font = "60px Verdana";          // 设置绘图中物体的颜色为白色(在此处设置的是文本的颜色)          ctx.fillStyle = "#fff";          // 在画布上绘制填色的文本          ctx.fillText(options.text, 0, 56, options.width);          // ctx.fillText(text,x,y,maxWidth);          // 参数       描述          // text      规定在画布上输出的文本。          // x         开始绘制文本的 x 坐标位置( 相对于画布)。          // y         开始绘制文本的 y 坐标位置( 相对于画布)。          // maxWidth  可选。 允许的最大文本宽度, 以像素计。          return canvas; // 返回画布给封装好的drawCanvas函数      } 复制代码
// 调用drawCanvas函数传入一个特定的对象(对象中的属性要符合封装函数的需求) var canvas = drawCanvas({     text: "立方体",     width: 256,     height: 64 }); // 创建一个纹理贴图,将其应用到一个表面 var spriteMapCube = new THREE.Texture(canvas); spriteMapCube.wrapS = THREE.RepeatWrapping; spriteMapCube.wrapT = THREE.RepeatWrapping; // wrapS定义了纹理贴图在水平方向上将如何包裹 // wrapT定义了纹理贴图在垂直方向上将如何包裹 // RepeatWrapping 一种包裹模式,纹理将简单地重复到无穷大。 // 如果编码类型在纹理已被一个材质使用之后发生了改变, 你需要来设置Material.needsUpdate为true来使得材质重新编译。 spriteMapCube.needsUpdate = true; // 创建精灵材质 var spriteMaterial = new THREE.SpriteMaterial({     map: spriteMapCube, // 将纹理贴在精灵的材质表面     color: 0xffffff // 白色 }); // 实例化精灵对象 var spriteCube = new THREE.Sprite(spriteMaterial); //设置精灵对象位置  spriteCube.position.set(30, 10, -5); //设置精灵对象缩放大小 spriteCube.scale.set(20, 5, 1); // 将设置好的精灵对象,添加到场景中 scene.add(spriteCube); 复制代码

3.0 案例截图:

image-20191226202700407

3.1 完整代码:

<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>     <!-- 引入 stats.js  -->     <script src="http://www.wjceo.com/lib/js/libs/stats.min.js"></script>     <!-- 引入相机插件 OrbitControls.js-->     <script src="./OrbitControls.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);         // 实例化相机插件对象         var control = new THREE.OrbitControls(camera, 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 = 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);         // 10、实例化性能监视插件         var stats = new Stats();         // 10.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;             // 10.2 更新性能插件             stats.update();             // cube.position.x = 3; //将模型的位置调整到x正轴距离原点为3的位置。             // cube.position.y += 5; //将模型的y轴位置以当前的位置向上移动5个单位。             // cube.position.z -= 6; //将模型的Z轴位置以当前的位置向后移动5个单位。             cube.position.set(2, 5, -6);             // 更新相机插件             control.update();             // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景             renderer.render(scene, camera);         };         // 调用动画函数         animate();         //创建canvas对象         function drawCanvas(options) {             // 创建Canvas画布             var canvas = document.createElement("canvas");             // 设置Canvas画布的宽度和高度             canvas.width = options.width;             canvas.height = options.height;             // 设置 在Canvas画布上的绘图环境为2D绘图             var ctx = canvas.getContext("2d");             // 设置 绘图环境的背景颜色填充颜色为黑色             ctx.fillStyle = "rgba(0, 0, 0, 0)";             // 绘制“被填充”的矩形(绘制矩形,该矩形的填充颜色为黑色)             ctx.fillRect(0, 0, canvas.width, canvas.height);             // ctx.fillRect(x,y,width,height);             // 参数    描述             // x      矩形左上角的 x 坐标             // y      矩形左上角的 y 坐标             // width  矩形的宽度, 以像素计             // height 矩形的高度, 以像素计             // 设置绘图环境的字体大小和字体(Verdana 为无衬线字体)             ctx.font = "60px Verdana";             // 设置绘图中物体的颜色为白色(在此处设置的是文本的颜色)             ctx.fillStyle = "#fff";             // 在画布上绘制填色的文本             ctx.fillText(options.text, 0, 56, options.width);             // ctx.fillText(text,x,y,maxWidth);             // 参数       描述             // text      规定在画布上输出的文本。             // x         开始绘制文本的 x 坐标位置( 相对于画布)。             // y         开始绘制文本的 y 坐标位置( 相对于画布)。             // maxWidth  可选。 允许的最大文本宽度, 以像素计。             return canvas; // 返回画布给封装好的drawCanvas函数         }                // 调用drawCanvas函数传入一个特定的对象(对象中的属性要符合封装函数的需求)         var canvas = drawCanvas({             text: "立方体",             width: 256,             height: 64         });         // 创建一个纹理贴图,将其应用到一个表面         var spriteMapCube = new THREE.Texture(canvas);         spriteMapCube.wrapS = THREE.RepeatWrapping;         spriteMapCube.wrapT = THREE.RepeatWrapping;         // wrapS定义了纹理贴图在水平方向上将如何包裹         // wrapT定义了纹理贴图在垂直方向上将如何包裹         // RepeatWrapping 一种包裹模式,纹理将简单地重复到无穷大。         // 如果编码类型在纹理已被一个材质使用之后发生了改变, 你需要来设置Material.needsUpdate为true来使得材质重新编译。         spriteMapCube.needsUpdate = true;         // 创建精灵材质         var spriteMaterial = new THREE.SpriteMaterial({             map: spriteMapCube, // 将纹理贴在精灵的材质表面             color: 0xffffff // 白色         });         // 实例化精灵对象         var spriteCube = new THREE.Sprite(spriteMaterial);         //设置精灵对象位置          spriteCube.position.set(30, 10, -5);         //设置精灵对象缩放大小         spriteCube.scale.set(20, 5, 1);         // 将设置好的精灵对象,添加到场景中         scene.add(spriteCube);     </script> </body> </html> 复制代码

2、粒子(Points)

**粒子(Points)和精灵(Sprite )**的效果是一样的,这两种对象共同点就是我们通过相机查看它们时,始终看到的是它们的正面,它们总朝向相机。它们之间的区别就是如果当前场景内的精灵过多的话,就会出现性能问题

**粒子(Points)**的作用就是为解决很多精灵而出现的,我们可以使用粒子去模拟数量很多的效果,比如下雨,下雪等,数量很多的时候就适合使用粒子来创建,相应的,提高性能的损失就是失去了对单个精灵的操作,所有的粒子的效果都是一样。总的来说,粒子就是提高性能减少的一些自由度,而精灵就是为了自由度而损失了一些性能。

但是粒子有一些特殊的情况就是THREE.Points是它们粒子个体的父元素,它的位置设置也是基于THREE.Points位置而定位,而修改THREE.Points的scale属性只会修改掉粒子个体的位置。

创建粒子

//创建球形几何体 var sphereGeometry = new THREE.SphereGeometry(5, 32, 32); // 创建粒子材质 var sphereMaterial = new THREE.PointsMaterial({     color: 0xff00ff,     size: 0.1 }); // 创建粒子实例(结合几何体和材质) // Points(几何体, 材质) var sphere = new THREE.Points(sphereGeometry, sphereMaterial); //  把粒子添加到场景中 scene.add(sphere); 复制代码

SphereGeometry( radius ,widthSegments, heightSegments)

radius — 球体半径,默认为1。 widthSegments — 水平分段数(沿着经线分段),最小值为3,默认值为8。 heightSegments — 垂直分段数(沿着纬线分段),最小值为2,默认值为6。

以下是设置的SphereGeometry(3, 4, 6)模型外观

image-20191228214037777

image-20191228214218619


以上代码创建粒子效果图:

粒子会吸附在几何体的表面

image-20191228213207540

上面是一个通过球体几何体创建的一个最简单的粒子特效。

使用任何几何体都可以创建粒子的几何体,甚至自己生成的几何体都可以

比如创建星空案例:

image-20191228222459786

// 创建跟几何体的相关属性的顶点(Geometry包含顶点位置,面信息,颜色等) var starsGeometry = new THREE.Geometry(); // 创建1万个点 for (var i = 0; i < 10000; i++) {     //通过三维向量创建点,因为三维向量可以代表一个位于三维空间中的点。     var star = new THREE.Vector3();     // 设置点的随机位置     star.x = THREE.Math.randFloatSpread(2500);     star.y = THREE.Math.randFloatSpread(2000);     star.z = THREE.Math.randFloatSpread(2500);     // 把创建好的点,添加到几何体的相关属性的顶点上。     // vertices(顶点的队列)保存了模型中每个顶点的位置信息。     starsGeometry.vertices.push(star) } // 设置粒子材质 var starsMaterial = new THREE.PointsMaterial({     color: 0x888888 }) // 创建粒子实例 var starField = new THREE.Points(starsGeometry, starsMaterial); // 将10000个点,添加到场景中 scene.add(starField); 复制代码

星空案例完整代码:

<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>     <!-- 引入 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.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);         // 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);         // 创建跟几何体的相关属性的顶点(Geometry包含顶点位置,面信息,颜色等)         var starsGeometry = new THREE.Geometry();         // 创建1万个点         for (var i = 0; i < 10000; i++) {             //通过三维向量创建点,因为三维向量可以代表一个位于三维空间中的点。             var star = new THREE.Vector3();             // 设置点的随机位置             star.x = THREE.Math.randFloatSpread(2500);             star.y = THREE.Math.randFloatSpread(2000);             star.z = THREE.Math.randFloatSpread(2500);             // 把创建好的点,添加到几何体的相关属性的顶点上。             // vertices(顶点的队列)保存了模型中每个顶点的位置信息。             starsGeometry.vertices.push(star)         }         // 设置粒子材质         var starsMaterial = new THREE.PointsMaterial({             color: 0x888888         })         // 创建粒子实例         var starField = new THREE.Points(starsGeometry, starsMaterial);         // 将1000个点,添加到场景中         scene.add(starField);         // 9、创建动画循环渲染函数         function animate() {             // 9.1 循环调用函数             requestAnimationFrame(animate);             // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景             renderer.render(scene, camera);         };         // 调用动画函数         animate();     </script> </body> </html> 复制代码

实现星空的转动:

var beforeDate = new Date(); //之前的时间 // console.log("beforeDate", beforeDate); // 9、创建动画循环渲染函数 function animate() {     var nowDate = new Date(); //现在的时间     console.log("nowDate", nowDate);     var t = nowDate - beforeDate; //时间差     beforeDate = nowDate; //把现在的时间赋值给之前的时间     //让相机转动以此来实现整个场景的旋转     camera.rotateY(-0.0001 * t);     camera.rotateX(0.00005 * t);     camera.rotateZ(0.00005 * t);     // 9.1 循环调用函数     requestAnimationFrame(animate);     // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景     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.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);         // 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);         // 创建跟几何体的相关属性的顶点(Geometry包含顶点位置,面信息,颜色等)         var starsGeometry = new THREE.Geometry();         // 创建1万个点         for (var i = 0; i < 10000; i++) {             //通过三维向量创建点,因为三维向量可以代表一个位于三维空间中的点。             var star = new THREE.Vector3();             // 设置点的随机位置             star.x = THREE.Math.randFloatSpread(2500);             star.y = THREE.Math.randFloatSpread(2000);             star.z = THREE.Math.randFloatSpread(2500);             // 把创建好的点,添加到几何体的相关属性的顶点上。             // vertices(顶点的队列)保存了模型中每个顶点的位置信息。             starsGeometry.vertices.push(star)         }         // 设置粒子材质         var starsMaterial = new THREE.PointsMaterial({             color: 0x888888         })         // 创建粒子实例         var starField = new THREE.Points(starsGeometry, starsMaterial);         // 将1000个点,添加到场景中         scene.add(starField); var beforeDate = new Date(); //之前的时间 // console.log("beforeDate", beforeDate); // 9、创建动画循环渲染函数 function animate() {     var nowDate = new Date(); //现在的时间     console.log("nowDate", nowDate);     var t = nowDate - beforeDate; //时间差     beforeDate = nowDate; //把现在的时间赋值给之前的时间     //让相机转动以此来实现整个场景的旋转     camera.rotateY(-0.0001 * t);     camera.rotateX(0.00005 * t);     camera.rotateZ(0.00005 * t);     // 9.1 循环调用函数     requestAnimationFrame(animate);     // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景     renderer.render(scene, camera); }; // 调用动画函数 animate();     </script> </body> </html> 复制代码

4、Three.js导入3D模型

复杂的3D模型(比如制作一个飞机模型)一般都是用第三方建模工具生成,然后加载到Three.js中。

4.1、常用建模制作工具

3Dmax

链接地址:www.autodesk.com.cn/products/3d…

最常见的3D建模软件,广泛应用于广告、影视、工业设计、建筑设计、三维动画、多媒体制作、游戏、辅助教学以及工程可视化等领域。

image-20191224174558250

SketchUp

链接地址:www.sketchup.com/zh-CN

SketchUp是一个极受欢迎并且易于使用的3D设计软件,官方网站将它比喻作电子设计中的“铅笔”。它的主要卖点就是使用简便,人人都可以快速上手。

image-20191224175012380

4.2、常用3D模型素材网站:

sketchupbar

链接地址:www.sketchupbar.com/default.php

image-20191224175354983

sketchfab

链接地址:sketchfab.com/

4.3、Three.js支持的3D模型格式

Three.js支持的导出格式

Three.js在线编辑器:threejs.org/editor/

Three.js支持的全部格式

github.com/mrdoob/thre…

4.4、在Three.js中导出3D模型步骤

(1)打开 Three.js在线编辑器

threejs.org/editor/

(2)点击添加按钮,选择将要添加的几何体模型

image-20191224181513486

(3)设置几何体模型的材质类型和材质颜色

image-20191224182133282

(4)设置几何体模型的属性(比如:位置、旋转、缩放)

image-20191224182430281

(5)将3D模型导出(选择导出场景,导出的是一个json格式的文件)

json格式,一般用于Three.js官方的editor导出

image-20191224182601071

4.5、在Three.js中导入3D模型步骤

(1)把下载好的json文件放入项目目录中(放入的位置随意)

(2)json文件中的JSON格式指的是Three.js可以将其转换为场景的3D对象的JSON格式模型。这种格式内部一般必有的四项为:

  • metadata 当前模型的相关信息以及生成的工具信息

  • geometries 存储当前模型所使用的几何体的数组

  • materials 存储当前模型所使用的材质的数组

  • object 当前模型的结构以及标示所应用到的材质和几何体标示

    所有的模型网格,几何体和材质都有一个固定的uuid标识符,JSON格式中都是通过uuid作为引用。

(3)使用ObjectLoader加载JSON模型

既然我们能够导出模型,肯定就可以导入。这里我们将使用到Three.js内置的对象THREE.ObjectLoader来加载模型:

//实例化ObjectLoader对象 var loader = new THREE.ObjectLoader(); //加载外部的JSON格式的模型,并在回调中将生成的模型对象添加到场景中 loader.load("./scene.json", function (group) {     scene.add(group); }); 复制代码

案例截图:

image-20191226202200653

完整代码如下:

<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>     <!-- 引入 stats.js  -->     <script src="http://www.wjceo.com/lib/js/libs/stats.min.js"></script>     <!-- 引入相机插件 OrbitControls.js-->     <script src="./OrbitControls.js"></script>     <script>         // 1、创建场景         var scene = new THREE.Scene();         // 2、创建相机(透视投影相机)         var camera = new THREE.PerspectiveCamera(             50, // 相机视野             window.innerWidth / window.innerHeight, // 水平方向和竖直方向长度的比值             0.1, // 近端渲染距离             1000 // 远端渲染距离         );         // 2、设置相机位置简写方式:         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);         // 实例化相机插件对象         var control = new THREE.OrbitControls(camera, renderer.domElement);         //实例化ObjectLoader对象         var loader = new THREE.ObjectLoader();         //加载外部的JSON格式的模型,并在回调中将生成的模型对象添加到场景中         loader.load("./scene.json", function (group) {             scene.add(group);         });         // 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);         // 10、实例化性能监视插件         var stats = new Stats();         // 10.1 把stats对象生成的dom,添加到页面中(这样就能在页面中看到性能监视器了)         document.body.appendChild(stats.dom);         // 9、创建动画循环渲染函数         function animate() {             // 9.1 循环调用函数             requestAnimationFrame(animate);             // 10.2 更新性能插件             stats.update();             // 更新相机插件             control.update();             // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景             renderer.render(scene, camera);         };         // 调用动画函数         animate();     </script> </body> </html> 复制代码

注意:只要是通过 loader.load()方法导入,必须要使用VSCode编辑器中的 live-server插件的方式打开页面。

不然会有跨域的问题。

4.6、glTF格式文件的导出和导入

Three.js官方推荐我们使用的3D模型的格式为glTF,由于glTF专注于传输,因此它的传输和解析的速度都很快。glTF模型功能包括:网格、材质、纹理、灯光、相机等。

先在VSCode编辑器中安装glTF Tools插件,安装这个插件后我们就能在VSCode编辑器中查看 .gltf的文件效果了

image-20191226151720865

glTF格式的3D格式文件我们可以在sketchfab官网下载,这是一个国外比较知名的模型网站。

sketchfab官网模型下载地址:

sketchfab.com/3d-models?d…

image-20191228202759504

glTF格式加载器(loader)地址:

github.com/mrdoob/thre…

  1. 首先,将GLTFLoader加载器插件引入到页面。

    <!-- 引入 glTF加载器,用于加载glTF格式的3D模型 --> <script src="./gltfloader.js"></script> 复制代码

  2. 然后创建一个加载器:

    // 实例化 GLTFLoader 对象 var loader = new THREE.GLTFLoader(); 复制代码

  3. 使用加载器去加载模型,并调节一下模型大小在场景内展示:

    //加载外部的gltf格式的模型,并在回调中将生成的模型对象添加到场景中 loader.load('./3D_gltf/scene.gltf', function (gltf) {     // 设置缩放大小     gltf.scene.scale.set(5, 5, 5);     scene.add(gltf.scene); }); 复制代码

**注意:**以上的scene.gltf文件必须跟3D_gltf在同一个目录中,不能单独把scene.gltf移动到3D_gltf目录的外边。

image-20191226164955709

案例截图:

image-20191226202253723

完整代码如下:

<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/92/three.js"></script>     <!-- <script src="./three.js"></script> -->     <!-- 引入 stats.js  -->     <script src="http://www.wjceo.com/lib/js/libs/stats.min.js"></script>     <!-- 引入相机插件 OrbitControls.js-->     <script src="./OrbitControls.js"></script>     <!-- 引入 glTF加载器,用于加载glTF格式的3D模型 -->     <script src="./gltfloader.js"></script>     <script>         // 1、创建场景         var scene = new THREE.Scene();         // 2、创建相机(透视投影相机)         var camera = new THREE.PerspectiveCamera(             50, // 相机视野             window.innerWidth / window.innerHeight, // 水平方向和竖直方向长度的比值             0.1, // 近端渲染距离             1000 // 远端渲染距离         );         // 2设置相机位置简写方式:         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);         // 实例化相机插件对象         var control = new THREE.OrbitControls(camera, renderer.domElement);         // 实例化 GLTFLoader 对象         var loader = new THREE.GLTFLoader();         //加载外部的gltf格式的模型,并在回调中将生成的模型对象添加到场景中         loader.load('./3D_gltf/scene.gltf', function (gltf) {             // 设置缩放大小             gltf.scene.scale.set(5, 5, 5);             scene.add(gltf.scene);         });         // 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);         // 10、实例化性能监视插件         var stats = new Stats();         // 10.1 把stats对象生成的dom,添加到页面中(这样就能在页面中看到性能监视器了)         document.body.appendChild(stats.dom);         // 9、创建动画循环渲染函数         function animate() {             // 9.1 循环调用函数             requestAnimationFrame(animate);             // 10.2 更新性能插件             stats.update();             // 更新相机插件             control.update();             // 3.3 结合场景和相机进行渲染,即用摄像机拍下此刻的场景             renderer.setClearColor('rgb(135,206,250)', 1.0);             renderer.render(scene, camera);         };         // 调用动画函数         animate();     </script> </body> </html> 复制代码

5、Three.js性能优化建议

image-20191226202901179

5.1、尽量共用相同的几何体和材质

如果你需要创建三百个简单的相同颜色的立方体模型:

for (var i = 0; i < 300; i++) { var geometry = new THREE.BoxGeometry(10, 10, 10);     var material = new THREE.MeshLambertMaterial({color: 0x00ffff});     var cube = new THREE.Mesh(geometry, material);       // group(组的意思),通过组,方便管理,结构更加清晰。    var group = new THREE.Group();     // group.add( cubeA );    // group.add( cubeB );     group.add(cube); } // 把组,添加到场景中 scene.add( group ); 复制代码

我们尽量共用相同的几何体和材质:

var geometry = new THREE.BoxGeometry(10, 10, 10); var material = new THREE.MeshLambertMaterial({color: 0x00ffff}); for (var i = 0; i < 300; i++) {     var cube = new THREE.Mesh(geometry, material);        // group(组的意思),通过组,方便管理,结构更加清晰。    var group = new THREE.Group();     // group.add( cubeA );    // group.add( cubeB );     group.add(cube); } // 把组,添加到场景中 scene.add( group ); 复制代码

5.2、删除模型时,将材质和几何体从内存中清除

使用remove()将模型从场景内删除掉,大家会发现内存基本上没有怎么降低。因为几何体和材质还保存在内存当中,我们需要手动调用dispose()方法将其从内存中删除。

// 删除group,释放内存 function deleteGroup(name) {     var group = scene.getObjectByName(name);     if (!group) return;     // 删除掉所有的模型组内的cube     group.traverse(function (item) {         if (item instanceof THREE.Mesh) {             item.geometry.dispose(); //删除几何体             item.material.dispose(); //删除材质         }     });     scene.remove(group); } 复制代码

5.3、在循环渲染中避免使用更新

这里的更新指的是当前的几何体、材质、纹理等发生了修改,需要Three.js重新更新显存的数据,具体包括:

几何体:

geometry.verticesNeedUpdate = true; //顶点发生了修改 geometry.elementsNeedUpdate = true; //面发生了修改 geometry.morphTargetsNeedUpdate = true; //变形目标发生了修改 geometry.uvsNeedUpdate = true; //uv映射发生了修改 geometry.normalsNeedUpdate = true; //法向发生了修改 geometry.colorsNeedUpdate = true; //顶点颜色发生的修改 复制代码

材质:

material.needsUpdate = true 复制代码

纹理:

texture.needsUpdate = true; 复制代码

如果它们发生更新,则将其设置为trueThree.js会通过判断,将数据重新传输到显存当中,并将配置项重新修改为false。这是一个很耗运行效率的过程,所以我们尽量只在需要的时候修改,不要放到render()方法当中循环设置。

5.4、只在需要的时候渲染

如果在没有操作的时候,让循环一直渲染,属于浪费资源,接下来我来带给大家一个只在需要时渲染的方法。

  1. 首先在循环渲染中加入一个判断,如果判断值为true时,才可以循环渲染:

var renderEnabled; function animate() {     if (renderEnabled) {         renderer.render(scene, camera);     }     requestAnimationFrame(animate); } animate(); 复制代码

  1. 然后设置一个延迟器函数,每次调用后,可以将renderEnabled设置为true,并延迟三秒将其设置为false,这个延迟时间大家可以根据需求来修改:

//调用一次可以渲染三秒 var timeOut = null; function timeRender() { //设置为可渲染状态     renderEnabled = true;     //清除上次的延迟器     if (timeOut) {         clearTimeout(timeOut);     }     timeOut = setTimeout(function () {         renderEnabled = false;     }, 3000); } 复制代码

  1. 接下来,我们在需要的时候调用这个timeRender()方法即可,比如在相机控制器更新后的回调中:

controls.addEventListener('change', function(){     timeRender(); }); 复制代码

如果相机位置发生变化,就会触发回调,开启循环渲染,更新页面显示。

  1. 如果我们添加了一个模型到场景中,直接调用一下重新渲染即可:

scene.add(cube); timeRender(); 复制代码

6、代码封装案例

代码封装:让代码复用、让代码更清晰、容易维护。

案例截图:

image-20191226201750263

案例目录结构

image-20191226201933262

index.html文件

<!DOCTYPE html> <html> <head>     <meta charset=utf-8>     <title>Three.js案例</title>     <style>         body {             margin: 0;         }         canvas {             width: 100%;             height: 100%;             display: block;         }     </style> </head> <body onload="init()">     <!-- 引入 Three.js文件 -->     <script src="https://cdn.bootcss.com/three.js/92/three.js"></script>     <!-- 引入stats 性能检测插件  -->     <script src="http://www.wjceo.com/lib/js/libs/stats.min.js"></script>     <!-- 引入相机插件 -->     <script src="./OrbitControls.js"></script>     <!-- 引入我们自己写的代码文件 -->     <script src="./index.js"></script> </body> </html> 复制代码

index.js文件

//声明一些全局变量(场景、相机、渲染器、几何体、材质、网格) var scene, camera, renderer, geometry, material, cube; // 性能插件,监听fps stats = new Stats(); document.body.appendChild(stats.dom); //初始化渲染器 function initRenderer() {     renderer = new THREE.WebGLRenderer(); //实例化渲染器     renderer.setSize(window.innerWidth, window.innerHeight); //设置宽和高     document.body.appendChild(renderer.domElement); //添加到dom } //初始化场景 function initScene() {     scene = new THREE.Scene(); //实例化场景 } // 初始化相机插件 function initControl() {     control = new THREE.OrbitControls(camera, renderer.domElement); } //初始化相机 function initCamera() {     camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200); //实例化相机     camera.position.set(0, 0, 15); // 设置相机的位置 } //创建模型 function initMesh() {     geometry = new THREE.BoxGeometry(2, 2, 2); //创建几何体     material = new THREE.MeshNormalMaterial(); // 创建材质     cube = new THREE.Mesh(geometry, material); //创建网格     cube.position.set(2, 5, -6); // 给网格设置定位     cube.scale.x = 2; //模型沿x轴放大一倍     cube.scale.y = 0.5; //模型沿y轴缩小一倍     cube.scale.z = 1; //模型沿z轴保持不变     scene.add(cube); //将网格添加到场景 } //运行动画 function animate() {     requestAnimationFrame(animate); //循环调用函数     cube.rotation.x += 0.01; //每帧网格模型的沿x轴旋转0.01弧度  半圈是180度     cube.rotation.y += 0.02; //每帧网格模型的沿y轴旋转0.02弧度     stats.update(); // 性能插件更新,监听fps     control.update(); // 相机插件更新     renderer.render(scene, camera); //渲染界面 } //初始化函数,页面加载完成时调用 function init() {     initRenderer(); // 渲染     initScene(); // 场景     initCamera(); // 相机     initMesh(); // 物体     initControl(); // 相机插件     animate(); // 旋转,动画 } 复制代码

7、模型拖拽案例

image-20191229093140729

1、引入相关文件和插件

<script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>   <!-- 轨迹球插件作用:       1. 鼠标按住左键可以旋转模型       2. 鼠标滚轮可以缩放模型 -->     <script src="./js/TrackballControls.js"></script>     <!--拖拽控件-->     <script src="./js/DragControls.js"></script>     <!--可视化平移控件-->     <script src="./js/TransformControls.js"></script> 复制代码

2、完整代码:

<!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <title>拖拽控件</title>     <style>         body {             margin: 0;             overflow: hidden;         }     </style>     <script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>     <!-- 轨迹球插件 -->     <script src="./js/TrackballControls.js"></script>     <!--拖拽控件-->     <script src="./js/DragControls.js"></script>     <!--可视化平移控件-->     <script src="./js/TransformControls.js"></script> </head> <body>     <script>         // 初始化场景、相机、渲染器、轨迹球控制器、灯光         var scene, camera, renderer, controls, light;         // 场景         function initScene() {             scene = new THREE.Scene();         }         // 相机         function initCamera() {             camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);             camera.position.set(0, 400, 600);             camera.lookAt(new THREE.Vector3(0, 0, 0));         }         // 渲染器         function initRenderer() {             renderer = new THREE.WebGLRenderer();             renderer.setSize(window.innerWidth, window.innerHeight);             document.body.appendChild(renderer.domElement);         }         // 初始化模型         function initContent() {             // 创建坐标格辅助对象.             var helper = new THREE.GridHelper(1200, 50, 0xCD3700, 0x4A4A4A);             // 把坐标格添加到场景中去             scene.add(helper);             // 创建立方体             var cubeGeometry = new THREE.BoxGeometry(100, 100, 100);             // 创建法线网格材质             var cubeMaterial = new THREE.MeshNormalMaterial();             // 创建网格             var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);             // 将网格添加到场景中             scene.add(cube);         }         // 窗口变动触发的方法         function onWindowResize() {             // 设置相机方向             camera.aspect = window.innerWidth / window.innerHeight;             // 设置渲染器的渲染大小             renderer.setSize(window.innerWidth, window.innerHeight);         }         // 初始化轨迹球控件         function initControls() {             // 创建轨迹球控制器             controls = new THREE.TrackballControls(camera, renderer.domElement);             //旋转速度              controls.rotateSpeed = 100;             //变焦速度              controls.zoomSpeed = 3;             //平移速度              controls.panSpeed = 100;             //是否不变焦              controls.noZoom = false;             //是否不平移              controls.noPan = false;             //是否开启移动惯性              controls.staticMoving = true;         }         // 添加拖拽控件         function initDragControls() {             // 添加平移控件             var transformControls = new THREE.TransformControls(camera, renderer.domElement);             scene.add(transformControls);             // 过滤不是 Mesh 的物体,例如辅助网格             var objects = [];             for (let i = 0; i < scene.children.length; i++) {                 if (scene.children[i].isMesh) {                     objects.push(scene.children[i]);                 }             }             // 初始化拖拽控件             var dragControls = new THREE.DragControls(objects, camera, renderer.domElement);             // 鼠标略过             dragControls.addEventListener('hoveron', function (event) {                 transformControls.attach(event.object);             });             // 开始拖拽             dragControls.addEventListener('dragstart', function (event) {                 controls.enabled = false;             });             // 拖拽结束             dragControls.addEventListener('dragend', function (event) {                 controls.enabled = true;             });         }         // 初始化灯光         function initLight() {             light = new THREE.SpotLight(0xffffff);             light.position.set(-300, 600, -400);             scene.add(light);         }         // 初始化         function init() {             initScene();             initCamera();             initRenderer();             initContent();             initLight();             initControls();             initDragControls();             window.addEventListener('resize', onWindowResize, false);         }         function animate() {             //更新轨迹球控件             controls.update();             requestAnimationFrame(animate);             renderer.render(scene, camera);         }         init();         animate();     </script> </body> </html>


作者:筱竹
链接:https://juejin.cn/post/7020422904248533029

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐