同步绘制视锥几何体和实际相机视锥体

通过 FrustumGeometry 绘制视锥体时,如果直接使用 HeadingPitchRoll 设置方向,可能会导致绘制的视锥体与实际相机的视锥体不一致。主要因为 HeadingPitchRoll 是基于局部坐标系的方向描述,而相机的视锥体方向是基于全局坐标系(通常是 ENU 坐标系)的。

为了确保绘制的视锥体与实际相机的视锥体一致,需要将相机的方向矩阵(Camera.direction)与 FrustumGeometry 的方向对齐。

1. 获取相机的视锥体参数

首先,获取相机的视锥体参数,包括:

相机的位置(Camera.position)。

相机的方向矩阵(Camera.direction)。

相机的视锥体角度(fov、aspectRatio 等)。

javascript 复制代码
let viewer = new Cesium.Viewer('cesiumContainer');
let camera = viewer.camera;

// 获取相机的位置
let cameraPosition = camera.position;

// 获取相机的方向矩阵
let cameraDirection = camera.direction;
let cameraUp = camera.up;
let cameraRight = camera.right;

// 获取相机的视锥体参数
let fov = Cesium.Math.toRadians(camera.frustum.fov); // 垂直视场角
let aspectRatio = camera.frustum.aspectRatio; // 宽高比
let near = camera.frustum.near; // 近裁剪面
let far = camera.frustum.far; // 远裁剪面

2. 创建视锥几何体

使用 FrustumGeometry 创建视锥几何体,并设置其方向与相机方向一致。

javascript 复制代码
// 创建视锥几何体
let frustumGeometry = new Cesium.FrustumGeometry({
    position: cameraPosition,
    orientation: Cesium.Transforms.rotationMatrixFromPositionVelocity(
        cameraPosition,
        cameraDirection,
        cameraUp
    ),
    frustum: new Cesium.PerspectiveFrustum({
        fov: fov,
        aspectRatio: aspectRatio,
        near: near,
        far: far
    })
});

// 创建几何体实例
let frustumInstance = new Cesium.GeometryInstance({
    geometry: frustumGeometry,
    attributes: {
        color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED.withAlpha(0.5))
    }
});

// 添加到图元集合
let primitive = viewer.scene.primitives.add(
    new Cesium.Primitive({
        geometryInstances: frustumInstance,
        appearance: new Cesium.PerInstanceColorAppearance({
            translucent: true,
            flat: true
        })
    })
);

3. 动态更新视锥体

如果相机的位置或方向发生变化,需要动态更新视锥几何体的位置和方向。

javascript 复制代码
viewer.scene.preUpdate.addEventListener(function () {
    // 更新相机参数
    cameraPosition = camera.position;
    cameraDirection = camera.direction;
    cameraUp = camera.up;

    // 更新视锥几何体的位置和方向
    frustumGeometry = new Cesium.FrustumGeometry({
        position: cameraPosition,
        orientation: Cesium.Transforms.rotationMatrixFromPositionVelocity(
            cameraPosition,
            cameraDirection,
            cameraUp
        ),
        frustum: new Cesium.PerspectiveFrustum({
            fov: fov,
            aspectRatio: aspectRatio,
            near: near,
            far: far
        })
    });

    // 更新几何体实例
    frustumInstance.geometry = frustumGeometry;
});

4. 解决差异问题

坐标系对齐:确保使用 Cesium.Transforms.rotationMatrixFromPositionVelocity 将方向矩阵与相机方向对齐。

视锥体参数:确保 fov、aspectRatio、near 和 far 参数与相机的视锥体参数一致。

几何体更新:如果相机位置或方向发生变化,必须动态更新视锥几何体的位置和方向。

5. 完整代码示例

以下是一个完整的代码示例:

javascript 复制代码
let viewer = new Cesium.Viewer('cesiumContainer');
let camera = viewer.camera;

// 获取相机参数
let cameraPosition = camera.position;
let cameraDirection = camera.direction;
let cameraUp = camera.up;
let fov = Cesium.Math.toRadians(camera.frustum.fov);
let aspectRatio = camera.frustum.aspectRatio;
let near = camera.frustum.near;
let far = camera.frustum.far;

// 创建视锥几何体
let frustumGeometry = new Cesium.FrustumGeometry({
    position: cameraPosition,
    orientation: Cesium.Transforms.rotationMatrixFromPositionVelocity(
        cameraPosition,
        cameraDirection,
        cameraUp
    ),
    frustum: new Cesium.PerspectiveFrustum({
        fov: fov,
        aspectRatio: aspectRatio,
        near: near,
        far: far
    })
});

// 创建几何体实例
let frustumInstance = new Cesium.GeometryInstance({
    geometry: frustumGeometry,
    attributes: {
        color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED.withAlpha(0.5))
    }
});

// 添加到图元集合
let primitive = viewer.scene.primitives.add(
    new Cesium.Primitive({
        geometryInstances: frustumInstance,
        appearance: new Cesium.PerInstanceColorAppearance({
            translucent: true,
            flat: true
        })
    })
);

// 动态更新视锥体
viewer.scene.preUpdate.addEventListener(function () {
    cameraPosition = camera.position;
    cameraDirection = camera.direction;
    cameraUp = camera.up;

    frustumGeometry = new Cesium.FrustumGeometry({
        position: cameraPosition,
        orientation: Cesium.Transforms.rotationMatrixFromPositionVelocity(
            cameraPosition,
            cameraDirection,
            cameraUp
        ),
        frustum: new Cesium.PerspectiveFrustum({
            fov: fov,
            aspectRatio: aspectRatio,
            near: near,
            far: far
        })
    });

    frustumInstance.geometry = frustumGeometry;
});
相关推荐
子兮曰13 小时前
AI Agent 完整入门指南:从 LLM 到生产落地的 30+ 个核心概念
前端·后端·agent
三十而立洋13 小时前
Promise到底是什么、怎么用
javascript
楚宝ovo13 小时前
新增一个 demo 子应用 - 微前端
前端
JarvanMo14 小时前
Dart 3.13:小版本,大动作
前端
纯粹的热爱14 小时前
Ubuntu 安装 Node.js 22.x(通过 NodeSource 官方源)
前端
Highcharts14 小时前
如何选择正确的图表:驱动理解和洞察力的三部分框架(第3部分)
前端·数据可视化
JavaGuide15 小时前
Github 史诗级故障,与此同时,Cursor 版「GitHub」正式上线!
前端·后端
郭邯15 小时前
用 AI 写了一个经纬度格式转换工具,从需求到落地的完整过程
前端
不一样的少年_15 小时前
修了 Bug、做了重构,为什么老板还是觉得你没产出?
前端·后端·程序员