4. Three.js核心入门:场景、相机、渲染器与第一个3D立方体

各位同学,欢迎来到Three.js的世界。

说实话,我第一次接触Three.js的时候,也被它那套「场景-相机-渲染器」的概念绕得有点晕。后来在做一个智慧园区项目时,甲方要求实时展示楼宇的3D模型,我才真正把这套东西吃透了。今天咱们就来聊聊这三个核心概念,再亲手搭一个3D立方体出来。

4.1 三个核心概念:场景、相机、渲染器

Three.js的3D渲染,说白了就是「搭台子、架机器、出画面」。你想想看,拍电影是不是也得有这三样?

  • 场景(Scene):就是你的3D世界。所有物体、灯光、特效都放在里面。
  • 相机(Camera):决定你从哪个角度、以什么视角看这个世界。
  • 渲染器(Renderer):把场景和相机的内容「画」到屏幕上。

我在项目中遇到过不少新手,上来就写代码,结果页面一片空白。为什么?因为相机没对准物体,或者渲染器没挂载到DOM上。嗯,这里要注意,这三者缺一不可。

核心公式:

3D画面 = 场景(Scene) + 相机(Camera) + 渲染器(Renderer)

下面这张图,帮你理清它们之间的关系:

场景 (Scene) 存放所有3D物体 灯光、特效等 立方体 (Mesh) 灯光 (Light) 相机 (Camera) 决定观察角度 透视/正交 透视相机 正交相机 渲染器 (Renderer) 将画面绘制到屏幕 WebGL/Canvas WebGL渲染器 Canvas渲染器 包含 渲染

4.2 场景(Scene)的创建

场景就是一个容器。你往里面放什么,它就装什么。创建起来非常简单:

const scene = new THREE.Scene();

就这一行。但别小看它,场景里可以设置背景色、雾效,甚至添加一些全局属性。我个人习惯在创建场景时顺手把背景色设了,省得后面再补:

scene.background = new THREE.Color(0x87CEEB); // 天蓝色背景

小技巧:背景色用十六进制颜色值,0x开头。0x87CEEB就是天蓝色,看着舒服。

4.3 相机(Camera)的创建

相机决定了你「怎么看」这个3D世界。Three.js提供了两种常用相机:

相机类型 特点 适用场景
透视相机 (PerspectiveCamera) 近大远小,符合人眼视觉 大多数3D场景,游戏、建筑漫游
正交相机 (OrthographicCamera) 物体大小不随距离变化 2D游戏、UI界面、技术图纸

我们做数字孪生,90%的情况用透视相机。它的构造函数有四个参数:

const camera = new THREE.PerspectiveCamera(
  75,          // 视野角度 (FOV),单位度
  window.innerWidth / window.innerHeight, // 宽高比
  0.1,         // 近裁剪面
  1000         // 远裁剪面
);

我曾经犯过一个低级错误——把近裁剪面设成了0,结果相机直接「穿模」了,画面一片混乱。后来查文档才知道,近裁剪面必须大于0。避坑指南:近裁剪面设0.1,远裁剪面设1000,基本够用。

相机创建后,记得调整它的位置:

camera.position.set(0, 0, 5); // 把相机往后拉5个单位

4.4 渲染器(Renderer)的创建

渲染器是最后一步,它把场景和相机的内容「画」到网页上。最常用的是WebGL渲染器:

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

这里要注意:renderer.domElement是一个canvas元素,你必须把它挂载到DOM树上,才能在页面上看到画面。

常见坑点:如果页面是空白的,先检查渲染器的canvas有没有被正确添加到DOM中。我见过有人忘了写appendChild,结果调试了半天。

另外,我建议开启渲染器的阴影支持,虽然会消耗一点性能,但效果真实很多:

renderer.shadowMap.enabled = true;

4.5 第一个3D立方体案例

好了,理论讲完了,咱们动手搭一个立方体。完整代码如下:

<!DOCTYPE html>
<html>
<head>
  <title>我的第一个Three.js立方体</title>
  <style>
    body { margin: 0; overflow: hidden; }
  </style>
</head>
<body>
<script type="importmap">
{
  "imports": {
    "three": "https://unpkg.com/three@0.160.0/build/three.module.js"
  }
}
</script>
<script type="module">
import * as THREE from 'three';

// 1. 创建场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e); // 深色背景

// 2. 创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.set(0, 0, 5);

// 3. 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 4. 创建立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00aaff });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 5. 添加灯光(不然立方体是黑的)
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 1, 1);
scene.add(light);

// 6. 动画循环
function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

// 7. 窗口自适应
window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>

这段代码跑起来,你会看到一个蓝色的立方体在深色背景中缓缓旋转。是不是挺有成就感的?

4.6 代码拆解与避坑指南

咱们把关键点拎出来说说:

  • 几何体(Geometry)BoxGeometry(1,1,1)定义了一个1x1x1的立方体。你可以改尺寸试试。
  • 材质(Material)MeshStandardMaterial是标准材质,需要灯光才能显示颜色。如果你用MeshBasicMaterial,就不需要灯光了,但效果比较平。
  • 网格(Mesh):几何体+材质=网格。网格才是真正添加到场景中的物体。
  • 灯光:没有灯光,标准材质就是黑的。我曾经忘了加灯光,盯着黑屏看了十分钟才反应过来。
  • 动画循环requestAnimationFrame是浏览器提供的动画API,比setInterval更流畅、更省资源。
  • 窗口自适应:当浏览器窗口大小变化时,需要更新相机的宽高比和渲染器的尺寸,否则画面会变形。

调试小技巧:在浏览器控制台输入cube.rotation.x = 1,可以实时改变立方体的旋转角度。Three.js的调试非常方便。

4.7 总结

今天咱们把Three.js的三大核心概念捋了一遍:场景是容器,相机是眼睛,渲染器是画笔。然后亲手搭了一个3D立方体,还让它转了起来。

说实话,这个立方体虽然简单,但它是你进入3D世界的第一步。我在做第一个数字孪生项目时,就是从这样一个立方体开始的,后来慢慢加上了灯光、阴影、交互,最后变成了一个完整的园区3D可视化系统。

嗯,今天的内容就到这里。代码拿回去跑一跑,改改颜色、尺寸、旋转速度,玩熟了再往下走。


公众号:蓝海资料掘金营,微信deep3321