🧠 三分视界:Three.js 离屏渲染与多重视角的艺术

作者:一名曾在帧缓存深渊里摸爬滚打的像素炼金术士


🍿 序章:主屏之外,另有洞天

在 Three.js 的世界里,渲染器 是那位负责把 3D 幻象灌注到你眼球里的魔术师。而默认的 WebGLRenderer 每次都是忠实地将图像渲染到屏幕的画布上,像一位守旧的戏剧演员,总演同一出好戏。

但如果我告诉你------我们可以偷天换日,偷偷把场景渲染到一块看不见的布上(也就是 离屏渲染),然后再像魔术贴画一样,把这块布拼接出更绚烂的视觉宇宙呢?

是的,这一切,都要从 WebGLRenderTarget 说起。


🎨 第一幕:RenderTarget 的神秘身世

在 WebGL 中,每一帧的绘制都会写入一个叫做 帧缓冲(Framebuffer) 的魔法盒。而 RenderTarget 就是我们在 Three.js 中对帧缓冲的一次"高雅封装"。

php 复制代码
const renderTarget = new THREE.WebGLRenderTarget(
  window.innerWidth,
  window.innerHeight,
  {
    minFilter: THREE.LinearFilter,
    magFilter: THREE.LinearFilter,
    format: THREE.RGBAFormat,
  }
);

这段代码创建了一个虚拟的画布,一块隐形的画卷,所有你渲染进去的图像都会被画在这里,而非屏幕上。我们可以:

  • 用它绘制阴影贴图
  • 做环境反射
  • 实现后处理(后期调色、模糊、辉光特效等)
  • 进行多 Pass 渲染(好戏还在后头)

🧭 第二幕:离屏渲染的三板斧

🪞1. 多重视角(多相机)

想象你在拍一部 3D 电影,一台相机拍主视角,另一台拍反光镜中的你。这该怎么实现?很简单,我们给每个相机准备一个自己的渲染目标。

ini 复制代码
const camera1 = new THREE.PerspectiveCamera();
const camera2 = new THREE.PerspectiveCamera();

const rt1 = new THREE.WebGLRenderTarget(w, h);
const rt2 = new THREE.WebGLRenderTarget(w, h);

renderer.setRenderTarget(rt1);
renderer.render(scene, camera1);

renderer.setRenderTarget(rt2);
renderer.render(scene, camera2);

// 回到主屏幕
renderer.setRenderTarget(null);

此时,你手里就拥有了两个不同角度的世界快照,可以把它们贴在场景的任何材质上,实现"上帝视角"、"镜中世界"、"后视镜"等视效。


🔮2. 多 Pass 渲染(层层递进的炼金术)

单次渲染太寡淡?那就分多个 Pass,让每一步都变得魔性:

第一步:渲染基础色(Albedo)

ini 复制代码
renderer.setRenderTarget(rtColor);
renderer.render(colorScene, camera);

第二步:计算光照或边缘高亮

ini 复制代码
renderer.setRenderTarget(rtLighting);
renderer.render(lightingScene, camera);

第三步:将它们合并输出

最终我们使用一个屏幕空间的正方形(THREE.PlaneGeometry)+ 自定义 Shader,将之前的结果混合输出:

ini 复制代码
fullScreenQuad.material = new THREE.ShaderMaterial({
  uniforms: {
    tColor: { value: rtColor.texture },
    tLighting: { value: rtLighting.texture },
  },
  vertexShader: `...`,
  fragmentShader: `
    uniform sampler2D tColor;
    uniform sampler2D tLighting;
    void main() {
      vec4 base = texture2D(tColor, gl_FragCoord.xy / resolution);
      vec4 light = texture2D(tLighting, gl_FragCoord.xy / resolution);
      gl_FragColor = base + light; // 简单叠加
    }
  `,
});
renderer.setRenderTarget(null);
renderer.render(screenScene, camera);

🎬 这样你就拥有了一个图层化的渲染流程,每一个 Pass 都是一次视觉炼金,可以做模糊、辉光、色彩分离、描边、GBuffer 等高级效果。


