首页 / Three.js 入门教程 / 渲染器详解

Three.js 入门教程

渲染器详解

本教程共 40 篇 · 第 5 篇 · 更新于 2026-08-14 · 约 8 分钟阅读

Three.jsWebGLRenderer抗锯齿pixelRatioshadowMap色彩管理

本节目标:掌握 WebGLRenderer 的常用配置:抗锯齿、像素比、画布尺寸、清屏颜色、阴影和色彩管理。学完你能按需配置渲染器,解决模糊、锯齿、透明背景等常见问题。

WebGLRenderer 的定位

WebGLRenderer 是 three.js 的主力渲染器,用 WebGL2 绘制场景。r163 起 three.js 移除了 WebGL 1 支持,所以它是 WebGL 路线上的唯一选择(另一个 WebGPURenderer 是面向 WebGPU 的新方向,等后面章节再聊)。

const renderer = new THREE.WebGLRenderer();

不传参数也能用,但实际项目里通常要传配置对象。常用的构造参数:

  • antialias:抗锯齿,默认 false,本章重点
  • alpha:透明背景,默认 false,本章会讲
  • powerPreference:‘high-performance’ 会优先使用独立显卡,适合 3D 应用
  • stencil:模板缓冲,默认 false(r163 起),一般不需要动;如果用到模板缓冲(如某些后期特效)再手动开启
  • premultipliedAlpha:默认 true,一般不用动
  • failIfMajorPerformanceCaveat:默认 false,设为 true 时,如果设备只有软件渲染就拒绝创建渲染器

antialias:抗锯齿

3D 物体的斜边在屏幕上会出现锯齿(jaggies)。antialias 开启后,浏览器用多重采样(MSAA)对边缘做平滑,斜线看起来就顺滑了:

const renderer = new THREE.WebGLRenderer({ antialias: true });

antialias 在创建渲染器时就要决定,之后改不了。它的代价是 GPU 开销略增,对现代设备来说可以忽略。

Note

antialias 处理的是低分辨率下的锯齿。高分屏上锯齿不明显,问题反而是模糊——那是 pixelRatio 的事,见下一节。

setPixelRatio:高清屏适配

屏幕物理像素和 CSS 像素的比值叫 devicePixelRatio。Retina 屏是 2,部分手机是 3。不设置像素比时,渲染器按 CSS 像素数绘制,高分屏上每个物理像素只能显示一部分内容,画面发虚。

renderer.setPixelRatio(window.devicePixelRatio);

实际项目中常用一个上限,防止 3x 屏把 GPU 跑满:

renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
Tip

像素数是平方关系:3x 的渲染开销是 2x 的约 2.25 倍。限制到 2 是画质和性能常见的平衡点。

想读取当前值,用 renderer.getPixelRatio()。屏幕像素比变化时(比如浏览器窗口拖到另一块屏幕),要重新调用 setPixelRatio。

setSize:画布尺寸

renderer.setSize(width, height, updateStyle);
  • width、height:逻辑像素,也就是 CSS 像素
  • updateStyle:默认 true,是否同步设置 canvas 的 CSS 样式

渲染器内部会把逻辑尺寸乘以 pixelRatio,得到真实的绘制分辨率。所以 canvas 的 width 属性和 CSS 宽度不一致是正常的,别去改它。设置成 false 的场景是:canvas 的尺寸完全由 CSS 控制(比如 flex 布局自适应),你只负责逻辑尺寸。

铺满窗口的写法:

renderer.setSize(window.innerWidth, window.innerHeight);

窗口大小变化时,要重新调用 setSize 并更新相机的 aspect,响应式适配后面有专章讲。

setClearColor:清屏颜色

每帧渲染前,渲染器会用清屏色把画布擦干净,默认黑色:

renderer.setClearColor(0x000000);
renderer.setClearAlpha(0); // 清屏透明度,0 为全透明

setClearColor 接受颜色值,十六进制、CSS 颜色名都可以:0x1a1a2e、‘skyblue’ 都行。

Note

如果 scene.background 设置了颜色,它会覆盖 setClearColor。优先级是:scene.background 优先于 setClearColor。想用渲染器的清屏色,就别给 scene.background 赋值。

实际项目中两者分工:scene.background 适合放场景氛围色(天空、太空),setClearColor 适合做纯粹的画布底色。

alpha:透明背景

默认情况下画布背景不透明。想要透明背景,比如页面本身有背景图、3D 物体浮在上面,需要两步:

const renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setClearAlpha(0);

这个技巧在官网首页、3D 叠加 UI 的场景里很常用。注意透明背景会引入排序问题,物体太多时性能也可能下降,非必要不用。

shadowMap:阴影开关

阴影默认关闭。要看到阴影,三步缺一不可:渲染器开总开关、灯光 castShadow、物体 receiveShadow。

渲染器侧:

renderer.shadowMap.enabled = true;

