如视 Five SDK
    Preparing search index...

    Screen & Space Projection (屏幕与空间坐标转换)

    • Summary: 详解屏幕二维坐标与三维空间坐标/射线之间的相互转换关系,以及如何在 DOM 层与 3D 场景进行联动(如显示标签)。
    • Schema: five.project2d 接口定义。
    • Concepts: World Space, Screen Space, NDC, Raycasting.
    • Examples: 空间点位转屏幕坐标 (标签功能)、屏幕坐标转空间射线。

    Definition: Five

    // defined in Five class
    interface Five {
    /**
    * 计算三维坐标对应到屏幕的二维坐标
    * @param vector - 三维空间坐标 (World Space)
    * @param testModel - 是否进行模型遮挡检测 (默认 false)。如果为 true,且该点被模型遮挡,则返回 null。
    * @returns 二维屏幕坐标 (相对于 Canvas 左上角) 或 null (如果点在视野外或被遮挡)
    */
    project2d(vector: THREE.Vector3, testModel?: boolean): THREE.Vector2 | null;
    }

    在 Five (Three.js) 中,坐标转换通常遵循以下流程:

    • World Space (世界坐标): 三维场景中的绝对坐标 (x, y, z),单位通常为米。
    • Camera Space (相机坐标): 相对于相机的坐标。
    • NDC (Normalized Device Coordinates): 归一化设备坐标,x, y, z 范围均为 [-1, 1]。
    • Screen Space (屏幕坐标): 对应 Canvas 画布的像素坐标。原点 (0, 0) 在左上角,x 向右增加,y 向下增加。
    方向 方法 核心逻辑 用途
    3D ➔ 2D five.project2d(vector) World ➔ NDC ➔ Screen 标签 (Tag)、HUD、跟随 3D 物体的 UI
    2D ➔ 3D Raycaster Screen ➔ NDC ➔ Ray 点击拾取 (Picking)、地面检测、放置物体

    five.project2d 是 Five 提供的便捷方法,它封装了以下逻辑:

    1. 将世界坐标投影 (Project) 到相机的 NDC 空间。
    2. 判断点是否在视锥体 (Frustum) 内(即是否在视野范围内)。
    3. (可选) 发射射线检测该点与相机之间是否有模型遮挡。
    4. 将 NDC 坐标转换为相对于 Canvas 左上角的像素坐标 (px)。

    最典型的应用场景是在 3D 场景中的某个物体上方显示一个 HTML 标签。

    import { Five, Mode } from "@realsee/five";
    import * as THREE from "three";

    const five = new Five();
    // ... 初始化 five ...

    // 1. 创建标签 DOM 元素
    const label = document.createElement("div");
    label.textContent = "Living Room";
    label.style.position = "absolute";
    label.style.padding = "4px 8px";
    label.style.background = "rgba(0, 0, 0, 0.6)";
    label.style.color = "white";
    label.style.borderRadius = "4px";
    label.style.pointerEvents = "none"; // 避免阻挡鼠标事件
    label.style.transform = "translate(-50%, -100%)"; // 居中并显示在点上方
    label.style.display = "none"; // 默认隐藏
    document.body.appendChild(label); // 添加到 container (注意 container 的定位 context)

    // 2. 定义目标空间坐标 (例如客厅中心)
    const targetPosition = new THREE.Vector3(1.5, 2.0, -3.0);

    // 3. 在每一帧渲染时更新标签位置
    five.on("render.prepare", () => {
    // 计算屏幕坐标
    // 参数2: false 表示不检测遮挡 (性能更好);true 表示如果被墙挡住则隐藏
    const screenPos = five.project2d(targetPosition, true);

    if (screenPos === null) {
    // 如果返回 null,说明点在相机背面,或者被遮挡(如果开启了 testModel)
    label.style.display = "none";
    } else {
    label.style.display = "block";
    // 更新 DOM 位置
    // 注意:screenPos 是相对于 Canvas 的坐标。
    // 如果 Canvas 占满全屏,直接使用即可。
    // 如果 Canvas 有偏移,需加上 Canvas 的 offset。
    label.style.left = `${screenPos.x}px`;
    label.style.top = `${screenPos.y}px`;
    }
    });

    将鼠标点击的屏幕坐标转换为 3D 射线,用于检测物体。

    注意: 更多射线检测细节请参考 Raycast

    import * as THREE from "three";

    // 假设 container 是 five 的容器元素
    const container = five.getElement()!.parentElement!;

    container.addEventListener("click", (event) => {
    const raycaster = new THREE.Raycaster();
    const mouse = new THREE.Vector2();

    // 1. 计算 NDC 坐标 (x, y 范围 [-1, 1])
    // event.clientX/Y 是相对于视口的坐标
    // getBoundingClientRect 用于获取容器的位置
    const rect = container.getBoundingClientRect();

    mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
    mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; // 注意 Y 轴翻转

    // 2. 从相机发射射线
    raycaster.setFromCamera(mouse, five.camera);

    // 3. 进行相交检测
    const intersects = five.model.intersectRaycaster(raycaster);

    if (intersects.length > 0) {
    console.log("Hit point:", intersects[0].point);
    }
    });
    1. 坐标系原点:

      • DOM/CSS 坐标系原点在左上角,Y 轴向下。
      • NDC/WebGL 坐标系原点在中心,Y 轴向上。
      • project2d 返回的是 DOM 风格 的坐标 (左上角原点),可以直接赋给 CSS left/top
      • 但在进行 Raycaster 转换时,需要手动将 DOM 坐标转换为 NDC (Y 轴翻转)。
    2. 性能开销:

      • project2d(pos, true) 开启 testModel 会进行射线检测,性能开销较大。如果在 render.prepare 中对大量点进行检测,可能会导致掉帧。
      • 建议:对于大量标签,默认使用 false;或者仅对可视范围内的关键标签进行遮挡检测;或者限制检测频率(如每 10 帧检测一次)。
    3. Canvas 尺寸:

      • project2d 内部使用 five.renderer.getSize()five.viewport 计算。确保 Canvas 尺寸与 DOM 显示尺寸一致 (通常 Five 会自动处理,但如果使用了 CSS 缩放需注意)。
    4. Null 返回值:

      • 务必检查 project2d 的返回值是否为 null。点在相机背面、超出视锥体裁剪范围、或被遮挡(开启 testModel 时)都会返回 null
    • Raycast: 详细的射线检测文档。
    • Five: Five 核心类说明。
    • State: 了解相机位姿 (Pose)。
    • Coordinate System: 坐标系定义,理解世界坐标与屏幕坐标的关系。

    tags: [标签, 坐标转换, 信息面板, coordinate, screen, project, label, ui, tag, HUD, 3D转2D, overlay, tooltip]