看前先知
WebGL
- WebGL(Web 图形库)是一个 JavaScript API
- 浏览器中渲染高性能的交互式 3D 和 2D 图形
- WebGL 通过引入一个与 OpenGL ES 2.0 非常一致的 API 来做到这一点,该 API 可以在 HTML5
<canvas>元素中使用 - 可以利用用户设备提供的硬件图形加速
- WebGL 程序由 javascript 的控制代码
结论:WebGL 给我们提供了一系列的图形接口,能够让我们通过 JavaScript 去使用 GPU 来进行浏览器图形渲染的工具。
ThreeJs
- Three.js 是采用js编写的类库
- 在 WebGL 的 API 接口基础上,又进行的一层封装的通用Web 3D引擎
- 以简单、直观的方式封装了 3D 图形编程中常用的对象
- 降低了图形编程的困难,易上手
three.js应用空间
在小游戏、产品展示、物联网、数字孪生、智慧城市园区、机械、建筑、全景看房、GIS等各个领域基本上都有three.js的身影。
threeJs三个基本概念
Three.js的第一步,就是认识场景Scene、相机Camera、渲染器Renderer三个基本概念
场景Scene
场景能够让你在什么地方、摆放什么东西来交给three.js来渲染,这是你放置物体、灯光和摄像机的地方。
可以把三维场景Scene对象理解为虚拟的3D场景,用来表示模拟生活中的真实三维场景,或者说三维世界。
// 创建3D场景对象Scene
const scene = new THREE.Scene();
相机Camera
把三维场景Scene渲染到web网页上,还需要定义一个虚拟相机Camera。
Threejs提供了正投影相机OrthographicCamera和透视投影相机PerspectiveCamera
正投影相机
- 在这种投影模式下,无论物体距离相机距离远或者近,在最终渲染的图片中物体的大小都保持不变。
- 对于渲染2D场景或者UI元素是非常有用的。
const camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 );
scene.add( camera );
透视投影相机
- 透视投影相机
PerspectiveCamera本质上就是在模拟人眼观察这个世界的规律。 - 是3D场景的渲染中使用得最普遍的投影模式。
const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
scene.add( camera );
- 视锥体
- 透视投影相机的四个参数
fov, aspect, near, far构成一个四棱台3D空间,被称为视锥体,只有视锥体之内的物体,才会渲染出来,视锥体范围之外的物体不会显示在Canvas画布上。 PerspectiveCamera参数介绍
- 透视投影相机的四个参数
PerspectiveCamera( fov, aspect, near, far )
| 参数 | 含义 | 默认值 |
|---|---|---|
| fov | 相机视锥体竖直方向视野角度 | 50 |
| aspect | 相机视锥体水平方向和竖直方向长度比,一般设置为Canvas画布宽高比width / height | 1 |
| near | 相机视锥体近裁截面相对相机距离 | 0.1 |
| far | 相机视锥体远裁截面相对相机距离,far-near构成了视锥体高度方向 | 2000 |
渲染器Renderer
用WebGL渲染出你精心制作的场景
渲染器Renderer决定了内容如何呈现在屏幕上
对于threejs而言,如果完成“咔”这个拍照动作,就需要一个新的对象,也就是WebGL渲染器WebGLRenderer 。
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
// 定义threejs输出画布的尺寸(单位:像素px)
const width = 800; //宽度
const height = 500; //高度
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
renderer.render(scene, camera); //执行渲染操作
// 渲染器`WebGLRenderer`通过属性`.domElement`可以获得渲染方法`.render()`生成的Canvas画布,`.domElement`本质上就是一个HTML元素:Canvas画布
document.body.appendChild(renderer.domElement);
三维坐标系
AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(150);
scene.add(axesHelper);
如上图所示:three.js坐标轴颜色红R、绿G、蓝B分别对应坐标系的x、y、z轴,对于three.js的3D坐标系默认y轴朝上。
绘制立方体
/**创建3D场景对象Scene*/
const scene = new THREE.Scene();
// 透视相机
const camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
1,
1000
);
// 渲染器
const renderer = new THREE.WebGLRenderer({
antialias: true, // 执行抗锯齿
});
// 设置颜色
renderer.setClearColor(0xffffff);
// 输出canvas的大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 渲染器在其上绘制输出一个canvas
document.body.appendChild(renderer.domElement);
// 创建一个立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 以简单着色(平面或线框)方式来绘制几何体的材质
const material = new THREE.MeshBasicMaterial({
color: 0x285b41, //颜色
wireframe: true, // 将几何体渲染为线框
});
// 表示基于以三角形为polygon mesh(多边形网格)的物体的类
const mesh = new THREE.Mesh(geometry, material);
// 网格模型mesh表示的物体 添加到三维场景scene中。
scene.add(mesh);
// 向量的z值
camera.position.z = 4;
const animate = () => {
// 一固定动画帧时间 渲染画布
requestAnimationFrame(animate);
// 物体的局部旋转,以弧度来表示
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.01;
mesh.rotation.z += 0.01;
// 把三维场景Scene呈现在canvas画布上面
renderer.render(scene, camera);
};
animate();
使用纹理贴图
// 创建一个纹理贴图,将其应用到一个表面,或者作为反射/折射贴图。
const texture = new THREE.TextureLoader().load( "img/crate.gif" );
// 以简单着色(平面或线框)方式来绘制几何体的材质
const material = new THREE.MeshBasicMaterial({
map:texture,// 颜色贴图
});
效果:
加载轨迹球控制器
- 可以使用鼠标旋转物体
- 需在文件中加载轨道球控制器文件
controls = new THREE.TrackballControls(
camera,
renderer.domElement
);
controls.update()
物体外部:
物体内部:
光源效果
生活中物体表面的明暗效果是会受到光照的影响,threejs中同样也要模拟光照Light对网格模型Mesh表面的影响。
threejs提供的网格材质,有的受光照影响,有的不受光照影响。
Three.js提供了多种模拟生活中光源的API
平行光
// 红色平行光
const directionalLight = new THREE.DirectionalLight("red");
// 光源位置
directionalLight.position.set(0, 30, 0);
scene.add(directionalLight);// 加入到场景中
环境光
// 环境光
const ambientLight = new THREE.AmbientLight('orange')
// 光源位置
ambientLight.position.set(0, 30, 0);
scene.add(ambientLight);// 加入到场景中
半球光
- 光源直接放置于场景之上,光照颜色从天空光线颜色渐变到地面光线颜色。
- 半球光不能投射阴影
const hemisphereLight = new THREE.HemisphereLight("red");
// 光源位置
hemisphereLight.position.set(0, 30, 0);
scene.add(hemisphereLight);// 加入到场景中