Cesium 实战 - 视锥体(Frustum)实现

发布时间:2023年12月22日

Cesium 实战 - 视锥体(Frustum)实现

在实现视频投射的时候,接触了一下视椎体,但是研究并不透彻。

后来在群里见到有人想在线看一下视椎体效果,以及实现过程,于是就试了一下。

本文包含视锥体核心代码、完整代码以及在线示例三部分。


椎体核心代码


// 定义创建四棱锥类
function CreateFrustum(options) {
    // 位置点
    this.position = options.position;
    // 方向
    this.orientation = options.orientation;
    // 相机视场角
    this.fov = options.fov || 30;
    // 近距离点,0 则会显示四棱锥的顶点
    this.near = options.near || 10;
    // 远距离点
    this.far = options.far || 100;
    // 视锥的宽度/高度
    this.aspectRatio = options.aspectRatio;
    this.add();
}

CreateFrustum.prototype.add = function add() {
    this.clear();
    this.addFrustum();
    this.addOutline();
}

CreateFrustum.prototype.update = function (position, orientation) {
    this.position = position;
    this.orientation = orientation;
    this.add();
}

CreateFrustum.prototype.clear = function () {
    this.clearFrustum();
    this.clearOutline();
}

CreateFrustum.prototype.clearFrustum = function () {
    if (this.frustumPrimitive) {
        viewer.scene.primitives.remove(this.frustumPrimitive);
        this.frustumPrimitive = null;
    }
}

CreateFrustum.prototype.clearOutline = function () {
    if (this.outlinePrimitive) {
        viewer.scene.primitives.remove(this.outlinePrimitive);
        this.outlinePrimitive = null;
    }
}

// 创建视锥体
CreateFrustum.prototype.addFrustum = function () {
    // 创建视锥
    let frustum = new Cesium.PerspectiveFrustum({
        fov: Cesium.Math.toRadians(this.fov),
        aspectRatio: this.aspectRatio,
        near: this.near,
        far: this.far,
    });
    // 创建视锥几何数据
    let geometry = new Cesium.FrustumGeometry({
        frustum: frustum,
        origin: this.position,
        orientation: this.orientation,
        vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
    });
    // 创建实例
    let instance = new Cesium.GeometryInstance({
        geometry: geometry,
        attributes: {
            color: Cesium.ColorGeometryInstanceAttribute.fromColor(
                new Cesium.Color(1.0, 1.0, 1.0, 0.2)
            ),
        },
    });
    let primitive = new Cesium.Primitive({
        geometryInstances: instance,
        appearance: new Cesium.PerInstanceColorAppearance({
            closed: true,
            flat: true,
        }),
        asynchronous: false,
    });
    this.frustumPrimitive = viewer.scene.primitives.add(primitive);
}

// 创建视锥边框
CreateFrustum.prototype.addOutline = function () {
    let frustum = new Cesium.PerspectiveFrustum({
        fov: Cesium.Math.toRadians(this.fov),
        aspectRatio: this.aspectRatio,
        near: this.near,
        far: this.far,
    });
    let geometry = new Cesium.FrustumOutlineGeometry({
        frustum: frustum,
        origin: this.position,
        orientation: this.orientation,
        vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
    });
    let instance = new Cesium.GeometryInstance({
        geometry: geometry,
        attributes: {
            color: Cesium.ColorGeometryInstanceAttribute.fromColor(
                new Cesium.Color(0.0, 1.0, 1.0, 1.0)
            ),
        },
    });
    let primitive = new Cesium.Primitive({
        geometryInstances: instance,
        appearance: new Cesium.PerInstanceColorAppearance({
            closed: true,
            flat: true,
        }),
        asynchronous: false,
    });
    this.outlinePrimitive = viewer.scene.primitives.add(primitive);
}


完整代码


<!DOCTYPE html>
<html lang="en">
<head>
    <!-- Use correct character set. -->
    <meta charset="utf-8"/>
    <!-- Tell IE to use the latest, best version. -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
    <meta
            name="viewport"
            content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <title>Cesium entity frustum</title>
    <script src="http://openlayers.vip/examples/csdn/Cesium.js"></script>
    <script src="./cesium_init.js"></script>
    <script src="http://www.openlayers.vip/examples/resources/jquery-3.5.1.min.js"></script>
    <style>
        @import url(./Widgets/widgets.css);

        html,
        body,
        #cesiumContainer {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>

    <script>
        var _hmt = _hmt || [];
        (function () {
            var hm = document.createElement("script");
            hm.src = "https://hm.baidu.com/hm.js?f80a36f14f8a73bb0f82e0fdbcee3058";
            var s = document.getElementsByTagName("script")[0];
            s.parentNode.insertBefore(hm, s);
        })();
    </script>
</head>
<body>

<button id="clearFunc" onClick="clearFunc()">清空</button>
<button id="restoreFunc" onClick="addFrustum()">还原</button>