🧪3. 使用多个 RenderTarget 同时输出多张贴图(MRT)

需要 GBuffer 吗?需要一次性输出法线图、深度图和颜色图?启用 MRT(Multiple Render Targets) 模式!

⚠️ 前提是浏览器支持 WEBGL_draw_buffers 扩展(大多数支持)

ini 复制代码
const rt = new THREE.WebGLMultipleRenderTargets(w, h, 3);
rt.texture[0].name = 'Color';
rt.texture[1].name = 'Normal';
rt.texture[2].name = 'Position';

// 在 Shader 中使用 gl_FragData[i] 输出不同纹理

你就可以一次性绘制出三张纹理贴图,然后再做你想做的后处理。


📦 第三幕:自定义渲染器?还是说自定义管线?

虽然 WebGLRenderer 已经做得很不错,但如果你想拥有更细节的控制(比如完全手动控制渲染顺序),可以考虑:

  • 写一个渲染调度器(Render Graph)
  • 使用低阶 WebGL API 实现更底层的渲染逻辑
  • 或者......直接改写 Three.js 的 WebGLRenderer.prototype.render 方法(魔法慎用)

例如手动执行一个完整的多 Pass 渲染:

scss 复制代码
function render() {
  renderer.setRenderTarget(rt1);
  renderer.clear();
  renderer.render(scene1, camera1);

  renderer.setRenderTarget(rt2);
  renderer.clear();
  renderer.render(scene2, camera2);

  // 最后合成
  renderer.setRenderTarget(null);
  renderer.render(finalScene, finalCamera);
}

这就像你成为了整场电影的导演,不再只是观众。


🧠 附加彩蛋:RenderTarget 的常见用途清单

用途 描述
后期特效 景深、模糊、泛光、色差
多视角合成 安全监控、上帝视角
光照贴图 动态阴影、烘焙反射
GBuffer 延迟渲染准备
镜面反射 反射探头、玻璃球反射
缓存复杂渲染 节省 GPU 性能

🧙 尾声:像素炼金术士的嘱咐

每一次 renderTarget 的使用,都是对 GPU 空间与显存的挑战;每一次多 Pass 的渲染,都是性能与画质的取舍。因此请你:

  • 记得释放不再使用的 RenderTarget(.dispose()
  • 理性使用多 Pass,避免过度渲染
  • 为你的离屏宇宙起一个浪漫的名字 🌌

📚 推荐延伸阅读


愿你在虚拟画布中,绘出万千真实。

------像素的仆人,光的使者,Three.js 开发者 💡

相关推荐
EndingCoder4 分钟前
中间件详解与自定义
服务器·javascript·中间件·node.js
测试者家园8 分钟前
Midscene.js为什么能通过大语言模型成功定位页面元素
javascript·自动化测试·人工智能·大语言模型·智能化测试·软件开发和测试·midscene
excel21 分钟前
全面解析 JavaScript 内置 Symbol 方法(含示例)
前端
excel23 分钟前
一文搞懂 Vue 的双向绑定
前端
卡布叻_星星5 小时前
前端JavaScript笔记之父子组件数据传递,watch用法之对象形式监听器的核心handler函数
前端·javascript·笔记
开发加微信:hedian1166 小时前
短剧小程序开发全攻略:从技术选型到核心实现(前端+后端+运营干货)
前端·微信·小程序
徐小夕@趣谈前端8 小时前
如何实现多人协同文档编辑器
javascript·vue.js·设计模式·前端框架·开源·编辑器·github
YCOSA20258 小时前
ISO 雨晨 26200.6588 Windows 11 企业版 LTSC 25H2 自用 edge 140.0.3485.81
前端·windows·edge
小白呀白9 小时前
【uni-app】树形结构数据选择框
前端·javascript·uni-app
吃饺子不吃馅9 小时前
深感一事无成,还是踏踏实实做点东西吧
前端·svg·图形学