Cesium实现天际线分析(原生cesium加载supermapS3M数据)

一:天际线实现思路:

利用Cesium 的边缘检测和后期处理效果的叠加。即在地图上检测此视角下的地形边缘,叠加标价效果层,叠加针对边缘实例和前一个边缘效果层的标记进行颜色处理和纹理处理。

主要用到的就是Cesium 提供的 Post Processing 功能:对整个场景后期处理的功能,类似模型描边,夜视效果,云雨雾之类的都用到。

二:参考官网文档:

1.supermap:Skyline - SuperMap3D Documentation
2.ceisum:PostProcessStage - Cesium Documentation

三:参考博客文章:Cesium实战记录(五)天际线分析_cesium 天际线分析-CSDN博客

四:代码部分:

1.主要引用:
<script src="../../../Cesium-1.99/Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="../../../Cesium-1.99/Build/Cesium/Widgets/widgets.css">
<script type="text/javascript" src="../dist/SuperMap3D.js"></script>

<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
 2.样式和html部分:
<style>
     #cesiumContainer {
            width: 100vw;
            height: 100vh;
            overflow: hidden;
        }
        .map-tool {
            position: fixed;
            top: 20px;
            left: 20px;
            z-index: 999;
        }
        .map-tool button {
            margin-bottom: 10px;
            padding: 10px;
            background-color: #007bff;
            color: white;
            border: none;
            cursor: pointer;
        }
        #mapContainer {
            width: 600px; /* 调整为合适的宽度 */
            height: 400px; /* 调整为合适的高度 */
            position: absolute;
            top: 80px;
            left: 20px;
            z-index: 1000;
            display: none; /* 默认隐藏 */
        }
</style>
<div class="map-tool">
        <button onclick="openSkylineAnay()">打开天际线</button>
        <button onclick="closeSkylineAnay()">关闭天际线</button>
        <button onclick="show2DSkyline()">显示二维天际线</button>
    </div>
    <div id="cesiumContainer"></div>
    <div id="mapContainer"></div> 