阴影的原理是:从光源的视角把场景渲染成一张深度图(阴影贴图),画物体时采样这张图判断某处是否被挡住。贴图分辨率越高,阴影边缘越清晰。渲染器提供三种算法:

renderer.shadowMap.type = THREE.PCFShadowMap;     // 默认,柔和
// renderer.shadowMap.type = THREE.BasicShadowMap; // 快,但边缘生硬
// renderer.shadowMap.type = THREE.VSMShadowMap;   // 更柔和,更费性能
Note

只开 renderer.shadowMap.enabled 是不够的。灯光不开 castShadow、地面不收 receiveShadow,照样没阴影。灯光和阴影的完整配置在第 17、19 章。

色彩管理:默认开启

r152 起色彩管理默认开启,渲染器输出使用 SRGBColorSpace:

console.log(renderer.outputColorSpace); // 输出 srgb

老教程里这两行代码已经不需要了:

// renderer.outputEncoding = THREE.sRGBEncoding; // r152 起属性已删除,写了也没效果

色彩管理要管的还不止输出:纹理图片也要标注色彩空间(第 16 章讲)。默认行为对绝大多数项目是正确的,你不需要为色彩写任何代码。只有做 HDR 这类高级颜色流程时才需要动它。

toneMapping:色调映射

默认是 NoToneMapping,即不做处理。做 PBR 光照时,场景亮度范围可能超过显示器能力,画面过曝,这时可以启用:

renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1;

ACES 是电影行业标准的色调映射算法,效果自然、暗部和亮部都有细节,是 three.js 项目里最常见的设置。入门阶段用默认值即可,第 18 章讲光照时再展开。

调试信息

  • renderer.info:统计每帧向 GPU 下达的绘制命令数(draw call)、三角形数等信息,性能调优时用
  • renderer.debug.checkShaderErrors:默认 true,开发时保持开启,着色器出错会打印详细日志

释放资源 dispose

页面销毁时调用,释放 GPU 内存。单页应用切换路由、组件卸载的场景尤其要注意:

renderer.dispose();
Tip

更完整的清理还包括几何体、材质的 dispose,以及移除事件监听。入门阶段先记住渲染器要 dispose 就够了。

综合示例

把本章知识点串起来:抗锯齿、像素比、清屏色、阴影、色调映射。保存为 index.html,用本地服务器打开:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>渲染器配置示例</title>
  <style>
    * { margin: 0; padding: 0; }
    html, body { height: 100%; }
    canvas { display: block; }
  </style>
  <script type="importmap">
  {
    "imports": {
      "three": "https://cdn.jsdelivr.net/npm/three@0.185.0/build/three.module.js",
      "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.185.0/examples/jsm/"
    }
  }
  </script>
</head>
<body>
  <script type="module">
    import * as THREE from 'three';

    // 渲染器配置
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setClearColor(0x111122);
    renderer.shadowMap.enabled = true;
    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    document.body.appendChild(renderer.domElement);

    // 场景与相机
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(
      60, window.innerWidth / window.innerHeight, 0.1, 100
    );
    camera.position.set(4, 4, 6);
    camera.lookAt(0, 0, 0);

    // 会投阴影的立方体
    const box = new THREE.Mesh(
      new THREE.BoxGeometry(1, 1, 1),
      new THREE.MeshStandardMaterial({ color: 0x4facfe })
    );
    box.castShadow = true;
    scene.add(box);

    // 接收阴影的地面
    const floor = new THREE.Mesh(
      new THREE.PlaneGeometry(20, 20),
      new THREE.MeshStandardMaterial({ color: 0x333344 })
    );
    floor.rotation.x = -Math.PI / 2;
    floor.receiveShadow = true;
    scene.add(floor);

    // 平行光,负责投影
    const light = new THREE.DirectionalLight(0xffffff, 3);
    light.position.set(3, 5, 2);
    light.castShadow = true;
    scene.add(light);

    // 环境光,避免暗部死黑
    const ambient = new THREE.AmbientLight(0xffffff, 0.6);
    scene.add(ambient);

    renderer.render(scene, camera);
  </script>
</body>
</html>

运行后能看到:深蓝背景上一个立方体,地面有柔和的影子,颜色经过 ACES 色调映射略微压暗。

建议做两个对比实验,这是理解渲染器配置最快的方式:把 antialias 改成 false 看边缘锯齿;把 shadowMap.enabled 注释掉看阴影消失。

常见坑

  • antialias 和 setPixelRatio 混淆:前者管锯齿,后者管清晰度
  • 阴影不显示:总开关、castShadow、receiveShadow 三缺一
  • 透明背景不生效:忘了传 alpha: true
  • 改 antialias 无效:它是构造参数,不能事后修改,必须重建渲染器
  • 忘记 dispose:长期运行的应用反复创建销毁渲染器,内存会持续上涨

下一节讲场景和相机,把「看什么、怎么看」彻底搞清楚。