简介
Three.js是一个基于原生WebGL,轻量级,跨平台的Javascript库,可以在浏览器上结合HTML5的canvas,SVG或者WebGL,创建和展示3D模型和动画。允许我们在不依赖任何浏览器插件的情况下,创建一个GPU加速的3D动画场景。
WebGL是一种JavaScript API,用于在不使用插件的情况下在任何兼容的网页浏览器中呈现交互式2D和3D图形。WebGL完全集成到浏览器的所有网页标准中,可将影像处理和效果的GPU加速使用方式当做网页Canvas的一部分。WebGL元素可以加入其他HTML元素之中并与网页或网页背景的其他部分混合,WebGL技术结合了HTML5和 Java Script,允许开发者在网页(Web页面)上创建和渲染三维图形。
WebGL 工作原理
WebGL在GPU上的工作基本上分为两部分,第一部分是将顶点(或数据流)转换到裁剪空间坐标, 第二部分是基于第一部分的结果绘制像素点。
左侧是你提供的数据。顶点着色器(Vertex Shader)是写进GLSL中的一个方法,每个顶点调用一次,在这个方法中做一些数学运算后设置了一个特殊的gl_Position
变量, 这个变量就是该顶点转换到裁剪空间中的坐标值,GPU接收该值并将其保存起来。
假设你正在画三角形,顶点着色器每完成三次顶点处理,WebGL就会用这三个顶点画一个三角形。 它计算出这三个顶点对应的像素后,就会光栅化这个三角形。对于每一个像素,它会调用片段着色器询问你使用什么颜色。 你通过给片段着色器的一个特殊变量gl_FragColor
设置一个颜色值,实现自定义像素颜色。
基本概念
ThreeJS 采用的是右手坐标系。
场景Scene
Scene对象可以理解为虚拟的3D场景,用来表示模拟生活中的真实三维场景,所有物品的容器。可以把场景想象成一个空房间,接下来会往房间里面放置要呈现的物体、相机、光源。
// 创建3D场景对象Scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
物体形状:几何体Geometry
形状决定物体的轮廓
//BoxGeometry:长方体 参数1: x 参数2: y 参数3: z
const geometry = new THREE.BoxGeometry(100, 100, 100);
// SphereGeometry:球体
const geometry = new THREE.SphereGeometry(50);
// CylinderGeometry:圆柱 参数1: 顶部半径 参数2: 底部半径 参数3: 高
const geometry = new THREE.CylinderGeometry(50,50,100);
// PlaneGeometry:矩形平面
const geometry = new THREE.PlaneGeometry(100,50);
// CircleGeometry:圆形平面
const geometry = new THREE.CircleGeometry(50);
物体外观:材质Material
材质则是物体的材料和质感,如果你想定义物体的外观效果,比如颜色,就需要通过材质Material
实现。
//创建一个材质对象Material, 参数: 用于定义材质外观的对象
const material = new THREE.MeshBasicMaterial({
color: 0x000000,//设置材质颜色为黑色
transparent:true,//开启透明
opacity:0.5,//设置透明度
});
物体:网格模型Mesh
实际生活中有各种各样的物体,在threejs中可以通过网格模型Mesh表示一个虚拟的物体。物体由形状和材质两部分组成。
// 两个参数分别为几何体geometry、材质material
const mesh = new THREE.Mesh(geometry, material);
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(0,10,0);
//通过add方法把网格模型Mesh添加到场景Scene
scene.add(mesh);
相机Camera
如果想把三维场景Scene
渲染到web网页上,还需要定义一个虚拟相机Camera
。
Threejs 必须要往场景中添加一个相机,用来确定观察位置、方向、角度,相机看到的内容,就是我们最终在屏幕上看到的内容。
Threejs提供了正交相机OrthographicCamera和透视相机PerspectiveCamera。
透视投影跟人眼看到的世界是一样的,近大远小;正交投影则远近都是一样的大小。
// 实例化一个透视投影相机对象
// fov — 相机视锥体垂直视野角度
// aspect — 相机视锥体长宽比
// near — 相机视锥体近端面
// far — 相机视锥体远端面
const camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
//通过position属性设置相机在坐标系中的位置
camera.position.set(200, 200, 200);
//通过lookAt设置相机观察目标指向3D空间中某个位置
camera.lookAt(0, 0, 0);
渲染器
Threejs 绘制的东西,最终需要在屏幕一块画布上显示出来。
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
// 定义输出的Canvas画布尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 场景Scene渲染在canvas上
renderer.render(scene, camera); //执行渲染操作
// Canvas插入到任意HTML元素中
document.body.appendChild(renderer.domElement);
光源对物体表面影响
实际生活中物体表面的明暗效果是会受到光照的影响,比如晚上不开灯,你就看不到物体,灯光比较暗,物体也比较暗。在threejs中,用网格模型Mesh
模拟生活中物体,所以threejs中模拟光照Light
对物体表面的影响,就是模拟光照Light
对网格模型Mesh
表面的影响。
基础网格材质MeshBasicMaterial不会受到光照影响。漫反射网格材质MeshLambertMaterial会受到光照影响。
一个立方体使用漫反射网格材质MeshLambertMaterial,不同面和光线夹角不同,立方体不同面就会呈现出来不同的明暗效果。
光源Light
假如没有光,摄像机看不到任何东西,因此需要往场景中添加光源。为了跟真实世界更加接近,Threejs 支持模拟不同光源,展现不同光照效果,有点光源、平行光、聚光灯、环境光等。
点光源
//点光源:两个参数分别表示光源颜色和光照强度
// 参数1:光源颜色
// 参数2:光照强度
const pointLight = new THREE.PointLight(0xffffff, 1.0);
// 或者通过intensity设置光照强度
pointLight.intensity = 1.0;
光源衰减
随着距离的改变,光线会衰减,越来越弱,光源衰减属性decay
默认值是2.0。
pointLight.decay = 0.0;//设置光源不随距离衰减
光源位置
把点光源想象为一个灯泡,在3D空间中,放的位置不同,模型的渲染效果就不一样。
//点光源位置
pointLight.position.set(400, 0, 0);
scene.add(pointLight); //点光源添加到场景中
点光源辅助观察PointLightHelper
通过点光源辅助观察对象PointLightHelper可视化点光源。
// 光源辅助观察
// 参数1:被模拟的光源.
// 参数2:尺寸. 默认为 1.
// 参数3:颜色,如果没有设置颜色将使用光源的颜色.
const pointLightHelper = new THREE.PointLightHelper(pointLight, 10, 0xff0000);
scene.add(pointLightHelper);
环境光
环境光AmbientLight没有特定方向,只是整体改变场景的光照明暗。
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);
平行光
平行光DirectionalLight就是沿着特定方向发射。亮度与光源和物体之间的距离无关,只与平行光的角度和物体所在平面有关。
// 平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算
directionalLight.position.set(80, 100, 50);
// 方向光指向对象网格模型mesh,可以不设置,默认的位置是0,0,0
directionalLight.target = mesh;
scene.add(directionalLight);
平行光辅助观察DirectionalLightHelper
// DirectionalLightHelper:可视化平行光
// 参数1:被模拟的光源.
// 参数2:尺寸. 默认为 1.
// 参数3:颜色,如果没有设置颜色将使用光源的颜色.
const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5,0xff0000);
scene.add(dirLightHelper);
聚光源
聚光源可以认为是一个沿着特定方会逐渐发散的光源,照射范围在三维空间中构成一个圆锥体。
// 聚光源
const spotLight = new THREE.SpotLight(0xffffff,1.0);
// 设置聚光光源位置
spotLight.position.set(100, 100, 100);
// 设置聚光光源发散角度
spotLight.angle = Math.PI / 6;//光锥角度的二分之一
scene.add(spotLight);//光源添加到场景中
// spotLight.target是一个模型对象Object3D,默认在坐标原点
spotLight.target.position.set(50,0,0);
//spotLight.target添加到场景中.target.position才会起作用
scene.add(spotLight.target);
聚光源辅助对象SpotLightHelper
// 聚广源辅助对象,可视化聚广源
const spotLightHelper = new THREE.SpotLightHelper(spotLight,0xffffff)
scene.add(spotLightHelper);
辅助观察坐标系
THREE.AxesHelper()
的参数表示坐标系坐标轴线段尺寸大小,可以根据需要改变尺寸。
// 辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(150);
scene.add(axesHelper);
相机控件OrbitControls
开发调试代码,或者展示模型的时候,可以通过相机控件OrbitControls实现旋转缩放预览效果。
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
renderer.render(scene, camera); //执行渲染操作
});
动画渲染循环
threejs可以借助HTML5的API请求动画帧window.requestAnimationFrame
实现动画渲染。
// 渲染函数
function animate() {
renderer.render(scene, camera); //执行渲染操作
mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
mesh.rotateX(0.01)
mesh.scale.x = 2; //延X方向放大
mesh.position.y += 0.1 * i; //延y轴移动
requestAnimationFrame(animate);//请求再次执行渲染函数render,渲染下一帧
}
animate();