3.js(最主要的是着色器渲染):
<script type="text/javascript">
        let viewer;
        let skylineAnayStages;
        let silhouette;
        let myChart;
        let mapContainer = document.getElementById('mapContainer');

        window.onload = function () {
            initMap();
            addS3M();
            // 延迟初始化 Skyline
            setTimeout(() => {
                if (!viewer.scene.skyline) {
                    viewer.scene.skyline = new SuperMap3D.Skyline(viewer.scene);
                }
                console.log(viewer.scene.skyline);
            }, 2000); // 延迟2秒
        };
        function initMap() {
            Cesium.Ion.defaultAccessToken = 'Your token'
            //初始化Cesium场景
            viewer = new Cesium.Viewer('cesiumContainer', {
               terrainProvider: Cesium.createWorldTerrain(),
               navigation: false,
               infoBox: false,
               selectionIndicator: false,
                terrainProvider: Cesium.createWorldTerrain({
                    requestVertexNormals: true,
                    requestWaterMask: true,
                })
            });
        }
        
        function addS3M() {
            // S3M 瓦片层的 URL
            var s3mUrl = 'your address';
    
            // S3M 瓦片层的选项
            var s3mOptions = {
                name: 'name'
            };

            // 地理边界
            var geoBounds = {
                bottom: 39.895410985427681,
                left: 116.42774386919061,
                right: 116.4844750738345,
                top: 39.932657418004872
            };

            // 添加 S3M 瓦片层到场景中
            var promise = viewer.scene.addS3MTilesLayerByScp(s3mUrl, s3mOptions);

            // 瓦片层加载成功后,飞行到指定区域
            promise.then(function(result) {
                viewer.camera.flyTo({
                    destination: Cesium.Rectangle.fromDegrees(
                        geoBounds.left,
                        geoBounds.bottom,
                        geoBounds.right,
                        geoBounds.top
                    ),
                    duration: 3.0
                });
            console.log('S3M 瓦片层成功加载', result);
            }).catch(function(error) {
                console.error('加载 S3M 瓦片层失败', error);
            });
        }

        function openSkylineAnay() {
            if (skylineAnayStages) {
                silhouette.enabled = true;
                return;
            }
            skylineAnayStages = viewer.scene.postProcessStages;
            let edgeDetection = Cesium.PostProcessStageLibrary.createEdgeDetectionStage();
            let postProccessStage = new Cesium.PostProcessStage({
                fragmentShader: 'uniform sampler2D colorTexture;' +
                    'uniform sampler2D depthTexture;' +
                    'varying vec2 v_textureCoordinates;' +
                    'void main(void) {' +
                    'float depth = czm_readDepth(depthTexture, v_textureCoordinates);' +
                    'vec4 color = texture2D(colorTexture, v_textureCoordinates);' +
                    'if (depth < 1.0 - 0.000001) {' +
                    'gl_FragColor = color;' +
                    '} else {' +
                    'gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);' +
                    '}' +
                    '}'
            });

            let postProccesStage_1 = new Cesium.PostProcessStage({
                fragmentShader: 'uniform sampler2D colorTexture;' +
                    'uniform sampler2D redTexture;' +
                    'uniform sampler2D silhouetteTexture;' +
                    'varying vec2 v_textureCoordinates;' +
                    'void main(void) {' +
                    'vec4 redcolor = texture2D(redTexture, v_textureCoordinates);' +
                    'vec4 silhouetteColor = texture2D(silhouetteTexture, v_textureCoordinates);' +
                    'vec4 color = texture2D(colorTexture, v_textureCoordinates);' +
                    'if (redcolor.r == 1.0) {' +
                    'gl_FragColor = mix(color, vec4(5.0, 0.0, 0.0, 1.0), silhouetteColor.a);' +
                    '} else {' +
                    'gl_FragColor = color;' +
                    '}' +
                    '}',
                uniforms: {
                    redTexture: postProccessStage.name,
                    silhouetteTexture: edgeDetection.name
                }
            });

            silhouette = new Cesium.PostProcessStageComposite({
                stages: [edgeDetection, postProccessStage, postProccesStage_1],
                inputPreviousStageTexture: false,
                uniforms: edgeDetection.uniforms
            });
            skylineAnayStages.add(silhouette);
        }

        function closeSkylineAnay() {
            if (silhouette) {
                silhouette.enabled = false;
            }
        }

        function show2DSkyline() {
            // 如果 Skyline 还未初始化,则进行初始化
            if (!viewer.scene.skyline) {
                viewer.scene.skyline = new SuperMap3D.Skyline(viewer.scene);
            }

            console.log(viewer.scene.skyline);

            if (!skylineAnayStages) {
                alert("请先打开天际线分析!");
                return;
            }

            // 获取二维天际线数据
            let object = viewer.scene.skyline.getSkyline2D();
            if (object) {
                // 使用 ECharts 绘制二维天际线
                if (myChart) {
                    myChart.dispose(); // 销毁旧的图表实例
                }

            myChart = echarts.init(mapContainer);
            let option = {
                backgroundColor: "rgba(73,139,156,0.9)",
                title: {
                    text: "二维天际线",
                },
                tooltip: {
                    trigger: "axis",
                },
                xAxis: [
                    {
                        type: "category",
                        boundaryGap: false,
                        data: object.x,
                        show: false,
                    },
                ],
                //遮挡率
                yAxis: [
                    {
                        type: "value",
                        min: 0,
                        max: 1,
                    },
                ],
                series: [
                    {
                        name: "",
                        type: "line",
                        data: object.y,
                    },
                ],
            };
            myChart.setOption(option);
            mapContainer.style.display = 'block'; // 显示图表容器
            } else {
                alert("无法获取二维天际线数据!");
            }
        }
      
    </script>
    </body>
    </html>

其中二维部分未能成功运行,具体原因可能是SuperMap3D 版本不支持这些功能或存在某些已知的bug,从两次console.log的返回信息来看,viewer.scene.skyline 对象在初始化时和在 show2DSkyline 函数中都是相同的。它在初始化时的状态和在 show2DSkyline 函数中是一样的,但缺少了一些关键的属性,比如 _depthBuffer, _command_lineCommand。这些缺失的属性可能导致 getSkyline2D 方法无法正常工作。

五:代码中需要自己添加和更改的地方:

1.Cesium.Ion.defaultAccessToken,可以在cesium官网申请,这里可以看:Cesium: The Platform for 3D Geospatial

2.var s3mUrl = 'your address',这里的三维服务可以在supermap iserver中找到,这里给出一个例子:

'https://www.supermapol.com/realspace/services/3D-CBD-2/rest/realspace/datas/Building@CBD/config'

下面的name字段改成:

'Building@CBD'

都弄完之后直接live server 就可以了。

六:运行结果展示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SteveJi666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值