Work 及其相关核心接口定义如下:
import * as THREE from "three";
import type { Mode } from "@realsee/five";
type CubeFace = 'up' | 'down' | 'left' | 'right' | 'front' | 'back';
/** Work 实体:VR 项目的根对象 */
export interface Work {
/** 唯一标识 (Work ID) */
workCode: string;
/** 项目名称 */
name: string;
/** 资源加载的基础路径 (Base URL) */
baseURL: string;
/** 数据签发人 */
issuer: string;
/** 过期时间 */
expire: Date;
/** 允许访问的安全域名列表 */
allowHosts: readonly string[];
/** 初始化参数 (默认模态、视角等) */
initial: WorkInitial;
/** 相对位姿 (用于多 Work 拼接时的坐标变换) */
transform: THREE.Matrix4;
/** 模型参数 (3D 模型资源信息) */
model?: WorkModel;
/** 全景点位信息 (所有可观测点位的列表) */
observers: readonly WorkObserver[];
}
/** 观察点:空间中可驻足观看的点位 */
export interface WorkObserver {
/** 所属 Work 引用 */
work: Work;
/** 在 observers 数组中的索引 */
index: number;
/** 点位序号 (通常与 index 相同) */
panoIndex: number;
/** 点位唯一 ID (通常格式为 `${workCode}[${panoIndex}]`) */
panoId: string;
/** 点位是否激活可用 */
active: boolean;
/** 点位是否可加载 */
loadable: boolean;
/** 点位所在楼层索引 */
floorIndex: number;
/** 点位在模型坐标系下的观察位置 (用于渲染相机位置) */
position: THREE.Vector3;
/** 点位在模型坐标系下的地面位置 (用于导航和 UI 定位) */
standingPosition: THREE.Vector3;
/** 点位和模型的旋转对齐四元数 */
quaternion: THREE.Quaternion;
/** 点位和模型的旋转对齐矩阵 */
matrix: THREE.Matrix4;
/** 可连通的相关点位序号 (用于全景游走) */
accessibleNodes: readonly number[];
/** 点位全景图资源信息 */
images: WorkImage;
/** 获取点位的全局坐标 */
getWorldPosition(this: WorkObserver): THREE.Vector3;
/** 获取点位的全局地面坐标 */
getWorldStandingPosition(this: WorkObserver): THREE.Vector3;
/** 将方向向量转化为全景图 uv */
vectorToEquirectangularUv(vector: THREE.Vector3, uvOrigin?: 'top-left' | 'bottom-left'): THREE.Vector2;
/** 将全景图 uv 转化为方向向量 */
equirectangularUvToVector(uv: THREE.Vector2, uvOrigin?: 'top-left' | 'bottom-left'): THREE.Vector3;
/** 将方向向量转化为获六视图 uv */
vectorToCubemapUv(vector: THREE.Vector3, uvOrigin?: 'top-left' | 'bottom-left'): [cubeFace: CubeFace, cubemapUv: THREE.Vector2];
/** 将六视图 uv 转化为方向向量 */
cubemapUvToVector(cubeFace: CubeFace, uv: THREE.Vector2, uvOrigin?: 'top-left' | 'bottom-left'): THREE.Vector3;
}
/** 初始化位姿参数 */
export interface WorkInitial {
work: Work;
/** 模态 */
mode?: Mode;
/** 点位序号 */
panoIndex?: number;
/** 相机水平角 */
longitude?: number;
/** 相机俯仰角 */
latitude?: number;
/** 相机可视角度(垂直)*/
fov?: number;
/** 相机观察点位置 [x, y, z] */
offset?: THREE.Vector3;
/** 相机距离观察点距离 */
distance?: number;
}
/** 模型数据 */
export interface WorkModel {
/** work */
work: Work;
/** 模型文件地址 at3d / domez */
file?: string;
/** 模型贴图文件地址 */
textures?: readonly string[];
/** 模型贴图文件地址的父目录 */
textureBase?: string;
/** 指定上方向,对于 obj, ply 等定义不明确的需要指定上方向 */
upAxis?: string;
/** 3d tile */
layers: readonly WorkModelLayer[];
}
/** 模型图层信息 */
export interface WorkModelLayer {
/** work */
work: Work;
/** 模型类型 point_cloud mesh gaussian_splatting */
type: 'point_cloud' | 'mesh' | 'gaussian_splatting';
/** 模型名称 */
name: string;
/** 指定上方向 */
upAxis: string;
/** tileset.json 地址 */
tileset: string;
}
/** 全景图资源信息 */
export interface WorkImage {
work: Work;
/** 分辨率表 */
sizeList: readonly number[];
/** 瓦片信息 */
tiles: readonly WorkTile[];
/** 缩略图/预览图等 */
[key: string]: any;
}
Work 是 Five 渲染内容的基石。它不仅包含资源地址,还包含空间结构数据。由于数据通常带有数字签名(防止篡改),开发者不应手动修改 Work 对象中的属性,尤其是资源路径和坐标数据。
Five 中有三种与 Work 相关的类型,它们分别对应不同的使用场景:
parseWork(json) 的输入。parseWork 解析生成。THREE.Vector3),且被冻结(不可变)。five.load(work)。workToJson(work) 生成。WorkModel 提供了两种定义模型数据的方式,其中 layers 是现代标准,file 主要用于兼容旧数据或简单场景。
layers: (推荐) 数组结构,用于定义多层级、多类型的模型资源。
mesh (模型), point_cloud (点云), gaussian_splatting (高斯泼溅)。file: (兼容) 字符串路径,用于定义单文件的 Mesh 模型。
.at3d, .obj, .glb)。加载优先级与兼容逻辑 (Fallback):
Five 在运行时会将 file 视为一个虚拟的 mesh 图层。加载逻辑如下:
优先加载 Layers:
Five 会遍历 work.model.layers 并加载其中定义的所有图层(包括 Mesh, PointCloud, GaussianSplatting 等)。
File 的条件加载:
检查当前已加载的图层中是否存在 type: 'mesh' 的图层。
work.model.file 字段(认为 layers 已经提供了更高精度的模型)。work.model.file 有值,Five 会自动创建一个临时的 Mesh ViewLayer 来加载该文件。Observer 是 VR 空间中预设的观察位置。在 Panorama (全景) 模式下,相机必须停留在某个 Observer 上。
workCode 是 Work 的全局唯一标识符。
workCode 来区分不同 Work 下的同名属性(如 panoIndex)。从服务端获取的原始 JSON 数据(LooseWork)可能包含相对路径或简写。parseWork 函数负责将其标准化为严格的 Work 对象,处理 URL 拼接、默认值填充和数据校验。
最基础的用法是从 API 获取数据并加载。
import { Five, parseWork } from "@realsee/five";
const five = new Five();
five.appendTo(document.getElementById("app"));
// 1. 获取数据
fetch("https://vrlab-public.ljcdn.com/release/web/work.json")
.then(res => res.json())
.then(json => {
// 2. 解析数据
const work = parseWork(json);
// 3. 加载到 Five
five.load(work);
});
加载完成后,可以通过 five.work 访问当前数据。
// 获取所有观察点
const observers = five.work.observers;
// 获取当前所在的观察点
const currentPanoIndex = five.state.panoIndex;
const currentObserver = observers[currentPanoIndex];
console.log("当前点位坐标:", currentObserver.position);
console.log("可通往的点位:", currentObserver.accessibleNodes);
Five 支持同时加载多个 Work,常用于楼盘小区的多个样板间拼接,或大型商业空间的区域拼接。
const work1 = parseWork(json1);
const work2 = parseWork(json2);
// 同时加载两个 Work
five.load([work1, work2]);
// 切换到指定 Work 的指定点位
five.setState({
mode: "Panorama",
workCode: work2.workCode, // 必须指定 workCode
panoIndex: 0
});
可以使用 load 方法的参数来控制是替换当前场景还是追加到当前场景。
const work3 = parseWork(json3);
// 追加 Work (保留原有场景)
// 第二个参数 "inherit" 表示保持当前相机视角和模态不变,不重置为新 Work 的初始视角
five.load(work3, "inherit", { mode: "add" });
// 替换 Work (清空原有场景) - 默认行为
five.load(work3, "inherit", { mode: "replace" });
work.observers[0].position.x = 100 虽不会报错,但可能导致渲染异常或签名验证失败。请视 Work 为只读对象。baseURL 指向的资源服务器必须配置正确的 CORS 头,否则 WebGL 无法加载纹理。Work 对象,总是使用 parseWork。服务端数据结构可能会升级,parseWork 会处理兼容性。tags: [VR数据, 数据加载, 点位, 全景点, 数据结构, 多work, work, core, entity, observer, parseWork, workCode, JSON, load]