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

通过 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;
});
相关推荐
前端摸鱼匠14 小时前
Vue 3 的v-bind合并行为:讲解v-bind与普通属性合并的规则
前端·javascript·vue.js·前端框架·ecmascript
REDcker14 小时前
浏览器端Web程序性能分析与优化实战 DevTools指标与工程清单
开发语言·前端·javascript·vue·ecmascript·php·js
donecoding16 小时前
一个 sudo 引发的血案:npm 全局包权限错乱彻底修复
前端·node.js·前端工程化
风骏时光牛马16 小时前
Raku正则匹配与数据批量处理实操案例
前端
nbwenren16 小时前
2026实测:Gemini 3 镜像站视觉能力实践——拍照原型图,一键生成 HTML+CSS 代码
前端·css·html
Lee川16 小时前
Prisma 实战指南:像搭积木一样设计古诗词数据库
前端·数据库·后端
Linsk16 小时前
Java和JavaScript的关系真是雷峰和雷峰塔的关系吗?
java·javascript·oracle
当时只道寻常16 小时前
浏览器文本复制到剪贴板:企业级最佳实践
javascript
jinanwuhuaguo16 小时前
(第二十九篇)OpenClaw 实时与具身的跃迁——从异步孤岛到数字世界的“原住民”
前端·网络·人工智能·重构·openclaw