非科班Java出身GISer

非科班Java出身GISer

Cesium 实战教程 - 调整 3dtiles 倾斜摄影大小

之前由于误解遇到一个特殊的需求:

后来经过搜索、尝试,终于实现了需求。

但是,后来发现是误解需求了,甲方只是需要放大缩小地图,不需要改变倾斜摄影的比例。

不过也算是学习了一个功能,这里记录一下。

本文主要包括。


核心代码

这里介绍一下修改倾斜摄影比例缩放的方法。

由于 Cesium 近期版本变动,本文介绍的内容包含 Cesium 1.107.0 之前的版本以及之后的版本

两个版本最主要的区别是改变了 3dtile 的加载方式以及异步解析方式。

1. 1.107.0 以及之后的版本核心代码:

Cesium 实战教程 - 调整 3dtiles 倾斜摄影大小-LMLPHP

注意:await 关键字,需要在异步方法内使用!

比如:


async function addCesium3DTileset() {
    try {
        const tileset = await Cesium.Cesium3DTileset.fromUrl(url, options);

        viewer.scene.primitives.add(tileSet);
    } catch (error) {
        console.log(`Failed to load tileset: ${error}`);
    }
}

异步加载倾斜摄影核心代码:

这里注意:Cesium 沙盒中应该本身就是异步方法,因此可以直接使用。


// 获取倾斜摄影
// 注意,Cesium 1.107.0 及以后版本需要通过异步方式加载倾斜摄影
const tileSet = await Cesium.Cesium3DTileset.fromUrl("https://earthsdk.com/v/last/Apps/assets/dayanta/tileset.json");

// 创建倾斜摄影
viewer.scene.primitives.add(tileSet);

// 定位至倾斜摄影
viewer.zoomTo(tileSet, new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90), 0));

// 设置瓦片加载完成监听事件
tileSet.initialTilesLoaded.addEventListener(function () {

    // 获取倾斜摄影中心点
    const cartographic = Cesium.Cartographic.fromCartesian(tileSet.boundingSphere.center);
    // 获取表面坐标
    const surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height);

    // 记录局部坐标系
    scaleFrame = Cesium.Transforms.eastNorthUpToFixedFrame(surface);

    // 缩放
    if (scale) {
        // 获取比例四元数
        const _scale = Cesium.Matrix4.fromUniformScale(scale);
        // 记录比例四元数
        scaleMatrix4 = _scale.clone();
        Cesium.Matrix4.multiply(scaleFrame, _scale, scaleFrame);
    }

    // 倾斜摄影重新设置比例
    tileSet._root.transform = scaleFrame;


    // 添加参照点
    const entity = {
        point: new Cesium.PointGraphics({
            // 设置贴地
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            // 设置颜色
            color: Cesium.Color.fromCssColorString("#ff0033"),
            // 设置大小
            pixelSize: 30,
            // 设置外边框
            outlineColor: Cesium.Color.fromCssColorString("#ff0033"),
            // 外边框宽度
            outlineWidth: 1,
        }),
        position: surface
    };
    viewer.entities.add(entity);
});


2. 1.107.0 之前的版本核心代码:


// 初始化倾斜摄影
const tileSet = new Cesium.Cesium3DTileset({
    url: "https://earthsdk.com/v/last/Apps/assets/dayanta/tileset.json"
});

// 异步读取倾斜摄影数据,并进行修改
tileSet.readyPromise.then(function () {

    // 添加倾斜摄影到地球中
    viewer.scene.primitives.add(tileSet);

    // 定位
    viewer.flyTo(tileSet);

    // 获取倾斜摄影中心点
    const cartographic = Cesium.Cartographic.fromCartesian(tileSet.boundingSphere.center);
    const surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height);
    // 记录局部坐标系
    const m = Cesium.Transforms.eastNorthUpToFixedFrame(surface);

    // 缩放
    if (scale) {
        const _scale = Cesium.Matrix4.fromUniformScale(scale);
        Cesium.Matrix4.multiply(m, _scale, m);
    }

    tileSet._root.transform = m;

    //参照点
    const entity = {
        id: "test",
        point: new Cesium.PointGraphics({
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            color: Cesium.Color.fromCssColorString("#ff0033"),
            pixelSize: 30,
            outlineColor: Cesium.Color.fromCssColorString("#ff0033"),
            outlineWidth: 1,
        }),
        position: surface
    };
    viewer.entities.add(entity);
});



完整代码


<!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 model video</title>
    <link rel="stylesheet" href="./popup.css" type="text/css">
    <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>
    <script src="./CesiumPopup.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>
