Flight monitoring system based on HTML5 WebGL

On a business trip a few days ago, I saw the overhead monitoring panel on the plane. In addition to playing TV shows and commercials, I switched to a plane navigation monitoring system from time to time. I suddenly wanted to make an upgraded version of the monitoring system using HT for Web. The effect of the demo was okay, and it was sent to everyone to learn from each other.

img

demo(https://www.hightopo.com/demo/flight-monitor/)

Implementation process

Effect of walking through the clouds

In order to achieve the effect of traveling through the cloud of the aircraft, the first problem I encountered was the sense of layering of the aircraft flight, also known as the perspective effect. Here I used the cloud channel and the cloud background to flow at different speeds to create a A flying perspective effect.

The cloud I used to present the texture, but only the texture will block the sky and the aircraft, which greatly affects the look and feel of the aircraft, so I turned on the transparent sum of  the corresponding primitives  opacity . The cloud background and cloud channel set different transparency, not only increase In addition to the sense of hierarchy, people will also have the illusion that clouds are floating in front of their eyes.

The cloud channel uses a  ht.Polyline type. The channel zoom enlarges the Y-axis ratio to make the cloud channel have a larger vertical space. Setting the  reverse.flip back copy makes the cloud channel also show the texture inside, as if letting the aircraft shuttle in the sea of ​​clouds; cloud background With the  ht.Node type, only one face display is set to serve as the cloud background.

The overall cloud flow effect is offset realized by  offset, and the texture offset of the corresponding primitive or the corresponding primitive face is changed to achieve the effect of traveling through the aircraft cloud. The code is as follows:

var i = 1, 
    p = 0;
setInterval(() => {
    i -= 0.1; p += 0.005;
    clouds.s('shape3d.uv.offset', [i, 0]);
    cloudBackground.s('all.uv.offset', [p, 0]);
}, 100);

Bumping effect

Although the effect of traveling through the clouds of the aircraft is achieved, if the aircraft is flying straight, it will also reduce the real sense of flight. I believe that friends who have been flying must have encountered bumps caused by the airflow and often feel the aircraft flying. The climb and descent on the way, this is actually because the aircraft's route is not always fixed at a height, and sometimes it climbs and sometimes drops, so I used the  ht-animation.js  HT animation extension to achieve the aircraft bump effect, the code is as follows :

dm.enableAnimation(20);
plane.setAnimation({
    back1: {
        from: 0,
        to: 160,
        easing: 'Cubic.easeInOut',
        duration: 8000,
        next: "up1",
        onUpdate: function (value) {
            value = parseInt(value);
            var p3 = this.p3();
            this.p3(value, p3[1], p3[2]);
        }
    },
    //...省略相似
    start: ["back1"]
});

Limitation of the angle of view of the ball sector

After the flight effect was perfect, I encountered a more difficult problem at this time, because in fact, although I watched the plane shuttle in the sea of ​​clouds, but only flying in the channel, the background is actually only a plane texture, so when the perspective reaches a certain At this level, there will be a strong sense of violation and unreality, and a perspective restriction is needed to make the adjustment of the perspective just within a range.

Then the general perspective of restrictions is to limit the g3d  eye and  center , not really friends can see 3d manual hightopo official website, which has detailed instructions, I will not repeat them here; because the relationship between viewing angle, so I decided to fix  center the Location, the code is as follows:

g3d.addPropertyChangeListener(e => {
    // 固定中心点
    if (e.property === 'center') {
        e.newValue[0] = center[0];
        e.newValue[1] = center[1];
        e.newValue[2] = center[2];
    }
}

Then you will be  eye limited to a certain range and you ’re done. However, it ’s not that simple here. At first, I  eye limited it to a cubic space, but the interaction effect is not ideal. Considering the default interaction of g3d, the mouse drags when panning perspective transformation, in fact,  eye it is in with a  center spherical surface center of the sphere of sports, so I decided to dig a ball in from as  eye space constraints, that is fan-shaped ball, not quite understanding friends can refer to this chart:

img

There are a total of three parameters required for the viewing angle limit of the ball sector, which are the central reference axis, the angle formed by the central axis and the outer edge,  eye and  center the radius of the ball limit. The maximum and minimum limits are as follows:

function limitEye(g3d, eye, center, options) {
    var limitMaxL   = options.limitMaxL,
        limitMinL   = options.limitMinL,
        limitA      = options.limitA;

    g3d.addPropertyChangeListener(e => {
        // 固定中心点
        if (e.property === 'center') {
            e.newValue[0] = center[0];
            e.newValue[1] = center[1];
            e.newValue[2] = center[2];
        }
        // 限制视角
        if (e.property === 'eye') {
            var newEyeV = new ht.Math.Vector3(e.newValue),
                centerV = new ht.Math.Vector3(center),
                refEyeV = new ht.Math.Vector3(eye),
                refVector = refEyeV.clone().sub(centerV),
                newVector = newEyeV.clone().sub(centerV);

            if (centerV.distanceTo(newEyeV) > limitMaxL) {
                newVector.setLength(limitMaxL);
                e.newValue[0] = newVector.x;
                e.newValue[1] = newVector.y;
                e.newValue[2] = newVector.z;
            }
            if (centerV.distanceTo(newEyeV) < limitMinL) {
                newVector.setLength(limitMinL);
                e.newValue[0] = newVector.x;
                e.newValue[1] = newVector.y;
                e.newValue[2] = newVector.z;
            }
            if (newVector.angleTo(refVector) > limitA) {
                var oldLength = newVector.length(),
                    oldAngle  = newVector.angleTo(refVector),
                    refLength = oldLength * Math.cos(oldAngle),
                    vertVector,
                    realVector,
                    realEye;

                refVector.setLength(refLength);

                newEyeV = newVector.clone().add(centerV);
                refEyeV = refVector.clone().add(centerV);
                vertVector = newEyeV.clone().sub(refEyeV);
                vertLength = refLength * Math.tan(limitA);

                vertVector.setLength(vertLength);

                realVector = vertVector.clone().add(refEyeV).sub(centerV);

                realVector.setLength(oldLength);

                realEye = realVector.clone().add(centerV);

                // 防止移动角度大于 180 度,视角反转
                if (oldAngle > Math.PI / 2) {
                    realEye.negate();
                }

                e.newValue[0] = realEye.x;
                e.newValue[1] = realEye.y;
                e.newValue[2] = realEye.z;
            }  
        }
    })
}

img

Aircraft monitoring system

Of course, as a monitoring system, it is natural to have monitoring. Add a small map in the lower right corner and provide three modes, focusing on the aircraft, focusing on the flight trajectory and focusing the map, and controlling the flow effect of the flight trajectory according to the flight direction of the aircraft Focusing the aircraft will follow the movement of  fitDatathe aircraft, keeping the aircraft at the center of the mini map, the code is as follows:

var fitFlowP = function (e) {
    if (e.property === 'position' && e.data === plane) {
        mapGV.fitData(plane, false);
    }
};
buttonP.s({
    'interactive': true,
    'onClick': function (event, data, view, point, width, height) {
        map.a('fitDataTag', 'plane2D');
        mapGV.fitData(plane, false);
        mapDM.md(fitFlowP);
    }
});
buttonL.s({
    'interactive': true,
    'onClick': function (event, data, view, point, width, height) {
        mapDM.umd(fitFlowP);
        map.a('fitDataTag', 'flyLine');
        mapGV.fitData(flyLine, false);
    }
});
// ...省略

img

Increase the mouse to move to the corresponding position of the aircraft to prompt the name, double-click to display the information panel of the corresponding position of the aircraft and focus the angle of view on the panel, click anywhere on the aircraft to switch back to the aircraft flight mode and other effects.

![img](data:image/svg+xml;utf8,<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="720" height="360"></svg>)

Add a monitoring panel on the left to replace the double-click corresponding position mentioned above. This operation directly focuses on the information panel at the corresponding position. Here the button starts the interaction and adds the corresponding interaction logic. The code is as follows:

button_JC.s({
    'interactive': true,
    'onClick': function (event, data, view, point, width, height) {
        event.preventDefault();
        let g3d = G.g3d,
            g3dDM = G.g3d.dm();
        g3d.fireInteractorEvent({
            kind: 'doubleClickData',
            data: g3dDM.getDataByTag(data.getTag())
        })
    }
});
//...省略

img

Sky rendering effect

Since the monitoring system must be 24 hours of indiscriminate monitoring, this involves a problem. I can't always fly the plane from the blue sky in the middle of the night, which is very lack of authenticity, so there must be a The process of the sky from light to dark and then from dark to light, this process I tentatively to the two time periods 06: 00-06: 30 and 19: 00-19: 30.

The sky uses a  shape3d : 'sphere' spherical shape, wraps the entire scene, and then uses  reverse.flip back copying and  blend coloring. After that, the sky can be rendered to the color I want. If you change the light and dark of the sky according to time, just change the coloring value.

However, due to the different lighting conditions during the day and night, the intensity of the reflected light from the cloud is also different, which results in the difference between the cloud during the day and the night. Therefore, the opacity transparency of the texture of the cloud road and the cloud background must also be adjusted  .

if ((hour > 6 && hour < 19) || (hour == 6 && minutes >= 30)) {
    timePane && timePane.a({
        'morning.visible': false,
        'day.visible': true,
        'dusk.visible': false,
        'night.visible': false,
        'day.opacity': 1
    })
    skyBox.s({
        "shape3d.blend": 'rgb(127, 200, 240)',
    })
    cloudBackground.s({
        "back.opacity": 0.7,
    })
    clouds.s({
        "shape3d.opacity": 0.7,
    })
} else if ((hour < 6 || hour > 19) || (hour == 19 && minutes >= 30)) {
//...省略
} else if (hour == 6 && minutes < 15 ) {
//...省略
} else if (hour == 6 && minutes >= 15 && minutes < 30) {
//...省略
} else if (hour == 19 && minutes < 15) {
//...省略
} else if (hour == 19 && minutes >= 15 && minutes < 30) {
//...省略
}

img

Here I also added support for the time status icon in the upper right corner of the time panel, and increased the fading effect when the icon is switched, and added the function of clicking to switch to the next time status for the time panel status icon position.

In order to demonstrate the effect, I added the time double speed button. The following figure shows the change at 500 times the time flow rate:

img

to sum up

Through this demo, I found that there are many details in life that have not been noticed by people. There is the possibility of data visualization. In this era of big data, more possibilities are worth discovering. Do n’t be wrong about every worthy data. Visual details, not only can you better tap the potential of HT for Web, but also strengthen your comprehensive quality as a programmer.

Published 314 original articles · Like 138 · Visit 390,000+

Guess you like

Origin blog.csdn.net/u013161495/article/details/103835448