4. Three.js核心入门:场景、相机、渲染器与第一个3D立方体
各位同学,欢迎来到Three.js的世界。
说实话,我第一次接触Three.js的时候,也被它那套「场景-相机-渲染器」的概念绕得有点晕。后来在做一个智慧园区项目时,甲方要求实时展示楼宇的3D模型,我才真正把这套东西吃透了。今天咱们就来聊聊这三个核心概念,再亲手搭一个3D立方体出来。
4.1 三个核心概念:场景、相机、渲染器
Three.js的3D渲染,说白了就是「搭台子、架机器、出画面」。你想想看,拍电影是不是也得有这三样?
- 场景(Scene):就是你的3D世界。所有物体、灯光、特效都放在里面。
- 相机(Camera):决定你从哪个角度、以什么视角看这个世界。
- 渲染器(Renderer):把场景和相机的内容「画」到屏幕上。
我在项目中遇到过不少新手,上来就写代码,结果页面一片空白。为什么?因为相机没对准物体,或者渲染器没挂载到DOM上。嗯,这里要注意,这三者缺一不可。
核心公式:
3D画面 = 场景(Scene) + 相机(Camera) + 渲染器(Renderer)
下面这张图,帮你理清它们之间的关系:
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