<div id="cesiumContainer"></div>
<script>

    // 创建三维球
    const viewer = init();

    // 定义创建四棱锥类
    function CreateFrustum(options) {
        // 位置点
        this.position = options.position;
        // 方向
        this.orientation = options.orientation;
        // 相机视场角
        this.fov = options.fov || 30;
        // 近距离点,0 则会显示四棱锥的顶点
        this.near = options.near || 10;
        // 远距离点
        this.far = options.far || 100;
        // 视锥的宽度/高度
        this.aspectRatio = options.aspectRatio;
        this.add();
    }

    CreateFrustum.prototype.add = function add() {
        this.clear();
        this.addFrustum();
        this.addOutline();
    }

    CreateFrustum.prototype.update = function (position, orientation) {
        this.position = position;
        this.orientation = orientation;
        this.add();
    }

    CreateFrustum.prototype.clear = function () {
        this.clearFrustum();
        this.clearOutline();
    }

    CreateFrustum.prototype.clearFrustum = function () {
        if (this.frustumPrimitive) {
            viewer.scene.primitives.remove(this.frustumPrimitive);
            this.frustumPrimitive = null;
        }
    }

    CreateFrustum.prototype.clearOutline = function () {
        if (this.outlinePrimitive) {
            viewer.scene.primitives.remove(this.outlinePrimitive);
            this.outlinePrimitive = null;
        }
    }

    // 创建视锥体
    CreateFrustum.prototype.addFrustum = function () {
        // 创建视锥
        let frustum = new Cesium.PerspectiveFrustum({
            fov: Cesium.Math.toRadians(this.fov),
            aspectRatio: this.aspectRatio,
            near: this.near,
            far: this.far,
        });
        // 创建视锥几何数据
        let geometry = new Cesium.FrustumGeometry({
            frustum: frustum,
            origin: this.position,
            orientation: this.orientation,
            vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
        });
        // 创建实例
        let instance = new Cesium.GeometryInstance({
            geometry: geometry,
            attributes: {
                color: Cesium.ColorGeometryInstanceAttribute.fromColor(
                    new Cesium.Color(1.0, 1.0, 1.0, 0.2)
                ),
            },
        });
        let primitive = new Cesium.Primitive({
            geometryInstances: instance,
            appearance: new Cesium.PerInstanceColorAppearance({
                closed: true,
                flat: true,
            }),
            asynchronous: false,
        });
        this.frustumPrimitive = viewer.scene.primitives.add(primitive);
    }

    // 创建视锥边框
    CreateFrustum.prototype.addOutline = function () {
        let frustum = new Cesium.PerspectiveFrustum({
            fov: Cesium.Math.toRadians(this.fov),
            aspectRatio: this.aspectRatio,
            near: this.near,
            far: this.far,
        });
        let geometry = new Cesium.FrustumOutlineGeometry({
            frustum: frustum,
            origin: this.position,
            orientation: this.orientation,
            vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
        });
        let instance = new Cesium.GeometryInstance({
            geometry: geometry,
            attributes: {
                color: Cesium.ColorGeometryInstanceAttribute.fromColor(
                    new Cesium.Color(0.0, 1.0, 1.0, 1.0)
                ),
            },
        });
        let primitive = new Cesium.Primitive({
            geometryInstances: instance,
            appearance: new Cesium.PerInstanceColorAppearance({
                closed: true,
                flat: true,
            }),
            asynchronous: false,
        });
        this.outlinePrimitive = viewer.scene.primitives.add(primitive);
    }

    let createFrustum, stopAnimation;
    function addFrustum() {
        stopAnimation = undefined;
        // 创建视点
        let origin = Cesium.Cartesian3.fromDegrees(120, 30, 1000000);

        let heading = 340;
        let pitch = 0;
        let roll = 130;

        let hpr = new Cesium.HeadingPitchRoll(
            Cesium.Math.toRadians(heading), pitch, Cesium.Math.toRadians(roll));

        let orientation = Cesium.Quaternion.fromHeadingPitchRoll(hpr);

        // 创建视锥体
        createFrustum = new CreateFrustum({
            position: origin,
            orientation: orientation,
            fov: 20,
            near: 1,
            far: 1000000,
            aspectRatio: 1080 / 1080,
        });

        let flag = false;

        // 创建视锥动画
        function Animation(){

            if(stopAnimation){
                return;
            }

            if (flag) {
                roll += 0.2;
            } else {
                roll -= 0.2;
            }

            // 设置角度范围
            if (roll < 125) {
                flag = true;
            } else if (roll > 135) {
                flag = false;
            }

            // 修改视锥姿态
            hpr = new Cesium.HeadingPitchRoll(heading, pitch, Cesium.Math.toRadians(roll))
            orientation = Cesium.Quaternion.fromHeadingPitchRoll(hpr);
            createFrustum.update(origin, orientation);
            requestAnimationFrame(Animation)
        }

        requestAnimationFrame(Animation)

        // 视角定位
        viewer.camera.flyTo({
            destination: origin,
        });
    }

    addFrustum();

    function clearFunc(){
        createFrustum && createFrustum.clear();
        createFrustum = undefined;
        stopAnimation = true;
    }

</script>
</body>
</html>

在这里插入图片描述


在线示例

Cesium 视椎体 Frustum

文章来源:https://blog.csdn.net/linzi19900517/article/details/134922660
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。