如何正确使用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
相关产品推荐
相关产品推荐

