You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Three.js时WebGL Canvas尺寸为何是CSS样式尺寸的两倍?

为什么Three.js的WebGL Canvas实际宽高是CSS宽高的两倍?(结合Effects Composer和自定义着色器的bug解析)

嘿,这个问题我之前在项目里踩过坑!核心原因其实是**设备像素比(Device Pixel Ratio, DPR)**在搞事情,下面给你拆解清楚:

1. 先搞懂Canvas尺寸的双重逻辑

Three.js里的Canvas元素有两个关键尺寸:

  • CSS样式宽高:这是你在resize函数里设置的、Canvas在页面布局中占据的可视尺寸,比如window.innerWidth和window.innerHeight。
  • 实际像素宽高:这是Canvas内部用于渲染的像素缓冲区大小,Three.js默认会把这个值设置为「CSS宽高 × 设备DPR」。

为啥要这么做?因为现在很多设备(比如Retina屏)的DPR是2,意味着屏幕上1个CSS像素对应2×2个物理像素。如果Canvas的实际像素尺寸和CSS一致,渲染出来的画面会因为像素不足而模糊,Three.js自动适配DPR就是为了让渲染结果在高分辨率屏幕上更清晰。

2. 为什么结合Effects Composer和自定义着色器会出bug?

问题出在「尺寸不匹配」上:

  • Effects Composer内部的渲染目标(WebGLRenderTarget)默认会继承Renderer的DPR设置,所以它的像素尺寸也是CSS宽高×DPR。
  • 如果你写自定义着色器的时候,没有考虑DPR的影响——比如直接用CSS尺寸计算纹理坐标、或者传递给着色器的resolution uniform是CSS尺寸而非实际像素尺寸——就会导致采样错位、画面拉伸、或者部分效果失效。

举个例子:如果你的着色器里用uv = gl_FragCoord.xy / vec2(window.innerWidth, window.innerHeight),但实际渲染的画布像素是两倍大,那么uv坐标就会被压缩,纹理显示就会出问题。

3. 解决思路

针对这个问题,有几个常用的修复方向:

  • 临时调试:强制关闭DPR适配
    初始化Renderer时手动设置像素比为1,这样Canvas实际尺寸就和CSS一致,方便快速验证问题:

    const renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio(1); // 强制禁用高清渲染
    

    缺点是高分辨率屏上画面会模糊,只适合调试用。

  • 让自定义着色器适配DPR
    给着色器传递正确的resolution uniform(即Canvas的实际像素尺寸),可以通过renderer.getDrawingBufferSize()获取:

    // 在resize函数中更新uniform
    const size = renderer.getDrawingBufferSize(new THREE.Vector2());
    yourMaterial.uniforms.resolution.value.set(size.width, size.height);
    

    然后在片元着色器里用这个resolution计算正确的uv:

    uniform vec2 resolution;
    void main() {
      vec2 uv = gl_FragCoord.xy / resolution;
      // 后续采样逻辑...
    }
    
  • 对齐Effects Composer的渲染目标尺寸
    创建Effects Composer时,显式指定渲染目标的像素比,确保和Renderer一致:

    const renderTarget = new THREE.WebGLRenderTarget(
      window.innerWidth,
      window.innerHeight,
      { pixelRatio: renderer.getPixelRatio() }
    );
    const composer = new THREE.EffectComposer(renderer, renderTarget);
    

    这样Composer内部的渲染流程就会和Renderer的尺寸逻辑对齐,避免不匹配的问题。

总结

Canvas实际尺寸是CSS两倍是Three.js的默认高清渲染策略,本身不是bug;你遇到的问题是因为自定义着色器或Effects Composer的配置没有和DPR逻辑对齐,只要调整好尺寸适配就能解决啦!

内容的提问来源于stack exchange,提问作者Mischawaka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:28:28