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

通过 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;
});
相关推荐
审小匠OpenCPAi12 小时前
银行流水核查怎么自动化?单边匹配、双向勾稽与图聚类异常检测的工程对比
java·前端·人工智能·python·审计
Revolution6113 小时前
一个公共表格组件,是怎么一步步失控的
前端·前端工程化
mONESY13 小时前
React useState 核心原理与最佳实践:从异步更新到性能优化全解
javascript
腻害兔13 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程
whyfail13 小时前
前端学 Spring Boot(2):一次点击,如何穿过整个后端?
前端·spring boot·后端
AI多Agent协作实战派13 小时前
AI多Agent协作系统实战(二十三):Agent读HEARTBEAT.md不读AGENTS.md——openclaw的文件加载之谜
前端·数据库·人工智能·uni-app
gis开发之家14 小时前
《Vue3 从入门到大神37篇》Vue3 源码详解(七):watch 与 watchEffect 源码对比——副作用是如何被追踪的?
javascript·前端框架·vue3·vue3源码
2601_9557600715 小时前
如何用 Claude Opus 5 API 批量扩展长尾关键词和文章选题
前端·python·搜索引擎
KaMeidebaby15 小时前
卡梅德生物技术快报|bli亲和力检测gst:告别批量跑胶:BLI实时酶切监测技术加速GST融合蛋白下游流程优化
前端·网络·数据库·人工智能·算法
bloglin9999915 小时前
langchain 和 langgraph 和 react
javascript·react.js·langchain