引言
一切都要从两个月前在网上看到的小米 SU7 在线体验网页说起。
第一部分 了解 three.js 背景
OpenGL
OpenGL 准确地说是一个函数规范,可以由不同的语言实现。目前的 OpenGL 库大多由显卡厂商开发。
参考阅读:主页 - LearnOpenGL CN OpenGL 学习教程
GPU
画面渲染使用 GPU 的原因在于,屏幕每一个像素点都需要计算,需要的计算量非常大,但是计算过程并不复杂。因此,相比于 CPU 使用几个强大的处理器而言,使用大量微处理器并行处理更为合适,而且部分计算过程可以通过硬件加速。
GLSL
OpenGL 的着色器语言,类 C 语言。着色器函数分为顶点着色器和片段着色器,可以理解为每个像素点的位置和颜色。
参考阅读:The Book of Shaders shaders 学习教程
着色器分享展示:https://www.shadertoy.com/view/Ms2SD1
WebGL
WebGL 是 OpenGL 图形库的 JavaScript 端口,允许 web 页面直接将渲染计算传递给设备的 GPU,这会以非常高的速度处理,并在 <canvas>
内渲染结果。
WebGL 作为 HTML <canvas>
元素的特定上下文运行,它让你能够在 JavaScript 中访问硬件加速的 3D 渲染(即 GPU 加速)。因为它在 <canvas>
元素中运行,WebGL 还可以完全集成所有 DOM 接口。
WebGL 程序由 JavaScript 编写的控制代码和 OpenGL Shading Language(GLSL)编写的着色器代码组成,着色器程序是以字符串的形式嵌入到 JS 文件中运行。
参考阅读:WebGL 基础概念
使用着色器程序绘制 3D 图形非常复杂。

参考阅读:
Three.js
基于 WebGL 的 JS 框架,简化了 WebGL 的使用,类似于 Echarts 这样的库。
参考阅读:three.js 官方手册
第二部分 three.js 基础
使用 three.js 编写一个最基础的旋转立方体
<template>
<div ref="canvasRef"></div>
</template>
<script setup>
import { onMounted, onUnmounted, ref, watch } from "vue";
import * as THREE from 'three';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
// 引入轨道控制器扩展库 OrbitControls.js
// 创建 3D 场景对象 Scene
const scene = new THREE.Scene();
// 创建一个长方体几何对象 Geometry
const geometry = new THREE.BoxGeometry(100, 20, 20);
// 创建一个材质对象 basic_material
// 基础材质不受光照影响
const basic_material = new THREE.MeshBasicMaterial({
color: 0x66ccff, // 0xff0000 设置材质颜色为蓝色
transparent: true, // 开启透明
opacity: 0.5, // 设置透明度
});
// MeshLambertMaterial 受光照影响
const lambert_material = new THREE.MeshLambertMaterial({
color: 0x66ccff
});
// 两个参数分别为几何体 geometry、材质 basic_material
const mesh = new THREE.Mesh(geometry, lambert_material); // 网格模型对象 Mesh
// 设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(10, 10, 0);
// AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(150);
scene.add(axesHelper);
// 将物体添加到场景中
scene.add(mesh);
// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
// 相机在 Three.js 三维坐标系中的位置
// 根据需要设置相机位置具体值
camera.position.set(20, 200, 200);
// 相机观察目标指向 Threejs 3D 空间中某个位置
camera.lookAt(0, 10, 10); // 坐标原点
// 定义相机输出画布的尺寸 (单位: 像素 px)
const width = 1200; // 宽度
const height = 800; // 高度
// 30: 视场角度, width / height: Canvas 画布宽高比, 1: 近裁截面, 3000:远裁截面
// 点光源:两个参数分别表示光源颜色和光照强度
// 参数1:0xffffff 是纯白光, 表示光源颜色
// 参数2:1.0, 表示光照强度,可以根据需要调整
const pointLight = new THREE.PointLight(0xffffff, 3.0);
// 点光源位置
pointLight.position.set(100, 100, 100); // 点光源放在 x 轴上
scene.add(pointLight); // 点光源添加到场景中
// 环境光: 没有特定方向,整体改变场景的光照明暗
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); // 设置 three.js 渲染区域的尺寸 (像素 px)
// renderer.render(scene, camera); // 执行渲染操作
// 设置相机控件轨道控制器 OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 如果 OrbitControls 改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
renderer.render(scene, camera); // 执行渲染操作
}); // 监听鼠标、键盘事件
// 平行光
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:可视化平行光
const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5, 0xff0000);
scene.add(dirLightHelper);
// 对比不同入射角,mesh 表面对光照的反射效果
directionalLight.position.set(50, 100, 0);
// 渲染函数
function render() {
renderer.render(scene, camera); // 执行渲染操作
mesh.rotateY(0.01); // 每次绕 y 轴旋转 0.01 弧度
requestAnimationFrame(render); // 请求再次执行渲染函数 render,渲染下一帧
}
render();
const canvasRef = ref();
onMounted(() => {
canvasRef.value.appendChild(renderer.domElement);
});
onUnmounted(() => {});
</script>
<style>
</style>