Three.js入门

155 阅读5分钟

看前先知

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三个基本概念 image.png

场景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参数介绍

image.png

PerspectiveCamera( fov, aspect, near, far )
参数含义默认值
fov相机视锥体竖直方向视野角度50
aspect相机视锥体水平方向和竖直方向长度比,一般设置为Canvas画布宽高比width / height1
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);

image.png 如上图所示:three.js坐标轴颜色红R、绿G、蓝B分别对应坐标系的xyz轴,对于three.js的3D坐标系默认y轴朝上

绘制立方体

image.png

			/**创建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,// 颜色贴图
	});

效果:

image.png

加载轨迹球控制器

  • 可以使用鼠标旋转物体
  • 需在文件中加载轨道球控制器文件
	controls = new THREE.TrackballControls(
		camera,
		renderer.domElement
	);
        controls.update()

物体外部:

image.png 物体内部:

image.png

光源效果

生活中物体表面的明暗效果是会受到光照的影响,threejs中同样也要模拟光照Light对网格模型Mesh表面的影响。

threejs提供的网格材质,有的受光照影响,有的不受光照影响。

Three.js提供了多种模拟生活中光源的API

image.png

平行光

image.png

        // 红色平行光
	const directionalLight = new THREE.DirectionalLight("red");
        // 光源位置
	directionalLight.position.set(0, 30, 0);
	scene.add(directionalLight);// 加入到场景中

环境光

image.png

        // 环境光
        const ambientLight = new THREE.AmbientLight('orange')
        // 光源位置
	ambientLight.position.set(0, 30, 0);
	scene.add(ambientLight);// 加入到场景中

半球光

  • 光源直接放置于场景之上,光照颜色从天空光线颜色渐变到地面光线颜色。
  • 半球光不能投射阴影

image.png

	const hemisphereLight = new THREE.HemisphereLight("red");
        // 光源位置
	hemisphereLight.position.set(0, 30, 0);
	scene.add(hemisphereLight);// 加入到场景中