关于 threejs-scene-setup
为 three.js 应用搭建场景基础的技能,面向初始化和排查渲染问题的开发者。内容包括模块加载、场景与相机、渲染循环、响应式调整和 OrbitControls。
主要功能
- 01配置 ES 模块加载
- 02创建场景、相机和渲染器
- 03设置动画渲染循环
- 04适配画布尺寸变化
- 05添加 OrbitControls
适用场景
- 01初始化 three.js 场景
- 02修复空白或黑色画布
- 03实现窗口调整时的画面适配
- 04为开发场景添加轨道控制
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill threejs-scene-setup安装后在 Claude Code 中输入/threejs-scene-setup确认已加载。
附带文件references/scene-graph.md
详细介绍
three.js 场景搭建
搭建 three.js 应用的基础:模块加载、场景/相机/渲染器三件套、渲染循环、自适应尺寸和相机控件。此处的模式面向 r186。修改现有项目之前,请先检查已安装的 three 版本,因为示例和附加组件会随版本变化。
适用场景
- 在初始化 three.js 场景、修复空白/黑色画布、让画布自适应尺寸、设置动画循环或添加
OrbitControls时使用。 - 在
package.json依赖three,且代码中使用import * as THREE from 'three'时使用。
不适用场景: 加载 .gltf/.glb 模型或骨骼动画 → threejs-gltf-loading。材质、灯光、阴影、环境贴图 → threejs-materials-lighting。2D 渲染 → pixijs-rendering。
核心工作流
- 使用导入映射表将 three.js 作为 ES 模块加载。 从 r147 开始,裸模块说明符
'three'和'three/addons/'必须进行映射(在 HTML 中或通过打包器)。附加组件(控件、加载器)位于three/addons/...下。 - 创建三件套。
Scene(场景图的根节点)、向原点后方移动的PerspectiveCamera(fov, aspect, near, far),以及domElement位于 DOM 中的WebGLRenderer。设置尺寸和pixelRatio。 - 添加网格。 使用
new Mesh(geometry, material)并调用scene.add(mesh)。使用受光照影响的材质时,还需要灯光(参见threejs-materials-lighting)。 - 使用
renderer.setAnimationLoop(fn)驱动渲染循环。 这是手动编写requestAnimationFrame的现代替代方案,且适用于 WebXR/WebGPU。使用Timer获取时间增量(自 r183 起,Clock已弃用)。 - 处理尺寸调整, 让相机宽高比和渲染器与画布匹配;更新
camera.aspect,调用updateProjectionMatrix(),并调用renderer.setSize(...)。 - 添加
OrbitControls, 以便在开发时旋转/平移/缩放。确认确实有内容渲染出来(受光照的立方体、能够响应的控件),再判断是否成功。
模式
1. HTML 导入映射表 + 模块入口(不使用打包器)
<canvas id="c"></canvas>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/"
}
}
</script>
<script type="module" src="./main.js"></script>
使用打包器(Vite/webpack)时,跳过导入映射表,直接运行
npm i three;相同的 import 语句即可解析。
2. 场景 + 相机 + 渲染器
// main.js
import * as THREE from 'three';
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // cap for perf
renderer.setSize(window.innerWidth, window.innerHeight);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x101018);
const camera = new THREE.PerspectiveCamera(
60, // vertical field of view (degrees)
window.innerWidth / window.innerHeight, // aspect
0.1, // near
100 // far
);
camera.position.set(3, 2, 5);
camera.lookAt(0, 0, 0);
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshNormalMaterial() // unlit; shows orientation without a light
);
scene.add(cube);
3. 渲染循环(setAnimationLoop + Timer)
const timer = new THREE.Timer(); // replaces the deprecated THREE.Clock (r183+)
timer.connect(document); // optional: no huge delta after a hidden tab
renderer.setAnimationLoop((time) => {
timer.update(time); // call once per frame, before getDelta()
const dt = timer.getDelta(); // seconds since last frame
cube.rotation.x += dt; // frame-rate independent
cube.rotation.y += dt * 0.7;
renderer.render(scene, camera);
});
// renderer.setAnimationLoop(null); // stop the loop
4. 自适应尺寸调整
function onResize() {
const w = window.innerWidth, h = window.innerHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix(); // required after changing aspect
renderer.setSize(w, h);
}
window.addEventListener('resize', onResize);
5. OrbitControls(旋转/平移/缩放)
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // inertial feel
controls.target.set(0, 0, 0);
renderer.setAnimationLoop(() => {
controls.update(); // needed every frame when damping is on
renderer.render(scene, camera);
});
常见问题
Failed to resolve module specifier "three"→ 缺少导入映射表(或打包器配置)。映射"three"和"three/addons/";附加组件路径必须以/结尾。- 画布全黑,没有报错 → 相机位于原点(在物体内部或后方),或者使用了受光照影响的材质(
MeshStandardMaterial),却没有灯光。将相机向后移;先使用MeshNormalMaterial/MeshBasicMaterial验证几何体。 - 没有任何动画 → 没有在循环中调用
renderer.render,或者调用了setAnimationLoop,却在循环外渲染。 - 调整尺寸后画面被拉伸/压扁 → 调整了渲染器尺寸,却没有更新
camera.aspect并调用updateProjectionMatrix()。 - HiDPI 屏幕上画面模糊或锯齿明显 → 设置
renderer.setPixelRatio(...);将其限制在约 2,避免 4K/Retina 屏幕导致性能骤降。 - OrbitControls 没有响应 → 设置
enableDamping = true后,必须在每一帧调用controls.update()。 - 旧教程使用
<script src="three.min.js">→ 自 r147 起,three.js 仅提供 ES 模块;请使用type="module"+ 导入映射表。
参考资料
- 关于坐标约定、场景图(
Group、父子变换、Object3D的添加/移除)、用于 2.5D 的OrthographicCamera,以及如何释放几何体/材质/纹理以避免内存泄漏,请阅读references/scene-graph.md。
相关技能
threejs-materials-lighting— 为表面添加受光照影响的外观(灯光、阴影、PBR)。threejs-gltf-loading— 加载 3D 模型并播放其动画。pixijs-rendering— 在浏览器中进行 2D 渲染。fps-shooter— 组合 three.js 技能的 3D 游戏类型模板。
评论
支持 Markdown