Three.js 超全入门综合案例
-
- 代码示例
- 一、文档说明
- 二、整体运行流程(核心逻辑)
- 三、核心模块详细解析
-
- [1. 基础三要素(必备)](#1. 基础三要素(必备))
-
- [1.1 Scene 场景](#1.1 Scene 场景)
- [1.2 PerspectiveCamera 透视相机](#1.2 PerspectiveCamera 透视相机)
- [1.3 WebGLRenderer 渲染器](#1.3 WebGLRenderer 渲染器)
- [2. 轨道控制器 OrbitControls(交互核心)](#2. 轨道控制器 OrbitControls(交互核心))
- [3. 场景辅助工具(开发调试必备)](#3. 场景辅助工具(开发调试必备))
- [4. 光照系统(画面质感关键)](#4. 光照系统(画面质感关键))
-
- [4.1 AmbientLight 环境光](#4.1 AmbientLight 环境光)
- [4.2 DirectionalLight 平行光(主光)](#4.2 DirectionalLight 平行光(主光))
- [4.3 PointLight 点光源(辅光/氛围光)](#4.3 PointLight 点光源(辅光/氛围光))
- [4.4 补光灯 FillLight](#4.4 补光灯 FillLight)
- [5. 几何体 \+ PBR 材质 \+ 网格模型](#5. 几何体 + PBR 材质 + 网格模型)
-
- [5.1 核心公式](#5.1 核心公式)
- [5.2 本案例包含几何体](#5.2 本案例包含几何体)
- [5.3 PBR 物理材质 MeshStandardMaterial](#5.3 PBR 物理材质 MeshStandardMaterial)
- [5.4 阴影开关](#5.4 阴影开关)
- [6. 射线拾取 Raycaster(3D交互核心)](#6. 射线拾取 Raycaster(3D交互核心))
- [7. 窗口自适应](#7. 窗口自适应)
- [8. 动画系统](#8. 动画系统)
-
- [8.1 Clock 时钟](#8.1 Clock 时钟)
- [8.2 requestAnimationFrame 渲染循环](#8.2 requestAnimationFrame 渲染循环)
- 四、画面美化核心优化点(解决原版昏暗问题)
- 五、知识点全覆盖清单
- 六、运行方式
- 七、拓展学习方向(进阶)
代码示例
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Three.js 综合入门示例</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
overflow: hidden;
background: #121826;
color: #fff;
font-family: system-ui;
}
#info {
position: absolute;
top: 12px;
left: 12px;
z-index: 10;
background: rgba(0, 0, 0, 0.45);
padding: 12px 16px;
border-radius: 10px;
font-size: 14px;
line-height: 1.7;
backdrop-filter: blur(4px);
}
canvas {
display: block;
}
</style>
</head>
<body>
<div id="info">
Three.js 入门综合示例<br>
🖱️鼠标拖拽旋转 | 滚轮缩放 | 右键平移<br>
点击物体,F12控制台查看拾取信息
</div>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.164.1/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.164.1/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
// 1.场景、相机、渲染器
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a2438);
scene.fog = new THREE.Fog(0x1a2438, 15, 80); // 雾化调远,不会近处灰蒙蒙
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(14, 11, 18);
const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping; // ACES色调映射,画面更通透
renderer.toneMappingExposure = 1.3; // 整体曝光提亮
document.body.appendChild(renderer.domElement);
// 2.轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 4;
controls.maxDistance = 60;
// 3.辅助
const axesHelper = new THREE.AxesHelper(9);
scene.add(axesHelper);
const gridHelper = new THREE.GridHelper(35, 35, 0x50648c, 0x2c3b58);
scene.add(gridHelper);
// 4.光照【大幅提亮】
const ambientLight = new THREE.AmbientLight(0xffffff, 0.65); // 环境光增强
scene.add(ambientLight);
// 主太阳光
const directionalLight = new THREE.DirectionalLight(0xfffdf5, 1.1);
directionalLight.position.set(14, 20, 10);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.set(2048, 2048);
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 80;
directionalLight.shadow.camera.left = -25;
directionalLight.shadow.camera.right = 25;
directionalLight.shadow.camera.top = 25;
directionalLight.shadow.camera.bottom = -25;
directionalLight.shadow.bias = -0.0008;
scene.add(directionalLight);
// 彩色点光源
const pointLight = new THREE.PointLight(0xff66aa, 0.8, 30);
pointLight.position.set(-10, 7, -7);
pointLight.castShadow = true;
scene.add(pointLight);
// 补光,消除死黑角落
const fillLight = new THREE.PointLight(0xaaccff, 0.4, 40);
fillLight.position.set(8, 5, -10);
scene.add(fillLight);
// 5.物体 PBR材质,调亮色彩
const cubeGeo = new THREE.BoxGeometry(2.3, 2.3, 2.3);
const cubeMat = new THREE.MeshStandardMaterial({
color: 0x44aaff,
metalness: 0.3,
roughness: 0.22
});
const cubeMesh = new THREE.Mesh(cubeGeo, cubeMat);
cubeMesh.position.set(-4.5, 1.3, 0);
cubeMesh.castShadow = true;
cubeMesh.receiveShadow = true;
scene.add(cubeMesh);
const sphereGeo = new THREE.SphereGeometry(1.7, 32, 32);
const sphereMat = new THREE.MeshStandardMaterial({
color: 0xff9944,
metalness: 0.55,
roughness: 0.18
});
const sphereMesh = new THREE.Mesh(sphereGeo, sphereMat);
sphereMesh.position.set(0, 1.7, -3.5);
sphereMesh.castShadow = true;
scene.add(sphereMesh);
const torusGeo = new THREE.TorusGeometry(1.5, 0.45, 24, 64);
const torusMat = new THREE.MeshStandardMaterial({
color: 0x36e0aa,
metalness: 0.65,
roughness: 0.16
});
const torusMesh = new THREE.Mesh(torusGeo, torusMat);
torusMesh.position.set(4.8, 1.5, 2.2);
torusMesh.castShadow = true;
scene.add(torusMesh);
// 地面
const planeGeo = new THREE.PlaneGeometry(45, 45);
const planeMat = new THREE.MeshStandardMaterial({
color: 0x232e46,
metalness: 0,
roughness: 0.75
});
const planeMesh = new THREE.Mesh(planeGeo, planeMat);
planeMesh.rotation.x = -Math.PI / 2;
planeMesh.receiveShadow = true;
scene.add(planeMesh);
// 6.射线拾取
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
window.addEventListener('click', (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects([cubeMesh, sphereMesh, torusMesh]);
if (intersects.length > 0) {
const obj = intersects[0].object;
console.log('✅点击物体:', obj);
}
})
// 7.窗口自适应
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
})
// 8.动画循环
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const elapsed = clock.getElapsedTime();
cubeMesh.rotation.y = elapsed * 0.4;
sphereMesh.rotation.x = elapsed * 0.32;
torusMesh.rotation.z = elapsed * 0.55;
pointLight.position.y = 7 + Math.sin(elapsed * 1.1) * 2.8;
controls.update();
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
一、文档说明
本文为Three.js 入门案例,整合了 Three.js 90% 入门核心知识点。
特点:
-
画面明亮美观、光影通透、无死黑区域
-
包含基础三件套、光照、阴影、PBR材质、动画、交互、自适应、射线拾取
-
代码结构标准,是企业级 Three.js 项目的基础模板
-
无需本地环境,联网双击 HTML 即可运行
二、整体运行流程(核心逻辑)
Three.js 所有项目固定执行流程:
创建场景 → 创建相机 → 创建渲染器 → 初始化灯光/物体 → 绑定控制器 → 动画循环渲染 → 窗口自适应 → 交互监听
三、核心模块详细解析
1. 基础三要素(必备)
Three.js 渲染的核心铁三角,缺一不可。
1.1 Scene 场景
所有模型、灯光、辅助线的容器,相当于"舞台"。
js
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a2438); // 背景色
scene.fog = new THREE.Fog(0x1a2438,15,80); // 雾化效果
雾化参数:(颜色, 开始距离, 最远可见距离),让场景更有空间层次感。
1.2 PerspectiveCamera 透视相机
模拟人眼视觉,近大远小,最常用的相机类型。
js
new THREE.PerspectiveCamera(视场角, 宽高比, 近裁剪面, 远裁剪面)
-
视场角60°:视觉自然,不畸变
-
近裁剪面0.1:防止近处模型被裁剪闪烁
-
远裁剪面1000:适配大范围场景
1.3 WebGLRenderer 渲染器
负责将场景和相机画面绘制到画布上。
关键优化配置:
-
antialias: true:开启抗锯齿,模型边缘顺滑 -
setPixelRatio:适配手机/高分屏,防止模糊 -
toneMapping:电影级色调映射,画面更通透 -
toneMappingExposure:全局曝光提亮,解决画面发黑问题
2. 轨道控制器 OrbitControls(交互核心)
实现鼠标操作3D场景,入门必备:
-
左键拖拽:旋转视角
-
滚轮:缩放场景
-
右键拖拽:平移场景
核心优化:enableDamping 开启阻尼惯性,拖拽手感丝滑、有回弹效果。
3. 场景辅助工具(开发调试必备)
-
AxesHelper 坐标轴:X红、Y绿、Z蓝,快速判断模型朝向
-
GridHelper 网格地面:辅助判断模型位置、高度、空间距离
生产环境可删除,开发调试必加。
4. 光照系统(画面质感关键)
本案例使用三灯组合,解决画面发黑、无层次问题,是行业通用打光方案:
4.1 AmbientLight 环境光
全局漫反射光,无方向、无阴影,提亮整个场景,消除死黑。
4.2 DirectionalLight 平行光(主光)
模拟太阳光,有方向、可投射阴影,是场景的主光源。
阴影优化关键点:
-
shadow.mapSize:阴影分辨率,数值越高越清晰 -
shadow.camera:控制阴影照射范围 -
shadow.bias:解决阴影条纹、锯齿瑕疵
4.3 PointLight 点光源(辅光/氛围光)
模拟灯泡、星光,彩色动态光源,增加画面氛围,可动态浮动动画。
4.4 补光灯 FillLight
填充暗部死角,让模型明暗过渡自然,画面通透柔和。
5. 几何体 + PBR 材质 + 网格模型
5.1 核心公式
网格模型(Mesh) = 几何体(形状) + 材质(外观)
5.2 本案例包含几何体
-
BoxGeometry 立方体
-
SphereGeometry 球体
-
TorusGeometry 圆环体
-
PlaneGeometry 平面地面
5.3 PBR 物理材质 MeshStandardMaterial
工业级写实材质,支持光照、阴影、金属度、粗糙度,是 Three.js 最常用材质:
-
color:基础颜色 -
metalness:金属度 0-1,越高越像金属 -
roughness:粗糙度 0-1,越高越磨砂,越低越光滑反光
5.4 阴影开关
-
castShadow = true:模型投射阴影 -
receiveShadow = true:模型接收阴影
6. 射线拾取 Raycaster(3D交互核心)
实现鼠标点击3D物体,是所有3D点击交互的底层原理。
执行逻辑:
-
将鼠标屏幕坐标转为 Three.js 标准化坐标(-1 ~ 1)
-
从相机位置发射一条射线穿过鼠标位置
-
检测射线与场景物体的相交结果
-
判断是否点击到模型,执行对应逻辑
7. 窗口自适应
监听窗口大小变化,动态更新:
-
相机宽高比
-
相机投影矩阵
-
渲染器尺寸
解决窗口拉伸、模型变形问题。
8. 动画系统
8.1 Clock 时钟
获取程序运行时间,基于时间做动画,不依赖帧率,动画丝滑、设备兼容。
8.2 requestAnimationFrame 渲染循环
浏览器原生动画帧,每秒60次刷新画面,实现动态效果:模型旋转、光源浮动、控制器更新。
四、画面美化核心优化点(解决原版昏暗问题)
-
开启 ACES 电影级色调映射,画面通透不发灰
-
调高全局曝光值,整体提亮场景
-
三重灯光组合(环境光+主光+补光),消除暗部死黑
-
弱化雾化效果,场景更清晰有层次
-
优化材质饱和度与粗糙度,色彩鲜亮质感拉满
-
阴影柔和优化,无锯齿、无瑕疵
-
UI毛玻璃样式,视觉更现代
五、知识点全覆盖清单
本案例一次性掌握以下所有入门核心:
-
✅ 场景、相机、渲染器三大基础
-
✅ 轨道控制器鼠标交互
-
✅ 环境光、平行光、点光源多光源打光
-
✅ 完整阴影系统与优化
-
✅ 主流几何体使用
-
✅ PBR物理写实材质
-
✅ 场景雾化、背景设置
-
✅ 坐标轴/网格辅助工具
-
✅ 射线拾取3D点击交互
-
✅ 窗口自适应适配
-
✅ 时间驱动动画系统
-
✅ 高分屏像素比适配
-
✅ 电影级色调渲染优化
六、运行方式
-
复制完整 HTML 代码,新建文件保存为
three-demo.html -
保证网络正常(加载 Three.js CDN)
-
双击文件直接浏览器打开运行
-
F12 打开控制台,可查看点击拾取日志
七、拓展学习方向(进阶)
-
纹理贴图(颜色贴图、法线贴图、粗糙度贴图)
-
GLB/GLTF 外部模型加载
-
粒子系统、星空背景
-
后期特效(泛光、模糊、调色)
-
GPU 着色器 Shader 动画