zoukankan      html  css  js  c++  java
  • shader之cesium飞线

    shader之cesium飞线入门

    cesium中的飞线效果的原理:

    1.通过算法获取到地球上两点之间的抛物线点集合。抛物线算法参考:https://www.cnblogs.com/s313139232/p/12804809.html

    2.通过抛物线点击创建线对象加入地球

    3.编写shader材质对象:PolylineMaterialAppearance

    4.编写顶点着色器、片元着色器

    基础飞线完整代码:

    <template>
        <div class="earthSence">
            <!-- 地图 -->
            <div id="earthContainer"></div>
        </div>
    </template>
    
    <script>
    import { mapUrl } from '@/config'
    export default {
        name: 'flyline',
        data() {
            return {
                _earth: {},
                _viewer: {}
            }
        },
        mounted() {
            XE.ready().then(() => {
                this.initMap()
            })
        },
        methods: {
            // 初始化earthSDK地图
            initMap() {
                //创建viewer实例
                Cesium.Ion.defaultAccessToken =
                    'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI2N2UwZWU2Zi1jN2UzLTQ3YTAtOTZmNC05MzNkM2IxZDViMzgiLCJpZCI6MjY1MzgsInNjb3BlcyI6WyJhc3IiLCJnYyJdLCJpYXQiOjE1ODc5MDQ0NTF9.lLpxvsIwB9Se5GeINW-jp5nm406S7KVWMdvH8swDHQ4'
                this.viewer = new Cesium.Viewer('earthContainer', {
                    geocoder: false, // 隐藏搜索
                    homeButton: false, // 隐藏主页
                    sceneModePicker: false, // 隐藏二三维转换
                    baseLayerPicker: false, // 隐藏图层选择控件
                    navigationHelpButton: false, // 隐藏帮助按钮
                    animation: false, // 隐藏时钟
                    timeline: false, // 隐藏时间轴
                    fullscreenButton: false, // 隐藏全屏
                    vrButton: false, // 隐藏双屏模式
                    infoBox: false, // 隐藏点击 entity 信息框
                    selectionIndicator: false, // 隐藏点击 entity 绿框
                    shouldAnimate: true,
                    // 设置底图
                    imageryProvider: new Cesium.UrlTemplateImageryProvider({
                        url: mapUrl,
                        style: 'default',
                        format: 'image/png'
                    })
                })
    
                // 定位到全国
                // 中国坐标
                let chinaPosition = Cesium.Cartesian3.fromDegrees(
                    113.41726298378288,
                    10.290411251106182,
                    7000000.0
                )
                this.viewer.camera.flyTo({
                    destination: chinaPosition,
                    // orientation: {
                    //     heading: Cesium.Math.toRadians(0.0),
                    //     pitch: Cesium.Math.toRadians(-25.0),
                    //     roll: 0.0
                    // },
                    duration: 1, // 飞行时间
                    offset: new Cesium.HeadingPitchRange(
                        0.0,
                        Cesium.Math.toRadians(-20.0)
                    ) // 偏移量
                })
                
                this.addFlyline()
            },
            // 根据经纬度、高计算飞线数据
            // 参数: [126.957, 45.547],[120.28429, 31.52853],50
            computeFlyline(
                point1 = [126.957, 45.547],
                point2 = [120.28429, 31.52853],
                h = 500000
            ) {
                let flyline = getBSRxyz(...point1, ...point2, h)
                return flyline
                // 将数据转换为cesium polyline positions格式
                function getBSRxyz(x1, y1, x2, y2, h) {
                    let arr3d = getBSRPoints(x1, y1, x2, y2, h)
                    let arrAll = []
                    for (let ite of arr3d) {
                        arrAll.push(ite[0])
                        arrAll.push(ite[1])
                        arrAll.push(ite[2])
                    }
                    return Cesium.Cartesian3.fromDegreesArrayHeights(arrAll)
                }
                function getBSRPoints(x1, y1, x2, y2, h) {
                    let point1 = [y1, 0]
                    let point2 = [(y2 + y1) / 2, h]
                    let point3 = [y2, 0]
                    let arr = getBSR(point1, point2, point3)
                    let arr3d = []
                    for (let i = 0;  i< arr.length; i++) {
                        let x = ((x2 - x1) * (arr[i][0] - y1)) / (y2 - y1) + x1
                        arr3d.push([x, arr[i][0], arr[i][1]])
                    }
                    return arr3d
                }
                // 生成贝塞尔曲线
                function getBSR(point1, point2, point3) {
                    var ps = [
                        { x: point1[0], y: point1[1] },
                        { x: point2[0], y: point2[1] },
                        { x: point3[0], y: point3[1] }
                    ]
                    // 100 每条线由100个点组成
                    let guijipoints = CreateBezierPoints(ps, 100)
                    return guijipoints
                }
                // 贝赛尔曲线算法
                // 参数:
                // anchorpoints: [{ x: 116.30, y: 39.60 }, { x: 37.50, y: 40.25 }, { x: 39.51, y: 36.25 }]
                function CreateBezierPoints(anchorpoints, pointsAmount) {
                    var points = []
                    for (var i = 0; i < pointsAmount; i++) {
                        var point = MultiPointBezier(anchorpoints, i / pointsAmount)
                        points.push([point.x, point.y])
                    }
                    return points
                }
                function MultiPointBezier(points, t) {
                    var len = points.length
                    var x = 0,
                        y = 0
                    var erxiangshi = function(start, end) {
                        var cs = 1,
                            bcs = 1
                        while (end > 0) {
                            cs *= start
                            bcs *= end
                            start--
                            end--
                        }
                        return cs / bcs
                    }
                    for (var i = 0; i < len; i++) {
                        var point = points[i]
                        x +=
                            point.x *
                            Math.pow(1 - t, len - 1 - i) *
                            Math.pow(t, i) *
                            erxiangshi(len - 1, i)
                        y +=
                            point.y *
                            Math.pow(1 - t, len - 1 - i) *
                            Math.pow(t, i) *
                            erxiangshi(len - 1, i)
                    }
                    return { x: x, y: y }
                }
            },
            // 编辑飞线材质
            getFlylineMaterial(){
                // 创建材质,在MaterialAppearance中若不添加基础材质,模型将会透明
                var material = new Cesium.Material.fromType('Color')
                material.uniforms.color = Cesium.Color.ORANGE
                // 飞线效果-飞线间隔,宽度2
                let fragmentShaderSource = `         
                            varying vec2 v_st;    
                            varying float v_width;    
                            varying float v_polylineAngle;
                            varying vec4 v_positionEC;
                            varying vec3 v_normalEC;
                            void main()
                            {
                                vec2 st = v_st;
    
                                float xx = fract(st.s - czm_frameNumber/60.0);
                                float r = xx;
                                float g = 0.0;
                                float b = 0.0;
                                float a = xx;
    
                                gl_FragColor = vec4(r,g,b,a);
                            }
    
                    `
                // 自定义材质
                const aper = new Cesium.PolylineMaterialAppearance({
                    material: material,
                    translucent: true,
                    vertexShaderSource: `
                            #define CLIP_POLYLINE 
                            void clipLineSegmentToNearPlane(
                                vec3 p0,
                                vec3 p1,
                                out vec4 positionWC,
                                out bool clipped,
                                out bool culledByNearPlane,
                                out vec4 clippedPositionEC)
                            {
                                culledByNearPlane = false;
                                clipped = false;
                                vec3 p0ToP1 = p1 - p0;
                                float magnitude = length(p0ToP1);
                                vec3 direction = normalize(p0ToP1);
                                float endPoint0Distance =  czm_currentFrustum.x + p0.z;
                                float denominator = -direction.z;
                                if (endPoint0Distance > 0.0 && abs(denominator) < czm_epsilon7)
                                {
                                    culledByNearPlane = true;
                                }
                                else if (endPoint0Distance > 0.0)
                                {
                                    float t = endPoint0Distance / denominator;
                                    if (t < 0.0 || t > magnitude)
                                    {
                                        culledByNearPlane = true;
                                    }
                                    else
                                    {
                                        p0 = p0 + t * direction;
                                        p0.z = min(p0.z, -czm_currentFrustum.x);
                                        clipped = true;
                                    }
                                }
                                clippedPositionEC = vec4(p0, 1.0);
                                positionWC = czm_eyeToWindowCoordinates(clippedPositionEC);
                            }
                            vec4 getPolylineWindowCoordinatesEC(vec4 positionEC, vec4 prevEC, vec4 nextEC, float expandDirection, float width, bool usePrevious, out float angle)
                            {
                                #ifdef POLYLINE_DASH
                                vec4 positionWindow = czm_eyeToWindowCoordinates(positionEC);
                                vec4 previousWindow = czm_eyeToWindowCoordinates(prevEC);
                                vec4 nextWindow = czm_eyeToWindowCoordinates(nextEC);
                                vec2 lineDir;
                                if (usePrevious) {
                                    lineDir = normalize(positionWindow.xy - previousWindow.xy);
                                }
                                else {
                                    lineDir = normalize(nextWindow.xy - positionWindow.xy);
                                }
                                angle = atan(lineDir.x, lineDir.y) - 1.570796327;
                                angle = floor(angle / czm_piOverFour + 0.5) * czm_piOverFour;
                                #endif
                                vec4 clippedPrevWC, clippedPrevEC;
                                bool prevSegmentClipped, prevSegmentCulled;
                                clipLineSegmentToNearPlane(prevEC.xyz, positionEC.xyz, clippedPrevWC, prevSegmentClipped, prevSegmentCulled, clippedPrevEC);
                                vec4 clippedNextWC, clippedNextEC;
                                bool nextSegmentClipped, nextSegmentCulled;
                                clipLineSegmentToNearPlane(nextEC.xyz, positionEC.xyz, clippedNextWC, nextSegmentClipped, nextSegmentCulled, clippedNextEC);
                                bool segmentClipped, segmentCulled;
                                vec4 clippedPositionWC, clippedPositionEC;
                                clipLineSegmentToNearPlane(positionEC.xyz, usePrevious ? prevEC.xyz : nextEC.xyz, clippedPositionWC, segmentClipped, segmentCulled, clippedPositionEC);
                                if (segmentCulled)
                                {
                                    return vec4(0.0, 0.0, 0.0, 1.0);
                                }
                                vec2 directionToPrevWC = normalize(clippedPrevWC.xy - clippedPositionWC.xy);
                                vec2 directionToNextWC = normalize(clippedNextWC.xy - clippedPositionWC.xy);
                                if (prevSegmentCulled)
                                {
                                    directionToPrevWC = -directionToNextWC;
                                }
                                else if (nextSegmentCulled)
                                {
                                    directionToNextWC = -directionToPrevWC;
                                }
                                vec2 thisSegmentForwardWC, otherSegmentForwardWC;
                                if (usePrevious)
                                {
                                    thisSegmentForwardWC = -directionToPrevWC;
                                    otherSegmentForwardWC = directionToNextWC;
                                }
                                else
                                {
                                    thisSegmentForwardWC = directionToNextWC;
                                    otherSegmentForwardWC =  -directionToPrevWC;
                                }
                                vec2 thisSegmentLeftWC = vec2(-thisSegmentForwardWC.y, thisSegmentForwardWC.x);
                                vec2 leftWC = thisSegmentLeftWC;
                                float expandWidth = width * 0.5;
                                if (!czm_equalsEpsilon(prevEC.xyz - positionEC.xyz, vec3(0.0), czm_epsilon1) && !czm_equalsEpsilon(nextEC.xyz - positionEC.xyz, vec3(0.0), czm_epsilon1))
                                {
                                    vec2 otherSegmentLeftWC = vec2(-otherSegmentForwardWC.y, otherSegmentForwardWC.x);
                                    vec2 leftSumWC = thisSegmentLeftWC + otherSegmentLeftWC;
                                    float leftSumLength = length(leftSumWC);
                                    leftWC = leftSumLength < czm_epsilon6 ? thisSegmentLeftWC : (leftSumWC / leftSumLength);
                                    vec2 u = -thisSegmentForwardWC;
                                    vec2 v = leftWC;
                                    float sinAngle = abs(u.x * v.y - u.y * v.x);
                                    expandWidth = clamp(expandWidth / sinAngle, 0.0, width * 2.0);
                                }
                                vec2 offset = leftWC * expandDirection * expandWidth * czm_pixelRatio;
                                return vec4(clippedPositionWC.xy + offset, -clippedPositionWC.z, 1.0) * (czm_projection * clippedPositionEC).w;
                            }
                            vec4 getPolylineWindowCoordinates(vec4 position, vec4 previous, vec4 next, float expandDirection, float width, bool usePrevious, out float angle)
                            {
                                vec4 positionEC = czm_modelViewRelativeToEye * position;
                                vec4 prevEC = czm_modelViewRelativeToEye * previous;
                                vec4 nextEC = czm_modelViewRelativeToEye * next;
                                return getPolylineWindowCoordinatesEC(positionEC, prevEC, nextEC, expandDirection, width, usePrevious, angle);
                            }
    
                            attribute vec3 position3DHigh;
                            attribute vec3 position3DLow;
                            attribute vec3 prevPosition3DHigh;
                            attribute vec3 prevPosition3DLow;
                            attribute vec3 nextPosition3DHigh;
                            attribute vec3 nextPosition3DLow;
                            attribute vec2 expandAndWidth;
                            attribute vec2 st;
                            attribute float batchId;
    
                            varying float v_width;
                            varying vec2 v_st;
                            varying float v_polylineAngle;
                            
                            varying vec4 v_positionEC;
                            varying vec3 v_normalEC;
                            void main()
                            {
                            float expandDir = expandAndWidth.x;
                            float width = abs(expandAndWidth.y) + 0.5;
                            bool usePrev = expandAndWidth.y < 0.0;
    
                            vec4 p = czm_computePosition();
                            vec4 prev = czm_computePrevPosition();
                            vec4 next = czm_computeNextPosition();
                            
                            float angle;
                            vec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev, angle);
                            gl_Position = czm_viewportOrthographic * positionWC;
                            
                            v_width = width;
                            v_st.s = st.s;
                            v_st.t = st.t;
                            // v_st.t = czm_writeNonPerspective(st.t, gl_Position.w);
                            v_polylineAngle = angle;
    
    
                            
                            vec4 eyePosition = czm_modelViewRelativeToEye * p;
                            v_positionEC =  czm_inverseModelView * eyePosition;      // position in eye coordinates
                            //v_normalEC = czm_normal * normal;                         // normal in eye coordinates
                            }
    
                        `,
                    fragmentShaderSource: fragmentShaderSource
                })
                return aper;
            },
            // 创建飞线对象
            addFlyline() {
                // 创建长方体对象
                const PolylineGeometry = new Cesium.PolylineGeometry({
                    positions: this.computeFlyline(),
                     2,
                })
                const instance = new Cesium.GeometryInstance({
                    geometry: PolylineGeometry,
                    id: 'flyline',
                })
                let en = this.viewer.scene.primitives.add(
                    new Cesium.Primitive({
                        geometryInstances: [instance],
                        appearance: this.getFlylineMaterial(),
                        releaseGeometryInstances: false,
                        compressVertices: false,
                    })
                )
            }
        }
    }
    </script>
    
    <style scoped lang="scss">
    .earthSence {
        width: 100%;
        height: 100%;
        background: grey;
        overflow: hidden;
        position: relative;
        #earthContainer {
            width: 100%;
            height: 100%;
            overflow: hidden;
            position: absolute;
        }
    }
    </style>
    View Code

    注意事项:

    1.飞线的顶点着色器坐标系换算较为复杂。代码中的vertexShaderSource部分为cesium源码中附带的顶点着色器。后期增加了一些传参方法。

    用到的GLSL的API:

    attribute vec2 st;
    两个分量为 st.s: 飞线的长度(0~1)   st.t:   飞线的宽度(0~1)
    czm_frameNumber
    每帧都会自增,用于标识时间
    飞线效果列举:
    1.
    varying vec2 v_st;    
                            varying float v_width;    
                            varying float v_polylineAngle;
                            varying vec4 v_positionEC;
                            varying vec3 v_normalEC;
                            void main()
                            {
                                vec2 st = v_st;
    
                                float num = 4.0;
                                float xx = fract(st.s*num - czm_frameNumber/60.0);
                                float r = xx;
                                float g = 0.0;
                                float b = 0.0;
                                float a = xx;
                                if(fract(st.s*num/4.0 - czm_frameNumber/240.0)<0.75){
                                    a=0.0;
                                }
    
                                gl_FragColor = vec4(r,g,b,a);
                            }
    View Code

    2.

                            varying vec2 v_st;    
                            varying float v_width;    
                            varying float v_polylineAngle;
                            varying vec4 v_positionEC;
                            varying vec3 v_normalEC;
                            void main()
                            {
                                vec2 st = v_st;
    
                                // 七彩渐变飞线,宽度2
                                float xx = fract(st.s*2.0 - czm_frameNumber/60.0);
                                float r = xx;
                                float g = sin(czm_frameNumber/30.0);
                                float b = cos(czm_frameNumber/30.0);
                                float a = xx;
    
                                gl_FragColor = vec4(r,g,b,a);
                            }
    View Code

    3.

                            varying vec2 v_st;    
                            varying float v_width;    
                            varying float v_polylineAngle;
                            varying vec4 v_positionEC;
                            varying vec3 v_normalEC;
                            void main()
                            {
                                vec2 st = v_st;
                                
                                //卡巴斯基
                                float xx = sin(st.s*6.0 -czm_frameNumber/5.0) - cos(st.t*6.0);
                                float r = 0.0;
                                float g = xx;
                                float b = xx;
                                float a = xx;
    
                                gl_FragColor = vec4(r,g,b,a);
                            }
    View Code

    4.

    varying vec2 v_st;    
                            varying float v_width;    
                            varying float v_polylineAngle;
                            varying vec4 v_positionEC;
                            varying vec3 v_normalEC;
                            void main()
                            {
                                vec2 st = v_st;
                                // 箭头飞线,宽度 8
                                float xx = fract(st.s*10.0 + st.t  - czm_frameNumber/60.0);
                                if (st.t<0.5) {
                                    xx = fract(st.s*10.0 - st.t - czm_frameNumber/60.0);
                                }
                                float r = 0.0;
                                float g = xx;
                                float b = xx;
                                float a = xx;
    
                                // 飞线边框
                                if (st.t>0.8||st.t<0.2) {
                                    g = 1.0;
                                    b = 1.0;
                                    a = 0.4;
                                }
    
                                gl_FragColor = vec4(r,g,b,a);
                            }
    View Code

    钻研不易,转载请注明出处。。。。。。

  • 相关阅读:
    django QuerySet对象转换成字典对象
    HTTP请求中三种参数类型
    django开发中遇到的问题
    win7下mysql8.0.12解压缩版安装
    Django小部件
    程序员上班有什么提高效率的技巧?
    Android应用AsyncTask处理机制详解及源码分析
    Android常用工具类
    Android Volley解析
    Android 开发有哪些新技术出现?
  • 原文地址:https://www.cnblogs.com/s313139232/p/14349406.html
Copyright © 2011-2022 走看看