如何使用OpenGL裁剪矩形区域内部的像素?
关于glScissor实现反向裁剪的问题解答
无法仅通过修改glScissor的配置参数直接实现反向裁剪效果。glScissor对应的裁剪测试是固定功能逻辑,规则固定为「仅保留落在配置矩形区域内的片元、丢弃区域外片元」,没有提供反转测试判定结果的配置项,单靠调整裁剪矩形的坐标、大小参数不可能实现保留外部、丢弃内部的效果。
可实现反向矩形裁剪的可行方案
方案1:多矩形拼接多次绘制(全版本兼容)
需要保留的区域外部分,最多可以拆分为4个互不重叠的规则矩形,以上下左右四个方位包裹中间要丢弃的矩形。你可以开启GL_SCISSOR_TEST后,依次为这4个矩形调用glScissor设置裁剪范围,每设置一次就重新绘制一遍目标内容,最终拼合出来的效果就是中间矩形区域被挖空、外部区域完整保留。
这个方案不需要额外的缓冲资源、不需要修改着色器,兼容所有版本的OpenGL,缺点是同一份内容需要重复绘制最多4次,绘制本身开销较高时会带来额外性能损耗。方案2:模板测试实现(性能最优、灵活性高)
借助模板缓冲可以单次绘制就实现反向裁剪,是工程上最常用的实现方式,操作步骤如下:- 初始化时确保帧缓冲带有模板位,先清空模板缓冲为0
- 调用
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)和glDepthMask(GL_FALSE),临时关闭颜色、深度写入,仅开启模板写入 - 绘制你需要丢弃的内部矩形,将对应位置的模板值设置为1
- 调用
glColorMask和glDepthMask恢复颜色、深度写入,开启模板测试,设置测试规则为glStencilFunc(GL_NOTEQUAL, 1, 0xFF),即仅模板值不等于1的片元可以通过测试 - 正常绘制你的目标场景,此时中间矩形区域的片元会因为模板测试失败被丢弃,正好实现反向裁剪效果
这个方案仅需要一次场景绘制,性能开销极低,后续如果要把裁剪区域换成圆形、多边形等非矩形形状,只需要替换第二步绘制的模板形状即可,灵活性很强。
方案3:片元着色器手动丢弃(逻辑最直观)
你可以在顶点着色器中计算每个片元对应的屏幕坐标,传递到片元着色器后,直接判断当前片元是否落在需要丢弃的矩形范围内,如果命中范围就直接调用discard关键字丢弃该片元。
这个方案不需要操作复杂的全局测试状态,逻辑简单直接,缺点是手动discard操作会打断部分GPU的Early-Z提前深度测试优化,在裁剪规则复杂时着色器分支判断也会带来一定的性能开销。
内容的提问来源于stack exchange,提问作者n3xtbyte
相关产品推荐
相关产品推荐

