运行时给你几何,不给你意义

场景理解是视觉模型在头显上最显而易见的用途,也正是 Web 平台划下了一条并不打算挪动的线的地方。

约 9 分钟

把这个缺口直说出来

命中测试返回一个点和一条法线。平面检测返回会生长、会合并的多边形。深度感知返回距离。这三样都是关于房间的几何事实,而它们没有一个回答了你的应用真正在问的问题 —— 那个问题几乎总是关于功能的:我能在这上面放东西吗、走这儿安全吗、这是不是一个用户会认为属于他自己的表面。

这两类陈述之间的距离就是全部的难处。「0.74 米处有一个水平平面」和「有一张书桌」不是同一个断言,而应用是照着第二个写的。每一个把虚拟物件放到合理位置上的 AR 体验,都在做这个翻译,而其中大多数用的是一套没人写下来的规则。

规范确实给了什么

平面检测模块里确实有一个语义标签挂在检测到的平面上,运行时通常会填上 floor、wall、ceiling、table 这一类的值。有的时候它值得用,而且检查它不花任何成本。

要注意的是它是提示性的,不是保证。取值集合不是封闭的,覆盖率在不同运行时之间、甚至同一运行时的不同会话之间都会变,而且一个平面可以先以「没有标签」的状态上报、之后才获得一个。那种不给「没有标签」留分支、直接按标签走判断的代码,在开发者自己的设备上能跑,在别人的设备上就漏下去了。以上依据规范与实际实现行为核对于 2026 年 9 月;这个领域一直在动,依赖它之前值得重读一遍。

把这个标签当成一个「有时候会来的强提示」。先把兜底写出来,让标签在出现时去改进结果;而不是照着标签写,然后发现兜底不存在。

光靠几何能走多远

比人们预期的远,而且几乎不花成本。三个你本来就有的数字 —— 离地高度、朝向、面积 —— 就能把大多数要紧的情况分开。

高度为零的水平面是地板。竖直的是墙,而一个下沿明显高于地板的竖直平面,更可能是窗或者一幅画而不是墙。水平表面按高度聚成几堆,而这些堆和家具是对得上的:大致 0.4 到 0.5 米是坐面高度,0.7 到 0.8 是桌面高度,0.9 上下是厨房台面,1.2 以上是搁板。然后用面积去消歧:一个 0.75 米高、两平方米的水平面是餐桌,而只有它十分之一大的那个是边几。

这不是机器学习,也不需要是。它是二十行算术,跑起来是微秒级,在每台设备上表现完全一致,而且常见情况都判对。在把这一层用尽之前就去拿模型,等于为一个高度阈值已经解决了的问题,付出大量的复杂度。

用几何给平面分类,标签可有可无

高度分档是需要本地核对的那部分。台面和桌面的高度在不同地区差得足够多,一套在某个市场调好的阈值,换个市场就会判错;而这恰恰是那种「在有人报告你的应用把他的书桌认成了厨房」之前完全看不见的假设。

// 高度分档是近似值,而且有地区差异。请拿你要发行的市场里的
// 真实家具去核对,不要把这几个数当成普适常量。
const BANDS = [
  { max: 0.15, kind: 'floor' },
  { max: 0.55, kind: 'seat' },
  { max: 0.85, kind: 'table' },
  { max: 1.05, kind: 'counter' },
  { max: Infinity, kind: 'shelf' },
];

function classify(plane, floorY) {
  // 标签只要存在,就胜过任何几何推断。
  if (plane.semanticLabel) return plane.semanticLabel;

  const normal = planeNormal(plane);
  const vertical = Math.abs(normal.y) < 0.3;
  if (vertical) return 'wall';

  const height = planeCentre(plane).y - floorY;
  return BANDS.find((band) => height <= band.max).kind;
}

先查标签、查不到再落到几何,意味着同一份代码在会上报标签的运行时上更准,在不上报的运行时上也不会坏。反过来写 —— 几何优先、标签当覆盖 —— 会让同一台硬件上的结果取决于标签什么时候到达。

光靠几何会在哪里失效

这些正是把人推去找模型的那些情况,而它们值得说具体 —— 因为其中有几种,模型也解决不了。

床和桌子一样高
两者都呈现一个 0.5 到 0.7 米上下的大面积水平表面。几何上几乎相同,功能上毫无共同点。面积能帮上一点忙;几何里再没有别的能帮忙了。
被占用的表面
一张放着显示器、键盘和咖啡杯的书桌,上报出来是一个平面 —— 因为平面检测描述的是表面,不是搁在它上面的东西。把物件放在那个平面的中心,等于把它放进了一台笔记本电脑里。
玻璃与高光
玻璃桌、镜子和高光泽表面对底层追踪本身就不可靠,所以它们要么变成闪烁的平面、要么是平面碎片、要么根本不出现。这是感知层面的限制,再多的语义推理也救不回来。
地毯、门槛和台阶
贴近地板的小高差,恰好落在「地板高度估计本身就不确定」的那个范围里。地毯算不算地板,对人来说不是个难题,对一个阈值来说是真的有歧义。
归属与社会含义
一个表面是不是用户会介意你盖住的那种,不是几何属性、不是语义标签,也不是视觉模型能拿到的东西。别人的书桌和你自己的形状完全一样。

Web 平台划下的那条线

对上面那张清单最自然的反应是:跑一个场景理解模型。在原生头显应用上这条路走得通 —— 申请摄像头权限、在画面上跑一个分割模型、拿到几何给不了的标签。

在 Web 上这条路是关着的,而且是故意关着的。WebXR 不会把摄像头画面交给你的页面。你收到的是运行时已经算好的抽象 —— 平面、网格、深度缓冲、光照估计 —— 正是为了让一个页面无法重建用户正站在其中的那个房间。来自头显的摄像头画面里有用户的家、家里的人、桌上的文件、台面上的药盒;而平台的立场是:一个网页不该用一次没人会仔细读的权限弹窗,换来这些东西。

把它理解成一个设计约束而不是一个缺失的功能,是值得的。它意味着 Web 应用在空间语义上的天花板,就是运行时愿意暴露的那些;也意味着原生应用永远能比页面更了解这个房间。如果你的产品依赖细粒度的场景理解,那个依赖本身就是一场「你要发在哪个平台上」的争论,而这场争论早点吵完更好。

而好处并不小。这道抽象边界意味着一个 WebXR 页面在隐私姿态上和原生应用是真的不同,这是一件可以实实在在告诉用户的事;它也意味着昂贵的感知计算在运行时里做一次,而不是在每个页面里各做一遍。

把应用设计成不需要知道

这个领域里最稳的那些应用,是那些安排好了自己不需要答案的。

让用户自己放,是最明显的那个版本,而它被低估了,因为它看起来像认输。它不是:用户知道哪个表面是书桌、知道上面已经有什么、也知道自己介不介意。一个花两秒的摆放交互,消掉的是一整类失败;而用户并不会把「被问了一句放哪儿」体验成一个缺陷。

在确实必须自动摆放的地方,为「优雅地错」而设计,胜过为「准」而设计。一个落在某个说得过去的位置、并且能被拖动的物件,没问题。一个因为平面被判错而落进墙里、还挪不动的物件,是同一个分类错误,但后果差得多。错误率是一个难题的属性;而错误的后果是一个设计决定

这些都不是在反对把模型用进 XR。它是在说:一旦你把本来就有的那三个数字用起来,几何到意义的缺口比看上去要窄;而剩下的那点宽度,在 Web 上不是靠加智能能补上的 —— 因为能补上它的那些信息,是被刻意不交给你的。

相关页面