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

通过 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;
});
相关推荐
Sword997 分钟前
🎮 AI编程新时代:Trae×Three.js打造沉浸式3D魔方游戏
前端·ai编程·trae
谜亚星10 分钟前
vue和react组件更新的一点思考
前端·前端框架
清秋14 分钟前
全网最全 ECMAScript 攻略( 更新至 ES2025)
前端·javascript·ecmascript 6
puffysang3317 分钟前
Android paging3实现本地缓存加载数据
前端
拉罐23 分钟前
React Query:彻底解决 React 数据获取难题的强大利器
前端
一涯1 小时前
用python写一个抓取股市关键词的程序
前端·python
情绪的稳定剂_精神的锚1 小时前
git提交前修改文件校验
前端
Moonbit1 小时前
MoonBit 作者寄语 2025 级清华深圳新生
前端·后端·程序员
前端的阶梯1 小时前
开发一个支持支付功能的微信小程序的注意事项,含泪送上
前端·后端·全栈
Juchecar1 小时前
Node.js package.json 配置详解 + TypeScript + ES Module 集成指南
javascript