空间 Panel 的尺寸/距离/视锥工程边界

2D 界面 Panel 大小靠 vp 数值,位置靠 margin/padding,一切在屏幕坐标系里。空间界面 Panel 要回答三个 2D 没有的问题:放多远、做多大、超出视锥怎么办。我们做空间商品详情页,信息 Panel 一开始放 3m 远 2m 宽,真机一看——Panel 左右两端超出视锥被裁掉了,价格在左边能看到、规格在右边看不到。调到 1m 远,又太近逼着对焦看久了眼累。来回调了一周才找到尺寸/距离/视锥的合理边界。这篇把这些边界量化,给一张能直接查的距离-尺寸-可读性表。

能力面:Panel 的 position/size 和视锥裁剪

空间 Panel 的核心属性:

  • position: Vector3 — Panel 中心在空间中的位置(x/y/z 米)
  • size: Size3 — Panel 的宽高厚(通常厚设 0 或很小)
  • rotation: Quaternion — Panel 朝向,通常朝向用户

Panel 是否在视野内,取决于它的位置和尺寸是否落在相机视锥内。视锥由 FOV(视场角)和 near/far 裁剪面定义。API 26 默认水平 FOV 约 94°、垂直约 70°、near=0.1m、far=10m。

Panel 超出视锥的部分直接不渲染,不是"缩小显示"而是"裁掉消失"。一个 2m 宽的 Panel 放 1m 远,水平方向占视角 2×arctan(1/1)=90°,刚好在 94° FOV 内。放 0.8m 远,占 2×arctan(1/0.8)=102°,超出 FOV 8°,两端被裁。

距离和尺寸的耦合关系

Panel 能放多大取决于放多远。同一尺寸,距离越近占视角越大越容易超出 FOV;同一距离,尺寸越大占视角越大。公式:

horizontalAngle = 2 × arctan(width / (2 × distance))

要保证 Panel 完全在视野内,horizontalAngle ≤ FOV_horizontal。反推最大宽度:

maxWidth = 2 × distance × tan(FOV_horizontal / 2)

距离 2m、FOV 94° 时,maxWidth = 2 × 2 × tan(47°) ≈ 4.3m。距离 1m 时 maxWidth ≈ 2.16m。距离 0.5m 时 maxWidth ≈ 1.08m。

但 maxWidth 是理论极限,Panel 贴着视锥边缘用户要转头才能看到两端。实用宽度要留 20% 余量,让 Panel 在中央视野内不转头就能看全。

约束面:舒适对焦距离和可读性

Panel 放多远不只看视锥,还要看人眼舒适对焦和文字可读性。

舒适对焦距离

人眼舒适对焦距离约 0.5m~3m。近于 0.5m 要强制对焦,看 5 分钟眼疲劳;远于 3m 文字太小看不清(3m 处 38sp 起步,前文算过)。

我们让 8 个同事在不同距离看 Panel 10 分钟,测眼疲劳主观评分(1~10,越高越累):

距离疲劳评分能看清最小字号备注
0.3m7.512sp太近,强制对焦
0.5m4.216sp可接受,不宜久看
1m2.820sp舒适
2m2.128sp最舒适
3m2.538sp字要很大
5m4.864sp字太大 Panel 装不下多少内容

2m 是最舒适距离,疲劳最低、字号适中、Panel 可以做 4m 宽放下不少内容。1m 是次选,适合需要交互的 Panel(手能够到)。0.5m 以内只适合短暂提示(Toast 之类),不适合长时间阅读。

Panel 尺寸和内容量的平衡

Panel 越大能放越多内容,但越大越容易超出视锥。距离 2m 时实用最大宽度 3.4m(4.3m × 80%),高度同理算约 2.2m。一个 3.4m×2.2m 的 Panel 面积 7.5 平方米,能放不少内容。

但内容多不等于信息密度高——前文说过空间界面信息密度 4~8 项为宜。Panel 大但内容少会显得空,Panel 小内容多会挤。我们的经验是 Panel 尺寸按内容量定,每项内容占 0.4m×0.3m 左右。8 项内容的 Panel 约 2.4m×1.2m,放在 2m 处占视角 62°×34°,在视野中央很合适。

场景落地:不同距离和尺寸的可读性

我们测了商品详情 Panel 在不同距离和尺寸下的表现:

距离Panel 宽×高占水平视角文字可读性内容量评价
0.5m1.0m×0.6m90°×67°16sp 清楚少“太近了眼累”
1m1.8m×1.0m84°×53°20sp 清楚中“能看能操作”
2m3.0m×1.5m73°×41°28sp 清楚多“最舒服”
3m4.0m×2.0m67°×36°38sp 勉强多“字有点大”
5m4.0m×2.0m43°×22°64sp 太大少“太远了不想看”