<div id="cesiumContainer"></div>
<script>


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

	// 初始化地球
const viewer = new Cesium.Viewer('cesiumContainer');

// 获取倾斜摄影
const tileSet = await Cesium.Cesium3DTileset.fromUrl("https://earthsdk.com/v/last/Apps/assets/dayanta/tileset.json");

// 创建倾斜摄影
viewer.scene.primitives.add(tileSet);

// 定位至倾斜摄影
viewer.zoomTo(tileSet, new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90), 0));


// 初始偏移参数
// 平移参数
const tx = 200;
const ty = 0;
const tz = -430;

// 旋转参数
const rx = 0;
const ry = 0;
const rz = 0;

// 初始比例
const scale = 1;

// 局部坐标系
let scaleFrame;

// 比例四元数
let scaleMatrix4;

// 设置瓦片加载完成监听事件
tileSet.initialTilesLoaded.addEventListener(function () {

    // 获取倾斜摄影中心点
    const cartographic = Cesium.Cartographic.fromCartesian(tileSet.boundingSphere.center);
    const surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height);

    // 记录局部坐标系
    scaleFrame = Cesium.Transforms.eastNorthUpToFixedFrame(surface);

    //平移
    const _tx = tx ? tx : 0;
    const _ty = ty ? ty : 0;
    const _tz = tz ? tz : 0;
    const tempTranslation = new Cesium.Cartesian3(_tx, _ty, _tz);
    const offset = Cesium.Matrix4.multiplyByPoint(scaleFrame, tempTranslation, new Cesium.Cartesian3(0, 0, 0));
    const translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
    tileSet.modelMatrix = Cesium.Matrix4.fromTranslation(translation);

    //旋转
    if (rx) {
        const mx = Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(rx));
        const rotate = Cesium.Matrix4.fromRotationTranslation(mx);
        Cesium.Matrix4.multiply(scaleFrame, rotate, scaleFrame);
    }

    if (ry) {
        const my = Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(ry));
        const rotate = Cesium.Matrix4.fromRotationTranslation(my);
        Cesium.Matrix4.multiply(scaleFrame, rotate, scaleFrame);
    }

    if (rz) {
        const mz = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(rz));
        const rotate = Cesium.Matrix4.fromRotationTranslation(mz);
        Cesium.Matrix4.multiply(scaleFrame, rotate, scaleFrame);
    }

    // 缩放
    if (scale) {
        const _scale = Cesium.Matrix4.fromUniformScale(scale);
        // 记录比例四元数
        scaleMatrix4 = _scale.clone();
        Cesium.Matrix4.multiply(scaleFrame, _scale, scaleFrame);
    }

    tileSet._root.transform = scaleFrame;


    // 参照点
    const entity = {
        point: new Cesium.PointGraphics({
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            color: Cesium.Color.fromCssColorString("#ff0033"),
            pixelSize: 30,
            outlineColor: Cesium.Color.fromCssColorString("#ff0033"),
            outlineWidth: 1,
        }),
        position: surface
    };
    viewer.entities.add(entity);
});


// 还原比例
function revertTransform(mtx4) {
    let inverse = Cesium.Matrix4.inverse(mtx4.clone(), new Cesium.Matrix4());
    Cesium.Matrix4.multiply(scaleFrame, inverse.clone(), scaleFrame);
}

// 默认缩放
const viewModel = {
    tileScale: 50,
};

// cesium 沙盒内置组件
Cesium.knockout.track(viewModel);
const toolbar = document.getElementById("toolbar");
Cesium.knockout.applyBindings(viewModel, toolbar);


Cesium.knockout
    .getObservable(viewModel, "tileScale")
    .subscribe(function (newValue) {
        console.log(newValue);
        // 缩放
        if (newValue) {
            // 修改后的比例
            const _scale = Cesium.Matrix4.fromUniformScale(parseFloat(newValue) / 50);
            // 还原模型比例
            revertTransform(scaleMatrix4);
            scaleMatrix4 = _scale.clone();
            // 设置模型比例
            Cesium.Matrix4.multiply(scaleFrame, _scale, scaleFrame);
        }
        tileSet._root.transform = scaleFrame;
    });

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


    

Cesium 实战教程 - 调整 3dtiles 倾斜摄影大小-LMLPHP


在线示例

Cesium 1.107.0 及以上版本调整模型大小(可手动调整模型大小)

Cesium 1.106.1 调整模型大小

Cesium 实战教程 - 调整 3dtiles 倾斜摄影大小-LMLPHP

08-05 15:45