本教程将围绕 WebGL 和 Three.js 展开。
- WebGL:是浏览器中用于渲染 3D 图形的底层 API,它非常强大,但直接使用它编写代码非常复杂,需要深入理解图形学知识(如着色器、缓冲区等)。
- Three.js:是一个基于 WebGL 的轻量级、易用的 3D 库,它极大地简化了 3D 开发过程,让开发者可以专注于创造内容,而不是处理底层的图形细节。对于绝大多数 Web 3D Three.js 是首选。
本教程将以 Three.js 为核心,因为它能让你最快地看到成果并理解 3D 开发的核心概念。
教程大纲
- 准备工作:搭建开发环境
- 核心概念:Three.js 的三大件
- 动手实践:创建你的第一个 3D 场景
- 步骤 1:创建 HTML 文件和引入库
- 步骤 2:初始化场景、相机和渲染器
- 步骤 3:创建几何体和材质,并添加到场景
- 步骤 4:添加光源
- 步骤 5:实现动画循环
- 步骤 6:完整代码与效果
- 进阶概念:交互与控制
- 学习资源与总结
准备工作:搭建开发环境
非常简单!你只需要一个文本编辑器(如 VS Code, Sublime Text)和一个现代浏览器(如 Chrome, Firefox, Edge)。
- 创建项目文件夹:在你的电脑上新建一个文件夹,
my-3d-project。 - 创建 HTML 文件:在文件夹中创建一个
index.html文件。 - 引入 Three.js 库:我们使用 CDN(内容分发网络)来引入 Three.js,这样无需下载任何文件。
在 index.html 中,我们将通过 <script> 标签引入 Three.js 的最新版本。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">我的第一个 3D 场景</title>
<style>
body { margin: 0; } /* 移除默认的页面边距 */
canvas { display: block; } /* 让画布充满整个屏幕 */
</style>
</head>
<body>
<!-- 在这里我们将用 JavaScript 来创建 3D 内容 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="your_script.js"></script> <!-- 我们接下来会创建这个 JS 文件 -->
</body>
</html>
再创建一个 your_script.js 文件,所有的 3D 代码都将写在这个文件里。
核心概念:Three.js 的三大件
想象一下你用相机拍摄一张照片:
- 场景:这是你的拍摄舞台,里面包含了所有要拍摄的对象(物体、灯光、背景等),在 Three.js 中,它是一个容器,
THREE.Scene。 - 相机:这是你的相机,它决定了你从哪个角度、以什么方式(透视或正交)来观察场景,在 Three.js 中,最常用的是
THREE.PerspectiveCamera(透视相机,模拟人眼)。 - 渲染器:这是相机本身,它负责将场景中的物体通过相机的视角“拍摄”下来,并最终绘制到网页的
<canvas>元素上,在 Three.js 中,是THREE.WebGLRenderer。
工作流程:你先设置好舞台(场景),然后把物体(物体)和灯光(光源)放到舞台上,再架好相机(相机),最后用渲染器(渲染器)把相机看到的东西画出来(渲染)。
动手实践:创建你的第一个 3D 场景
打开 your_script.js 文件,我们一步步来构建场景。
步骤 1:创建 HTML 文件和引入库
(已完成,见上一节)
步骤 2:初始化场景、相机和渲染器
我们需要一个地方来放置我们的 3D 场景,这个就是 <canvas>,Three.js 的渲染器会自动创建它并添加到页面中。
// your_script.js // 1. 创建场景 const scene = new THREE.Scene(); scene.background = new THREE.Color(0x00ff00); // 设置场景背景为绿色 // 2. 创建相机 // 透视相机 (PerspectiveCamera) // 参数:视野角度(FOV),长宽比,近裁剪面,远裁剪面 const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); // 3. 创建渲染器 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染器大小为窗口大小 document.body.appendChild(renderer.domElement); // 将渲染器的 dom 元素(canvas)添加到 body 中
解释:
new THREE.Scene(): 创建了一个空的场景。new THREE.PerspectiveCamera(...): 创建了一个透视相机。75是视野角度(越广看到的东西越多),window.innerWidth / window.innerHeight是画布的宽高比,1和1000是相机能看到的最近和最远的距离,超出这个范围的物体将不会被渲染。new THREE.WebGLRenderer(): 创建了 WebGL 渲染器。renderer.setSize(...): 告诉渲染器,画布应该多大。document.body.appendChild(...): 将渲染器创建的<canvas>元素插入到 HTML 页面中,这样我们才能看到它。
步骤 3:创建几何体和材质,并添加到场景
一个 3D 物体通常由两部分组成:
- 几何体:物体的形状,比如立方体、球体、圆环等。
- 材质:物体的外观,比如颜色、光泽、透明度等。
我们创建一个红色的立方体。
// your_script.js (接续上面的代码)
// 4. 创建几何体和材质
const geometry = new THREE.BoxGeometry(); // 创建一个立方体几何体
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); // 创建一个基础材质,颜色为红色
// 5. 创建网格,它将几何体和材质组合在一起
const cube = new THREE.Mesh(geometry, material);
// 6. 将网格添加到场景中
scene.add(cube);
// 7. 将相机位置向后移动,否则我们会在立方体内部(默认位置是0,0,0)
camera.position.z = 5;
解释:
new THREE.BoxGeometry(): 创建了一个默认大小的立方体。new THREE.MeshBasicMaterial(...): 创建了一种简单的材质,color: 0xff0000表示红色(十六进制颜色码)。new THREE.Mesh(geometry, material):Mesh(网格)是物体在 Three.js 中的标准表示,它将几何体和材质结合起来,形成我们可以在场景中看到的物体。scene.add(cube): 将立方体添加到场景中。camera.position.z = 5: 将相机沿着 Z 轴向后移动 5 个单位,在 Three.js 中,Z 轴指向屏幕外,X 轴水平,Y 轴垂直,默认情况下,相机和物体都在原点 (0,0,0),所以需要移动相机才能看到物体。
步骤 4:添加光源
MeshBasicMaterial 不受光源影响,它总是显示自己定义的颜色,为了让物体看起来更真实,我们需要使用对光源敏感的材质,MeshPhongMaterial,并添加光源。
// your_script.js (接续上面的代码) // 8. 添加光源 // 环境光:照亮场景中所有的物体,没有方向 const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // 白色,强度为0.5 scene.add(ambientLight); // 点光源:从一个点向所有方向发射光 const pointLight = new THREE.PointLight(0xffffff, 1); // 白色,强度为1 pointLight.position.set(2, 3, 4); // 设置光源位置 scene.add(pointLight);
解释:
THREE.AmbientLight: 环境光,模拟漫反射光,能均匀地照亮整个场景,让物体没有死黑的角落。THREE.PointLight: 点光源,像灯泡一样从一个点发光,照亮周围的物体。
我们需要修改立方体的材质,让它对光源有反应。
// 修改步骤 5 中的材质
const material = new THREE.MeshPhongMaterial({ color: 0xff0000 }); // 改为 MeshPhongMaterial
步骤 5:实现动画循环
静态的 3D 场景很无聊,我们想让立方体动起来,这需要一个动画循环,在每一帧都重新渲染场景。
// your_script.js (接续上面的代码)
// 9. 动画循环
function animate() {
requestAnimationFrame(animate); // 请求下一帧动画
// 让立方体旋转
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera); // 使用渲染器渲染场景
}
animate(); // 启动动画循环
解释:
requestAnimationFrame(animate): 这是浏览器提供的 API,用于创建一个高效的动画循环,它会告诉浏览器:“我准备要更新动画了,请在下一次重绘之前调用animate函数。”cube.rotation.x += 0.01;: 每一帧都让立方体绕 X 轴旋转一点点。renderer.render(scene, camera): 在每一帧中,都用当前的相机视角重新渲染整个场景。
步骤 6:完整代码与效果
将所有代码整合起来,your_script.js 的最终内容如下:
// your_script.js
// 1. 创建场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x222222); // 深灰色背景
// 2. 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 3. 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 4. 创建几何体和材质
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshPhongMaterial({ color: 0x00aaff }); // 使用对光源敏感的材质
const cube = new THREE.Mesh(geometry, material);
// 5. 添加物体到场景
scene.add(cube);
// 6. 设置相机位置
camera.position.z = 5;
// 7. 添加光源
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const pointLight = new THREE.PointLight(0xffffff, 1);
pointLight.position.set(2, 3, 4);
scene.add(pointLight);
// 8. 动画循环
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
用浏览器打开 index.html 文件,你应该能看到一个在深灰色背景上旋转的蓝色立方体!
进阶概念:交互与控制
一个可以旋转的立方体很棒,但如果我们能用鼠标控制它,那就更好了,Three.js 有一个非常有用的辅助库叫做 OrbitControls。
-
引入 OrbitControls:在
index.html中,在引入three.min.js之后引入它。<!-- index.html --> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
-
在 JavaScript 中初始化控制器:
// your_script.js // ... (在创建渲染器之后) // 添加轨道控制器 const controls = new THREE.OrbitControls(camera, renderer.domElement); controls.enableDamping = true; // 启用阻尼(惯性) controls.dampingFactor = 0.05; // 阻尼系数 // ... (在 animate 函数中更新控制器) function animate() { requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; // 更新控制器 controls.update(); renderer.render(scene, camera); }
你就可以用鼠标来拖动、缩放和旋转你的视角了!
学习资源与总结
恭喜!你已经掌握了 Web 3D 开发最核心的基础知识。
总结核心要点:
- 三大件:
Scene(场景)、Camera(相机)、Renderer(渲染器)是构建任何 3D 场景的基础。 - 物体:
Mesh(网格) =Geometry(几何体) +Material(材质)。 - 光源:
AmbientLight(环境光)和PointLight(点光源)是基础。 - 动画:使用
requestAnimationFrame创建循环,并在每一帧更新物体属性后调用renderer.render()。 - 交互:使用
OrbitControls可以轻松实现鼠标控制视角。
进阶学习资源:
- Three.js 官方文档:https://threejs.org/docs/ (最权威,但可能对初学者有点难)
- Three.js 教程(官方):https://threejs.org/docs/#manual/en/introduction/Creating-a-scene
- The Book of Shaders:如果你想深入了解着色器,这是必读的圣经:https://thebookofshaders.com/
- Brackeys 的 Three.js 系列视频:在 YouTube 上搜索 "Brackeys Three.js",有非常棒的入门视频。
- 实践!实践!实践!:尝试修改代码,创建不同的几何体(
SphereGeometry,ConeGeometry),更换材质,添加更多物体和灯光,构建你自己的小世界。
从现在开始,尽情探索 Web 3D 的奇妙世界吧!
