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

通过 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;
});
相关推荐
7 分钟前
前端页面空白监控:从检测到溯源的全链路实战方案
前端
妮妮喔妮10 分钟前
如何把HTML转化成桌面Electron
前端·javascript·electron
日月晨曦11 分钟前
React 在线 playground 实现指南:让代码在浏览器里「原地爆炸」的黑科技
前端·react.js
南北是北北11 分钟前
Flow 里的上游/下游
前端·面试
金州_拉文11 分钟前
uniapp
前端·uni-app
鹏程十八少12 分钟前
10. Android <卡顿十>高度封装Matrix卡顿, 修改Matrix源码和发布自己的插件
前端
写代码的stone13 分钟前
antd时间选择器组件体验优化之useLayoutEffect 深度解析:确保 DOM 更新时序的关键机制
前端
Lazy_zheng13 分钟前
8 个高频 JS 手写题全面解析:含 Promise A+ 测试实践
前端·javascript·面试
子轩学长说13 分钟前
Nano banana极致能力测试,不愧为P图之神~
前端
月出14 分钟前
社交登录 - Twitter(前后端完整实现)
前端·twitter