2m 距离 3m×1.5m Panel 是最佳配置。73° 水平视角在 94° FOV 内留了 21° 余量,不转头能看全。28sp 字号清楚,内容量适中。

把尺寸和距离的相互拉扯画成一条计算链,尺寸超了就缩或拉远,距离不对就重算,直到两个约束同时满足。

否

是

否

是

确定内容项数

按每项 0.4m×0.3m 算基础尺寸

按距离算占角 horizontalAngle

占角不超清晰区 60°?

缩尺寸或拉远距离

距离落在舒适对焦区 0.5m~3m?

调整距离后重算

定稿 Panel 尺寸与距离

代码里的 getPanelSize 和 maxWidthAtDistance 就是这条链的落地实现。

// entry/src/main/ets/components/SpatialInfoPanel.ets
import { SpatialNode } from '@kit.ArkUI';

@Component
export struct SpatialInfoPanel {
  @Prop distance: number = 2.0;  // 默认 2m
  @Prop items: PanelItem[] = [];

  // 按距离和项数算 Panel 尺寸
  private getPanelSize(): Size {
    const itemWidth = 0.4;  // 每项 0.4m 宽
    const itemHeight = 0.3; // 每项 0.3m 高
    const cols = 3;         // 3 列
    const rows = Math.ceil(this.items.length / cols);
    return {
      width: Math.min(cols * itemWidth, this.maxWidthAtDistance()),
      height: rows * itemHeight
    };
  }

  // 按距离和 FOV 算最大宽度,留 20% 余量
  private maxWidthAtDistance(): number {
    const FOV_H = 94;  // 水平 FOV
    return 2 * this.distance * Math.tan(FOV_H / 2 * Math.PI / 180) * 0.8;
  }

  build() {
    SpatialNode({
      position: { x: 0, y: 0, z: -this.distance },
      size: this.getPanelSize()
    }) {
      PanelContent({ items: this.items })
    }
  }
}

maxWidthAtDistance 按距离和 FOV 自动算最大宽度,留 20% 余量。业务方只设距离和内容,Panel 尺寸自动算。

踩坑与取舍

坑一:Panel 太远超出视锥被裁

第一版信息 Panel 放 3m 远 4m 宽。4m 宽在 3m 距离占 67° 水平视角,在 94° FOV 内不会被裁。但 Panel 上的内容是左对齐排的,右侧内容在 Panel 边缘附近。虽然 Panel 没被裁,但右侧内容在视野边缘(距中央 33°),用户不转头看不清。视野清晰区只有中央 60°,超出要转头。

修复是把 Panel 缩到 3m 宽,占 53° 水平视角,内容全在清晰区内。代价是内容量减少——从 12 项砍到 8 项。我们觉得值得,不转头能看全比多放几项重要。

坑二:Panel 太近导致眼疲劳

有一版把交互 Panel 放 0.5m 远,想着"近一点手能够到好操作"。0.5m 处手确实容易够到,但看 3 分钟眼就累。用户测试时有人揉眼睛说"看久了不舒服"。

交互距离和阅读距离要分开。交互 Panel 可以放 1m(手能够到,眼不太累),阅读 Panel 放 2m(眼最舒服,手够不到但可以用手势射线)。我们最终是交互类 Panel(按钮/开关)放 1m,阅读类 Panel(详情/说明)放 2m,两类 Panel 不混放。

被放弃的方案:Panel 跟随用户距离

试过让 Panel 跟随用户头部位置,保持固定距离——用户前移 Panel 也前移,后退也后退。想法是"永远在舒适距离"。但用户前移是想"凑近看清楚",Panel 跟着退保持距离,用户永远凑不近,很反直觉。放弃了,Panel 固定在场景位置不跟随。

小小总结哦

  • Panel 距离 2m 最舒适,1m 适合交互,0.5m 以内只适合短暂提示
  • Panel 宽度按距离和 FOV 算,留 20% 余量保证不超出清晰视野
  • 视野清晰区中央 60°,Panel 占角不超 60° 不用转头
  • 每项内容占 0.4m×0.3m,Panel 尺寸按项数算
  • 交互 Panel 和阅读 Panel 距离分开设,不混放
  • near/far 裁剪面默认 0.1m/10m,Panel 别贴近裁剪面会有渲染伪影

目前 Panel 尺寸是按项数线性算的,换内容类型(图片比文字占空间不同)要改系数。下一步打算把每项尺寸做成内容类型的函数——文字项 0.4m×0.3m、图片项 0.5m×0.5m、混合项按比例算。另外 FOV 跨设备不同的问题,Panel 尺寸算的时候要按设备 FOV 而不是写死 94°,这个归一化前面 Z 轴那篇提过,这里也要接上。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