【方案分享】基于Three.js和Stencil Buffer的AR实物遮挡方案,支持不规则动态区域(AR地下设施、AR虚实遮挡)

2022年初,使用安卓原生(基于filament渲染引擎)采用AR虚实遮挡的技术实现了地下隐蔽设施的显示效果【AR开发示例】实现AR管线巡检,近期有粉丝问到其实现原理。现针对WebXR中使用Three.js,做一版解析。

在这里插入图片描述

类似文档:
【AR开发示例】实现AR管线巡检


以下正文


一、背景与应用场景

1.1 AR 中的“实挡虚”需求

在增强环境中,“实挡虚”是很重要的一种渲染技术。它的意思是:

实际物体可以遮挡虚拟对象,使得虚拟对象看起来真正在环境中。

例如,一个虚拟人物走进桌子后面,那么它应该被桌子遮挡,而不是全部显示出来。

1.2 常见的遮挡技术对比

方法原理优点缺点
使用深度摄像头利用深度信息自动化,真实成本高,依赖硬件
人工遮罩模型按照环境建模可控性强工作量大,无法实时
使用 Stencil Buffer基于模板缓冲的裁剪性能好,实时实现处理繁琐

而地下设施的显示,则是需要利用模板测试,裁剪出显示范围。


二、技术方案概述

2.1 Three.js 的裁剪限制

Three.js 本身提供了 setScissor() 和 clipping planes,但都有限制:

  • setScissor() 只能做矩形裁剪,无法处理不规则形状
  • clippingPlanes 是平面裁剪,无法包围一个多边形区域

2.2 举揭 Stencil Buffer 技术

Stencil Buffer (模板缓冲),是一种可用于 WebGL 渲染流程中的控制技术:

  • 先将遮挡区域写入 stencil buffer
  • 再渲染场景,仅在 stencil 区域中显示
  • 可实现 任意形状、实时更新的遮挡

三、实现过程:实时多边形遮挡

3.1 初始化 renderer

const renderer = new THREE.WebGLRenderer({
  antialias: true,
  stencil: true // 启用 stencil buffer
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

3.2 构造遮挡区域多边形

假设我们通过实体识别/检测得到了桌子的边界点、或是通过获取开挖地下坑洞模型的尺寸计算边界:

const shape = new THREE.Shape();
shape.moveTo(p0.x, p0.y);
points.forEach(p => shape.lineTo(p.x, p.y));
const geometry = new THREE.ShapeGeometry(shape);

3.3 创建 stencil 模型,不写入颜色

const stencilMaterial = new THREE.MeshBasicMaterial({
  colorWrite: false // 不写入颜色缓冲
});
const stencilMesh = new THREE.Mesh(geometry, stencilMaterial);
stencilScene.add(stencilMesh);

3.4 渲染流程

(一)Stencil Pass :写入 stencil
renderer.state.buffers.stencil.setTest(true);
renderer.state.buffers.stencil.setFunc(gl.ALWAYS, 1, 0xff);
renderer.state.buffers.stencil.setOp(gl.REPLACE, gl.REPLACE, gl.REPLACE);
renderer.state.buffers.color.setMask(false);
renderer.state.buffers.depth.setMask(false);

renderer.render(stencilScene, orthoCamera);
(二)Scene Pass :仅在 stencil = 1 区域渲染
renderer.state.buffers.stencil.setFunc(gl.EQUAL, 1, 0xff);
renderer.state.buffers.stencil.setOp(gl.KEEP, gl.KEEP, gl.KEEP);
renderer.state.buffers.color.setMask(true);
renderer.state.buffers.depth.setMask(true);

renderer.render(mainScene, camera);

四、实时更新遮挡区域

对于需要实时识别/检测遮挡区域的场景,可以进行下列操作:

  1. 通过图像识别、点云进行线描边界
  2. 生成新的多边形顶点 array
  3. 重置 ShapeGeometry 更新 stencil mesh
shape.currentPath = new THREE.Path();
points.forEach(p => shape.lineTo(p.x, p.y));
mesh.geometry.dispose();
mesh.geometry = new THREE.ShapeGeometry(shape);

每帧样更新,就可以达到实时遮挡效果


五、实战场景

5.1 场景说明

显示地下设施

5.2 实现流程

  1. 根据模型计算开挖坑洞的3D空间坐标
  2. 转换成屏幕2D坐标
  3. 创建 stencilMesh
  4. 培入渲染流程,实现遮挡

5.3 效果展示

以下数据非真实数据,仅是功能测试时编造的数据。

在这里插入图片描述


六、进阶技巧与优化

6.1 多个遮挡区域支持

  • 使用多个 stencilMesh 合并成一个 geometry
  • 可通过不同值 stencil id 区分区域

6.2 控制遮挡优先级

  • 利用 renderOrder 先后顺序
  • 配合 depthTest,确保正确遮挡

6.3 半透明遮挡

  • 结合 alpha mask + stencil 实现透明遮挡
  • 可用于玻璃遮挡效果

七、总结

  • 通过 stencil buffer,可以在 WebAR/现实场景中实现实物遮挡虚拟效果
  • 支持任意形状,高性能,可实时调整
  • 推荐配合 AI 规划或点云线描实现自动遮挡
  • 未来可展望进一步接入 WebXR 和深度信息,进一步提升真实感

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQ-雪梨蛋花汤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值