本教程将围绕 WebGLThree.js 展开。

  • WebGL:是浏览器中用于渲染 3D 图形的底层 API,它非常强大,但直接使用它编写代码非常复杂,需要深入理解图形学知识(如着色器、缓冲区等)。
  • Three.js:是一个基于 WebGL 的轻量级、易用的 3D 库,它极大地简化了 3D 开发过程,让开发者可以专注于创造内容,而不是处理底层的图形细节。对于绝大多数 Web 3D Three.js 是首选。

本教程将以 Three.js 为核心,因为它能让你最快地看到成果并理解 3D 开发的核心概念。


教程大纲

  1. 准备工作:搭建开发环境
  2. 核心概念:Three.js 的三大件
  3. 动手实践:创建你的第一个 3D 场景
    • 步骤 1:创建 HTML 文件和引入库
    • 步骤 2:初始化场景、相机和渲染器
    • 步骤 3:创建几何体和材质,并添加到场景
    • 步骤 4:添加光源
    • 步骤 5:实现动画循环
    • 步骤 6:完整代码与效果
  4. 进阶概念:交互与控制
  5. 学习资源与总结

准备工作:搭建开发环境

非常简单!你只需要一个文本编辑器(如 VS Code, Sublime Text)和一个现代浏览器(如 Chrome, Firefox, Edge)。

  1. 创建项目文件夹:在你的电脑上新建一个文件夹,my-3d-project
  2. 创建 HTML 文件:在文件夹中创建一个 index.html 文件。
  3. 引入 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 是画布的宽高比,11000 是相机能看到的最近和最远的距离,超出这个范围的物体将不会被渲染。
  • 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

  1. 引入 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>
  2. 在 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 开发最核心的基础知识。

总结核心要点:

  1. 三大件Scene(场景)、Camera(相机)、Renderer(渲染器)是构建任何 3D 场景的基础。
  2. 物体Mesh(网格) = Geometry(几何体) + Material(材质)。
  3. 光源AmbientLight(环境光)和 PointLight(点光源)是基础。
  4. 动画:使用 requestAnimationFrame 创建循环,并在每一帧更新物体属性后调用 renderer.render()
  5. 交互:使用 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 的奇妙世界吧!