简介
网页上已经可以做出很多复杂的动画,精美的效果。下图就是通过WebGL在网页中绘制高性能的3D图形。
threejs是一个让用户通过javascript入手进入搭建webgl项目的类库。
1、搭建第一个场景和物体
三维的物体要渲染在二维的屏幕上。首先要创建一个场景来放置物体,那么最终怎么显示三维的内容,就应该找一个相机,将相机放在场景的某个位置,然后想要显示就要把相机拍的内容渲染出来。所以就引出三个基本概念:场景、相机、渲染器
用vuecli搭建一个脚手架之后,可以在src/main.js中编写three.js,代码如下(代码下面会进行讲解):
// 1、创建场景——————场景const scene = new THREE.Scene();// 2、创建相机——————相机const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000);// 设置相机位置camera.position.set(0, 0, 10);// 初始化渲染器——————渲染器,就是施展魔法的地方const renderer = new THREE.WebGLRenderer();// 设置渲染的尺寸大小renderer.setSize(window.innerWidth, window.innerHeight);// console.log(renderer);// 将webgl渲染的canvas内容添加到bodydocument.body.appendChild(renderer.domElement);// 使用渲染器,通过相机将场景渲染进来renderer.render(scene, camera);
相机:
three.js里有几种不同的相机,在这里,我们使用的是PerspectiveCamera(透视摄像机)。
第一个参数是视野角度(FOV)。视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)。
第二个参数是长宽比(aspect ratio)。 也就是你用一个物体的宽除以它的高的值。比如说,当你在一个宽屏电视上播放老电影时,可以看到图像仿佛是被压扁的。
接下来的两个参数是近截面(near)和远截面(far)。 当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中。或许现在你不用担心这个值的影响,但未来为了获得更好的渲染性能,你将可以在你的应用程序里去设置它。
渲染器:
除了创建一个渲染器的实例之外,我们还需要在我们的应用程序里设置一个渲染器的尺寸。比如说,我们可以使用所需要的渲染区域的宽高,来让渲染器渲染出的场景填充满我们的应用程序。因此,我们可以将渲染器宽高设置为浏览器窗口宽高。对于性能比较敏感的应用程序来说,你可以使用setSize传入一个较小的值,例如window.innerWidth/2和window.innerHeight/2,这将使得应用程序在渲染时,以一半的长宽尺寸渲染场景。
接下来将renderer(渲染器)的dom元素(renderer.domElement)添加到我们的HTML文档中。渲染器用来显示场景给我们看的canvas元素。
最后就是对将相机对场景进行拍照渲染啦。这一句就可以将画面渲染到canvas上显示出来
加入立方体:
// 添加物体// 创建几何体const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });// 根据几何体和材质创建物体const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);// 将几何体添加到场景中scene.add(cube);
1、要创建一个立方体,我们需要一个BoxGeometry(立方体)对象. 这个对象包含了一个立方体中所有的顶点(vertices)和面(faces)。
2、对于这个立方体,我们需要给它一个材质,来让它有颜色。这里我们使用的是MeshBasicMaterial。所有的材质都存有应用于他们的属性的对象。为了简单起见,我们只设置一个color属性,值为0x00ff00,也就是绿色。这里和CSS或者Photoshop中使用十六进制(hex colors)颜色格式来设置颜色的方式一致。
3、我们需要一个Mesh(网格)。 网格包含一个几何体以及作用在此几何体上的材质,我们可以直接将网格对象放入到我们的场景中,并让它在场景中自由移动。
默认情况下,当我们调用**scene.add()的时候,物体将会被添加到(0,0,0)**坐标。但将使得摄像机和立方体彼此在一起。为了防止这种情况的发生,我们只需要将摄像机稍微向外移动一些即可。
综上,在前面创建的项目中的main.js文件写入完整代码如下:
import * as THREE from "three";// console.log(THREE);// 1、创建场景const scene = new THREE.Scene();// 2、创建相机const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000);// 设置相机位置camera.position.set(0, 0, 10);scene.add(camera);// 添加物体// 创建几何体const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });// 根据几何体和材质创建物体const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);// 将几何体添加到场景中scene.add(cube);// 初始化渲染器const renderer = new THREE.WebGLRenderer();// 设置渲染的尺寸大小renderer.setSize(window.innerWidth, window.innerHeight);// console.log(renderer);// 将webgl渲染的canvas内容添加到bodydocument.body.appendChild(renderer.domElement);// 使用渲染器,通过相机将场景渲染进来renderer.render(scene, camera);
2、如何360度的查看立方体
我们知道了如何渲染出一个立方体物体,但是不能很好的全方位观看立方体。这个时候可以使用控制控制器,让相机围绕立方体运动,就像地球围绕太阳一样运动,去观察立方体。
1、首先创建轨道控制器
// 创建轨道控制器const controls = new OrbitControls(camera, renderer.domElement);// 必须传入2个参数:// 相机,让哪一个相机围绕目标运动。默认目标是原点。立方体在原点处。// 渲染的画布dom对象,用于监听鼠标事件控制相机的围绕运动。
因为控制器监听鼠标事件之后,要根据鼠标的拖动,来控制相机围绕目标运动,并根据运动之后的效果,显示出画面来。为了保证画面流畅渲染,选择使用请求动画帧requestAnimationFrame,在屏幕渲染下一帧画面时触发回调函数来执行画面的渲染。
function render() { //如果后期需要控制器带有阻尼效果,或者自动旋转等效果,就需要加入controls.update() controls.update() renderer.render(scene, camera); // 渲染下一帧的时候就会调用render函数 requestAnimationFrame(render);}render();
requestAnimationFrame(render):
是HTML5的新特性,区别于setTimeout和setInterval。requestAnimationFrame比后两者精确,采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。
requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销。
完整代码如下:
import * as THREE from "three";// 导入轨道控制器import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";// console.log(THREE);// 目标:使用控制器查看3d物体// 1、创建场景const scene = new THREE.Scene();// 2、创建相机const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000);// 设置相机位置camera.position.set(0, 0, 10);scene.add(camera);// 添加物体// 创建几何体const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });// 根据几何体和材质创建物体const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);// 将几何体添加到场景中scene.add(cube);// 初始化渲染器const renderer = new THREE.WebGLRenderer();// 设置渲染的尺寸大小renderer.setSize(window.innerWidth, window.innerHeight);// console.log(renderer);// 将webgl渲染的canvas内容添加到bodydocument.body.appendChild(renderer.domElement);// // 使用渲染器,通过相机将场景渲染进来// renderer.render(scene, camera);// 创建轨道控制器const controls = new OrbitControls(camera, renderer.domElement);// 添加坐标轴辅助器const axesHelper = new THREE.AxesHelper(5);scene.add(axesHelper);function render() { renderer.render(scene, camera); // 渲染下一帧的时候就会调用render函数 requestAnimationFrame(render);}render();
未完待续...