项目部署
# 1. 创建 Vite 项目
npm create vite@latest my-threejs-project
# 2. 进入项目目录
cd my-threejs-project
# 3. 安装基础依赖(Vite、Vue 等)
npm install
# 4. 安装 Three.js
npm install three
# 5. 【可选】如果是 TypeScript 项目,安装类型定义
npm install –save-dev @types/three
# 注意:这是为 TypeScript 提供类型提示和自动补全的依赖,
# JavaScript 项目不需要安装!
创建完后package.json中依赖如下:


有了依赖之后在想使用three.js的地方引入依赖即可
//引入three库
import * as Three form 'three'
如何用three.js创建一个几何体?
three.js有核心三大要素:scene(场景),camera(相机),renderer(渲染器)
1、场景(scene)
3d世界的容器,相当于一个展示的舞台,电影拍摄的摄影棚
//创建一个场景
const scene=new Three.Scene();
// 场景的主要属性
scene.background = new THREE.Color(0x87CEEB); // 背景颜色
scene.fog = new THREE.Fog(0x000000, 10, 100); // 雾化效果
scene.environment = environmentMap; // 环境贴图
scene.overrideMaterial = null; // 强制所有物体使用同一材质
2、相机(camera)
相当于观察者的眼睛,决定能看到什么
而相机分为两种:
| 透视相机 (PerspectiveCamera) | 模拟人眼视角,近大远小 |
| 正交相机 (OrthographicCamera) | 等轴视图,无透视变形 |
//创建透视相机
const camera = new Three.PerspectiveCamera(
45,//视角,数值越大视角越大,看到的东西越多(0-180)
window.innerWidth / window.innerHeight,//相机宽高比,设置的窗口大小宽高比
0.1,//近平面,最近能看到的物体位置
1000//远平面,最远能看到的物体位置
);
//创建正交相机
const camera =new Three.OrthographicCamera(
left, // 左裁剪面
right, // 右裁剪面
top, // 上裁剪面
bottom, // 下裁剪面
near, // 近裁剪面
far // 远裁剪面
);
相机通常会预先设置一些属性,如:
- 位置 camera.position.set()
- 看向某个点 camera.lookAt()
- 缩放倍数 camera.zoom = ;
3、渲染器(renderer)
将3d绘制到2d画布,是展示的中最后一步
const renderer = new Three.WebGLRenderer({
canvas: canvasElement, // 使用现有canvas元素
antialias: true, // 开启抗锯齿,性能开销大
alpha: true, // 透明背景
precision: "highp", // 精度:highp/mediump/lowp
})
创建物体的完整流程
第一步:几何体定义形状
下面展示不同的常见基本图形:
//1、立方体
const boxGeometry = new Three.BoxGeometry();
// 默认值
new THREE.BoxGeometry(
1, // width: 宽度 = 1
1, // height: 高度 = 1
1, // depth: 深度 = 1
1, // widthSegments: 宽度分段数 = 1
1, // heightSegments: 高度分段数 = 1
1 // depthSegments: 深度分段数 = 1
);
// 所以以下代码创建的是:
const box = new THREE.BoxGeometry();
// 一个 1×1×1 大小的立方体,没有细分
// 只有6个面,8个顶点
//2、球体
const sphereGeometry = new Three.SphereGeometry();
// 默认值
new THREE.SphereGeometry(
1, // radius: 半径 = 1
32, // widthSegments: 水平分段数 = 32
16, // heightSegments: 垂直分段数 = 16
0, // phiStart: 水平起始角度 = 0
Math.PI * 2, // phiLength: 水平扫描角度 = 2π(360度)
0, // thetaStart: 垂直起始角度 = 0
Math.PI // thetaLength: 垂直扫描角度 = π(180度,完整球体)
);
// 所以以下代码创建的是:
const sphere = new THREE.SphereGeometry();
// 一个半径为1的完整球体
// 有32×16=512个细分面
//3、平面
const planeGeometry = new Three.PlaneGeometry();
// 默认值
new THREE.PlaneGeometry(
1, // width: 宽度 = 1
1, // height: 高度 = 1
1, // widthSegments: 宽度分段数 = 1
1 // heightSegments: 高度分段数 = 1
);
// 所以以下代码创建的是:
const plane = new THREE.PlaneGeometry();
// 一个1×1大小的平面
// 只有2个三角面,4个顶点
//4、圆柱体
const cylinderGeometry = new Three.CylinderGeometry();
// 默认值
new THREE.CylinderGeometry(
1, // radiusTop: 顶部半径 = 1
1, // radiusBottom: 底部半径 = 1
1, // height: 高度 = 1
8, // radialSegments: 径向分段数 = 8
1, // heightSegments: 高度分段数 = 1
false, // openEnded: 是否开口 = false
0, // thetaStart: 起始角度 = 0
Math.PI * 2 // thetaLength: 扫描角度 = 2π(360度,完整圆柱)
);
// 所以以下代码创建的是:
const cylinder = new THREE.CylinderGeometry();
// 一个顶部半径=1,底部半径=1,高度=1的完整圆柱
// 侧面有8个分段
第二步:材质-定义外观
材质类型对比
| MeshBasicMaterial | ❌ 否 | 高 | 不受光照影响,纯色或纹理 | 基础展示 |
| MeshLambertMaterial | ✅ 是 | 中 | 漫反射材质,哑光效果 | 塑料、布料 |
| MeshPhongMaterial | ✅ 是 | 中 | 镜面高光,光泽效果 | 金属、玻璃 |
| MeshStandardMaterial | ✅ 是 | 中 | 基于物理的渲染(PBR) | 真实感材质 |
| MeshPhysicalMaterial | ✅ 是 | 低 | 标准材质的扩展,更真实 | 车漆、清漆 |
| MeshNormalMaterial | ❌ 否 | 高 | 将法线显示为RGB颜色 | 调试用 |
| MeshDepthMaterial | ❌ 否 | 高 | 显示深度信息 | 深度图 |
| MeshMatcapMaterial | ❌ 否 | 高 | 材质捕捉材质 | 风格化 |
// 基础材质示例
const basicMaterial = new THREE.MeshBasicMaterial({
// 基础颜色
color: 0x00ff00, // 颜色(16进制)
opacity: 1.0, // 透明度(0-1)
transparent: false, // 是否透明(opacity<1时需为true)
alphaTest: 0.5, // 透明度测试阈值
// 线框模式
wireframe: false, // 是否显示为线框
wireframeLinewidth: 1, // 线框线宽
// 面渲染
side: THREE.FrontSide, // 渲染的面:FrontSide/BackSide/DoubleSide
vertexColors: false, // 是否使用顶点颜色
// 贴图
map: colorMap, // 颜色贴图
alphaMap: alphaMap, // 透明度贴图
aoMap: aoMap, // 环境光遮蔽贴图
envMap: environmentMap, // 环境贴图
// 混合模式
blending: THREE.NormalBlending, // 混合模式
depthTest: true, // 深度测试
depthWrite: true, // 深度写入
polygonOffset: false, // 多边形偏移
});
第三步:创建网格
// 创建网格(组合几何体和材质)
const mesh = new THREE.Mesh(geometry, material);
// 也可以先创建后指定材质
const mesh = new THREE.Mesh(geometry);
mesh.material = material;
总结一下思路:
核心对象的层级关系图
渲染器 (Renderer)
│
└── canvas元素 (domElement)
场景 (Scene) ← 独立于渲染器存在
│
├── 相机 (Camera) ← 可以添加到场景,但不是必须
│
├── 网格 (Mesh)
│ ├── 几何体 (Geometry) ← 被网格引用
│ └── 材质 (Material) ← 被网格引用
│
├── 灯光 (Light)
│
├── 辅助对象 (AxesHelper, GridHelper)
│
└── 其他3D对象
首次尝试搓出一个自动旋转的正方体
代码
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import *as Three from "three"
createApp(App).mount('#app')
//1、创建场景
const scene = new Three.Scene();
//2、创建相机(透视相机)
const camera = new Three.PerspectiveCamera(
45,//视角,数值越大视角越大,看到的东西越多
window.innerWidth / window.innerHeight,//相机宽高比设置的窗口大小宽高比
0.1,//近平面,最近能看到的物体位置
1000//远平面,最远能看到的物体位置
)
//3、创建渲染器
const renderer = new Three.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
//测试:创建几何体
const geometry = new Three.BoxGeometry(1, 1, 1);
//创建材质
const material = new Three.MeshBasicMaterial({ color: 0x00ff00 });
//创建网格
const cube = new Three.Mesh(geometry, material);
//将网格添加到场景中
scene.add(cube);
//设置相机位置
camera.position.z = 5;
//相机看向?
camera.lookAt(0, 0, 0);
//动态渲染附加函数,渲染
function animate() {
requestAnimationFrame(animate);
//实现旋转
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
//静态渲染
// renderer.render(scene, camera);
animate();
关于渲染函数
代码所示是自动旋转,而渲染函数的整体步骤和结构就应该是:
(1)在外部提供渲染函数入口
(2)内部先调用requestAnimationFrame(animate);
(3)中间写变化
(4)结尾重新渲染renderer.render(scene,camera);
由于好奇所以又探索了如何通过鼠标来旋转:
要引入Three官方的函数
// 必须导入 OrbitControls
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
创建控制器对象:
// 6、创建 OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 7、配置控制器
controls.enableDamping = true; // 启用阻尼(惯性效果)
controls.dampingFactor = 0.05; // 阻尼系数
controls.rotateSpeed = 0.5; // 旋转速度
controls.enableZoom = true; // 允许缩放
controls.enablePan = true; // 允许平移
controls.minDistance = 2; // 最小缩放距离
controls.maxDistance = 10; // 最大缩放距离
并且略微修改渲染函数的中间代码:
//动态渲染附加函数,渲染
function animate() {
requestAnimationFrame(animate);
//实现旋转
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
controls.update();
renderer.render(scene, camera);
}
上述基本过程对于如何整合到框架中不再赘述
添加坐标辅助器
添加世界坐标系可以帮助我们了解位置
//添加世界坐标辅助器(可以看成一个物体)
const axesHelper = new Three.AxesHelper(5);//相当于设置线段长度
scene.add(axesHelper);
一个疑问:canvas到底是什么
// 当你创建渲染器时
const renderer = new THREE.WebGLRenderer();
// 实际上内部发生了这些事:
// 1. Three.js 在内存中创建了一个 <canvas> 元素
// 2. 将这个 canvas 存储在 renderer.domElement
// 3. 设置 WebGL 上下文
// 这个 canvas 元素是:
console.log(renderer.domElement); // 输出: <canvas></canvas>
console.log(renderer.domElement instanceof HTMLCanvasElement); // true
画布自适应
为了解决用户时而会改变窗口大小但画布只渲染一次的问题,现在要解决画布自适应
主要是更新相机的视角以及渲染器的大小(宽高)
window.addEventListener('resize', () => {
const width = window.innerWidth;
const height = window.innerHeight;
// 更新相机
camera.aspect = width / height;
camera.updateProjectionMatrix();
// 更新渲染器
renderer.setSize(width, height);
renderer.setPixelRatio(window.devicePixelRatio);
});
网硕互联帮助中心





评论前必须登录!
注册