threejs-scene-setup
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesethree.js Scene Setup
three.js 场景搭建
Create the foundation of a three.js app: module loading, the
scene/camera/renderer trio, the render loop, responsive resizing, and camera
controls. Patterns target r165+ and are verified against r184.
创建three.js应用的基础:模块加载、场景/相机/渲染器三件套、渲染循环、响应式调整大小以及相机控制。模式针对r165+版本,并已在r184版本中验证。
When to use
使用场景
- Use when bootstrapping a three.js scene, fixing a blank/black canvas, making the
canvas responsive, setting up the animation loop, or adding .
OrbitControls - Use when depends on
package.jsonand code doesthree.import * as THREE from 'three'
When not to use: loading / models or skinned animation →
. Materials, lights, shadows, environment maps →
. 2D rendering → .
.gltf.glbthreejs-gltf-loadingthreejs-materials-lightingpixijs-rendering- 适用于初始化three.js场景、修复空白/黑色画布、实现画布响应式、设置动画循环或添加时。
OrbitControls - 适用于依赖
package.json且代码中使用three的场景。import * as THREE from 'three'
不适用于: 加载/模型或蒙皮动画 → 使用。材质、灯光、阴影、环境贴图 → 使用。2D渲染 → 使用。
.gltf.glbthreejs-gltf-loadingthreejs-materials-lightingpixijs-renderingCore workflow
核心流程
- Load three.js as an ES module with an import map. Since r147 the bare
specifier and
'three'must be mapped (in HTML or by a bundler). Addons (controls, loaders) live under'three/addons/'.three/addons/... - Create the trio. A (root of the graph), a
Scenemoved back from the origin, and aPerspectiveCamera(fov, aspect, near, far)whoseWebGLRendereris in the DOM. Set size anddomElement.pixelRatio - Add a mesh. and
new Mesh(geometry, material). With a lit material you also need a light (seescene.add(mesh)).threejs-materials-lighting - Drive a render loop with . It's the modern, WebXR-/WebGPU-safe replacement for hand-rolled
renderer.setAnimationLoop(fn). Use arequestAnimationFramefor delta time.Clock - Handle resize so the camera aspect and renderer match the canvas; update
, call
camera.aspect, andupdateProjectionMatrix().renderer.setSize(...) - Add for orbit/pan/zoom while developing. Confirm something actually renders (a lit cube, the controls responding) before assuming success.
OrbitControls
- 通过导入映射以ES模块形式加载three.js。自r147版本起,必须映射裸标识符和
'three'(在HTML中或通过打包工具)。扩展组件(控制器、加载器)位于'three/addons/'路径下。three/addons/... - 创建三件套。(场景图的根节点)、从原点向后移动的
Scene,以及其PerspectiveCamera(fov, aspect, near, far)已加入DOM的domElement。设置尺寸和WebGLRenderer。pixelRatio - 添加网格。创建并调用
new Mesh(geometry, material)。若使用受光材质,还需要添加灯光(详见scene.add(mesh))。threejs-materials-lighting - 使用驱动渲染循环。这是替代手动实现
renderer.setAnimationLoop(fn)的现代方案,支持WebXR/WebGPU。使用requestAnimationFrame获取增量时间。Clock - 处理窗口大小调整,使相机宽高比和渲染器匹配画布尺寸;更新,调用
camera.aspect,并执行updateProjectionMatrix()。renderer.setSize(...) - 添加,以便在开发时实现轨道漫游/平移/缩放操作。在确认渲染成功(如受光立方体、控制器响应)前,不要默认操作已完成。
OrbitControls
Patterns
实现模式
1. HTML import map + module entry (no bundler)
1. HTML导入映射 + 模块入口(无打包工具)
html
<canvas id="c"></canvas>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.184.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.184.0/examples/jsm/"
}
}
</script>
<script type="module" src="./main.js"></script>With a bundler (Vite/webpack), skip the import map and just
; the same statements resolve.
npm i threeimporthtml
<canvas id="c"></canvas>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.184.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.184.0/examples/jsm/"
}
}
</script>
<script type="module" src="./main.js"></script>若使用打包工具(Vite/webpack),可跳过导入映射,直接执行;相同的语句会自动解析。
npm i threeimport2. Scene + camera + renderer
2. 场景 + 相机 + 渲染器
js
// 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);js
// 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)); // 为性能限制最大值
renderer.setSize(window.innerWidth, window.innerHeight);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x101018);
const camera = new THREE.PerspectiveCamera(
60, // 垂直视野角度(度)
window.innerWidth / window.innerHeight, // 宽高比
0.1, // 近裁剪面
100 // 远裁剪面
);
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() // 不受光材质;无需灯光即可显示方向
);
scene.add(cube);3. The render loop (setAnimationLoop + Clock)
3. 渲染循环(setAnimationLoop + Clock)
js
const clock = new THREE.Clock();
renderer.setAnimationLoop(() => {
const dt = clock.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 loopjs
const clock = new THREE.Clock();
renderer.setAnimationLoop(() => {
const dt = clock.getDelta(); // 距上一帧的时间(秒)
cube.rotation.x += dt; // 帧率无关
cube.rotation.y += dt * 0.7;
renderer.render(scene, camera);
});
// renderer.setAnimationLoop(null); // 停止循环4. Responsive resize
4. 响应式大小调整
js
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);js
function onResize() {
const w = window.innerWidth, h = window.innerHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix(); // 更改宽高比后必须调用
renderer.setSize(w, h);
}
window.addEventListener('resize', onResize);5. OrbitControls (orbit / pan / zoom)
5. OrbitControls(轨道漫游/平移/缩放)
js
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);
});js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 惯性效果
controls.target.set(0, 0, 0);
renderer.setAnimationLoop(() => {
controls.update(); // 启用阻尼时必须每帧调用
renderer.render(scene, camera);
});Pitfalls
常见陷阱
- → missing import map (or bundler config). Map both
Failed to resolve module specifier "three"and"three"; addon paths must end with"three/addons/"./ - Black canvas, no errors → camera is at the origin (inside/behind the object),
or you used a lit material () with no light. Move the camera back; use
MeshStandardMaterial/MeshNormalMaterialto verify geometry first.MeshBasicMaterial - Nothing animates → you never called inside the loop, or you call
renderer.renderbut render outside it.setAnimationLoop - Stretched / squashed view on resize → you resized the renderer but didn't
update +
camera.aspect.updateProjectionMatrix() - Blurry or jagged on HiDPI → set ; cap it (≈2) so 4K/retina screens don't tank performance.
renderer.setPixelRatio(...) - OrbitControls feel dead → with you must call
enableDamping = trueevery frame.controls.update() - Old tutorials use → since r147 three.js ships ES modules only; use
<script src="three.min.js">+ import maps.type="module"
- → 缺少导入映射(或打包工具配置)。需同时映射
Failed to resolve module specifier "three"和"three";扩展组件路径必须以"three/addons/"结尾。/ - 黑色画布,无报错 → 相机位于原点(在物体内部/后方),或使用了受光材质()但未添加灯光。将相机向后移动;先使用
MeshStandardMaterial/MeshNormalMaterial验证几何体是否正确。MeshBasicMaterial - 无动画效果 → 未在循环内调用,或调用了
renderer.render但在循环外执行渲染。setAnimationLoop - 窗口调整大小时视图拉伸/挤压 → 调整了渲染器尺寸但未更新+
camera.aspect。updateProjectionMatrix() - 高DPI屏幕下模糊或锯齿 → 设置;限制最大值(≈2),避免4K/视网膜屏幕导致性能下降。
renderer.setPixelRatio(...) - OrbitControls无响应 → 启用时必须每帧调用
enableDamping = true。controls.update() - 旧教程使用→ 自r147版本起three.js仅提供ES模块;需使用
<script src="three.min.js">+ 导入映射。type="module"
References
参考资料
- For coordinate conventions, the scene-graph (, parent/child transforms,
Groupadd/remove),Object3Dfor 2.5D, and disposing of geometries/materials/textures to avoid leaks, readOrthographicCamera.references/scene-graph.md
- 关于坐标规范、场景图(、父子变换、
Group添加/移除)、用于2.5D的Object3D,以及销毁几何体/材质/纹理以避免内存泄漏,请阅读OrthographicCamera。references/scene-graph.md
Related skills
相关技能
- — give surfaces a lit look (lights, shadows, PBR).
threejs-materials-lighting - — load 3D models and play their animations.
threejs-gltf-loading - — 2D rendering in the browser.
pixijs-rendering - — a 3D genre template that composes three.js skills.
fps-shooter
- — 实现表面受光效果(灯光、阴影、PBR)。
threejs-materials-lighting - — 加载3D模型并播放动画。
threejs-gltf-loading - — 浏览器中的2D渲染。
pixijs-rendering - — 组合three.js技能的3D类型模板。
fps-shooter