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

如何正确使用gl Scissor实现WebGL弹窗?解决渲染后外部内容变黑问题

解决WebGL弹窗渲染时弹窗外内容变黑的问题

嘿,我帮你捋捋这个问题——你遇到的弹窗外变成黑色的情况,核心原因是Three.js的Renderer默认每次调用render()都会自动执行gl.clear()清除整个画布,哪怕你设置了scissorRect也没用,因为清除操作会先把整个画布擦黑,之后的scissor限制只影响渲染,不影响之前的清除。下面给你具体的解决步骤和代码示例:

1. 调整渲染逻辑:分两次渲染

咱们需要把主场景和弹窗场景的渲染分开,精准控制清除范围:

  • 第一步:渲染主场景,关闭自动清除,保留原屏幕内容
  • 第二步:如果要显示弹窗,再单独渲染弹窗区域,只清除弹窗那块的缓冲

具体代码如下:

// 先渲染主场景,关闭自动清除,这样不会擦掉之前的内容
this.renderer.autoClear = false;
this.renderer.render(mainScene, mainCamera);

// 处理弹窗渲染
if (this.options.showPopUP) {
  // 开启scissor测试,限制后续操作的区域
  this.renderer.setScissorTest(true);
  
  // 定义弹窗的位置和尺寸(注意WebGL的y轴是从画布底部开始计算的)
  const popupX = 100;
  const popupY = 100;
  const popupWidth = 300;
  const popupHeight = 200;
  
  // 设置scissor区域和视口,两者要保持一致,确保弹窗只渲染在指定区域
  this.renderer.setScissor(popupX, popupY, popupWidth, popupHeight);
  this.renderer.setViewport(popupX, popupY, popupWidth, popupHeight);
  
  // 手动清除弹窗区域的颜色和深度缓冲,避免和主场景内容重叠混乱
  this.renderer.clearColor();
  this.renderer.clearDepth();
  
  // 渲染弹窗场景
  this.renderer.render(popupScene, popupCamera);
  
  // 恢复默认设置,避免影响后续的主场景渲染
  this.renderer.setScissorTest(false);
  this.renderer.setViewport(0, 0, this.renderer.domElement.width, this.renderer.domElement.height);
}

// 恢复自动清除,保证后续正常渲染主场景时的行为符合预期
this.renderer.autoClear = true;

2. 关键细节解释

  • autoClear的作用:默认是true,每次调用render()都会清掉整个画布。把它设为false后,第一次渲染主场景时就会保留之前的内容(或者直接渲染主场景而不清除)。
  • scissor和viewport必须配对:只设置scissor的话,视口还是整个画布,弹窗场景的内容会被缩放到scissor区域,可能变形。配对设置后,弹窗场景会正常渲染在指定区域内。
  • 手动清除弹窗区域:因为关闭了全局自动清除,所以需要手动清除弹窗区域的缓冲,不然弹窗内容会和主场景的旧内容叠在一起,显得混乱。
  • 一定要恢复设置:渲染完弹窗后记得关掉scissor测试,把视口恢复成全画布,不然下次渲染主场景时,内容只会出现在弹窗区域里。

3. 额外提醒

  • 弹窗场景的相机要适配弹窗尺寸,比如用正交相机的话,要把相机的宽高设置成弹窗的宽高,这样弹窗里的内容不会变形。
  • 如果主场景是动态更新的(比如有动画),每次渲染循环都要按照这个顺序来:先渲染主场景,再渲染弹窗(如果需要显示的话)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:35:58